Merge "msm: Update the kernel log messages"
diff --git a/AndroidKernel.mk b/AndroidKernel.mk
index 3684a3f..d97d3c3 100644
--- a/AndroidKernel.mk
+++ b/AndroidKernel.mk
@@ -5,7 +5,11 @@
 
 KERNEL_OUT := $(TARGET_OUT_INTERMEDIATES)/KERNEL_OBJ
 KERNEL_CONFIG := $(KERNEL_OUT)/.config
+ifeq ($(TARGET_KERNEL_APPEND_DTB), true)
+TARGET_PREBUILT_INT_KERNEL := $(KERNEL_OUT)/arch/arm/boot/zImage-dtb
+else
 TARGET_PREBUILT_INT_KERNEL := $(KERNEL_OUT)/arch/arm/boot/zImage
+endif
 KERNEL_HEADERS_INSTALL := $(KERNEL_OUT)/usr
 KERNEL_MODULES_INSTALL := system
 KERNEL_MODULES_OUT := $(TARGET_OUT)/lib/modules
diff --git a/Documentation/arm/msm/msm_smp2p.txt b/Documentation/arm/msm/msm_smp2p.txt
index 4f77614..77bfb50 100644
--- a/Documentation/arm/msm/msm_smp2p.txt
+++ b/Documentation/arm/msm/msm_smp2p.txt
@@ -128,8 +128,10 @@
   |                        section.                                           |
    ---------------------------------------------------------------------------
   | Feature      3 Bytes   Refer to Version                                   |
-  | flags                  and Feature Negotiation  Must be set to zero.      |
-  |                        section.                                           |
+  | flags                  and Feature Negotiation                            |
+  |                        section for details.                               |
+  |   bit 0                SSR_ACK Feature          Supported when set to 1   |
+  |   bits 1:31            Reserved                 Must be set to 0.         |
    ---------------------------------------------------------------------------
   | Entries      2 Bytes   Total number of          Must be 0 or greater.     |
   | Total                  entries.                                           |
@@ -137,7 +139,11 @@
   | Entries      2 Bytes   Number of valid          Must be between 0         |
   | Valid                  entries.                 and Entries Total.        |
    ---------------------------------------------------------------------------
-  | Reserved     4 Bytes   Reserved                 Must be set to 0.         |
+  | Flags        4 Bytes                                                      |
+  |   bit 0                RESTART_DONE             Toggle for every restart  |
+  |   bit 1                RESTART_ACK              Toggle to ACK remote      |
+  |                                                 RESTART_DONE              |
+  |   bits 2:31            Reserved                 Must be set to 0.         |
    ---------------------------------------------------------------------------
                            Table 1 - SMEM Item Header
 
@@ -299,6 +305,12 @@
        has changed.
     2) Compare Entries Valid to cached value.  If changed, initialize new entries.
 
+Security
+========
+Since the implementation resides in the kernel and does not expose interfaces
+to userspace, no security issues are anticipated.  The usage of separate SMEM
+items allows for future security enhancements in SMEM.
+
 Performance
 ===========
 No performance issues are anticipated as the signaling rate is expected to be
@@ -311,19 +323,18 @@
 
 To map an entry to the client, the client must add two nodes to the Device
 Tree:
-  1) A node that matches "qcom,smp2pgpio" to create the entry
-  2) A node that matches the client driver to provide the GPIO pin mapping
+    1) A node that matches "qcom,smp2pgpio" to create the entry
+    2) A node that matches the client driver to provide the GPIO pin mapping
 
-The details of the device tree entries are contained in the file
-Documentionat/devicetree/bindings/arm/msm/smp2p.txt.
-
+The details of the device tree entries for the GPIO interface are contained in
+the file Documentation/devicetree/bindings/gpio/gpio-smp2p.txt.
 
     /* SMP2P Test Driver for inbound entry. */
     smp2pgpio_smp2p_7_in: qcom,smp2pgpio-smp2p-7-in {
         compatible = "qcom,smp2pgpio";
         qcom,entry-name = "smp2p";
         qcom,remote-pid = <7>;
-        qcom,is_inbound;
+        qcom,is-inbound;
         gpio-controller;
         #gpio-cells = <2>;
         interrupt-controller;
@@ -374,6 +385,48 @@
 
 Please reference the unit test code for example usage.
 
+Subsystem Restart
+=================
+SMP2P is unaffected by SubSystem Restart (SSR) on the high-level OS side and is
+actually used as an underlying communication mechanism for SSR.  On the
+peripheral system that is being restarted, SMP2P will zero out all existing
+state entries upon reboot as part of the SMP2P initialization process and if the
+SSR_ACK feature is enabled, then it waits for an acknowledgement as outlined in
+the following subsections.
+
+SSR_ACK Feature - Reboot Use Case (Non-HLOS Only)
+-------------------------------------------------
+If a remote system boots up after an SSR and sees that the remote and local
+version numbers and feature flags are equal, then it zeros out entry values.  If
+the SSR_ACK feature is enabled, it will wait for an acknowledgement from the other
+processor that it has seen the zero entry before completing the negotiation
+sequence.
+
+    if remote and local version numbers and feature flags are equal
+        Zero out all entry values
+        if SSR_ACK feature is enabled
+            Set local RESTART_DONE flag to inverse of the remote RESTART_ACK
+            Send interrupt to remote system
+            Wait for interrupt and for remote RESTART_ACK to be equal to local
+            RESTART_DONE
+    Continue with normal negotiation sequence
+
+Interrupt Use Case
+------------------
+For every interrupt triggered by a remote change, SMP2P will notify the client
+of a change in state.  In addition, if the SSR_ACK feature is enabled, the SSR
+handshaking will also be handled.
+
+    if SSR_ACK feature is enabled
+        if remote RESTART_DONE != local RESTART_ACK
+            Notify client of entry change (will be * -> 0 transition)
+            Toggle local RESTART_ACK
+            Send interrupt to remote system
+        else
+            Notify client of entry change as usual
+    else
+        Notify client of entry change as usual
+
 Debug
 =====
 The state values and names for all entries accessible by the Apps are
@@ -395,12 +448,13 @@
 
 Config options
 ==============
-Configuration of interrupts will be done using Device Tree.  By default, the
-testing components will be enabled since it does not affect performance and has
-a minimal impact on kernel size.  However, customers can disable the testing
-components for size optimization.
+Configuration of interrupts will be done using Device Tree per the format in
+Documentation/devicetree/bindings/arm/msm/smp2p.txt.  By default, the testing
+components will be enabled since it does not affect performance and has a
+minimal impact on kernel size.  However, customers can disable the testing
+component for size optimization.
 
-    CONFIG_MSM_SMP2P - enables SMP2P core functionality
+    CONFIG_MSM_SMP2P - enables SMP2P
     CONFIG_MSM_SMP2P_TEST - enables unit test support
 
 Dependencies
diff --git a/Documentation/devicetree/bindings/arm/msm/cpr-regulator.txt b/Documentation/devicetree/bindings/arm/msm/cpr-regulator.txt
index b489f7a..a0b2f6d 100644
--- a/Documentation/devicetree/bindings/arm/msm/cpr-regulator.txt
+++ b/Documentation/devicetree/bindings/arm/msm/cpr-regulator.txt
@@ -22,16 +22,12 @@
 				should be 1 for SVS corner
 - regulator-max-microvolt:	Maximum corner value as max constraint, which
 				should be 4 for SUPER_TURBO or 3 for TURBO
-- qcom,pvs-bin-process:		A list of integers whose length is equal to 2 to
-				the power of qcom,pvs-fuse[num-of-bits]. The location or
-				0-based index of an element in the list corresponds
-				to the bin number. The value of each integer
-				corresponds to the PVS process speed of the APC
-				silicon for a chip with one of these cases:
-					1 = APC_PVS_SLOW
-					2 = APC_PVS_NOM
-					3 = APC_PVS_FAST
-					0 or other values = No PVS
+- qcom,pvs-init-voltage:  	A list of integers whose length is equal to 2
+				to the power of qcom,pvs-fuse[num-of-bits]. The
+				location or 0-based index of an element in the
+				list corresponds to the bin number. The value of
+				each integer corresponds to the initial voltage
+				of the PVS bin in turbo mode in microvolts.
 - qcom,pvs-corner-ceiling-slow:	Ceiling voltages of all corners for APC_PVS_SLOW
 - qcom,pvs-corner-ceiling-nom:	Ceiling voltages of all corners for APC_PVS_NOM
 - qcom,pvs-corner-ceiling-fast:	Ceiling voltages of all corners for APC_PVS_FAST
@@ -136,6 +132,8 @@
 					is present, and vise versa.
 - qcom,cpr-enable:		Present: CPR enabled by default.
 				Not Present: CPR disable by default.
+- qcom,use-tz-api:		Present: CPR reads efuse parameters through trustzone API.
+				Not Present: CPR reads efuse parameters directly.
 
 
 Example:
@@ -153,8 +151,14 @@
 		qcom,pvs-fuse-redun-sel = <22 24 3 2>;
 		qcom,pvs-fuse-redun = <22 27 5>;
 
-		qcom,pvs-bin-process = <0 0 0 0 0 1 1 1 1 1 2 2 2 2 2 2
-					2 2 2 2 3 3 3 3 3 3 3 3 0 0 0 0>;
+		qcom,pvs-init-voltage = <1330000 1330000 1330000 1320000
+						1310000 1300000 1290000 1280000
+						1270000 1260000 1250000 1240000
+						1230000 1220000 1210000 1200000
+						1190000 1180000 1170000 1160000
+						1150000 1140000 1140000 1140000
+						1140000 1140000 1140000 1140000
+						1140000 1140000 1140000 1140000>;
 		qcom,pvs-corner-ceiling-slow = <1050000 1160000 1275000>;
 		qcom,pvs-corner-ceiling-nom  =  <975000 1075000 1200000>;
 		qcom,pvs-corner-ceiling-fast =  <900000 1000000 1140000>;
diff --git a/Documentation/devicetree/bindings/arm/msm/msm_thermal.txt b/Documentation/devicetree/bindings/arm/msm/msm_thermal.txt
index d07eba6..3947f75 100644
--- a/Documentation/devicetree/bindings/arm/msm/msm_thermal.txt
+++ b/Documentation/devicetree/bindings/arm/msm/msm_thermal.txt
@@ -28,11 +28,21 @@
 			core can be used for freq control.
 - qcom,core-limit-temp: Threshold temperature to start shutting down cores
 			in degC
-- qcom,core-temp-hysterisis: Degrees C below which the cores will be brought
+- qcom,core-temp-hysteresis: Degrees C below which the cores will be brought
 			online in sequence.
 - qcom,core-control-mask: The cpu mask that will be used to determine if a
 			core can be controlled or not. A mask of 0 indicates
 			the feature is disabled.
+- qcom,hotplug-temp: Threshold temperature to start shutting down cores
+			in degC. This will be used when polling based
+			core control is disabled. The difference between hotplug-temp
+			and core-limit-temp is that core-limit-temp is used during
+			early boot prior to thermal_sys being available for hotplug.
+- qcom,hotplug-temp-hysteresis: Degrees C below which thermal will not force the
+			cores to be offlined. Cores can be brought online if needed.
+- qcpm,cpu-sensors:     List of type names in thermal zone device struct which maps
+			to cpu0, cpu1, cpu2, cpu3 in sequence depending on how many
+			cpus there are.
 - qcom,vdd-restriction-temp: When temperature is below this threshold, will
 			enable vdd restriction which will set higher voltage on
 			key voltage rails, in degC.
@@ -81,8 +91,12 @@
 		qcom,freq-step = <2>;
 		qcom,freq-control-mask = <0xf>
 		qcom,core-limit-temp = <90>;
-		qcom,core-temp-hysterisis = <10>;
+		qcom,core-temp-hysteresis = <10>;
 		qcom,core-control-mask = <7>;
+		qcom,hotplug-temp = <110>;
+		qcom,hotplug-temp-hysteresis = <20>;
+		qcom,cpu-sensors = "tsens_tz_sensor5", "tsens_tz_sensor6",
+				"tsens_tz_sensor7", "tsens_tz_sensor8";
 		qcom,pmic-sw-mode-temp = <90>;
 		qcom,pmic-sw-mode-temp-hysteresis = <80>;
 		qcom,pmic-sw-mode-regs = "vdd-dig";
diff --git a/Documentation/devicetree/bindings/arm/msm/rpm-master-stats.txt b/Documentation/devicetree/bindings/arm/msm/rpm-master-stats.txt
new file mode 100644
index 0000000..0239674
--- /dev/null
+++ b/Documentation/devicetree/bindings/arm/msm/rpm-master-stats.txt
@@ -0,0 +1,29 @@
+* RPM Master Stats
+
+RPM maintains each master data in RPM message RAM at a specific
+offset. It tells about the individual masters information at
+any given time like "number of active cores in sub system",
+"number of shutdowns" and "wakeup reason for SS" etc. These stats
+can be show to the user using the debugfs interface of the kernel.
+To achieve this device tree node has been added and it will hold
+the address of the RPM RAM from where master stats are read.
+Added version number to distinguish the type of data structure
+being read from the RAM for different targets.
+
+The required properties for rpm-master-stats are:
+
+- compatible: "qcom,rpm-master-stats".
+- reg: The address on the RPM RAM from where stats are read.
+- qcom,masters: Each master name.
+- qcom,master-offset: Offset required to access each master stats area.
+- qcom,master-stats-version: Version number.
+
+Example:
+
+qcom,rpm-stats@fc428150 {
+		compatible = "qcom,rpm-stats";
+		reg = <0xfc428150 0x1000>;
+		qcom,masters = "APSS", "MPSS", "LPSS", "PRONTO";
+		qcom,master-offset = <2560>;
+		qcom,master-stats-version = <2>;
+};
diff --git a/Documentation/devicetree/bindings/arm/msm/smdtty.txt b/Documentation/devicetree/bindings/arm/msm/smdtty.txt
new file mode 100644
index 0000000..f661b84
--- /dev/null
+++ b/Documentation/devicetree/bindings/arm/msm/smdtty.txt
@@ -0,0 +1,40 @@
+Qualcomm Shared Memory TTY Driver (smdtty)
+
+[Root level node]
+Required properties:
+-compatible : should be "qcom,smdtty"
+
+[Second level nodes]
+qcom,smdtty-port-names
+Required properties:
+-qcom,smdtty-remote: the remote subsystem name
+-qcom,smdtty-port-name : the smd channel name
+
+Optional properties:
+-qcom,smdtty-dev-name : the smdtty device name
+
+Required alias:
+- The index into TTY subsystem is specified via an alias with the following format
+         'smd{n}' where n is the tty device index.
+
+Example:
+	aliases {
+		smd1 = &smdtty_apps_fm;
+		smd36 = &smdtty_loopback;
+	};
+
+	qcom,smdtty {
+		compatible = "qcom,smdtty";
+
+		smdtty_apps_fm: qcom,smdtty-apps-fm {
+			qcom,smdtty-remote = "wcnss";
+			qcom,smdtty-port-name = "APPS_FM";
+		};
+
+		smdtty_loopback: smdtty-loopback {
+			qcom,smdtty-remote = "modem";
+			qcom,smdtty-port-name = "LOOPBACK";
+			qcom,smdtty-dev-name = "LOOPBACK_TTY";
+		};
+	};
+
diff --git a/Documentation/devicetree/bindings/arm/msm/spm-regulator.txt b/Documentation/devicetree/bindings/arm/msm/spm-regulator.txt
index c012eec..3c42ac4 100644
--- a/Documentation/devicetree/bindings/arm/msm/spm-regulator.txt
+++ b/Documentation/devicetree/bindings/arm/msm/spm-regulator.txt
@@ -12,6 +12,13 @@
 - A qcom,spm-regulator node must be a child of an SPMI node that has specified
 	the spmi-slave-container property
 
+Optional properties:
+- qcom,mode:       A string which specifies the mode to use for the regulator.
+		    Supported values are "pwm" and "auto".  PWM mode is more
+		    robust, but draws more current than auto mode.  If this
+		    property is not specified, then the regulator will remain
+		    in whatever mode hardware or bootloaders set it to.
+
 All properties specified within the core regulator framework can also be used.
 These bindings can be found in regulator.txt.
 
diff --git a/Documentation/devicetree/bindings/arm/msm/spm-v2.txt b/Documentation/devicetree/bindings/arm/msm/spm-v2.txt
index a2d8359..d9a0d59 100644
--- a/Documentation/devicetree/bindings/arm/msm/spm-v2.txt
+++ b/Documentation/devicetree/bindings/arm/msm/spm-v2.txt
@@ -42,6 +42,10 @@
 - qcom,saw2-spm-cmd-spc: The Standalone PC command sequence
 - qcom,saw2-spm-cmd-pc: The Power Collapse command sequence
 - qcom,saw2-spm-cmd-gdhs: L2 GDHS command sequence
+- qcom,L2-spm-is-apcs-master: Boolean indicates if the target uses L2 SAW to
+	control the gang rail. If this is not specified the driver assumes
+	that the cpus run with their own separate rails and each cpu's spm
+	talks to its regulator.
 
 Example:
 	qcom,spm@f9089000 {
diff --git a/Documentation/devicetree/bindings/batterydata/batterydata.txt b/Documentation/devicetree/bindings/batterydata/batterydata.txt
index 985fb4c..8fbb1bd 100644
--- a/Documentation/devicetree/bindings/batterydata/batterydata.txt
+++ b/Documentation/devicetree/bindings/batterydata/batterydata.txt
@@ -22,7 +22,10 @@
 - qcom,v-cutoff-uv : The cutoff voltage of the battery at which the device
 			should shutdown gracefully.
 - qcom,chg-term-ua : The termination charging current of the battery.
-- qcom,batt-id-kohm : The battery id resistance of the battery.
+- qcom,batt-id-kohm : The battery id resistance of the battery. It can be
+			used as an array which could support multiple IDs for one battery
+			module when the ID resistance of some battery modules goes across
+			several ranges.
 
 Profile data node required subnodes:
 - qcom,fcc-temp-lut : An 1-dimensional lookup table node that encodes
diff --git a/Documentation/devicetree/bindings/coresight/coresight.txt b/Documentation/devicetree/bindings/coresight/coresight.txt
index 7f7ee25..17ff3f0 100644
--- a/Documentation/devicetree/bindings/coresight/coresight.txt
+++ b/Documentation/devicetree/bindings/coresight/coresight.txt
@@ -95,16 +95,24 @@
 - coresight-ctis : list of ctis that this component interacts with
 - qcom,pc-save : program counter save implemented
 - qcom,blk-size : block size for tmc-etr to usb transfers
+- qcom,memory-size : size of coherent memory to be allocated for tmc-etr buffer
 - qcom,round-robin : indicates if per core etms are allowed round-robin access
 		     by the funnel
 - qcom,reset-flush-race : indicates if a race exists between flushing and ddr
 			  being put into self-refresh during watchdog reset
 - qcom,write-64bit : only 64bit data writes supported by stm
-- vdd-supply: phandle to the regulator device tree node. Used for tpiu component
-- qcom,vdd-voltage-level : specifies voltage level for vdd supply. Should be
-			   specified in pairs (min, max) with units being uV
-- qcom,vdd-current-level : specifies current load levels for vdd supply. Should
-			   be specified in paris (lpm, hpm) with units being uA
+- <supply-name>-supply: phandle to the regulator device tree node. The required
+			<supply-name> is "vdd" for SD card and "vdd-io" for SD
+			I/O supply. Used for tpiu component
+- qcom,<supply>-voltage-level : specifies voltage level for vdd supply. Should
+				be specified in pairs (min, max) with units
+				being uV. Here <supply> can be "vdd" for SD card
+				vdd supply or "vdd-io" for SD I/O vdd supply.
+- qcom,<supply>-current-level : specifies current load levels for vdd supply.
+				Should be specified in pairs (lpm, hpm) with
+				units being uA. Here <supply> can be "vdd" for
+				SD card vdd supply or "vdd-io" for SD I/O vdd
+				supply.
 - qcom,seta-gpios : specifies gpios included in set A that are routed to the
 		    mictor connector. Used for tpiu component
 - qcom,seta-gpios-func : active function select for set A gpios
@@ -138,6 +146,7 @@
 		interrupt-names = "byte-cntr-irq";
 
 		qcom,byte-cntr-absent;
+		qcom,memory-size = <0x100000>;
 
 		coresight-id = <0>;
 		coresight-name = "coresight-tmc-etr";
diff --git a/Documentation/devicetree/bindings/dma/sps/sps.txt b/Documentation/devicetree/bindings/dma/sps/sps.txt
index a979c56..26102c8 100644
--- a/Documentation/devicetree/bindings/dma/sps/sps.txt
+++ b/Documentation/devicetree/bindings/dma/sps/sps.txt
@@ -7,7 +7,11 @@
   - compatible: should be "qcom,msm_sps"
 
 Optional properties:
-  - reg: offset and size of the register set in the memory map
+  - reg: offset and size for the memory mapping, including maps for
+    BAM DMA BAM, BAM DMA peripheral, pipe memory and reserved memory.
+  - reg-names: indicates various resources passed to driver (via reg
+    property) by name. "reg-names" examples are "bam_mem", "core_mem"
+    , "pipe_mem" and "res_mem".
   - interrupts: IRQ line
   - qcom,device-type: specify the device configuration of BAM DMA and
     pipe memory. Can be one of
diff --git a/Documentation/devicetree/bindings/fb/mdss-dsi-ctrl.txt b/Documentation/devicetree/bindings/fb/mdss-dsi-ctrl.txt
index 4cec0cd..7187908 100644
--- a/Documentation/devicetree/bindings/fb/mdss-dsi-ctrl.txt
+++ b/Documentation/devicetree/bindings/fb/mdss-dsi-ctrl.txt
@@ -12,6 +12,7 @@
 - vdda-supply:				Phandle for vreg regulator device node.
 - qcom,mdss-fb-map:			pHandle that specifies the framebuffer to which the
 					interface is mapped.
+- qcom,mdss-mdp:			pHandle that specifies the mdss-mdp device.
 - qcom,platform-regulator-settings:	An array of length 7 that specifies the PHY
 					regulator settings.
 - qcom,platform-strength-ctrl:		An array of length 2 that specifies the PHY
@@ -20,6 +21,8 @@
 					BIST ctrl settings.
 - qcom,platform-lane-config:		An array of length 45 that specifies the PHY
 					lane configuration settings.
+- qcom,dsi-pref-prim-pan:		phandle that specifies the primary panel to be used
+					with the controller.
 
 Optional properties:
 - label:		        	A string used to describe the controller used.
@@ -41,6 +44,8 @@
 - qcom,platform-enable-gpio:		Specifies the panel lcd/display enable gpio.
 - qcom,platform-reset-gpio:		Specifies the panel reset gpio.
 - qcom,platform-te-gpio:		Specifies the gpio used for TE.
+- qcom,platform-mode-gpio:		Select video/command mode of panel through gpio when it supports
+					both modes.
 - qcom,platform-reset-sequence:		An array that lists the
 					sequence of reset gpio values and sleeps
 					Each command will have the format defined
@@ -57,6 +62,7 @@
 		vdd-supply = <&pm8226_l15>;
 		vddio-supply = <&pm8226_l8>;
 		vdda-supply = <&pm8226_l4>;
+		qcom,dsi-pref-prim-pan = <&dsi_tosh_720_vid>;
 		qcom,platform-strength-ctrl = [ff 06];
 		qcom,platform-bist-ctrl = [00 00 b1 ff 00 00];
 		qcom,platform-regulator-settings = [07 09 03 00 20 00 01];
@@ -66,9 +72,11 @@
 			00 00 00 00 0f 00 00 01 97
 			00 c0 00 00 00 00 00 01 bb];
 		qcom,mdss-fb-map = <&mdss_fb0>;
+		qcom,mdss-mdp = <&mdss_mdp>;
 		qcom,platform-reset-gpio = <&msmgpio 25 1>;
 		qcom,platform-te-gpio = <&msmgpio 24 0>;
 		qcom,platform-enable-gpio = <&msmgpio 58 1>;
+		qcom,platform-mode-gpio = <&msmgpio 7 0>;
 		qcom,platform-reset-sequence = <1 25 0 20 1 10>;
 		qcom,platform-supply-entry1 {
 			qcom,supply-name = "vdd";
diff --git a/Documentation/devicetree/bindings/fb/mdss-dsi-panel.txt b/Documentation/devicetree/bindings/fb/mdss-dsi-panel.txt
index 44134f8..9ad8abe 100644
--- a/Documentation/devicetree/bindings/fb/mdss-dsi-panel.txt
+++ b/Documentation/devicetree/bindings/fb/mdss-dsi-panel.txt
@@ -4,14 +4,23 @@
 are compatable with MIPI display serial interface specification.
 
 Required properties:
-- compatible:				Specifies the version for DSI HW. that
-					this panel will be worked with
-					"qcom,mdss-dsi-panel" = DSI v6.0
+- compatible:				This property applies to DSI V2 panels only.
+					This property should not be added for panels
+					that work based on version "V6.0"
+					DSI panels that are of different versions
+					are initialized by the drivers for dsi controller.
+					This property specifies the version
+					for DSI HW that this panel will work with
 					"qcom,dsi-panel-v2" = DSI V2.0
-- status:        			A string that has to be set to "okay/ok" to enable
-					the panel driver. By default this property will be
-					set to "disable". Will be set to "ok/okay" status
-					for specific platforms.
+- status:        			This property applies to DSI V2 panels only.
+					This property should not be added for panels
+					that work based on version "V6.0"
+					DSI panels that are of different versions
+					are initialized by the drivers for dsi controller.
+					A string that has to be set to "okay/ok"
+					to enable the panel driver. By default this property
+					will be set to "disable". Will be set to "ok/okay"
+					status for specific platforms.
 - qcom,mdss-dsi-panel-controller:	Specifies the phandle for the DSI controller that
 					this panel will be mapped to.
 - qcom,mdss-dsi-panel-width:		Specifies panel width in pixels.
@@ -215,17 +224,23 @@
 - qcom,mdss-dsi-off-command-state:	String that specifies the ctrl state for sending OFF commands.
 					"dsi_lp_mode" = DSI low power mode (default)
 					"dsi_hs_mode" = DSI high speed mode
+- qcom,mdss-pan-physical-width-dimension:	Specifies panel physical width in mm which corresponds
+					to the physical width in the framebuffer information.
+- qcom,mdss-pan-physical-height-dimension:	Specifies panel physical height in mm which corresponds
+					to the physical height in the framebuffer information.
+- qcom,mdss-dsi-panel-mode-gpio-state:	String that specifies the mode state for panel if it is defined
+					in dsi controller.
+					"high" = Set GPIO to HIGH
+					"low" = Set GPIO to LOW
 
 
 Note, if a given optional qcom,* binding is not present, then the driver will configure
 the default values specified.
 
 Example:
-&soc {
-	qcom,mdss_dsi_sim_video {
-		compatible = "qcom,mdss-dsi-panel";
+&mdss_mdp {
+	dsi_sim_vid: qcom,mdss_dsi_sim_video {
 		qcom,mdss-dsi-panel-name = "simulator video mode dsi panel";
-		status = "disable";
 		qcom,mdss-dsi-panel-controller = <&mdss_dsi0>;
 		qcom,mdss-dsi-panel-height = <1280>;
 		qcom,mdss-dsi-panel-width = <720>;
@@ -303,5 +318,8 @@
 		qcom,mdss-dsi-bl-pmic-bank-select = <0>;
 		qcom,mdss-dsi-bl-pmic-pwm-frequency = <0>;
 		qcom,mdss-dsi-pwm-gpio = <&pm8941_mpps 5 0>;
+		qcom,mdss-pan-physical-width-dimension = <60>;
+		qcom,mdss-pan-physical-height-dimension = <140>;
+		qcom,mdss-dsi-panel-mode-gpio-state = "low";
 	};
 };
diff --git a/Documentation/devicetree/bindings/fb/mdss-mdp.txt b/Documentation/devicetree/bindings/fb/mdss-mdp.txt
index 7ba9a88..829cce2 100644
--- a/Documentation/devicetree/bindings/fb/mdss-mdp.txt
+++ b/Documentation/devicetree/bindings/fb/mdss-mdp.txt
@@ -94,7 +94,16 @@
 				The offsets are calculated from "mdp_phys"
 				defined in reg property. The number of offsets
 				defiend should reflect the number of progammable
-				interface blocks avaialble in hardware.
+				interface blocks available in hardware.
+- qcom,mdss-pref-prim-intf:	A string which indicates the configured hardware
+				interface between MDP and the primary panel.
+				Individual panel controller drivers initialize
+				hardware based on this property.
+				Based on the interfaces supported at present,
+				possible values are:
+				- "dsi"
+				- "edp"
+				- "hdmi"
 
 Optional properties:
 - qcom,vbif-settings :	Array with key-value pairs of constant VBIF register
@@ -156,7 +165,7 @@
 			 size is greater than max mixer width.
 
 Example:
-	qcom,mdss_mdp@fd900000 {
+	mdss_mdp: qcom,mdss_mdp@fd900000 {
 		compatible = "qcom,mdss_mdp";
 		reg = <0xfd900000 0x22100>,
 			<0xfd924000 0x1000>;
@@ -179,6 +188,7 @@
 		qcom,mdss-smp-data = <22 4096>;
 		qcom,mdss-rot-block-size = <64>;
 		qcom,mdss-smp-mb-per-pipe = <2>;
+		qcom,mdss-pref-prim-intf = "dsi";
 		qcom,mdss-has-bwc;
 		qcom,mdss-has-decimation;
 		qcom,mdss-has-wfd-blk;
diff --git a/Documentation/devicetree/bindings/hwmon/qpnp-adc-current.txt b/Documentation/devicetree/bindings/hwmon/qpnp-adc-current.txt
index e336429..31bf540 100644
--- a/Documentation/devicetree/bindings/hwmon/qpnp-adc-current.txt
+++ b/Documentation/devicetree/bindings/hwmon/qpnp-adc-current.txt
@@ -20,10 +20,17 @@
 Optional properties:
 - qcom,rsense : Use this property when external rsense should be used
 		for current calculation and specify the units in nano-ohms.
+- qcom,iadc-poll-eoc: Use polling instead of interrupts for End of Conversion completion.
 
 Channel node
 NOTE: Atleast one Channel node is required.
 
+Client required property:
+- qcom,<consumer name>-iadc : The phandle to the corresponding iadc device.
+			The consumer name passed to the driver when calling
+			qpnp_get_iadc() is used to associate the client
+			with the corresponding device.
+
 Required properties:
 - label : Channel name used for sysfs entry.
 - reg : AMUX channel number.
@@ -113,3 +120,9 @@
                                 qcom,fast-avg-setup = <0>;
                         };
 	};
+
+Client device example:
+/* Add to the clients node that needs the IADC */
+client_node {
+	qcom,client-iadc = <&pm8941_iadc>;
+};
diff --git a/Documentation/devicetree/bindings/hwmon/qpnp-adc-voltage.txt b/Documentation/devicetree/bindings/hwmon/qpnp-adc-voltage.txt
index 7f34a8f..ae7d039 100644
--- a/Documentation/devicetree/bindings/hwmon/qpnp-adc-voltage.txt
+++ b/Documentation/devicetree/bindings/hwmon/qpnp-adc-voltage.txt
@@ -20,6 +20,9 @@
 Channel nodes
 NOTE: Atleast one Channel node is required.
 
+Optional properties:
+- qcom,vadc-poll-eoc: Use polling instead of interrupts for End of Conversion completion.
+
 Client required property:
 - qcom,<consumer name>-vadc : The phandle to the corresponding vadc device.
 			The consumer name passed to the driver when calling
diff --git a/Documentation/devicetree/bindings/input/misc/cm36283.txt b/Documentation/devicetree/bindings/input/misc/cm36283.txt
new file mode 100644
index 0000000..b5ee7d9
--- /dev/null
+++ b/Documentation/devicetree/bindings/input/misc/cm36283.txt
@@ -0,0 +1,40 @@
+Capella cm36283 L/P sensor
+
+Required properties:
+
+ - compatible		: Should be "capella,cm36283".
+ - reg				: i2c slave address of the device.
+ - interrupt-parent	: Parent of interrupt.
+ - interrupts		: L/P sample interrupt to indicate new data ready.
+ - vdd-supply		: Power supply needed to power up the device.
+ - vio-supply		: IO power supply needed for IO and I2C.
+ - capella,interrupt-gpio	: The gpio pin for the interrupt.
+ - capella,levels	: The adc value for light sensor to trigger different light level.
+ - capella,ps_close_thd_set	: The threshold adc value for proximity sensor to trigger close  interrupt.
+ - capella,ps_away_thd_set: The threshold adc value for proximity sensor to trigger away interrupt.
+ - capella,ls_cmd	: The initial value to configure cm36283 ALS_CONF register.
+ - capella,ps_conf1_val	: The initial value to configure cm36283 PS_CONF1 register.
+ - capella,ps_conf3_val	: The initial value to configure cm36283 PS_CONF3 register.
+
+Optional properties:
+
+ - capella,use-polling	: Property to specify if using polling instead of interrupt for adc value report.
+
+Example:
+
+		capella@60 {
+				compatible = "capella,cm36283";
+				reg = <0x60>;
+				interrupt-parent = <&msmgpio>;
+				interrupts = <80 0x2>;
+				vdd-supply = <&pm8110_l19>;
+				vio-supply = <&pm8110_l14>;
+				capella,use-polling;
+				capella,interrupt-gpio = <80>;
+				capella,levels = <0x0A 0xA0 0xE1 0x140 0x280 0x500 0xA28 0x16A8 0x1F40 0x2800>;
+				capella,ps_close_thd_set = <0xa>;
+				capella,ps_away_thd_set = <0x5>;
+				capella,ls_cmd = <0x44>;  /* PS_IT=160ms, INT_PERS=2*/
+				capella,ps_conf1_val = <0x0006>;  /*CM36283_PS_ITB_1_2 | CM36283_PS_DR_1_40| CM36283_PS_IT_1T | CM36283_PS_PERS_2 | CM36283_PS_RES_1*/
+				capella,ps_conf3_val = <0x3010>;  /* CM36283_PS_MS_NORMAL | CM36283_PS_PROL_255 | CM36283_PS_SMART_PERS_ENABLE, */
+		};
diff --git a/Documentation/devicetree/bindings/input/misc/stk-stk3x1x.txt b/Documentation/devicetree/bindings/input/misc/stk-stk3x1x.txt
new file mode 100644
index 0000000..59136ee
--- /dev/null
+++ b/Documentation/devicetree/bindings/input/misc/stk-stk3x1x.txt
@@ -0,0 +1,51 @@
+Sensortek stk301x, stk321x and stk331x ambient light/proximity 3-in-1 sensor
+
+Required properties:
+
+ - compatible		: Should be "stk,stk3x1x".
+ - reg					: i2c slave address of the device.
+ - interrupt-parent	: Parent of interrupt.
+ - interrupts		: Sensor will issue interrupt when preset condition is met,
+				typically when proximity sensor detect a change on near/far state.
+ - vdd-supply		: Main power supply to power sensor.
+ - vio-supply		: Power supply required to pullup I2C bus.
+ - stk,irq-gpio	: irq gpio which is to provide interrupts to host, same as
+				"interrupts" node.
+ - stk,transmittance : Transmittance rate of glass above the ambient light
+				detection window. The value may not be equal to real transmittance
+				but just a relative value.
+ - stk,state-reg	: The default setting of state register.
+ - stk,psctrl-reg	: The default setting for proximity sensor.
+ - stk,alsctrl-reg	: The default setting for ambient light sensor.
+ - stk,ledctrl-reg	: The default setting for IR LED.
+ - stk,wait-reg	: The default setting for wait time.
+ - stk,ps-thdh	: High threshold for proximity sensor, sensor will report
+				"near" if the proximity sensor reading is larger or equal to this
+				value.
+ - stk,ps-thdl	: Low threshold for proximity sensor, sensor will report
+				"far" if the proximity sensor reading is larger than this value.
+
+Optional properties:
+
+ - stk,use-fir	: Boolean to enable light data jitter suppressing FIR filter.
+
+Example:
+	i2c@f9925000 {
+		stk@48 {
+			compatible = "stk,stk3x1x";
+			reg = <0x48>;
+			interrupt-parent = <&msmgpio>;
+			interrupts = <80 0x2>;
+			vdd-supply = <&pm8110_l19>;
+			vio-supply = <&pm8110_l14>;
+			stk,irq-gpio = <&msmgpio 80 0x02>;
+			stk,transmittance = <500>;
+			stk,state-reg = <0x00>;
+			stk,psctrl-reg = <0x71>;
+			stk,alsctrl-reg = <0x38>;
+			stk,ledctrl-reg = <0xFF>;
+			stk,wait-reg = <0x07>;
+			stk,ps-thdh = <1700>;
+			stk,ps-thdl = <1500>;
+			stk,use-fir;
+		};
diff --git a/Documentation/devicetree/bindings/input/touchscreen/ft5x06-ts.txt b/Documentation/devicetree/bindings/input/touchscreen/ft5x06-ts.txt
index d77e96c..c563067e 100644
--- a/Documentation/devicetree/bindings/input/touchscreen/ft5x06-ts.txt
+++ b/Documentation/devicetree/bindings/input/touchscreen/ft5x06-ts.txt
@@ -23,6 +23,10 @@
  - focaltech,display-coords : display coordinates in pixels. It is a four
 				tuple consisting of min x, min y, max x and
 				max y values
+ - focaltech,name	: name of the controller
+ - focaltech,group-id	: group id of this device
+ - focaltech,hard-reset-delay-ms : hard reset delay in ms
+ - focaltech,soft-reset-delay-ms : soft reset delay in ms
 
 Optional properties:
 
@@ -33,21 +37,45 @@
  - focaltech,no-force-update : to specify force update is allowed
  - focaltech,button-map : button map of key codes. The number
 				of key codes depend on panel
+ - focaltech,fw-name	: specify the firmware file name
+ - focaltech,fw-delay-aa-ms : specify the "aa" delay in ms for firmware upgrade
+ - focaltech,fw-delay-55-ms : specify the "55" delay in ms for firmware upgrade
+ - focaltech,fw-upgrade-id1 : specify the upgrade id1 for firmware upgrade
+ - focaltech,fw-upgrade-id2 : specify the upgrade id2 for firmware upgrade
+ - focaltech,fw-delay-readid-ms : specify the read id delay in ms for firmware upgrade
+ - focaltech,fw-delay-era-flsh-ms : specify the erase flash delay in ms for firmware upgrade
+ - focaltech,fw-auto-cal	: specify whether calibration is needed after firmware upgrade
+ - focaltech,fw-vkey-support	: specify if virtual keys are supported through firmware
 
 Example:
-	i2c@f9924000 {
-		ft5x06_ts@38 {
+	i2c@f9923000{
+		focaltech@38{
 			compatible = "focaltech,5x06";
 			reg = <0x38>;
 			interrupt-parent = <&msmgpio>;
-			interrupts = <61 0x2>;
-			vdd-supply = <&pm8941_l22>;
-			vcc_i2c-supply = <&pm8941_s3>;
-			focaltech,reset-gpio = <&msmgpio 60 0x00>;
-			focaltech,irq-gpio = <&msmgpio 61 0x00>;
-			focaltech,panel-coords = <0 0 480 800>;
+			interrupts = <1 0x2>;
+			vdd-supply = <&pm8110_l19>;
+			vcc_i2c-supply = <&pm8110_l14>;
+			focaltech,name = "ft6x06";
+			focaltech,family-id = <0x06>;
+			focaltech,reset-gpio = <&msmgpio 0 0x00>;
+			focaltech,irq-gpio = <&msmgpio 1 0x00>;
 			focaltech,display-coords = <0 0 480 800>;
-			focaltech,button-map= <158 102 139 217>;
-			focaltech,family-id = <0x0a>;
+			focaltech,panel-coords = <0 0 480 800>;
+			focaltech,button-map= <139 102 158>;
+			focaltech,no-force-update;
+			focaltech,i2c-pull-up;
+			focaltech,group-id = <1>;
+			focaltech,hard-reset-delay = <20>;
+			focaltech,soft-reset-delay = <150>;
+			focaltech,num-max-touches = <2>;
+			focaltech,fw-name = "ft_8610_qrd_fw.bin";
+			focaltech,fw-delay-aa-ms = <100>;
+			focaltech,fw-delay-55-ms = <30>;
+			focaltech,fw-upgrade-id1 = <0x79>;
+			focaltech,fw-upgrade-id2 = <0x08>;
+			focaltech,fw-delay-readid-ms = <10>;
+			focaltech,fw-delay-era-flsh-ms = <2000>;
+			focaltech,fw-auto-cal;
 		};
 	};
diff --git a/Documentation/devicetree/bindings/input/touchscreen/gt9xx/gt9xx.txt b/Documentation/devicetree/bindings/input/touchscreen/gt9xx/gt9xx.txt
new file mode 100644
index 0000000..3e223e6
--- /dev/null
+++ b/Documentation/devicetree/bindings/input/touchscreen/gt9xx/gt9xx.txt
@@ -0,0 +1,74 @@
+Goodix GT9xx series touch controller
+
+Required properties:
+
+ - compatible		: Should be "goodix,gt9xx"
+ - reg			: I2C slave address of the device.
+ - interrupt-parent	: Parent of interrupt.
+ - interrupts		: Configuration of touch panel controller interrupt
+				GPIO.
+ - goodix,family-id	: Family identification of the controller.
+ - interrupt-gpios	: Interrupt gpio which is to provide interrupts to
+				host, same as "interrupts" node.
+ - reset-gpios		: Reset gpio to control the reset of chip.
+ - goodix,display-coords	: Display coordinates in pixels. It is a four
+				tuple consisting of min x, min y, max x and
+				max y values.
+
+Optional properties:
+
+ - avdd-supply		: Power supply needed to power up the device, this is
+				for fixed voltage external regulator.
+ - vdd-supply		: Power supply needed to power up the device, when use
+				external regulator, do not add this property.
+ - vcc-i2c-supply	: Power source required to power up i2c bus.
+				GT9xx series can provide 1.8V from internal
+				LDO, add this properties base on hardware
+				design.
+ - goodix,panel-coords	: Panel coordinates for the chip in pixels.
+				It is a four tuple consisting of min x,
+				min y, max x and max y values.
+ - goodix,i2c-pull-up	: To specify pull up is required.
+ - goodix,no-force-update	: To specify force update is allowed.
+ - goodix,button-map	: Button map of key codes. The number of key codes
+				depend on panel.
+ - goodix,cfg-data	: Touchpanel controller configuration data, ask vendor
+				to provide that. Default configuration will be
+				used if this property is not present.
+
+Example:
+i2c@f9927000 {
+		goodix@5d {
+			compatible = "goodix,gt9xx";
+			reg = <0x5d>;
+			interrupt-parent = <&msmgpio>;
+			interrupts = <17 0x2008>;
+			reset-gpios = <&msmgpio 16 0x00>;
+			interrupt-gpios = <&msmgpio 17 0x00>;
+			avdd-supply = <&tp_power>;
+			goodix,panel-coords = <0 0 720 1200>;
+			goodix,display-coords = <0 0 720 1080>;
+			goodix,button-map= <158 102 139>;
+			goodix,family-id = <0x0>;
+			goodix,cfg-data = [
+		41 D0 02 00 05 0A 05 01 01 08
+		12 58 50 41 03 05 00 00 00 00
+		00 00 00 00 00 00 00 8C 2E 0E
+		28 24 73 13 00 00 00 83 03 1D
+		40 02 00 00 00 03 64 32 00 00
+		00 1A 38 94 C0 02 00 00 00 04
+		9E 1C 00 8D 20 00 7A 26 00 6D
+		2C 00 60 34 00 60 10 38 68 00
+		F0 50 35 FF FF 27 00 00 00 00
+		00 01 1B 14 0C 14 00 00 01 00
+		00 00 00 00 00 00 00 00 00 00
+		00 00 02 04 06 08 0A 0C 0E 10
+		12 14 16 18 1A 1C FF FF FF FF
+		FF FF FF FF FF FF FF FF FF FF
+		FF FF 00 02 04 06 08 0A 0C 0F
+		10 12 13 14 16 18 1C 1D 1E 1F
+		20 21 22 24 26 28 29 2A FF FF
+		FF FF FF FF FF FF FF 22 22 22
+		22 22 22 FF 07 01];
+		};
+};
diff --git a/Documentation/devicetree/bindings/input/touchscreen/synaptics_i2c_rmi4.txt b/Documentation/devicetree/bindings/input/touchscreen/synaptics_i2c_rmi4.txt
index 0f35e73..4f9307a 100644
--- a/Documentation/devicetree/bindings/input/touchscreen/synaptics_i2c_rmi4.txt
+++ b/Documentation/devicetree/bindings/input/touchscreen/synaptics_i2c_rmi4.txt
@@ -14,12 +14,18 @@
  - vdd-supply		: Analog power supply needed to power device
  - vcc_i2c-supply		: Power source required to pull up i2c bus
  - synaptics,i2c-pull-up	: specify to indicate pull up is needed
+ - synaptics,disable-gpios	: specify to disable gpios in suspend (power saving)
  - synaptics,button-map		: virtual key code mappings to be used
  - synaptics,x-flip		: modify orientation of the x axis
  - synaptics,y-flip		: modify orientation of the y axis
- - synaptics,panel-x		: panel x dimension
- - synaptics,panel-y		: panel y dimension
+ - synaptics,panel-coords	: touch panel min x, min y, max x and
+					max y resolution
+ - synaptics,display-coords	: display min x, min y, max x and
+					max y resolution
+ - synaptics,reset-delay	: reset delay for controller (ms), default 100
  - synaptics,fw-image-name	: name of firmware .img file in /etc/firmware
+ - synaptics,power-down		: fully power down regulators in suspend
+ - synaptics,do-lockdown	: perform one time lockdown procedure
 
 Example:
 	i2c@f9927000 { /* BLSP1 QUP5 */
diff --git a/Documentation/devicetree/bindings/leds/leds-qpnp.txt b/Documentation/devicetree/bindings/leds/leds-qpnp.txt
index b60760e..af6a0b5 100644
--- a/Documentation/devicetree/bindings/leds/leds-qpnp.txt
+++ b/Documentation/devicetree/bindings/leds/leds-qpnp.txt
@@ -38,15 +38,16 @@
 Flash is used primarily as a camera or video flash.
 
 Optional properties for flash:
-- qcom,headroom: headroom to use, mV
-- qcom,duration: duration of the flash, ms
+- qcom,headroom: headroom to use. Values should be 0, 1, 2, 3 for 250mV, 300mV, 400mV and 500mV
+- qcom,duration: duration of the flash and torch, 10ms - 1280ms for flash and 2s - 33s for torch
 - qcom,clamp-curr: current to clamp at, mA
-- qcom,startup-dly: delay before flashing after flash executed, us
+- qcom,startup-dly: delay before flashing after flash executed. Values should 0, 1, 2, 3 for 10us, 32us, 64us, and 128us
 - qcom,saftey-timer: include for safety timer use, otherwise watchdog timer will be used
 - linux,default-trigger: trigger the led from external modules such as display
 - qcom,default-state:  default state of the led, should be "on" or "off"
-- qcom,torch-enable: set flash led to torch mode
-- flash_boost-supply: SMBB regulator for LED flash mode
+- qcom,torch-enable: set flash led to torch mode functionality and triggers software workaround for torch if hardware does not support
+- flash-boost-supply: SMBB regulator for LED flash mode
+- torch-boost-supply: SMBB regulator for LED torch mode
 
 RGB Led is a tri-colored led, Red, Blue & Green.
 
@@ -221,7 +222,8 @@
 	qcom,leds@d300 {
 			compatible = "qcom,leds-qpnp";
 			status = "okay";
-			flash_boost-supply = <&pm8941_chg_boost>;
+			flash-boost-supply = <&pm8941_chg_boost>;
+			torch-boost-supply = <&pm8941_boost>;
 			qcom,flash_0 {
 				qcom,max-current = <1000>;
 				qcom,default-state = "off";
@@ -236,6 +238,7 @@
 				linux,name = "led:flash_0";
 				qcom,current = <625>;
 				qcom,id = <1>;
+				qcom,no-torch-module;
 			};
 	};
 
diff --git a/Documentation/devicetree/bindings/media/video/msm-camera-flash.txt b/Documentation/devicetree/bindings/media/video/msm-camera-flash.txt
index 72b32be..d848baf 100644
--- a/Documentation/devicetree/bindings/media/video/msm-camera-flash.txt
+++ b/Documentation/devicetree/bindings/media/video/msm-camera-flash.txt
@@ -13,6 +13,10 @@
 - qcom,flash-source : Should contain array of phandles to flash source nodes.
     - pm8941_flash0 pm8941_flash1
 
+Optional properties:
+-qcom,torch-source : Should contain phandle to torch source node.
+    -pm8941_torch
+
 Example:
 
 qcom,camera-led-flash {
@@ -20,4 +24,5 @@
 	compatible = "qcom,camera-led-flash";
 	qcom,flash-type = <1>;
 	qcom,flash-source = <&pm8941_flash0 &pm8941_flash1>;
+	qcom,torch-source = <&pm8941_torch>;
 };
diff --git a/Documentation/devicetree/bindings/media/video/msm-cci.txt b/Documentation/devicetree/bindings/media/video/msm-cci.txt
index b8156c3..c60441f 100644
--- a/Documentation/devicetree/bindings/media/video/msm-cci.txt
+++ b/Documentation/devicetree/bindings/media/video/msm-cci.txt
@@ -49,6 +49,7 @@
 Required properties:
 - compatible : should be manufacturer name followed by sensor name
     - "qcom,s5k3l1yx"
+    - "qcom,imx135"
     - "shinetech,gc0339"
     - "shinetech,hi256"
     - "shinetech,s5k4e1"
diff --git a/Documentation/devicetree/bindings/media/video/msm-eeprom.txt b/Documentation/devicetree/bindings/media/video/msm-eeprom.txt
new file mode 100644
index 0000000..893c033
--- /dev/null
+++ b/Documentation/devicetree/bindings/media/video/msm-eeprom.txt
@@ -0,0 +1,106 @@
+* Qualcomm MSM EEPROM
+
+EEPROM is an one time programmed(OTP) device that stores the calibration data
+use for camera sensor. It may either be integrated in the sensor module or in
+the sensor itself. As a result, the power, clock and GPIOs may be the same as
+the camera sensor. The following describes the page block map, power supply,
+clock, GPIO and power on sequence properties of the EEPROM device.
+
+Required properties:
+- cell-index: eeprom hardware core index
+- compatible :
+    - "qcom,eeprom"
+- reg : offset and length of eeprom device registers.
+- qcom,eeprom-name : should specify relevant names of the eeprom module
+    library.
+- qcom,slave-addr : should specify the slave address of the eeprom.
+- qcom,cci-master : should specify the cci core index that eeprom use.
+- qcom,num-blocks : should specify the total block number that eeprom contains,
+    every block should contains page poll and mem.
+- qcom,page%d : number %d page size, start address, address type, data,
+    data type, delay in ms. size 0 stand for non-paged.
+    - address type : 1 byte, 2 word.
+    - data type : 1 byte, 2 word.
+- qcom,poll%d : number %d poll size, poll reg address, address type, data,
+    data type, delay in ms. size 0 stand for not used.
+    - address type : 1 byte, 2 word.
+    - data type : 1 byte, 2 word.
+- qcom,mem%d : number %d memory size, start address, address type, data,
+    data type, delay in ms. size 0 stand for not used.
+    - address type : 1 byte, 2 word.
+    - data type : 1 byte, 2 word.
+- cam_vdig-supply : should contain regulator to be used for the digital vdd.
+- cam_vio-supply : should contain regulator to be used for the IO vdd.
+- qcom,cam-vreg-name : should specify the regulator name to be used for
+    this eeprom.
+- qcom,cam-vreg-type : should specify the regulator type to be used for
+    this eeprom.
+- qcom,cam-vreg-min-voltage : should specify minimum voltage level
+    for eeprom in uV.
+- qcom,cam-vreg-max-voltage : should specify maximum voltage level
+    for eeprom in uV.
+- qcom,cam-vreg-op-mode : should specify current level for eeprom in uA.
+- qcom,gpio-no-mux : should specify the gpio mux type.
+- gpios : should specify the gpios to be used for the eeprom.
+- qcom,gpio-reset : should specify the reset gpio index.
+- qcom,gpio-standby : should specify the standby gpio index.
+- qcom,gpio-req-tbl-num : should specify the gpio table index.
+- qcom,gpio-req-tbl-flags : should specify the gpio functions.
+- qcom,gpio-req-tbl-label : should specify the gpio labels.
+- qcom,cam-power-seq-type : should specify the power on sequence types.
+- qcom,cam-power-seq-val : should specify the power on sequence values.
+- qcom,cam-power-seq-cfg-val : should specify the power on sequence config
+    values.
+- qcom,cam-power-seq-delay : should specify the power on sequence delay
+    time in ms.
+
+Optional properties:
+- qcom,pageen%d : number %d page enable reg size, start address, address type,
+    data, data type, delay in ms. size 0 stand for not used.
+
+Example:
+
+    eeprom0: qcom,eeprom@60 {
+        cell-index = <0>;
+        reg = <0x60 0x0>;
+        qcom,eeprom-name = "msm_eeprom";
+        compatible = "qcom,eeprom";
+        qcom,slave-addr = <0x60>;
+        qcom,cci-master = <0>;
+        qcom,num-blocks = <2>;
+        qcom,page0 = <1 0x0100 2 0x01 1 1>;
+        qcom,poll0 = <0 0x0 2 0 1 1>;
+        qcom,mem0 = <0 0x0 2 0 1 0>;
+        qcom,page1 = <1 0x0200 2 0x8 1 1>;
+        qcom,pageen1 = <1 0x0202 2 0x01 1 10>;
+        qcom,poll1 = <0 0x0 2 0 1 1>;
+        qcom,mem1 = <32 0x3000 2 0 1 0>;
+
+        cam_vdig-supply = <&pm8226_l5>;
+        cam_vio-supply = <&pm8226_lvs1>;
+        qcom,cam-vreg-name = "cam_vdig", "cam_vio";
+        qcom,cam-vreg-type = <0 1>;
+        qcom,cam-vreg-min-voltage = <1200000 0>;
+        qcom,cam-vreg-max-voltage = <1200000 0>;
+        qcom,cam-vreg-op-mode = <200000 0>;
+        qcom,gpio-no-mux = <0>;
+        gpios = <&msmgpio 26 0>,
+            <&msmgpio 37 0>,
+            <&msmgpio 36 0>;
+        qcom,gpio-reset = <1>;
+        qcom,gpio-standby = <2>;
+        qcom,gpio-req-tbl-num = <0 1 2>;
+        qcom,gpio-req-tbl-flags = <1 0 0>;
+        qcom,gpio-req-tbl-label = "CAMIF_MCLK",
+            "CAM_RESET1",
+            "CAM_STANDBY";
+        qcom,cam-power-seq-type = "sensor_vreg",
+            "sensor_vreg", "sensor_clk",
+            "sensor_gpio", "sensor_gpio";
+        qcom,cam-power-seq-val = "cam_vdig",
+            "cam_vio", "sensor_cam_mclk",
+            "sensor_gpio_reset",
+            "sensor_gpio_standby";
+        qcom,cam-power-seq-cfg-val = <1 1 24000000 1 1>;
+        qcom,cam-power-seq-delay = <1 1 5 5 10>;
+    };
diff --git a/Documentation/devicetree/bindings/media/video/msm-vfe.txt b/Documentation/devicetree/bindings/media/video/msm-vfe.txt
index f02f35e..dd8eb15 100644
--- a/Documentation/devicetree/bindings/media/video/msm-vfe.txt
+++ b/Documentation/devicetree/bindings/media/video/msm-vfe.txt
@@ -8,9 +8,13 @@
 - reg : offset and length of the register set for the device
     for the vfe operating in compatible mode.
 - reg-names : should specify relevant names to each reg property defined.
+    - "vfe" - Required.
+    - "vfe_vbif" - Optional for "vfe32". Required for "vfe40".
+    - "tcsr" - Optional for "vfe32". Required for "vfe40".
 - interrupts : should contain the vfe interrupt.
 - interrupt-names : should specify relevant names to each interrupts
   property defined.
+    - "vfe" - Required.
 - vdd-supply: phandle to GDSC regulator controlling VFE core.
 
 Example:
diff --git a/Documentation/devicetree/bindings/media/video/msm-vidc.txt b/Documentation/devicetree/bindings/media/video/msm-vidc.txt
index cc2506d..6f6f68d 100644
--- a/Documentation/devicetree/bindings/media/video/msm-vidc.txt
+++ b/Documentation/devicetree/bindings/media/video/msm-vidc.txt
@@ -12,6 +12,7 @@
 Optional properties:
 - reg : offset and length of the register set for the device.
 - interrupts : should contain the vidc interrupt.
+- vdd-supply : regulator to supply venus.
 - qcom,vidc-cp-map : start and size of device virtual address range for
   secure buffers. Video hardware uses this address range to identify if
   the buffers are secure or non-secure.
@@ -66,6 +67,7 @@
 		compatible = "qcom,msm-vidc";
 		reg = <0xfdc00000 0xff000>;
 		interrupts = <0 44 0>;
+		vdd-supply = <&gdsc_venus>;
 		qcom,vidc-cp-map = <0x1000000 0x40000000>;
 		qcom,vidc-ns-map = <0x40000000 0x40000000>;
 		qcom,load-freq-tbl = <979200 410000000>,
diff --git a/Documentation/devicetree/bindings/media/video/ovti-image-sensor.txt b/Documentation/devicetree/bindings/media/video/ovti-image-sensor.txt
new file mode 100644
index 0000000..cef9cf5
--- /dev/null
+++ b/Documentation/devicetree/bindings/media/video/ovti-image-sensor.txt
@@ -0,0 +1,9 @@
+OmniVision Image Sensor Device Tree Bindings.
+========================================
+
+Boards with the OmniVision Image Sensor shall have the following properties:
+
+Required root node properties:
+    - compatible:
+    - "ovti,ov8865" : OmniVision OV8865 8 megapixel Image Sensor.
+    - "ovti,ov5648" : OmniVision OV5648 5 megapixel Image Sensor.
diff --git a/Documentation/devicetree/bindings/mmc/sdhci-msm.txt b/Documentation/devicetree/bindings/mmc/sdhci-msm.txt
index 013d56e..d502f78 100644
--- a/Documentation/devicetree/bindings/mmc/sdhci-msm.txt
+++ b/Documentation/devicetree/bindings/mmc/sdhci-msm.txt
@@ -73,7 +73,8 @@
 	- qcom,pad-pull-off - Suspend pull configuration for sdc tlmm pins.
 	- qcom,pad-drv-on - Active drive strength configuration for sdc tlmm pins.
 	- qcom,pad-drv-off - Suspend drive strength configuration for sdc tlmm pins.
-	Tlmm pins are specified as <clk cmd data>
+	Tlmm pins are specified as <clk cmd data> and starting with eMMC5.0 as
+	<clk cmd data rclk>
 
 	- qcom,bus-bw-vectors-bps: specifies array of throughput values in
 	Bytes/sec. The values in the array are determined according to
diff --git a/Documentation/devicetree/bindings/power/qpnp-bms.txt b/Documentation/devicetree/bindings/power/qpnp-bms.txt
index 2da5c72..b076475 100644
--- a/Documentation/devicetree/bindings/power/qpnp-bms.txt
+++ b/Documentation/devicetree/bindings/power/qpnp-bms.txt
@@ -13,7 +13,15 @@
 		to determine whether the BMS is using an internal or external
 		rsense to accumulate the Coulomb Counter and read current.
 
-Additionally, an optional subnode may be included:
+Additionally, optional subnodes may be included:
+- qcom,batt-pres-status : A subnode with a register address for the SMBB
+		battery interface's BATT_PRES_STATUS register. If this node is
+		added, then the BMS will try to detect offmode battery removal
+		via the battery interface's offmode battery removal circuit.
+- qcom,soc-storage-reg : A subnode with a register address to a spare PMIC
+		register. If this node is included, then the BMS will store its
+		shutdown SOC in the specified register instead of the default
+		BMS data register.
 - qcom,battery-data : A phandle to a node containing the available batterydata
 		profiles. See the batterydata bindings documentation for more
 		details.
@@ -75,8 +83,8 @@
 - qcom,min-fcc-learning-soc: An interger value which defines the minimum SOC
 			to start FCC learning. This is applicable only if
 			FCC learning is enabled.
-- qcom,min-fcc-ocv-pc:	An interger value which defines the minimum PC-lookup(OCV)
-			to start FCC learning. This is applicable only if
+- qcom,min-fcc-ocv-pc:	An interger value which defines the minimum PC-lookup
+			(OCV) to start FCC learning. This is applicable only if
 			FCC learning is enabled.
 - qcom,min-fcc-learning-samples: An interger value which defines the minimum
 			number of the FCC measurement cycles required to
@@ -87,6 +95,7 @@
 			For example - A value of 10 indicates:
 			FCC value (in mAh) = (8-bit register value) * 10.
 - qcom,bms-vadc: Corresponding VADC device's phandle.
+- qcom,bms-iadc: Corresponding IADC device's phandle.
 
 Parent node optional properties:
 - qcom,ignore-shutdown-soc: A boolean that controls whether BMS will
@@ -102,12 +111,23 @@
 - qcom,use-ocv-thresholds : A boolean that controls whether BMS will take
 			new OCVs only between the defined thresholds.
 - qcom,enable-fcc-learning: A boolean that defines if FCC learning is enabled.
+- qcom,bms-adc_tm: Corresponding ADC_TM device's phandle to set recurring
+			measurements and receive notifications for
+			die_temperature and vbatt.
 
+qcom,batt-pres-status node required properties:
+- reg : offset and length of the PMIC SMBB battery interface BATT_PRES_STATUS
+		register.
 
-All sub node required properties:
+qcom,soc-storage-reg node required properties:
+- reg : address and length of the spare PMIC register that the BMS will store
+		shutdown SoC in.
+
+qcom,bms-iadc node required properties:
 - reg : offset and length of the PMIC peripheral register map.
 
 qcom,bms-bms node required properties:
+- reg : offset and length of the PMIC peripheral register map.
 - interrupts : the interrupt mappings.
 		The format should be
 		<slave-id peripheral-id interrupt-number>.
@@ -150,6 +170,12 @@
 	qcom,tm-temp-margin = <5000>;
 	qcom,battery-data = <&mtp_batterydata>;
 	qcom,bms-vadc = <&pm8941_vadc>;
+	qcom,bms-iadc = <&pm8941_iadc>;
+	qcom,bms-adc_tm = <&pm8941_adc_tm>;
+
+	qcom,batt-pres-status@1208 {
+		reg = <0x1208 0x1>;
+	}
 
 	qcom,bms-iadc@3800 {
 		reg = <0x3800 0x100>;
diff --git a/Documentation/devicetree/bindings/power/qpnp-charger.txt b/Documentation/devicetree/bindings/power/qpnp-charger.txt
index d0f4313..b1c4ebb 100644
--- a/Documentation/devicetree/bindings/power/qpnp-charger.txt
+++ b/Documentation/devicetree/bindings/power/qpnp-charger.txt
@@ -81,6 +81,11 @@
 - qcom,resume-soc			Capacity in percent at which charging should resume
 					when a fully charged battery drops below this level.
 - qcom,chg-vadc				Corresponding VADC device's phandle.
+- qcom,pmic-revid			The phandle to the revid node of the pmic on which charger
+					peripheral is present. This property is a must on PMIC chips
+					that exhibit inaccuracies in battery current readings. This
+					phandle is used to check the version of the PMIC and apply
+					necessary software workarounds.
 
 Sub node required structure:
 - A qcom,chg node must be a child of an SPMI node that has specified
@@ -89,6 +94,8 @@
 	to the collective charging device. For example USB detection
 	and the battery interface are each seperate peripherals and
 	each should be their own subnode.
+- qcom,chg-adc_tm			Corresponding ADC TM device's phandle to set recurring
+					measurements and receive notification for batt_therm.
 
 Sub node required properties:
 - compatible:		Must be "qcom,qpnp-charger".
@@ -174,6 +181,9 @@
 			 - regulator-name:	A string used as a descriptive name
 						for the boost regulator.
 
+			qcom,batfet:
+			 - regulator-name:	A string used as a descriptive name
+						for the batfet regulator.
 Example:
 	pm8941-chg {
 		spmi-dev-container;
@@ -202,6 +212,8 @@
 		qcom,batt-cold-percent = <85>;
 		qcom,btc-disabled = <0>;
 		qcom,chg-vadc = <&pm8941_vadc>;
+		qcom,chg-adc_tm = <&pm8941_adc_tm>;
+		qcom,pmic-revid = <&pm8941_revid>;
 
 		qcom,chgr@1000 {
 			reg = <0x1000 0x100>;
@@ -300,6 +312,10 @@
 		regulator-name = "8941_smbb_boost";
 	};
 
+	&pm8941_chg_batif  {
+		regulator-name = "batfet";
+	};
+
 	&pm8941_chg_otg {
 		regulator-name = "8941_smbb_otg";
 	};
diff --git a/Documentation/devicetree/bindings/pwm/qpnp-pwm.txt b/Documentation/devicetree/bindings/pwm/qpnp-pwm.txt
index 95be46c..3bb63de 100644
--- a/Documentation/devicetree/bindings/pwm/qpnp-pwm.txt
+++ b/Documentation/devicetree/bindings/pwm/qpnp-pwm.txt
@@ -18,6 +18,8 @@
 - qcom,channel-id:	channel Id for the PWM.
 
 Optional device bindings:
+- qcom,force-pwm-size:	For certain LPG channels, PWM size can be forced.
+			Possible values  6, 7, 8 and 9.
 - qcom,channel-owner:	A string value to supply owner information.
 - qcom,mode-select:	0 = PWM mode
 			1 = LPG mode
@@ -110,6 +112,7 @@
                                       <0xb040 0x80>;
 				reg-names = "qpnp-lpg-channel-base", "qpnp-lpg-lut-base";
                                 qcom,channel-id = <1>;
+                                qcom,force-pwm-size = <9>;
                                 qcom,period = <6000000>;
 				status = "okay";
 				qcom,pwm {
diff --git a/Documentation/devicetree/bindings/regulator/krait-regulator-pmic.txt b/Documentation/devicetree/bindings/regulator/krait-regulator-pmic.txt
new file mode 100644
index 0000000..a0730f6
--- /dev/null
+++ b/Documentation/devicetree/bindings/regulator/krait-regulator-pmic.txt
@@ -0,0 +1,47 @@
+Krait Voltage regulators in the PMIC
+
+In certain MSMs the CPUs are powered using a single supply powered by PMIC ganged regulators
+operating in different phases. The krait-regulator-pmic node represents the gang leader and its
+associated control, power stage and frequency peripherals.
+
+[First Level Nodes]
+Required properties:
+- compatible:			Must be "qcom,krait-regulator-pmic".
+- spmi-dev-container:	        Specifies that all the device nodes specified
+				within this node should have their resources coalesced into a
+				single spmi_device.  This is used to specify all SPMI peripherals
+				that logically make up the gang leader.
+ - #address-cells:		The number of cells dedicated to represent an address
+				This must be set to '1'.
+ - #size-cells:			The number of cells dedicated to represent address
+				space range of a peripheral. This must be set to '1'.
+
+[Second Level Nodes]
+Required properties:
+- reg:             Specifies the SPMI address and size for this peripheral.
+There must be exactly three subnodes qcom,ctl qcom,ps and qcom,freq representing control,
+power stage and frequency SPMI peripherals respectively of the gang leader.
+
+Example:
+		krait_regulator_pmic: qcom,krait-regulator-pmic {
+			spmi-dev-container;
+			compatible = "qcom,krait-regulator-pmic";
+			#address-cells = <1>;
+			#size-cells = <1>;
+			status = "disabled";
+
+			qcom,ctl@2000 {
+				status = "disabled";
+				reg = <0x2000 0x100>;
+			};
+
+			qcom,ps@2100 {
+				status = "disabled";
+				reg = <0x2100 0x100>;
+			};
+
+			qcom,freq@2200 {
+				status = "disabled";
+				reg = <0x2200 0x100>;
+			};
+		};
diff --git a/Documentation/devicetree/bindings/sound/qcom-audio-dev.txt b/Documentation/devicetree/bindings/sound/qcom-audio-dev.txt
index b618597..5e686a4f 100644
--- a/Documentation/devicetree/bindings/sound/qcom-audio-dev.txt
+++ b/Documentation/devicetree/bindings/sound/qcom-audio-dev.txt
@@ -434,7 +434,10 @@
 			    amplifier.
 
 - qcom,headset-jack-type-NO: Adjust GPIO level based on the headset jack type.
-
+- qcom,tapan-codec-9302: Indicates that this device node is for WCD9302 audio
+			    codec.
+- qcom,mbhc-bias-internal: Flag to indicate if internal micbias should be used
+			   for headset detection.
 
 * APQ8074 ASoC Machine driver
 
@@ -664,6 +667,7 @@
 - qcom,cdc-us-euro-gpios : GPIO on which gnd/mic swap signal is coming.
 - qcom,cdc-lineout-spkr-gpios : GPIO which controls external PAs to enable Lineout1/2 speaker
 - qcom,cdc-vdd-spkr-gpios : GPIO which controls PA for VDD speaker
+- qcom,headset-jack-type-NC: Set if the headset jack type is NC (Normally Closed)
 
 Example:
 
diff --git a/Documentation/devicetree/bindings/sound/taiko_codec.txt b/Documentation/devicetree/bindings/sound/taiko_codec.txt
index 9abf54e..489eb38 100644
--- a/Documentation/devicetree/bindings/sound/taiko_codec.txt
+++ b/Documentation/devicetree/bindings/sound/taiko_codec.txt
@@ -35,6 +35,12 @@
  - qcom,cdc-vddcx-2-voltage: cx-2 supply's voltage level min and max in mV.
  - qcom,cdc-vddcx-2-current: cx-2 supply's max current in mA.
 
+ - cdc-vdd-buckhelper-supply: phandle of helper regulator supply's
+				device tree node. This supply is a helper regulator for
+				cdc-vdd-buck-supply regulator.
+ - cdc-vdd-buckhelper-voltage: helper supply's voltage level min and max in mV.
+ - qcom,cdc-vdd-buckhelper-current: helper supply's max current in mA.
+
  - qcom,cdc-static-supplies: List of supplies to be enabled prior to codec
 			     hardware probe.  Supplies in this list will be
 			     stay enabled.
@@ -76,6 +82,10 @@
 				dynamically.
 				Supplies in this list are off by default.
 
+- qcom,cdc-cp-supplies: List of supplies required for codec chargepump enable
+				Supplies in this list can be enabled/disabled dynamically and
+				are off by default.
+
  - qcom,cdc-micbias2-headset-only: Boolean. Allow micbias 2 only to headset mic.
 
 Example:
diff --git a/Documentation/devicetree/bindings/thermal/qpnp-adc-tm.txt b/Documentation/devicetree/bindings/thermal/qpnp-adc-tm.txt
index 64c44b5..e1681ca 100644
--- a/Documentation/devicetree/bindings/thermal/qpnp-adc-tm.txt
+++ b/Documentation/devicetree/bindings/thermal/qpnp-adc-tm.txt
@@ -27,6 +27,12 @@
 		crosses a set threshold, read temperature and enable/set trip types supported
 		by the thermal framework.
 
+Client required property:
+- qcom,<consumer name>-adc_tm : The phandle to the corresponding adc_tm device.
+			The consumer name passed to the driver when calling
+			qpnp_get_adc_tm() is used to associate the client
+			with the corresponding device.
+
 Channel nodes
 NOTE: Atleast one Channel node is required.
 
@@ -97,6 +103,12 @@
 			    allocated to the corresponding channel node.
 - qcom,adc_tm-vadc : phandle to the corresponding VADC device to read the ADC channels.
 
+Client device example:
+/* Add to the clients node that needs the ADC_TM channel A/D */
+client_node {
+	qcom,client-adc_tm = <&pm8941_adc_tm>;
+};
+
 Example:
 	/* Main Node */
 	qcom,vadc@3400 {
diff --git a/Documentation/devicetree/bindings/usb/msm-ehci-hsic.txt b/Documentation/devicetree/bindings/usb/msm-ehci-hsic.txt
index f2707f6..24f21b4 100644
--- a/Documentation/devicetree/bindings/usb/msm-ehci-hsic.txt
+++ b/Documentation/devicetree/bindings/usb/msm-ehci-hsic.txt
@@ -7,7 +7,8 @@
 - interrupt-names : Required interrupt resource entries are:
 	"core_irq" : Interrupt for HSIC core
 - <supply-name>-supply: handle to the regulator device tree node
-  Required "supply-name" is "HSIC_VDDCX" and optionally - "HSIC_GDSC".
+  Required "supply-name" is either "hsic_vdd_dig" or "HSIC_VDDCX" and
+  optionally - "HSIC_GDSC".
 
 Optional properties :
 - interrupt-parent - This must provide reference to the current
@@ -39,7 +40,11 @@
 - hsic,data-pad-offset : Offset of TLMM register for configuring HSIC
   DATA GPIO PAD.
 - qcom,phy-sof-workaround : If present then HSIC PHY has h/w BUGs related to
-  SOFs. Software workarounds are required for the same.
+  SOFs. All the relevant software workarounds are required for the same during
+  suspend, reset and resume.
+- qcom,phy-susp-sof-workaround : If present then HSIC PHY has h/w BUG related to
+  SOFs while entering SUSPEND. Relevant software workaround is required for the same
+  during SUSPEND only.
 - qcom,pool-64-bit-align: If present then the pool's memory will be aligned
   to 64 bits
 - qcom,enable_hbm: if present host bus manager is enabled.
@@ -77,6 +82,9 @@
   the reset and enumeration. Since some devices might take more than 100ms
   for initialization when receiving the bus reset, add delay to avoid the
   problem that enmueration is before device initialization done.
+- hsic,vdd-voltage-level: This property must be a list of three integer
+  values (no, min, max) where each value represents either a voltage in
+  microvolts or a value corresponding to voltage corner
 
 - Refer to "Documentation/devicetree/bindings/arm/msm/msm_bus.txt" for
   below optional properties:
@@ -100,7 +108,7 @@
 			1 &intc 0 148 0
 			2 &msmgpio 144 0x8>;
 		interrupt-names = "core_irq", "async_irq", "wakeup";
-		HSIC_VDDCX-supply = <&pm8019_l12>;
+		hsic_vdd_dig-supply = <&pm8841_s2_corner>;
 		HSIC_GDSC-supply = <&gdsc_usb_hsic>;
 		hsic,strobe-gpio = <&msmgpio 144 0x00>;
 		hsic,data-gpio = <&msmgpio 145 0x00>;
@@ -109,6 +117,7 @@
 		hsic,strobe-pad-offset = <0x2050>;
 		hsic,data-pad-offset = <0x2054>;
 		hsic,consider-ipa-handshake;
+		hsic,vdd-voltage-level = <1 5 7>;
 
 		qcom,msm-bus,name = "hsic";
 		qcom,msm-bus,num-cases = <2>;
@@ -122,6 +131,7 @@
 
 Required properties :
 - compatible : should be "qcom,hsic-smsc-hub"
+- smsc,model-id : should be either <3503> or <4604> depending on hub model
 - smsc,<gpio-name>-gpio : handle to the GPIO node, see "gpios property"
   in Documentation/devicetree/bindings/gpio/gpio.txt.
   Required "gpio-name" is "reset" and optionally - "refclk", "int".
@@ -133,6 +143,7 @@
 Example SMSC HSIC HUB :
 	hsic_hub {
 		compatible = "qcom,hsic-smsc-hub";
+		smsc,model-id = <4604>;
 		ranges;
 		smsc,reset-gpio = <&pm8941_gpios 8 0x00>;
 		smsc,refclk-gpio = <&pm8941_gpios 16 0x00>;
diff --git a/Documentation/devicetree/bindings/usb/msm-hsusb.txt b/Documentation/devicetree/bindings/usb/msm-hsusb.txt
index ad1b5ad..e7eae76 100644
--- a/Documentation/devicetree/bindings/usb/msm-hsusb.txt
+++ b/Documentation/devicetree/bindings/usb/msm-hsusb.txt
@@ -130,7 +130,8 @@
 - interrupt-names : Required interrupt resource entries are:
             HSUSB EHCI expects "core_irq" and optionally "async_irq".
 - <supply-name>-supply: handle to the regulator device tree node
-  Required "supply-name" is "HSUSB_VDDCX" "HSUSB_1p8-supply" "HSUSB_3p3-supply".
+  Required "supply-name" is either "hsusb_vdd_dig" or "HSUSB_VDDCX"
+  "HSUSB_1p8-supply" "HSUSB_3p3-supply".
 - qcom,usb2-power-budget: maximum vbus power (in mA) that can be provided.
 
 Optional properties :
@@ -138,6 +139,15 @@
 - qcom,resume-gpio: if present then peripheral connected to usb controller
   cannot wakeup from XO shutdown using in-band usb bus resume. Use resume
   gpio to wakeup peripheral.
+- qcom,vdd-voltage-level: This property must be a list of five integer
+  values (no, 0.5vsuspend, 0.75suspend, min, max) where each value respresents
+  either a voltage in microvolts or a value corresponding to voltage corner.
+  First value represents value to vote when USB is not at all active, second
+  value represents value to vote when target is not connected to dock during low
+  power mode, third value represents vlaue to vote when target is connected to dock
+  and no peripheral connected over dock during low power mode, fourth value represents
+  minimum value to vote when USB is operational, fifth item represents maximum value
+  to vote for USB is operational.
 
 Example MSM HSUSB EHCI controller device node :
 	ehci: qcom,ehci-host@f9a55000 {
@@ -145,11 +155,12 @@
 		reg = <0xf9a55000 0x400>;
 		interrupts = <0 134 0>, <0 140 0>;
 		interrupt-names = "core_irq", "async_irq";
-		HSUSB_VDDCX-supply = <&pm8841_s2>;
+		hsusb_vdd_dig-supply = <&pm8841_s2_corner>;
 		HSUSB_1p8-supply = <&pm8941_l6>;
 		HSUSB_3p3-supply = <&pm8941_l24>;
 		qcom,usb2-enable-hsphy2;
 		qcom,usb2-power-budget = <500>;
+		qcom,vdd-voltage-level = <1 2 3 5 7>;
 	};
 
 ANDROID USB:
@@ -164,7 +175,8 @@
   for DMA latency in microsecs.
 - qcom,android-usb-cdrom : if this property is present then device creates
   a new LUN as CD-ROM
-
+- qcom,android-usb-internal-ums : if this property is present then device
+  creates a new LUN as internal usb mass storage
 Example Android USB device node :
 	android_usb@fc42b0c8 {
 		compatible = "qcom,android-usb";
diff --git a/Documentation/devicetree/bindings/usb/msm-ssusb.txt b/Documentation/devicetree/bindings/usb/msm-ssusb.txt
index ff7b03d..53e912a 100644
--- a/Documentation/devicetree/bindings/usb/msm-ssusb.txt
+++ b/Documentation/devicetree/bindings/usb/msm-ssusb.txt
@@ -49,6 +49,13 @@
   is not supported and attached host should always be assumed as SDP.
 - USB3_GDSC-supply : phandle to the globally distributed switch controller
   regulator node to the USB controller.
+- qcom,dwc_usb3-adc_tm: Corresponding ADC_TM device's phandle to set recurring
+		measurements on USB_ID channel when using ADC and receive
+		notifications for set thresholds.
+- qcom,dwc-usb3-msm-tx-fifo-size: If present, represents RAM size available for
+		TX fifo allocation in bytes
+- qcom,dwc-usb3-msm-qdss-tx-fifo-size: If present, represent RAM size available
+		for TX fifo allocation in QDSS composition
 
 Sub nodes:
 - Sub node for "DWC3- USB3 controller".
@@ -72,6 +79,9 @@
 		qcom,dwc-usb3-msm-dbm-eps = <4>
 		qcom,vdd-voltage-level = <1 5 7>;
 		qcom,dwc-hsphy-init = <0x00D195A4>;
+		qcom,dwc_usb3-adc_tm = <&pm8941_adc_tm>;
+		qcom,dwc-usb3-msm-tx-fifo-size = <29696>;
+		qcom,dwc-usb3-msm-qdss-tx-fifo-size = <16384>;
 
 		qcom,msm_bus,name = "usb3";
 		qcom,msm_bus,num_cases = <2>;
diff --git a/Documentation/devicetree/bindings/vendor-prefixes.txt b/Documentation/devicetree/bindings/vendor-prefixes.txt
index a3a3807..1eec990 100644
--- a/Documentation/devicetree/bindings/vendor-prefixes.txt
+++ b/Documentation/devicetree/bindings/vendor-prefixes.txt
@@ -9,6 +9,7 @@
 arm	ARM Ltd.
 atmel	Atmel Corporation
 bosch	Bosch Sensortec GmbH
+capella	Capella Microsystems, Inc.
 cavium	Cavium, Inc.
 chrp	Common Hardware Reference Platform
 cortina	Cortina Systems, Inc.
@@ -19,6 +20,7 @@
 focaltech Focaltech systems
 fsl	Freescale Semiconductor
 GEFanuc	GE Fanuc Intelligent Platforms Embedded Systems, Inc.
+goodix	Goodix. Ltd.
 gef	GE Fanuc Intelligent Platforms Embedded Systems, Inc.
 hp	Hewlett Packard
 ibm	International Business Machines (IBM)
@@ -34,6 +36,7 @@
 nintendo	Nintendo
 nvidia	NVIDIA
 nxp	NXP Semiconductors
+ovti	OmniVision Technologies, Inc.
 picochip	Picochip Ltd
 powervr	Imagination Technologies
 qcom	Qualcomm, Inc.
@@ -42,6 +45,7 @@
 samsung	Samsung Semiconductor
 sbs	Smart Battery System
 schindler	Schindler
+stk	Sensortek Technology Corporation.(formerly Sitronix Technology Co., Ltd.)
 shinetech	Shine Tech Corporation, Ltd.
 sil	Silicon Image
 simtek
diff --git a/Documentation/devicetree/bindings/wcnss/wcnss-wlan.txt b/Documentation/devicetree/bindings/wcnss/wcnss-wlan.txt
index d0bbc47..5201827 100644
--- a/Documentation/devicetree/bindings/wcnss/wcnss-wlan.txt
+++ b/Documentation/devicetree/bindings/wcnss/wcnss-wlan.txt
@@ -20,6 +20,7 @@
 - gpios: gpio numbers to configure 5-wire interface of WLAN connectivity
 - qcom,has-48mhz-xo: boolean flag to determine the usage of 24MHz XO from RF
 - qcom,has-pronto-hw: boolean flag to determine the revId of the WLAN subsystem
+- qcom,wcnss-adc_tm: ADC handle for vbatt notification APIs.
 
 Optional properties:
 - qcom,has-autodetect-xo: boolean flag to determine whether Iris XO auto detect
@@ -49,4 +50,5 @@
                 <&msmgpio 39 0>, <&msmgpio 40 0>;
         qcom,has-48mhz-xo;
         qcom,has-pronto-hw;
+        qcom,wcnss-adc_tm = <&pm8226_adc_tm>;
     };
diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig
index 0f527cc..aa37edc 100644
--- a/arch/arm/Kconfig
+++ b/arch/arm/Kconfig
@@ -290,6 +290,14 @@
 	 timer counter page should be mapped by the kernel.  User-space apps
 	 will read directly from the page at this address.
 
+config ARCH_RANDOM
+	bool "SOC specific random number generation"
+	help
+	 Allow the kernel to use an architecture specific implementation for
+	 random number generation
+
+	 If unsure, say N
+
 source "init/Kconfig"
 
 source "kernel/Kconfig.freezer"
@@ -2020,6 +2028,21 @@
 	help
 	  Include support for flattened device tree machine descriptions.
 
+config BUILD_ARM_APPENDED_DTB_IMAGE
+	bool "Build a concatenated zImage/dtb by default"
+	depends on OF
+	help
+	  Enabling this option will cause a concatenated zImage and list of
+	  DTBs to be built by default (instead of a standalone zImage.)
+	  The image will built in arch/arm/boot/zImage-dtb
+
+config BUILD_ARM_APPENDED_DTB_IMAGE_NAMES
+	string "Default dtb names"
+	depends on BUILD_ARM_APPENDED_DTB_IMAGE
+	help
+	  Space separated list of names of dtbs to append when
+	  building a concatenated zImage-dtb.
+
 # Compressed boot loader in ROM.  Yes, we really want to ask about
 # TEXT and BSS so we preserve their values in the config files.
 config ZBOOT_ROM_TEXT
diff --git a/arch/arm/Makefile b/arch/arm/Makefile
index 2f2603f..d43e69bf 100644
--- a/arch/arm/Makefile
+++ b/arch/arm/Makefile
@@ -261,6 +261,8 @@
 # Default target when executing plain make
 ifeq ($(CONFIG_XIP_KERNEL),y)
 KBUILD_IMAGE := xipImage
+else ifeq ($(CONFIG_BUILD_ARM_APPENDED_DTB_IMAGE),y)
+KBUILD_IMAGE := zImage-dtb
 else
 KBUILD_IMAGE := zImage
 endif
@@ -292,6 +294,9 @@
 dtbs: scripts
 	$(Q)$(MAKE) $(build)=$(boot) MACHINE=$(MACHINE) $(boot)/$@
 
+zImage-dtb: vmlinux scripts
+	$(Q)$(MAKE) $(build)=$(boot) MACHINE=$(MACHINE) $(boot)/$@
+
 # We use MRPROPER_FILES and CLEAN_FILES now
 archclean:
 	$(Q)$(MAKE) $(clean)=$(boot)
@@ -306,7 +311,7 @@
   echo  '  Image         - Uncompressed kernel image (arch/$(ARCH)/boot/Image)'
   echo  '* xipImage      - XIP kernel image, if configured (arch/$(ARCH)/boot/xipImage)'
   echo  '  uImage        - U-Boot wrapped zImage'
-  echo  '  bootpImage    - Combined zImage and initial RAM disk' 
+  echo  '  bootpImage    - Combined zImage and initial RAM disk'
   echo  '                  (supply initrd image via make variable INITRD=<path>)'
   echo  '* dtbs          - Build device tree blobs for enabled boards'
   echo  '  install       - Install uncompressed kernel'
diff --git a/arch/arm/boot/.gitignore b/arch/arm/boot/.gitignore
index 3c79f85..ad7a025 100644
--- a/arch/arm/boot/.gitignore
+++ b/arch/arm/boot/.gitignore
@@ -4,3 +4,4 @@
 bootpImage
 uImage
 *.dtb
+zImage-dtb
\ No newline at end of file
diff --git a/arch/arm/boot/Makefile b/arch/arm/boot/Makefile
index c877087..bc8ee6c 100644
--- a/arch/arm/boot/Makefile
+++ b/arch/arm/boot/Makefile
@@ -27,6 +27,14 @@
 
 targets := Image zImage xipImage bootpImage uImage
 
+DTB_NAMES := $(subst $\",,$(CONFIG_BUILD_ARM_APPENDED_DTB_IMAGE_NAMES))
+ifneq ($(DTB_NAMES),)
+DTB_LIST := $(addsuffix .dtb,$(DTB_NAMES))
+else
+DTB_LIST := $(dtb-y)
+endif
+DTB_OBJS := $(addprefix $(obj)/,$(DTB_LIST))
+
 ifeq ($(CONFIG_XIP_KERNEL),y)
 
 $(obj)/xipImage: vmlinux FORCE
@@ -55,15 +63,19 @@
 	$(call if_changed,objcopy)
 	@echo '  Kernel: $@ is ready'
 
+$(obj)/zImage-dtb:	$(obj)/zImage $(DTB_OBJS) FORCE
+	$(call if_changed,cat)
+	@echo '  Kernel: $@ is ready'
+
 endif
 
-targets += $(dtb-y)
+targets += $(DTB_LIST)
 
 # Rule to build device tree blobs
 $(obj)/%.dtb: $(src)/dts/%.dts FORCE
 	$(call if_changed_dep,dtc)
 
-$(obj)/dtbs: $(addprefix $(obj)/, $(dtb-y))
+$(obj)/dtbs: $(DTB_OBJS)
 
 clean-files := *.dtb
 
diff --git a/arch/arm/boot/dts/apq8026-v1-cdp.dts b/arch/arm/boot/dts/apq8026-v1-cdp.dts
index 8c6daa6..d7e283b 100644
--- a/arch/arm/boot/dts/apq8026-v1-cdp.dts
+++ b/arch/arm/boot/dts/apq8026-v1-cdp.dts
@@ -18,5 +18,5 @@
 / {
 	model = "Qualcomm APQ 8026 CDP";
 	compatible = "qcom,apq8026-cdp", "qcom,apq8026", "qcom,cdp";
-	qcom,msm-id = <199 1 0>;
+	qcom,board-id = <1 0>;
 };
diff --git a/arch/arm/boot/dts/apq8026-v1-mtp.dts b/arch/arm/boot/dts/apq8026-v1-mtp.dts
index b89c676..d24875c 100644
--- a/arch/arm/boot/dts/apq8026-v1-mtp.dts
+++ b/arch/arm/boot/dts/apq8026-v1-mtp.dts
@@ -18,5 +18,12 @@
 / {
 	model = "Qualcomm APQ 8026 MTP";
 	compatible = "qcom,apq8026-mtp", "qcom,apq8026", "qcom,mtp";
-	qcom,msm-id = <199 8 0>;
+	qcom,board-id = <8 0>;
+};
+
+&cci {
+	/* Rotate rear camera to 180 degrees */
+	qcom,camera@6f {
+	qcom,mount-angle = <180>;
+	};
 };
diff --git a/arch/arm/boot/dts/apq8026-v1-xpm.dts b/arch/arm/boot/dts/apq8026-v1-xpm.dts
index 8c97823..f69511b 100644
--- a/arch/arm/boot/dts/apq8026-v1-xpm.dts
+++ b/arch/arm/boot/dts/apq8026-v1-xpm.dts
@@ -18,5 +18,5 @@
 / {
 	model = "Qualcomm APQ 8026 XPM";
 	compatible = "qcom,apq8026-xpm", "qcom,apq8026", "qcom,xpm";
-	qcom,msm-id = <199 14 0>;
+	qcom,board-id = <14 0>;
 };
diff --git a/arch/arm/boot/dts/apq8026-v1.dtsi b/arch/arm/boot/dts/apq8026-v1.dtsi
index 7fbfcb5..eaea002 100644
--- a/arch/arm/boot/dts/apq8026-v1.dtsi
+++ b/arch/arm/boot/dts/apq8026-v1.dtsi
@@ -21,6 +21,8 @@
 / {
 	model = "Qualcomm APQ 8026";
 	compatible = "qcom,apq8026";
+	qcom,msm-id = <199 0>,
+		      <219 0x20000>;
 };
 
 &tsens {
diff --git a/arch/arm/boot/dts/apq8026-v2-cdp.dts b/arch/arm/boot/dts/apq8026-v2-cdp.dts
index 74608dd..cb68779 100644
--- a/arch/arm/boot/dts/apq8026-v2-cdp.dts
+++ b/arch/arm/boot/dts/apq8026-v2-cdp.dts
@@ -18,5 +18,5 @@
 / {
 	model = "Qualcomm APQ 8026v2 CDP";
 	compatible = "qcom,apq8026-cdp", "qcom,apq8026", "qcom,cdp";
-	qcom,msm-id = <199 1 0x20000>;
+	qcom,board-id = <1 0>;
 };
diff --git a/arch/arm/boot/dts/apq8026-v2-mtp.dts b/arch/arm/boot/dts/apq8026-v2-mtp.dts
index c6b7f2a..40856c8 100644
--- a/arch/arm/boot/dts/apq8026-v2-mtp.dts
+++ b/arch/arm/boot/dts/apq8026-v2-mtp.dts
@@ -18,5 +18,5 @@
 / {
 	model = "Qualcomm APQ 8026v2 MTP";
 	compatible = "qcom,apq8026-mtp", "qcom,apq8026", "qcom,mtp";
-	qcom,msm-id = <199 8 0x20000>;
+	qcom,board-id = <8 0>;
 };
diff --git a/arch/arm/boot/dts/apq8026-v2-xpm.dts b/arch/arm/boot/dts/apq8026-v2-xpm.dts
index 42acd98..324516d 100644
--- a/arch/arm/boot/dts/apq8026-v2-xpm.dts
+++ b/arch/arm/boot/dts/apq8026-v2-xpm.dts
@@ -18,5 +18,5 @@
 / {
 	model = "Qualcomm APQ 8026v2 XPM";
 	compatible = "qcom,apq8026-xpm", "qcom,apq8026", "qcom,xpm";
-	qcom,msm-id = <199 14 0x20000>;
+	qcom,board-id = <14 0>;
 };
diff --git a/arch/arm/boot/dts/apq8026-v2.dtsi b/arch/arm/boot/dts/apq8026-v2.dtsi
index 4c0d3ce..3ee8d94 100644
--- a/arch/arm/boot/dts/apq8026-v2.dtsi
+++ b/arch/arm/boot/dts/apq8026-v2.dtsi
@@ -21,6 +21,8 @@
 / {
 	model = "Qualcomm APQ 8026";
 	compatible = "qcom,apq8026";
+	qcom,msm-id = <199 0x20000>,
+		      <219 0x20000>;
 };
 
 &tsens {
diff --git a/arch/arm/boot/dts/apq8074-dragonboard.dtsi b/arch/arm/boot/dts/apq8074-dragonboard.dtsi
index 53e9b3b..60bb518 100644
--- a/arch/arm/boot/dts/apq8074-dragonboard.dtsi
+++ b/arch/arm/boot/dts/apq8074-dragonboard.dtsi
@@ -62,6 +62,7 @@
 
 	hsic_hub {
 		compatible = "qcom,hsic-smsc-hub";
+		smsc,model-id = <4604>;
 		#address-cells = <1>;
 		#size-cells = <1>;
 		ranges;
@@ -83,13 +84,15 @@
 				1 &intc 0 148 0
 				2 &msmgpio 144 0x8>;
 			interrupt-names = "core_irq", "async_irq", "wakeup";
-			HSIC_VDDCX-supply = <&pm8841_s2>;
+			hsic_vdd_dig-supply = <&pm8841_s2_corner>;
 			HSIC_GDSC-supply = <&gdsc_usb_hsic>;
 			hsic,strobe-gpio = <&msmgpio 144 0x00>;
 			hsic,data-gpio = <&msmgpio 145 0x00>;
 			hsic,ignore-cal-pad-config;
 			hsic,strobe-pad-offset = <0x2050>;
 			hsic,data-pad-offset = <0x2054>;
+			qcom,phy-susp-sof-workaround;
+			hsic,vdd-voltage-level = <1 5 7>;
 
 			qcom,msm-bus,name = "hsic";
 			qcom,msm-bus,num-cases = <2>;
@@ -603,7 +606,7 @@
 	};
 
 	qcom,dc-chgpth@1400 {
-		status = "ok";
+		status = "disabled";
 	};
 
 	qcom,boost@1500 {
diff --git a/arch/arm/boot/dts/apq8074-v2.0-1.dtsi b/arch/arm/boot/dts/apq8074-v2.0-1.dtsi
index 8314fab..2b75fa2 100644
--- a/arch/arm/boot/dts/apq8074-v2.0-1.dtsi
+++ b/arch/arm/boot/dts/apq8074-v2.0-1.dtsi
@@ -55,3 +55,8 @@
 	status = "ok";
 };
 
+&ehci {
+	hsusb_vdd_dig-supply = <&pm8841_s2_corner>;
+	qcom,vdd-voltage-level = <1 2 3 5 7>;
+};
+
diff --git a/arch/arm/boot/dts/apq8084-coresight.dtsi b/arch/arm/boot/dts/apq8084-coresight.dtsi
index 6cd238a..22c260f 100644
--- a/arch/arm/boot/dts/apq8084-coresight.dtsi
+++ b/arch/arm/boot/dts/apq8084-coresight.dtsi
@@ -348,4 +348,29 @@
 		coresight-name = "coresight-cti-cpu3";
 		coresight-nr-inports = <0>;
 	};
+
+	hwevent: hwevent@fd828018 {
+		compatible = "qcom,coresight-hwevent";
+		reg = <0xfd828018 0x80>,
+		      <0xf9011080 0x80>,
+		      <0xfd4ab160 0x80>,
+		      <0xfc401600 0x80>;
+		reg-names = "mmss-mux", "apcs-mux", "ppss-mux", "gcc-mux";
+
+		coresight-id = <29>;
+		coresight-name = "coresight-hwevent";
+		coresight-nr-inports = <0>;
+
+		qcom,hwevent-clks = "core_mmss_clk";
+	};
+
+	fuse: fuse@fc4be024 {
+		compatible = "arm,coresight-fuse";
+		reg = <0xfc4be024 0x8>;
+		reg-names = "fuse-base";
+
+		coresight-id = <30>;
+		coresight-name = "coresight-fuse";
+		coresight-nr-inports = <0>;
+	};
 };
diff --git a/arch/arm/boot/dts/apq8084-regulator.dtsi b/arch/arm/boot/dts/apq8084-regulator.dtsi
index 0c9ca7d..3d5fc7c 100644
--- a/arch/arm/boot/dts/apq8084-regulator.dtsi
+++ b/arch/arm/boot/dts/apq8084-regulator.dtsi
@@ -326,9 +326,9 @@
 };
 
 &rpm_bus {
-	rpm-regulator-smpb1 {
+	rpm-regulator-smpa1 {
 		compatible = "qcom,rpm-regulator-smd-resource";
-		qcom,resource-name = "smpb";
+		qcom,resource-name = "smpa";
 		qcom,resource-id = <1>;
 		qcom,regulator-type = <1>;
 		qcom,hpm-min-load = <100000>;
@@ -342,9 +342,9 @@
 		};
 	};
 
-	rpm-regulator-smpb2 {
+	rpm-regulator-smpa2 {
 		compatible = "qcom,rpm-regulator-smd-resource";
-		qcom,resource-name = "smpb";
+		qcom,resource-name = "smpa";
 		qcom,resource-id = <2>;
 		qcom,regulator-type = <1>;
 		qcom,hpm-min-load = <100000>;
diff --git a/arch/arm/boot/dts/apq8084.dtsi b/arch/arm/boot/dts/apq8084.dtsi
index 943f2a3..8eed58e 100644
--- a/arch/arm/boot/dts/apq8084.dtsi
+++ b/arch/arm/boot/dts/apq8084.dtsi
@@ -75,8 +75,6 @@
 		compatible = "qcom,cache_dump";
 		qcom,l1-dump-size = <0x100000>;
 		qcom,l2-dump-size = <0x500000>;
-		qcom,memory-reservation-type = "EBI1";
-		qcom,memory-reservation-size = <0x600000>; /* 6M EBI1 buffer */
 	};
 
 	rpm_bus: qcom,rpm-smd {
diff --git a/arch/arm/boot/dts/batterydata-qrd-4v2-1300mah.dtsi b/arch/arm/boot/dts/batterydata-qrd-4v2-1300mah.dtsi
new file mode 100644
index 0000000..103da50
--- /dev/null
+++ b/arch/arm/boot/dts/batterydata-qrd-4v2-1300mah.dtsi
@@ -0,0 +1,105 @@
+/* Copyright (c) 2013, The Linux Foundation. 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 and
+ * only 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.
+ */
+
+qcom,qrd-4v2-1300mah-data {
+	qcom,fcc-mah = <1300>;
+	qcom,default-rbatt-mohm = <172>;
+	qcom,rbatt-capacitive-mohm = <0>;
+	qcom,flat-ocv-threshold-uv = <3800000>;
+	qcom,max-voltage-uv = <4200000>;
+	qcom,v-cutoff-uv = <3400000>;
+	qcom,chg-term-ua = <100000>;
+	qcom,batt-id-kohm = <100>;
+
+	qcom,rbatt-sf-lut {
+		qcom,lut-col-legend = <(-20) 0 25 40 60>;
+		qcom,lut-row-legend = <100 95 90 85 80>,
+				<75 70 65 60 55>,
+				<50 45 40 35 30>,
+				<25 20 15 10 9>,
+				<8 7 6 5 4>,
+				<3 2 1 0>;
+		qcom,lut-data = <604 192 100 79 71>,
+				<605 192 100 79 71>,
+				<641 205 103 81 72>,
+				<641 221 108 84 75>,
+				<622 238 115 87 77>,
+				<612 254 123 92 79>,
+				<605 252 137 96 83>,
+				<607 219 154 104 87>,
+				<613 202 135 109 89>,
+				<626 200 106 90 77>,
+				<656 201 101 82 75>,
+				<684 204 100 84 77>,
+				<710 211 100 85 79>,
+				<747 224 106 89 82>,
+				<806 241 116 90 80>,
+				<905 260 119 87 77>,
+				<1046 291 113 87 77>,
+				<1309 329 116 90 79>,
+				<1476 300 126 97 83>,
+				<1598 311 127 98 84>,
+				<1771 323 130 99 85>,
+				<1984 342 136 101 86>,
+				<2438 368 140 101 86>,
+				<3381 388 137 100 84>,
+				<4913 414 141 99 86>,
+				<6979 468 155 104 90>,
+				<9968 565 192 113 98>,
+				<16163 833 350 140 120>,
+				<36511 6483 4872 472 1095>;
+	};
+
+	qcom,fcc-temp-lut {
+		qcom,lut-col-legend = <(-20) 0 25 40 60>;
+		qcom,lut-data = <1343 1353 1408 1345 1342>;
+	};
+
+	qcom,pc-temp-ocv-lut {
+		qcom,lut-col-legend = <(-20) 0 25 40 60>;
+		qcom,lut-row-legend = <100 95 90 85 80>,
+				<75 70 65 60 55>,
+				<50 45 40 35 30>,
+				<25 20 15 10 9>,
+				<8 7 6 5 4>,
+				<3 2 1 0>;
+		qcom,lut-data = <4177 4174 4199 4167 4162>,
+				<4107 4112 4141 4109 4106>,
+				<4058 4064 4091 4061 4059>,
+				<3996 4015 4044 4017 4015>,
+				<3947 3975 4001 3978 3976>,
+				<3909 3939 3962 3943 3940>,
+				<3874 3901 3926 3911 3907>,
+				<3845 3858 3892 3882 3878>,
+				<3821 3826 3851 3849 3846>,
+				<3801 3804 3815 3810 3808>,
+				<3788 3789 3793 3789 3787>,
+				<3778 3780 3778 3776 3773>,
+				<3769 3776 3770 3767 3764>,
+				<3757 3772 3766 3762 3757>,
+				<3740 3765 3762 3754 3744>,
+				<3714 3747 3750 3739 3724>,
+				<3668 3706 3717 3710 3697>,
+				<3602 3644 3662 3662 3654>,
+				<3533 3571 3601 3607 3605>,
+				<3518 3557 3583 3592 3590>,
+				<3500 3543 3565 3576 3574>,
+				<3478 3528 3546 3559 3557>,
+				<3451 3506 3521 3538 3534>,
+				<3417 3473 3481 3505 3496>,
+				<3377 3423 3424 3454 3444>,
+				<3327 3361 3351 3391 3380>,
+				<3261 3279 3258 3310 3297>,
+				<3165 3165 3138 3198 3182>,
+				<3000 3000 3000 3000 3000>;
+	};
+};
diff --git a/arch/arm/boot/dts/batterydata-qrd-4v2-1800mah.dtsi b/arch/arm/boot/dts/batterydata-qrd-4v2-1800mah.dtsi
new file mode 100644
index 0000000..e44e943
--- /dev/null
+++ b/arch/arm/boot/dts/batterydata-qrd-4v2-1800mah.dtsi
@@ -0,0 +1,105 @@
+/* Copyright (c) 2013, The Linux Foundation. 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 and
+ * only 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.
+ */
+
+qcom,qrd-4v2-1800mah-data {
+	qcom,fcc-mah = <1800>;
+	qcom,default-rbatt-mohm = <146>;
+	qcom,rbatt-capacitive-mohm = <0>;
+	qcom,flat-ocv-threshold-uv = <3800000>;
+	qcom,max-voltage-uv = <4200000>;
+	qcom,v-cutoff-uv = <3400000>;
+	qcom,chg-term-ua = <100000>;
+	qcom,batt-id-kohm = <47>;
+
+	qcom,rbatt-sf-lut {
+		qcom,lut-col-legend = <(-20) 0 25 40 60>;
+		qcom,lut-row-legend = <100 95 90 85 80>,
+				<75 70 65 60 55>,
+				<50 45 40 35 30>,
+				<25 20 15 10 9>,
+				<8 7 6 5 4>,
+				<3 2 1 0>;
+		qcom,lut-data = <904 234 100 85 80>,
+				<905 234 100 85 80>,
+				<934 244 102 86 81>,
+				<928 254 105 87 82>,
+				<933 268 109 89 84>,
+				<924 280 114 91 85>,
+				<913 283 123 96 88>,
+				<916 267 135 103 91>,
+				<930 252 137 110 95>,
+				<954 247 117 106 95>,
+				<990 247 103 88 85>,
+				<1036 253 104 86 84>,
+				<1101 264 108 89 85>,
+				<1211 286 112 93 88>,
+				<1366 340 120 95 87>,
+				<1601 394 128 95 87>,
+				<2178 402 128 97 89>,
+				<5419 423 126 97 89>,
+				<10789 528 128 97 91>,
+				<13463 589 132 100 91>,
+				<17695 678 137 102 92>,
+				<23046 814 145 104 93>,
+				<30725 1019 153 106 93>,
+				<41382 1359 156 106 93>,
+				<56311 1959 165 108 95>,
+				<77209 3523 189 117 99>,
+				<104609 6039 235 127 105>,
+				<138858 9711 352 141 112>,
+				<165825 15373 1069 246 226>;
+	};
+
+	qcom,fcc-temp-lut {
+		qcom,lut-col-legend = <(-20) 0 25 40 60>;
+		qcom,lut-data = <1859 1868 1873 1861 1859>;
+	};
+
+	qcom,pc-temp-ocv-lut {
+		qcom,lut-col-legend = <(-20) 0 25 40 60>;
+		qcom,lut-row-legend = <100 95 90 85 80>,
+				<75 70 65 60 55>,
+				<50 45 40 35 30>,
+				<25 20 15 10 9>,
+				<8 7 6 5 4>,
+				<3 2 1 0>;
+		qcom,lut-data = <4178 4176 4174 4169 4163>,
+				<4090 4100 4105 4101 4099>,
+				<4029 4049 4053 4050 4048>,
+				<3973 3998 4006 4004 4002>,
+				<3932 3959 3965 3962 3960>,
+				<3891 3920 3928 3925 3922>,
+				<3855 3882 3894 3891 3889>,
+				<3825 3844 3862 3862 3859>,
+				<3803 3813 3829 3834 3831>,
+				<3788 3792 3797 3802 3800>,
+				<3777 3780 3778 3776 3773>,
+				<3764 3775 3771 3767 3763>,
+				<3749 3769 3766 3763 3757>,
+				<3725 3756 3758 3755 3750>,
+				<3687 3727 3736 3735 3729>,
+				<3631 3675 3698 3698 3691>,
+				<3571 3607 3637 3642 3637>,
+				<3514 3548 3568 3572 3570>,
+				<3458 3506 3519 3522 3522>,
+				<3444 3498 3511 3516 3515>,
+				<3430 3489 3503 3509 3508>,
+				<3413 3477 3493 3500 3500>,
+				<3395 3461 3478 3488 3486>,
+				<3373 3433 3446 3463 3456>,
+				<3346 3394 3397 3418 3410>,
+				<3307 3341 3334 3361 3352>,
+				<3251 3270 3254 3287 3277>,
+				<3160 3167 3152 3183 3172>,
+				<3000 3000 3000 3000 3000>;
+	};
+};
diff --git a/arch/arm/boot/dts/batterydata-qrd-4v2-2000mah.dtsi b/arch/arm/boot/dts/batterydata-qrd-4v2-2000mah.dtsi
new file mode 100644
index 0000000..f24513c
--- /dev/null
+++ b/arch/arm/boot/dts/batterydata-qrd-4v2-2000mah.dtsi
@@ -0,0 +1,105 @@
+/* Copyright (c) 2013, The Linux Foundation. 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 and
+ * only 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.
+ */
+
+qcom,qrd-4v2-2000mah-data {
+	qcom,fcc-mah = <2000>;
+	qcom,default-rbatt-mohm = <138>;
+	qcom,rbatt-capacitive-mohm = <0>;
+	qcom,flat-ocv-threshold-uv = <3800000>;
+	qcom,max-voltage-uv = <4200000>;
+	qcom,v-cutoff-uv = <3400000>;
+	qcom,chg-term-ua = <100000>;
+	qcom,batt-id-kohm = <130 115>;
+
+	qcom,rbatt-sf-lut {
+		qcom,lut-col-legend = <(-20) 0 25 40 60>;
+		qcom,lut-row-legend = <100 95 90 85 80>,
+				<75 70 65 60 55>,
+				<50 45 40 35 30>,
+				<25 20 15 10 9>,
+				<8 7 6 5 4>,
+				<3 2 1 0>;
+		qcom,lut-data = <1191 250 100 78 69>,
+				<1192 250 100 78 69>,
+				<1242 263 102 80 70>,
+				<1192 277 105 81 71>,
+				<1202 294 108 83 72>,
+				<1205 308 113 86 73>,
+				<1234 313 118 90 76>,
+				<1255 294 131 96 80>,
+				<1284 276 139 103 84>,
+				<1321 271 115 89 74>,
+				<1363 273 104 81 72>,
+				<1400 283 103 79 71>,
+				<1404 295 105 81 71>,
+				<1428 313 108 84 73>,
+				<1489 341 112 87 74>,
+				<1615 374 115 84 73>,
+				<1813 404 117 85 73>,
+				<2121 387 127 89 76>,
+				<2310 366 115 88 77>,
+				<2543 386 116 89 77>,
+				<2879 415 118 92 78>,
+				<3633 457 122 93 78>,
+				<5901 507 128 94 79>,
+				<9939 561 131 93 79>,
+				<16631 634 129 94 78>,
+				<26968 794 134 97 81>,
+				<42610 1203 145 102 85>,
+				<64024 2628 174 115 94>,
+				<115224 17430 577 620 4155>;
+	};
+
+	qcom,fcc-temp-lut {
+		qcom,lut-col-legend = <(-20) 0 25 40 60>;
+		qcom,lut-data = <2024 2033 2035 2031 2027>;
+	};
+
+	qcom,pc-temp-ocv-lut {
+		qcom,lut-col-legend = <(-20) 0 25 40 60>;
+		qcom,lut-row-legend = <100 95 90 85 80>,
+				<75 70 65 60 55>,
+				<50 45 40 35 30>,
+				<25 20 15 10 9>,
+				<8 7 6 5 4>,
+				<3 2 1 0>;
+		qcom,lut-data = <4179 4177 4173 4170 4164>,
+				<4097 4107 4108 4106 4104>,
+				<4040 4060 4059 4057 4054>,
+				<3974 4007 4012 4012 4009>,
+				<3929 3968 3972 3972 3969>,
+				<3889 3933 3937 3935 3933>,
+				<3852 3896 3905 3904 3900>,
+				<3822 3859 3876 3875 3872>,
+				<3797 3827 3846 3847 3844>,
+				<3777 3803 3809 3809 3806>,
+				<3758 3787 3788 3786 3784>,
+				<3740 3779 3777 3774 3771>,
+				<3717 3774 3771 3768 3763>,
+				<3685 3767 3767 3764 3758>,
+				<3649 3757 3761 3756 3749>,
+				<3613 3734 3747 3738 3724>,
+				<3578 3689 3711 3706 3694>,
+				<3538 3615 3649 3648 3643>,
+				<3483 3543 3564 3568 3567>,
+				<3470 3533 3553 3556 3556>,
+				<3453 3522 3542 3545 3545>,
+				<3434 3509 3531 3534 3533>,
+				<3414 3492 3519 3521 3519>,
+				<3388 3467 3498 3499 3492>,
+				<3358 3428 3457 3459 3447>,
+				<3321 3374 3397 3400 3387>,
+				<3268 3300 3318 3323 3307>,
+				<3182 3188 3207 3213 3191>,
+				<3000 3000 3000 3000 3000>;
+	};
+};
diff --git a/arch/arm/boot/dts/batterydata-qrd-4v35-2000mah.dtsi b/arch/arm/boot/dts/batterydata-qrd-4v35-2000mah.dtsi
new file mode 100644
index 0000000..b45f0f8
--- /dev/null
+++ b/arch/arm/boot/dts/batterydata-qrd-4v35-2000mah.dtsi
@@ -0,0 +1,109 @@
+/* Copyright (c) 2013, The Linux Foundation. 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 and
+ * only 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.
+ */
+
+qcom,qrd-4v35-2000mAh-data {
+	qcom,fcc-mah = <2000>;
+	qcom,default-rbatt-mohm = <172>;
+	qcom,rbatt-capacitive-mohm = <0>;
+	qcom,flat-ocv-threshold-uv = <3800000>;
+	qcom,max-voltage-uv = <4350000>;
+	qcom,v-cutoff-uv = <3400000>;
+	qcom,chg-term-ua = <100000>;
+	qcom,batt-id-kohm = <200>;
+
+	qcom,rbatt-sf-lut {
+		qcom,lut-col-legend = <(-20) 0 25 40 60>;
+		qcom,lut-row-legend = <100 95 90 85 80>,
+				<75 70 65 60 55>,
+				<50 45 40 35 30>,
+				<25 20 16 13 11>,
+				<10 9 8 7 6>,
+				<5 4 3 2 1>;
+		qcom,lut-data = <2422 324 100 79 72>,
+				<2417 325 100 79 71>,
+				<2344 327 100 80 72>,
+				<2416 336 102 81 73>,
+				<2072 354 107 82 73>,
+				<1961 372 113 84 75>,
+				<1929 341 118 87 77>,
+				<1929 321 130 93 80>,
+				<2041 306 140 104 85>,
+				<2202 292 119 96 83>,
+				<2374 290 98 80 73>,
+				<2550 292 98 79 72>,
+				<2727 294 99 81 73>,
+				<2904 303 100 82 75>,
+				<3091 323 100 81 73>,
+				<3278 348 100 80 73>,
+				<3470 376 99 79 72>,
+				<3627 386 100 79 72>,
+				<3672 398 100 80 71>,
+				<3812 424 100 80 73>,
+				<3895 443 101 80 73>,
+				<3985 465 102 82 75>,
+				<4094 497 105 83 76>,
+				<4211 533 109 85 79>,
+				<4335 579 113 87 80>,
+				<4505 612 113 85 76>,
+				<4693 643 113 86 77>,
+				<4930 712 120 90 81>,
+				<5283 835 145 111 107>,
+				<10293 15765 5566 6904 2547>;
+	};
+
+	qcom,fcc-temp-lut {
+		qcom,lut-col-legend = <(-20) 0 25 40 60>;
+		qcom,lut-data = <2096 2124 2121 2118 2103>;
+	};
+
+	qcom,pc-temp-ocv-lut {
+		qcom,lut-col-legend = <(-20) 0 25 40 60>;
+		qcom,lut-row-legend = <100 95 90 85 80>,
+				<75 70 65 60 55>,
+				<50 45 40 35 30>,
+				<25 20 16 13 11>,
+				<10 9 8 7 6>,
+				<5 4 3 2 1>,
+				<0>;
+		qcom,lut-data = <4340 4340 4335 4330 4323>,
+				<4217 4260 4265 4263 4258>,
+				<4135 4203 4207 4205 4201>,
+				<4084 4150 4152 4150 4146>,
+				<3992 4101 4101 4097 4093>,
+				<3934 4049 4051 4046 4044>,
+				<3889 3974 3995 3998 3999>,
+				<3852 3926 3958 3961 3959>,
+				<3832 3892 3921 3923 3921>,
+				<3819 3859 3874 3877 3877>,
+				<3807 3831 3838 3838 3838>,
+				<3796 3809 3815 3815 3814>,
+				<3784 3792 3797 3797 3796>,
+				<3770 3780 3783 3782 3781>,
+				<3754 3770 3772 3769 3764>,
+				<3737 3758 3763 3754 3742>,
+				<3717 3737 3744 3735 3720>,
+				<3700 3713 3718 3710 3696>,
+				<3687 3701 3692 3683 3671>,
+				<3674 3695 3689 3681 3669>,
+				<3667 3692 3688 3680 3669>,
+				<3659 3690 3687 3680 3668>,
+				<3649 3687 3685 3678 3667>,
+				<3636 3683 3683 3676 3664>,
+				<3618 3674 3679 3671 3658>,
+				<3596 3652 3663 3652 3632>,
+				<3566 3611 3620 3606 3584>,
+				<3522 3547 3555 3540 3517>,
+				<3460 3449 3461 3446 3424>,
+				<3356 3282 3312 3299 3273>,
+				<3000 3000 3000 3000 3000>;
+	};
+};
diff --git a/arch/arm/boot/dts/batterydata-qrd-4v35-2500mah.dtsi b/arch/arm/boot/dts/batterydata-qrd-4v35-2500mah.dtsi
new file mode 100644
index 0000000..e3540f0
--- /dev/null
+++ b/arch/arm/boot/dts/batterydata-qrd-4v35-2500mah.dtsi
@@ -0,0 +1,105 @@
+/* Copyright (c) 2013, The Linux Foundation. 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 and
+ * only 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.
+ */
+
+qcom,qrd-4v35-2500mAh-data {
+	qcom,fcc-mah = <2500>;
+	qcom,default-rbatt-mohm = <198>;
+	qcom,rbatt-capacitive-mohm = <0>;
+	qcom,flat-ocv-threshold-uv = <3800000>;
+	qcom,max-voltage-uv = <4350000>;
+	qcom,v-cutoff-uv = <3400000>;
+	qcom,chg-term-ua = <100000>;
+	qcom,batt-id-kohm = <470>;
+
+	qcom,rbatt-sf-lut {
+		qcom,lut-col-legend = <(-20) 0 25 40 60>;
+		qcom,lut-row-legend = <100 95 90 85 80>,
+				<75 70 65 60 55>,
+				<50 45 40 35 30>,
+				<25 20 15 10 9>,
+				<8 7 6 5 4>,
+				<3 2 1 0>;
+		qcom,lut-data = <1809 428 100 64 57>,
+				<1805 428 100 64 57>,
+				<1674 443 103 65 57>,
+				<1611 447 108 66 58>,
+				<1407 474 113 69 59>,
+				<1379 462 122 74 61>,
+				<1335 381 124 74 63>,
+				<1346 388 135 79 66>,
+				<1410 382 123 82 68>,
+				<1479 372 101 68 60>,
+				<1542 363 100 66 59>,
+				<1605 368 101 66 60>,
+				<1665 406 102 68 61>,
+				<1722 460 103 70 61>,
+				<1779 525 103 68 61>,
+				<1840 593 104 66 59>,
+				<1914 669 104 65 58>,
+				<2016 779 104 65 59>,
+				<1955 827 107 67 60>,
+				<2006 855 112 69 61>,
+				<2057 882 116 71 63>,
+				<2103 925 123 72 66>,
+				<2162 955 128 73 62>,
+				<2218 991 123 69 61>,
+				<2286 1035 122 69 62>,
+				<2382 1083 130 72 65>,
+				<2780 1158 153 83 81>,
+				<5073 1464 724 393 147>,
+				<46882 49515 42109 55595 11697>;
+	};
+
+	qcom,fcc-temp-lut {
+		qcom,lut-col-legend = <(-20) 0 25 40 60>;
+		qcom,lut-data = <2578 2580 2590 2584 2573>;
+	};
+
+	qcom,pc-temp-ocv-lut {
+		qcom,lut-col-legend = <(-20) 0 25 40 60>;
+		qcom,lut-row-legend = <100 95 90 85 80>,
+				<75 70 65 60 55>,
+				<50 45 40 35 30>,
+				<25 20 15 10 9>,
+				<8 7 6 5 4>,
+				<3 2 1 0>;
+		qcom,lut-data = <4326 4323 4321 4319 4311>,
+				<4192 4235 4253 4254 4249>,
+				<4110 4175 4198 4199 4194>,
+				<4058 4121 4146 4146 4141>,
+				<3952 4076 4096 4096 4091>,
+				<3906 4017 4052 4048 4043>,
+				<3859 3942 3990 3997 3999>,
+				<3828 3905 3954 3962 3959>,
+				<3813 3869 3911 3918 3916>,
+				<3799 3836 3866 3870 3868>,
+				<3786 3808 3837 3840 3840>,
+				<3772 3788 3815 3818 3817>,
+				<3758 3777 3796 3799 3798>,
+				<3743 3765 3780 3783 3781>,
+				<3726 3751 3767 3767 3761>,
+				<3707 3733 3753 3749 3736>,
+				<3684 3713 3731 3727 3713>,
+				<3654 3697 3699 3697 3685>,
+				<3616 3678 3683 3680 3669>,
+				<3605 3673 3682 3679 3667>,
+				<3594 3667 3680 3678 3666>,
+				<3578 3660 3676 3675 3662>,
+				<3561 3647 3666 3667 3647>,
+				<3541 3628 3637 3640 3610>,
+				<3514 3598 3586 3590 3556>,
+				<3478 3550 3515 3523 3485>,
+				<3425 3476 3414 3429 3387>,
+				<3330 3350 3272 3276 3222>,
+				<3000 3000 3000 3000 3000>;
+	};
+};
diff --git a/arch/arm/boot/dts/dsi-panel-generic-720p-cmd.dtsi b/arch/arm/boot/dts/dsi-panel-generic-720p-cmd.dtsi
new file mode 100644
index 0000000..23091f0
--- /dev/null
+++ b/arch/arm/boot/dts/dsi-panel-generic-720p-cmd.dtsi
@@ -0,0 +1,80 @@
+/* Copyright (c) 2013, The Linux Foundation. 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 and
+ * only 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.
+ */
+
+/*---------------------------------------------------------------------------
+ * This file is autogenerated file using gcdb parser. Please do not edit it.
+ * Update input XML file to add a new entry or update variable in this file
+ * VERSION = "1.0"
+ *---------------------------------------------------------------------------*/
+&mdss_mdp {
+	dsi_generic_720p_cmd: qcom,mdss_dsi_generic_720p_cmd {
+		qcom,mdss-dsi-panel-name = "generic 720p cmd mode dsi panel";
+		qcom,mdss-dsi-panel-controller = <&mdss_dsi0>;
+		qcom,mdss-dsi-panel-type = "dsi_cmd_mode";
+		qcom,mdss-dsi-panel-destination = "display_1";
+		qcom,mdss-dsi-panel-framerate = <60>;
+		qcom,mdss-dsi-stream = <0>;
+		qcom,mdss-dsi-panel-width = <768>;
+		qcom,mdss-dsi-panel-height = <1280>;
+		qcom,mdss-dsi-h-front-porch = <26>;
+		qcom,mdss-dsi-h-back-porch = <26>;
+		qcom,mdss-dsi-h-pulse-width = <26>;
+		qcom,mdss-dsi-h-sync-skew = <0>;
+		qcom,mdss-dsi-v-back-porch = <2>;
+		qcom,mdss-dsi-v-front-porch = <2>;
+		qcom,mdss-dsi-v-pulse-width = <2>;
+		qcom,mdss-dsi-h-left-border = <0>;
+		qcom,mdss-dsi-h-right-border = <0>;
+		qcom,mdss-dsi-v-top-border = <0>;
+		qcom,mdss-dsi-v-bottom-border = <0>;
+		qcom,mdss-dsi-bpp = <24>;
+		qcom,mdss-dsi-color-order = <0>;
+		qcom,mdss-dsi-underflow-color = <0xff>;
+		qcom,mdss-dsi-border-color = <0>;
+		qcom,mdss-dsi-on-command = [05 01 00 00 78 00 01 11
+				15 01 00 00 0a 00 02 36 00
+				05 01 00 00 0a 00 01 29
+				15 01 00 00 0a 00 02 53 24
+				15 01 00 00 0a 00 02 35 00];
+		qcom,mdss-dsi-off-command = [05 01 00 00 0a 00 01 34
+				 05 01 00 00 78 00 01 10
+				05 01 00 00 78 00 01 28
+				 15 01 00 00 0a 00 02 53 00];
+		qcom,mdss-dsi-on-command-state = "dsi_lp_mode";
+		qcom,mdss-dsi-off-command-state = "dsi_hs_mode";
+		qcom,mdss-dsi-h-sync-pulse = <0>;
+		qcom,mdss-dsi-traffic-mode = <1>;
+		qcom,mdss-dsi-lane-map = <0>;
+		qcom,mdss-dsi-bllp-eof-power-mode;
+		qcom,mdss-dsi-bllp-power-mode;
+		qcom,mdss-dsi-lane-0-state;
+		qcom,mdss-dsi-lane-1-state;
+		qcom,mdss-dsi-lane-2-state;
+		qcom,mdss-dsi-lane-3-state;
+		qcom,mdss-dsi-te-pin-select = <1>;
+		qcom,mdss-dsi-te-v-sync-rd-ptr-irq-line = <0x2c>;
+		qcom,mdss-dsi-te-v-sync-continues-lines = <0x3c>;
+		qcom,mdss-dsi-te-dcs-command = <1>;
+		qcom,mdss-dsi-te-check-enable;
+		qcom,mdss-dsi-te-using-te-pin;
+		qcom,mdss-dsi-panel-timings = [6e 26 1b 00 35 34 20 28 17 03 04 00];
+		qcom,mdss-dsi-t-clk-post = <0x20>;
+		qcom,mdss-dsi-t-clk-pre = <0x2a>;
+		qcom,mdss-dsi-bl-min-level = <1>;
+		qcom,mdss-dsi-bl-max-level = <255>;
+		qcom,mdss-dsi-bl-pmic-pwm-frequency = <100>;
+		qcom,mdss-dsi-bl-pmic-bank-select = <7>;
+		qcom,mdss-dsi-dma-trigger = <4>;
+		qcom,mdss-dsi-mdp-trigger = <0>;
+		qcom,mdss-dsi-bl-pmic-control-type = "bl_ctrl_pwm";
+	};
+};
diff --git a/arch/arm/boot/dts/dsi-panel-hx8379a-wvga-video.dtsi b/arch/arm/boot/dts/dsi-panel-hx8379a-wvga-video.dtsi
new file mode 100644
index 0000000..4230018
--- /dev/null
+++ b/arch/arm/boot/dts/dsi-panel-hx8379a-wvga-video.dtsi
@@ -0,0 +1,123 @@
+/* Copyright (c) 2013, The Linux Foundation. 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 and
+ * only 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.
+ */
+
+/*---------------------------------------------------------------------------
+ * This file is autogenerated file using gcdb parser. Please do not edit it.
+ * Update input XML file to add a new entry or update variable in this file
+ * VERSION = "1.0"
+ *---------------------------------------------------------------------------*/
+&mdss_mdp {
+	dsi_hx8379a_wvga_vid: qcom,mdss_dsi_hx8379a_wvga_video {
+		qcom,mdss-dsi-panel-name = "HX8379A wvga video mode dsi panel";
+		qcom,mdss-dsi-panel-controller = <&mdss_dsi0>;
+		qcom,mdss-dsi-panel-type = "dsi_video_mode";
+		qcom,mdss-dsi-panel-destination = "display_1";
+		qcom,mdss-dsi-panel-framerate = <60>;
+		qcom,mdss-dsi-virtual-channel-id = <0>;
+		qcom,mdss-dsi-stream = <0>;
+		qcom,mdss-dsi-panel-width = <480>;
+		qcom,mdss-dsi-panel-height = <800>;
+		qcom,mdss-dsi-h-front-porch = <100>;
+		qcom,mdss-dsi-h-back-porch = <94>;
+		qcom,mdss-dsi-h-pulse-width = <40>;
+		qcom,mdss-dsi-h-sync-skew = <0>;
+		qcom,mdss-dsi-v-back-porch = <4>;
+		qcom,mdss-dsi-v-front-porch = <6>;
+		qcom,mdss-dsi-v-pulse-width = <6>;
+		qcom,mdss-dsi-h-left-border = <0>;
+		qcom,mdss-dsi-h-right-border = <0>;
+		qcom,mdss-dsi-v-top-border = <0>;
+		qcom,mdss-dsi-v-bottom-border = <0>;
+		qcom,mdss-dsi-bpp = <24>;
+		qcom,mdss-dsi-color-order = <0>;
+		qcom,mdss-dsi-underflow-color = <0xff>;
+		qcom,mdss-dsi-border-color = <0>;
+		qcom,mdss-dsi-on-command = [
+			39 01 00 00 00 00 04
+				B9 FF 83 79
+			39 01 00 00 00 00 03
+				BA 51 93
+			39 01 00 00 00 00 14
+				B1 00 50 44
+				EA 8D 08 11
+				11 11 27 2F
+				9A 1A 42 0B
+				6E F1 00 E6
+			39 01 00 00 00 00 0E
+				B2 00 00 3C
+				08 04 19 22
+				00 FF 08 04
+				19 20
+			39 01 00 00 00 00 20
+				B4 80 08 00
+				32 10 03 32
+				13 70 32 10
+				08 37 01 28
+				07 37 08 35
+				08 3D 44 08
+				00 40 08 28
+				08 30 30 04
+			39 01 00 00 00 00 30
+				D5 00 00 0A
+				00 01 05 00
+				03 00 88 88
+				88 88 23 01
+				67 45 02 13
+				88 88 88 88
+				88 88 88 88
+				88 88 54 76
+				10 32 31 20
+				88 88 88 88
+				88 88 00 00
+				00 00 00 00
+			39 01 00 00 00 00 24
+				E0 79 05 0F
+				14 26 20 3F
+				2A 43 04 0C
+				11 15 17 15
+				15 10 13 05
+				0F 14 26 20
+				3F 2A 43 04
+				0C 11 15 17
+				15 15 10 13
+			23 01 00 00 00 00 02
+				cc 02
+			39 01 00 00 00 00 05
+				B6 00 9C 00
+				9C
+			05 01 00 00 96 00 02
+				11 00
+			05 01 00 00 78 00 02
+				29 00
+			];
+		qcom,mdss-dsi-off-command = [05 01 00 00 32 00 02 28 00
+					05 01 00 00 78 00 02 10 00];
+		qcom,mdss-dsi-on-command-state = "dsi_lp_mode";
+		qcom,mdss-dsi-off-command-state = "dsi_lp_mode";
+		qcom,mdss-dsi-h-sync-pulse = <1>;
+		qcom,mdss-dsi-traffic-mode = <2>;
+		qcom,mdss-dsi-lane-map = <1>;
+		qcom,mdss-dsi-bllp-eof-power-mode;
+		qcom,mdss-dsi-bllp-power-mode;
+		qcom,mdss-dsi-lane-0-state;
+		qcom,mdss-dsi-lane-1-state;
+		qcom,mdss-dsi-panel-timings = [78 1B 11 00 3E 43 16 1E 1D 03 04 00];
+		qcom,mdss-dsi-t-clk-post = <0x04>;
+		qcom,mdss-dsi-t-clk-pre = <0x1b>;
+		qcom,mdss-dsi-bl-min-level = <1>;
+		qcom,mdss-dsi-bl-max-level = <255>;
+		qcom,mdss-dsi-dma-trigger = <4>;
+		qcom,mdss-dsi-mdp-trigger = <0>;
+		qcom,mdss-dsi-bl-pmic-control-type = "bl_ctrl_wled";
+
+	};
+};
diff --git a/arch/arm/boot/dts/dsi-panel-hx8394a-720p-video.dtsi b/arch/arm/boot/dts/dsi-panel-hx8394a-720p-video.dtsi
index c8d150a..c9d887b 100644
--- a/arch/arm/boot/dts/dsi-panel-hx8394a-720p-video.dtsi
+++ b/arch/arm/boot/dts/dsi-panel-hx8394a-720p-video.dtsi
@@ -15,10 +15,8 @@
  * Update input XML file to add a new entry or update variable in this file
  * VERSION = "1.0"
  *---------------------------------------------------------------------------*/
-&soc {
-	qcom,mdss_dsi_hx8394a_720p_video {
-		compatible = "qcom,mdss-dsi-panel";
-		status = "disable";
+&mdss_mdp {
+	dsi_hx8394a_720_vid: qcom,mdss_dsi_hx8394a_720p_video {
 		qcom,mdss-dsi-panel-name = "hx8394a 720p video mode dsi panel";
 		qcom,mdss-dsi-panel-controller = <&mdss_dsi0>;
 		qcom,mdss-dsi-panel-type = "dsi_video_mode";
diff --git a/arch/arm/boot/dts/dsi-panel-nt35521-720p-video.dtsi b/arch/arm/boot/dts/dsi-panel-nt35521-720p-video.dtsi
new file mode 100644
index 0000000..829197a
--- /dev/null
+++ b/arch/arm/boot/dts/dsi-panel-nt35521-720p-video.dtsi
@@ -0,0 +1,273 @@
+/* Copyright (c) 2013, The Linux Foundation. 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 and
+ * only 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.
+ */
+
+/*---------------------------------------------------------------------------
+ * This file is autogenerated file using gcdb parser. Please do not edit it.
+ * Update input XML file to add a new entry or update variable in this file
+ * VERSION = "1.0"
+ *---------------------------------------------------------------------------*/
+&mdss_mdp {
+	dsi_nt35521_720_vid: qcom,mdss_dsi_nt35521_720p_video {
+		qcom,mdss-dsi-panel-name = "nt35521 720p video mode dsi panel";
+		qcom,mdss-dsi-panel-controller = <&mdss_dsi0>;
+		qcom,mdss-dsi-panel-type = "dsi_video_mode";
+		qcom,mdss-dsi-panel-destination = "display_1";
+		qcom,mdss-dsi-panel-framerate = <60>;
+		qcom,mdss-dsi-virtual-channel-id = <0>;
+		qcom,mdss-dsi-stream = <0>;
+		qcom,mdss-dsi-panel-width = <720>;
+		qcom,mdss-dsi-panel-height = <1280>;
+		qcom,mdss-dsi-h-front-porch = <44>;
+		qcom,mdss-dsi-h-back-porch = <55>;
+		qcom,mdss-dsi-h-pulse-width = <11>;
+		qcom,mdss-dsi-h-sync-skew = <0>;
+		qcom,mdss-dsi-v-back-porch = <15>;
+		qcom,mdss-dsi-v-front-porch = <14>;
+		qcom,mdss-dsi-v-pulse-width = <1>;
+		qcom,mdss-dsi-h-left-border = <0>;
+		qcom,mdss-dsi-h-right-border = <0>;
+		qcom,mdss-dsi-v-top-border = <0>;
+		qcom,mdss-dsi-v-bottom-border = <0>;
+		qcom,mdss-dsi-bpp = <24>;
+		qcom,mdss-dsi-color-order = <0>;
+		qcom,mdss-dsi-underflow-color = <0xff>;
+		qcom,mdss-dsi-border-color = <0>;
+		qcom,mdss-dsi-pixel-packing = <0>;
+		qcom,mdss-dsi-on-command = [29 01 00 00 00 00 06 F0 55 AA 52 08 00
+				29 01 00 00 00 00 03 B1 68 21
+				23 01 00 00 00 00 02 B5 C8
+				29 01 00 00 00 00 02 B6 0F
+				29 01 00 00 00 00 05 B8 00 00 0A 00
+				23 01 00 00 00 00 02 B9 00
+				23 01 00 00 00 00 02 BA 02
+				29 01 00 00 00 00 03 BB 63 63
+				29 01 00 00 00 00 03 BC 00 00
+				29 01 00 00 00 00 06 BD 02 7F 0D 0B 00
+				29 01 00 00 00 00 11 CC 41 36 87 54 46 65 10 12 14 10 12 14 40 08 15 05
+				23 01 00 00 00 00 02 D0 00
+				29 01 00 00 00 00 11 D1 00 04 08 0C 10 14 18 1C 20 24 28 2C 30 34 38 3C
+				23 01 00 00 00 00 02 D3 00
+				29 01 00 00 00 00 03 D6 44 44
+				29 01 00 00 00 00 0D D7 00 00 00 00 00 00 00 00 00 00 00 00
+				29 01 00 00 00 00 0E D8 00 00 00 00 00 00 00 00 00 00 00 00 00
+				29 01 00 00 00 00 03 D9 03 06
+				29 01 00 00 00 00 03 E5 00 FF
+				29 01 00 00 00 00 05 E6 F3 EC E7 DF
+				29 01 00 00 00 00 0B E7 F3 D9 CC CD B3 A6 99 99 99 95
+				29 01 00 00 00 00 0B E8 F3 D9 CC CD B3 A6 99 99 99 95
+				29 01 00 00 00 00 03 E9 00 04
+				23 01 00 00 00 00 02 EA 00
+				29 01 00 00 00 00 05 EE 87 78 00 00
+				29 01 00 00 00 00 03 EF 07 FF
+				29 01 00 00 00 00 06 F0 55 AA 52 08 01
+				29 01 00 00 00 00 03 B0 0D 0D
+				29 01 00 00 00 00 03 B1 0D 0D
+				29 01 00 00 00 00 03 B3 2D 2D
+				29 01 00 00 00 00 03 B4 19 19
+				29 01 00 00 00 00 03 B5 06 06
+				29 01 00 00 00 00 03 B6 05 05
+				29 01 00 00 00 00 03 B7 05 05
+				29 01 00 00 00 00 03 B8 05 05
+				29 01 00 00 00 00 03 B9 44 44
+				29 01 00 00 00 00 03 BA 36 36
+				29 01 00 00 00 00 03 BC 50 00
+				29 01 00 00 00 00 03 BD 50 00
+				23 01 00 00 00 00 02 BE 39
+				23 01 00 00 00 00 02 BF 39
+				23 01 00 00 00 00 02 C0 0C
+				23 01 00 00 00 00 02 C1 00
+				29 01 00 00 00 00 03 C2 19 19
+				29 01 00 00 00 00 03 C3 0A 0A
+				29 01 00 00 00 00 03 C4 23 23
+				29 01 00 00 00 00 04 C7 00 80 00
+				29 01 00 00 00 00 07 C9 00 00 00 00 00 00
+				23 01 00 00 00 00 02 CA 01
+				29 01 00 00 00 00 03 CB 0B 53
+				23 01 00 00 00 00 02 CC 00
+				29 01 00 00 00 00 04 CD 0B 52 53
+				23 01 00 00 00 00 02 CE 44
+				29 01 00 00 00 00 04 CF 00 50 50
+				29 01 00 00 00 00 03 D0 50 50
+				29 01 00 00 00 00 03 D1 50 50
+				23 01 00 00 00 00 02 D2 39
+				23 01 00 00 00 00 02 D3 39
+				29 01 00 00 00 00 06 F0 55 AA 52 08 02
+				29 01 00 00 00 00 11 B0 00 AC 00 BA 00 D9 00 ED 01 01 01 1E 01 3A 01 62
+				29 01 00 00 00 00 11 B1 01 85 01 B8 01 E4 02 27 02 5B 02 5D 02 8C 02 BE
+				29 01 00 00 00 00 11 B2 02 DF 03 0C 03 2A 03 51 03 6D 03 8D 03 A4 03 BE
+				29 01 00 00 00 00 05 B3 03 CC 03 CC
+				29 01 00 00 00 00 11 B4 00 AC 00 BA 00 D9 00 ED 01 01 01 1E 01 3A 01 62
+				29 01 00 00 00 00 11 B5 01 85 01 B8 01 E4 02 27 02 5B 02 5D 02 8C 02 BE
+				29 01 00 00 00 00 11 B6 02 DF 03 0C 03 2A 03 51 03 6D 03 8D 03 A4 03 BE
+				29 01 00 00 00 00 05 B7 03 CC 03 CC
+				29 01 00 00 00 00 11 B8 00 AC 00 BA 00 D9 00 ED 01 01 01 1E 01 3A 01 62
+				29 01 00 00 00 00 11 B9 01 85 01 B8 01 E4 02 27 02 5B 02 5D 02 8C 02 BE
+				29 01 00 00 00 00 11 BA 02 DF 03 0C 03 2A 03 51 03 6D 03 8D 03 A4 03 BE
+				29 01 00 00 00 00 05 BB 03 CC 03 CC
+				29 01 00 00 00 00 11 BC 00 AC 00 BA 00 D9 00 ED 01 01 01 1E 01 3A 01 62
+				29 01 00 00 00 00 11 BD 01 85 01 B8 01 E4 02 27 02 5B 02 5D 02 8C 02 BE
+				29 01 00 00 00 00 11 BE 02 DF 03 0C 03 2A 03 51 03 6D 03 8D 03 A4 03 BE
+				29 01 00 00 00 00 05 BF 03 CC 03 CC
+				29 01 00 00 00 00 11 C0 00 AC 00 BA 00 D9 00 ED 01 01 01 1E 01 3A 01 62
+				29 01 00 00 00 00 11 C1 01 85 01 B8 01 E4 02 27 02 5B 02 5D 02 8C 02 BE
+				29 01 00 00 00 00 11 C2 02 DF 03 0C 03 2A 03 51 03 6D 03 8D 03 A4 03 BE
+				29 01 00 00 00 00 05 C3 03 CC 03 CC
+				29 01 00 00 00 00 11 C4 00 AC 00 BA 00 D9 00 ED 01 01 01 1E 01 3A 01 62
+				29 01 00 00 00 00 11 C5 01 85 01 B8 01 E4 02 27 02 5B 02 5D 02 8C 02 BE
+				29 01 00 00 00 00 11 C6 02 DF 03 0C 03 2A 03 51 03 6D 03 8D 03 A4 03 BE
+				29 01 00 00 00 00 05 C7 03 CC 03 CC
+				23 01 00 00 00 00 02 EE 00
+				29 01 00 00 00 00 06 F0 55 AA 52 08 03
+				29 01 00 00 00 00 03 B0 00 00
+				29 01 00 00 00 00 03 B1 00 00
+				29 01 00 00 00 00 06 B2 03 00 00 00 00
+				29 01 00 00 00 00 06 B3 03 00 00 00 00
+				29 01 00 00 00 00 06 B4 03 00 00 00 00
+				29 01 00 00 00 00 06 B5 03 00 00 00 00
+				29 01 00 00 00 00 06 B6 03 00 00 00 00
+				29 01 00 00 00 00 06 B7 03 00 00 00 00
+				29 01 00 00 00 00 06 B8 03 00 00 00 00
+				29 01 00 00 00 00 06 B9 03 00 00 00 00
+				29 01 00 00 00 00 06 BA 35 10 00 00 00
+				29 01 00 00 00 00 06 BB 35 10 00 00 00
+				29 01 00 00 00 00 06 BC 35 10 00 00 00
+				29 01 00 00 00 00 06 BD 35 10 00 00 00
+				29 01 00 00 00 00 05 C0 00 34 00 00
+				29 01 00 00 00 00 05 C1 00 34 00 00
+				29 01 00 00 00 00 05 C2 00 34 00 00
+				29 01 00 00 00 00 05 C3 00 34 00 00
+				23 01 00 00 00 00 02 C4 40
+				23 01 00 00 00 00 02 C5 40
+				23 01 00 00 00 00 02 C6 40
+				23 01 00 00 00 00 02 C7 40
+				23 01 00 00 00 00 02 EF 00
+				29 01 00 00 00 00 06 F0 55 AA 52 08 05
+				29 01 00 00 00 00 03 B0 1B 10
+				29 01 00 00 00 00 03 B1 1B 10
+				29 01 00 00 00 00 03 B2 1B 10
+				29 01 00 00 00 00 03 B3 1B 10
+				29 01 00 00 00 00 03 B4 1B 10
+				29 01 00 00 00 00 03 B5 1B 10
+				29 01 00 00 00 00 03 B6 1B 10
+				29 01 00 00 00 00 03 B7 1B 10
+				23 01 00 00 00 00 02 B8 00
+				23 01 00 00 00 00 02 B9 00
+				23 01 00 00 00 00 02 BA 00
+				23 01 00 00 00 00 02 BB 00
+				23 01 00 00 00 00 02 BC 00
+				29 01 00 00 00 00 06 BD 03 03 03 00 01
+				23 01 00 00 00 00 02 C0 03
+				23 01 00 00 00 00 02 C1 05
+				23 01 00 00 00 00 02 C2 03
+				23 01 00 00 00 00 02 C3 05
+				23 01 00 00 00 00 02 C4 80
+				23 01 00 00 00 00 02 C5 A2
+				23 01 00 00 00 00 02 C6 80
+				23 01 00 00 00 00 02 C7 A2
+				29 01 00 00 00 00 03 C8 01 20
+				29 01 00 00 00 00 03 C9 00 20
+				29 01 00 00 00 00 03 CA 01 00
+				29 01 00 00 00 00 03 CB 00 00
+				29 01 00 00 00 00 04 CC 00 00 01
+				29 01 00 00 00 00 04 CD 00 00 01
+				29 01 00 00 00 00 04 CE 00 00 01
+				29 01 00 00 00 00 04 CF 00 00 01
+				23 01 00 00 00 00 02 D0 00
+				29 01 00 00 00 00 06 D1 03 00 00 07 10
+				29 01 00 00 00 00 06 D2 13 00 00 07 11
+				29 01 00 00 00 00 06 D3 23 00 00 07 10
+				29 01 00 00 00 00 06 D4 33 00 00 07 11
+				23 01 00 00 00 00 02 E5 06
+				23 01 00 00 00 00 02 E6 06
+				23 01 00 00 00 00 02 E7 06
+				23 01 00 00 00 00 02 E8 06
+				23 01 00 00 00 00 02 E9 06
+				23 01 00 00 00 00 02 EA 06
+				23 01 00 00 00 00 02 EB 06
+				23 01 00 00 00 00 02 EC 06
+				23 01 00 00 00 00 02 ED 31
+				29 01 00 00 00 00 06 F0 55 AA 52 08 06
+				29 01 00 00 00 00 03 B0 10 11
+				29 01 00 00 00 00 03 B1 12 13
+				29 01 00 00 00 00 03 B2 08 00
+				29 01 00 00 00 00 03 B3 2D 2D
+				29 01 00 00 00 00 03 B4 2D 34
+				29 01 00 00 00 00 03 B5 34 2D
+				29 01 00 00 00 00 03 B6 2D 34
+				29 01 00 00 00 00 03 B7 34 34
+				29 01 00 00 00 00 03 B8 02 0A
+				29 01 00 00 00 00 03 B9 00 08
+				29 01 00 00 00 00 03 BA 09 01
+				29 01 00 00 00 00 03 BB 0B 03
+				29 01 00 00 00 00 03 BC 34 34
+				29 01 00 00 00 00 03 BD 34 2D
+				29 01 00 00 00 00 03 BE 2D 34
+				29 01 00 00 00 00 03 BF 34 2D
+				29 01 00 00 00 00 03 C0 2D 2D
+				29 01 00 00 00 00 03 C1 01 09
+				29 01 00 00 00 00 03 C2 19 18
+				29 01 00 00 00 00 03 C3 17 16
+				29 01 00 00 00 00 03 C4 19 18
+				29 01 00 00 00 00 03 C5 17 16
+				29 01 00 00 00 00 03 C6 01 09
+				29 01 00 00 00 00 03 C7 2D 2D
+				29 01 00 00 00 00 03 C8 2D 34
+				29 01 00 00 00 00 03 C9 34 2D
+				29 01 00 00 00 00 03 CA 2D 34
+				29 01 00 00 00 00 03 CB 34 34
+				29 01 00 00 00 00 03 CC 0B 03
+				29 01 00 00 00 00 03 CD 09 01
+				29 01 00 00 00 00 03 CE 00 08
+				29 01 00 00 00 00 03 CF 02 0A
+				29 01 00 00 00 00 03 D0 34 34
+				29 01 00 00 00 00 03 D1 34 2D
+				29 01 00 00 00 00 03 D2 2D 34
+				29 01 00 00 00 00 03 D3 34 2D
+				29 01 00 00 00 00 03 D4 2D 2D
+				29 01 00 00 00 00 03 D5 08 00
+				29 01 00 00 00 00 03 D6 10 11
+				29 01 00 00 00 00 03 D7 12 13
+				29 01 00 00 00 00 06 D8 55 55 55 55 55
+				29 01 00 00 00 00 06 D9 55 55 55 55 55
+				29 01 00 00 00 00 03 E5 34 34
+				29 01 00 00 00 00 03 E6 34 34
+				23 01 00 00 00 00 02 E7 05
+				29 01 00 00 00 00 06 F0 55 AA 52 00 00
+				05 01 00 00 00 00 02 11 00
+				05 01 00 00 14 00 02 29 00
+				29 01 00 00 00 00 06 F0 55 AA 52 08 01
+				29 01 00 00 00 00 06 F0 55 AA 52 00 00
+				29 01 00 00 00 00 02 53 2C];
+		qcom,mdss-dsi-off-command = [05 01 00 00 00 00 02 28 00
+					05 01 00 00 00 00 02 10 00];
+		qcom,mdss-dsi-on-command-state = "dsi_lp_mode";
+		qcom,mdss-dsi-off-command-state = "dsi_hs_mode";
+		qcom,mdss-dsi-h-sync-pulse = <1>;
+		qcom,mdss-dsi-traffic-mode = <2>;
+		qcom,mdss-dsi-lane-map = <0>;
+		qcom,mdss-dsi-bllp-eof-power-mode;
+		qcom,mdss-dsi-bllp-power-mode;
+		qcom,mdss-dsi-lane-0-state;
+		qcom,mdss-dsi-lane-1-state;
+		qcom,mdss-dsi-lane-2-state;
+		qcom,mdss-dsi-lane-3-state;
+		qcom,mdss-dsi-panel-timings = [93 1F 17 00 2F 2E 1C 21 26 03 04 00];
+		qcom,mdss-dsi-t-clk-post = <0x20>;
+		qcom,mdss-dsi-t-clk-pre = <0x2D>;
+		qcom,mdss-dsi-bl-min-level = <1>;
+		qcom,mdss-dsi-bl-max-level = <255>;
+		qcom,mdss-dsi-dma-trigger = <4>;
+		qcom,mdss-dsi-mdp-trigger = <0>;
+		qcom,mdss-dsi-bl-pmic-control-type = "bl_ctrl_dcs";
+
+	};
+};
diff --git a/arch/arm/boot/dts/dsi-panel-nt35590-720p-cmd.dtsi b/arch/arm/boot/dts/dsi-panel-nt35590-720p-cmd.dtsi
index d0b4da8..0918cf4 100644
--- a/arch/arm/boot/dts/dsi-panel-nt35590-720p-cmd.dtsi
+++ b/arch/arm/boot/dts/dsi-panel-nt35590-720p-cmd.dtsi
@@ -15,10 +15,8 @@
  * Update input XML file to add a new entry or update variable in this file
  * VERSION = "1.0"
  *---------------------------------------------------------------------------*/
-&soc {
-	qcom,mdss_dsi_nt35590_720p_cmd {
-		compatible = "qcom,mdss-dsi-panel";
-		status = "disable";
+&mdss_mdp {
+	dsi_nt35590_720_cmd: qcom,mdss_dsi_nt35590_720p_cmd {
 		qcom,mdss-dsi-panel-name = "nt35590 720p command mode dsi panel";
 		qcom,mdss-dsi-panel-controller = <&mdss_dsi0>;
 		qcom,mdss-dsi-panel-type = "dsi_cmd_mode";
diff --git a/arch/arm/boot/dts/dsi-panel-nt35590-720p-video.dtsi b/arch/arm/boot/dts/dsi-panel-nt35590-720p-video.dtsi
index a171a5c..6d68a3e 100644
--- a/arch/arm/boot/dts/dsi-panel-nt35590-720p-video.dtsi
+++ b/arch/arm/boot/dts/dsi-panel-nt35590-720p-video.dtsi
@@ -15,10 +15,8 @@
  * Update input XML file to add a new entry or update variable in this file
  * VERSION = "1.0"
  *---------------------------------------------------------------------------*/
-&soc {
-	qcom,mdss_dsi_nt35590_720p_video {
-		compatible = "qcom,mdss-dsi-panel";
-		status = "disable";
+&mdss_mdp {
+	dsi_nt35590_720_vid: qcom,mdss_dsi_nt35590_720p_video {
 		qcom,mdss-dsi-panel-name = "nt35590 720p video mode dsi panel";
 		qcom,mdss-dsi-panel-controller = <&mdss_dsi0>;
 		qcom,mdss-dsi-panel-type = "dsi_video_mode";
diff --git a/arch/arm/boot/dts/dsi-panel-nt35596-1080p-video.dtsi b/arch/arm/boot/dts/dsi-panel-nt35596-1080p-video.dtsi
index 998799a..49aef24 100644
--- a/arch/arm/boot/dts/dsi-panel-nt35596-1080p-video.dtsi
+++ b/arch/arm/boot/dts/dsi-panel-nt35596-1080p-video.dtsi
@@ -15,10 +15,8 @@
  * Update input XML file to add a new entry or update variable in this file
  * VERSION = "1.0"
  *---------------------------------------------------------------------------*/
-&soc {
-	qcom,mdss_dsi_nt35596_1080p_video {
-		compatible = "qcom,mdss-dsi-panel";
-		status = "disable";
+&mdss_mdp {
+	dsi_nt35596_1080_vid: qcom,mdss_dsi_nt35596_1080p_video {
 		qcom,mdss-dsi-panel-name = "nt35596 1080p video mode dsi panel";
 		qcom,mdss-dsi-panel-controller = <&mdss_dsi0>;
 		qcom,mdss-dsi-panel-type = "dsi_video_mode";
diff --git a/arch/arm/boot/dts/dsi-panel-orise-720p-video.dtsi b/arch/arm/boot/dts/dsi-panel-orise-720p-video.dtsi
index 478541f..30eda91 100644
--- a/arch/arm/boot/dts/dsi-panel-orise-720p-video.dtsi
+++ b/arch/arm/boot/dts/dsi-panel-orise-720p-video.dtsi
@@ -10,11 +10,9 @@
  * GNU General Public License for more details.
  */
 
-&soc {
-	qcom,mdss_dsi_orise_720p_video {
-		compatible = "qcom,mdss-dsi-panel";
+&mdss_mdp {
+	dsi_orise_720_vid: qcom,mdss_dsi_orise_720p_video {
 		label = "orise 720p video mode dsi panel";
-		status = "disable";
 		qcom,dsi-ctrl-phandle = <&mdss_dsi1>;
 		qcom,mdss-pan-res = <720 1280>;
 		qcom,mdss-pan-bpp = <24>;
diff --git a/arch/arm/boot/dts/dsi-panel-otm8018b-fwvga-video.dtsi b/arch/arm/boot/dts/dsi-panel-otm8018b-fwvga-video.dtsi
new file mode 100644
index 0000000..89a5063
--- /dev/null
+++ b/arch/arm/boot/dts/dsi-panel-otm8018b-fwvga-video.dtsi
@@ -0,0 +1,266 @@
+/* Copyright (c) 2013, The Linux Foundation. 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 and
+ * only 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.
+ */
+
+/*---------------------------------------------------------------------------
+ * This file is autogenerated file using gcdb parser. Please do not edit it.
+ * Update input XML file to add a new entry or update variable in this file
+ * VERSION = "1.0"
+ *---------------------------------------------------------------------------*/
+&mdss_mdp {
+	dsi_otm8018b_fwvga_vid: qcom,mdss_dsi_otm8018b_fwvga_video {
+		qcom,mdss-dsi-panel-name = "OTM8018b fwvga video mode dsi panel";
+		qcom,mdss-dsi-panel-controller = <&mdss_dsi0>;
+		qcom,mdss-dsi-panel-type = "dsi_video_mode";
+		qcom,mdss-dsi-panel-destination = "display_1";
+		qcom,mdss-dsi-panel-framerate = <60>;
+		qcom,mdss-dsi-virtual-channel-id = <0>;
+		qcom,mdss-dsi-stream = <0>;
+		qcom,mdss-dsi-panel-width = <480>;
+		qcom,mdss-dsi-panel-height = <854>;
+		qcom,mdss-dsi-h-front-porch = <80>;
+		qcom,mdss-dsi-h-back-porch = <54>;
+		qcom,mdss-dsi-h-pulse-width = <8>;
+		qcom,mdss-dsi-h-sync-skew = <0>;
+		qcom,mdss-dsi-v-back-porch = <16>;
+		qcom,mdss-dsi-v-front-porch = <12>;
+		qcom,mdss-dsi-v-pulse-width = <2>;
+		qcom,mdss-dsi-h-left-border = <0>;
+		qcom,mdss-dsi-h-right-border = <0>;
+		qcom,mdss-dsi-v-top-border = <0>;
+		qcom,mdss-dsi-v-bottom-border = <0>;
+		qcom,mdss-dsi-bpp = <24>;
+		qcom,mdss-dsi-color-order = <0>;
+		qcom,mdss-dsi-underflow-color = <0xff>;
+		qcom,mdss-dsi-border-color = <0>;
+		qcom,mdss-dsi-on-command = [
+					29 01 00 00 00 00 02
+						00 00
+					29 01 00 00 00 00 04
+						ff 80 09 01
+					29 01 00 00 00 00 02
+						00 80
+					29 01 00 00 00 00 03
+						ff 80 09
+					29 01 00 00 00 00 02
+						00 80
+					29 01 00 00 00 00 02
+						d6 48
+					29 01 00 00 00 00 02
+						00 03
+					29 01 00 00 00 00 02
+						ff 01
+					29 01 00 00 00 00 02
+						00 B4
+					29 01 00 00 00 00 02
+						C0 10
+					29 01 00 00 00 00 02
+						00 82
+					29 01 00 00 00 00 02
+						C5 A3
+					29 01 00 00 00 00 02
+						00 90
+					29 01 00 00 00 00 03
+						C5 96 87
+					29 01 00 00 00 00 02
+						00 00
+					29 01 00 00 00 00 03
+						D8 74 72
+					29 01 00 00 00 00 02
+						00 00
+					29 01 00 00 00 00 02
+						D9 56
+					29 01 00 00 00 00 02
+						00 00
+					29 01 00 00 00 00 11
+						E1 00 06 0A
+						07 03 16 08
+						0A 04 06 07
+						08 0F 23 22
+						05
+					29 01 00 00 00 00 02
+						00 00
+					29 01 00 00 00 00 11
+						E2 00 06 0A
+						07 03 16 08
+						0A 04 06 07
+						08 0F 23 22
+						05
+					29 01 00 00 00 00 02
+						00 81
+					29 01 00 00 00 00 02
+						C1 77
+					29 01 00 00 00 00 02
+						00 A0
+					29 01 00 00 00 00 02
+						C1 EA
+					29 01 00 00 00 00 02
+						00 A1
+					29 01 00 00 00 00 02
+						C1 08
+					29 01 00 00 00 00 02
+						00 89
+					29 01 00 00 00 00 02
+						C4 08
+					29 01 00 00 00 00 02
+						00 81
+					29 01 00 00 00 00 02
+						C4 83
+					29 01 00 00 00 00 02
+						00 92
+					29 01 00 00 00 00 02
+						C5 01
+					29 01 00 00 00 00 02
+						00 B1
+					29 01 00 00 00 00 02
+						C5 A9
+					29 01 00 00 00 00 02
+						00 92
+					29 01 00 00 00 00 02
+						B3 45
+					29 01 00 00 00 00 02
+						00 90
+					29 01 00 00 00 00 02
+						B3 02
+					29 01 00 00 00 00 02
+						00 80
+					29 01 00 00 00 00 06
+						C0 00 58 00
+						14 16
+					29 01 00 00 00 00 02
+						00 80
+					29 01 00 00 00 00 02
+						C4 30
+					29 01 00 00 00 00 02
+						00 90
+					29 01 00 00 00 00 07
+						C0 00 44 00
+						00 00 03
+					29 01 00 00 00 00 02
+						00 A6
+					29 01 00 00 00 00 04
+						C1 01 00 00
+					29 01 00 00 00 00 02
+						00 80
+					29 01 00 00 00 00 0D
+						CE 87 03 00
+						85 03 00 86
+						03 00 84 03
+						00
+					29 01 00 00 00 00 02
+						00 A0
+					29 01 00 00 00 00 0f
+						CE 38 03 03
+						58 00 00 00
+						38 02 03 59
+						00 00 00
+					29 01 00 00 00 00 02
+						00 B0
+					29 01 00 00 00 00 0f
+						CE 38 01 03
+						5A 00 00 00
+						38 00 03 5B
+						00 00 00
+					29 01 00 00 00 00 02
+						00 C0
+					29 01 00 00 00 00 0f
+						CE 30 00 03
+						5C 00 00 00
+						30 01 03 5D
+						00 00 00
+					29 01 00 00 00 00 02
+						00 D0
+					29 01 00 00 00 00 0f
+						CE 30 02 03
+						5E 00 00 00
+						30 03 03 5F
+						00 00 00
+					29 01 00 00 00 00 02
+						00 C7
+					29 01 00 00 00 00 02
+						CF 00
+					29 01 00 00 00 00 02
+						00 C9
+					29 01 00 00 00 00 02
+						CF 00
+					29 01 00 00 00 00 02
+						00 D0
+					29 01 00 00 00 00 02
+						CF 00
+					29 01 00 00 00 00 02
+						00 C4
+					29 01 00 00 00 00 07
+						CB 04 04 04
+						04 04 04
+					29 01 00 00 00 00 02
+						00 D9
+					29 01 00 00 00 00 07
+						CB 04 04 04
+						04 04 04
+					29 01 00 00 00 00 02
+						00 84
+					29 01 00 00 00 00 07
+						CC 0C 0A 10
+						0E 03 04
+					29 01 00 00 00 00 02
+						00 9E
+					29 01 00 00 00 00 02
+						CC 0B
+					29 01 00 00 00 00 02
+						00 A0
+					29 01 00 00 00 00 06
+						CC 09 0F 0D
+						01 02
+					29 01 00 00 00 00 02
+						00 B4
+					29 01 00 00 00 00 07
+						CC 0D 0F 09
+						0B 02 01
+					29 01 00 00 00 00 02
+						00 CE
+					29 01 00 00 00 00 02
+						CC 0E
+					29 01 00 00 00 00 02
+						00 D0
+					29 01 00 00 00 00 06
+						CC 10 0A 0C
+						04 03
+					29 01 00 00 00 00 02
+						00 00
+					29 01 00 00 00 00 04
+						ff ff ff ff
+					05 01 00 00 78 00 02
+						11 00
+					05 01 00 00 32 00 02
+						29 00
+					];
+		qcom,mdss-dsi-off-command = [05 01 00 00 32 00 02 28 00
+					05 01 00 00 78 00 02 10 00];
+		qcom,mdss-dsi-on-command-state = "dsi_lp_mode";
+		qcom,mdss-dsi-off-command-state = "dsi_lp_mode";
+		qcom,mdss-dsi-h-sync-pulse = <0>;
+		qcom,mdss-dsi-traffic-mode = <1>;
+		qcom,mdss-dsi-lane-map = <1>;
+		qcom,mdss-dsi-bllp-eof-power-mode;
+		qcom,mdss-dsi-bllp-power-mode;
+		qcom,mdss-dsi-lane-0-state;
+		qcom,mdss-dsi-lane-1-state;
+		qcom,mdss-dsi-panel-timings = [8B 1F 14 00 45 4A 19 23 23 03 04 00];
+		qcom,mdss-dsi-t-clk-post = <0x04>;
+		qcom,mdss-dsi-t-clk-pre = <0x1b>;
+		qcom,mdss-dsi-bl-min-level = <1>;
+		qcom,mdss-dsi-bl-max-level = <255>;
+		qcom,mdss-dsi-dma-trigger = <4>;
+		qcom,mdss-dsi-mdp-trigger = <0>;
+		qcom,mdss-dsi-bl-pmic-control-type = "bl_ctrl_wled";
+
+	};
+};
diff --git a/arch/arm/boot/dts/dsi-panel-sharp-qhd-video.dtsi b/arch/arm/boot/dts/dsi-panel-sharp-qhd-video.dtsi
index 7fe0f7f..c627e7a 100644
--- a/arch/arm/boot/dts/dsi-panel-sharp-qhd-video.dtsi
+++ b/arch/arm/boot/dts/dsi-panel-sharp-qhd-video.dtsi
@@ -15,10 +15,8 @@
  * Update input XML file to add a new entry or update variable in this file
  * VERSION = "1.0"
  *---------------------------------------------------------------------------*/
-&soc {
-	qcom,mdss_dsi_sharp_qhd_video {
-		compatible = "qcom,mdss-dsi-panel";
-		status = "disable";
+&mdss_mdp {
+	dsi_sharp_qhd_vid: qcom,mdss_dsi_sharp_qhd_video {
 		qcom,mdss-dsi-panel-name = "sharp QHD LS043T1LE01 video mode dsi panel";
 		qcom,mdss-dsi-panel-controller = <&mdss_dsi0>;
 		qcom,mdss-dsi-panel-type = "dsi_video_mode";
diff --git a/arch/arm/boot/dts/dsi-panel-sim-video.dtsi b/arch/arm/boot/dts/dsi-panel-sim-video.dtsi
index 271e373..ccbb659 100644
--- a/arch/arm/boot/dts/dsi-panel-sim-video.dtsi
+++ b/arch/arm/boot/dts/dsi-panel-sim-video.dtsi
@@ -10,12 +10,9 @@
  * GNU General Public License for more details.
  */
 
-&soc {
-
-	qcom,mdss_dsi_sim_video {
-		compatible = "qcom,mdss-dsi-panel";
+&mdss_mdp {
+	dsi_sim_vid: qcom,mdss_dsi_sim_video {
 		label = "simulator video mode dsi panel";
-		status = "disable";
 		qcom,dsi-ctrl-phandle = <&mdss_dsi0>;
 		qcom,mdss-pan-res = <640 480>;
 		qcom,mdss-pan-bpp = <24>;
diff --git a/arch/arm/boot/dts/dsi-panel-ssd2080m-720p-video.dtsi b/arch/arm/boot/dts/dsi-panel-ssd2080m-720p-video.dtsi
new file mode 100644
index 0000000..7bb414a
--- /dev/null
+++ b/arch/arm/boot/dts/dsi-panel-ssd2080m-720p-video.dtsi
@@ -0,0 +1,119 @@
+/* Copyright (c) 2013, The Linux Foundation. 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 and
+ * only 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.
+ */
+
+/*---------------------------------------------------------------------------
+ * This file is autogenerated file using gcdb parser. Please do not edit it.
+ * Update input XML file to add a new entry or update variable in this file
+ * VERSION = "1.0"
+ *---------------------------------------------------------------------------*/
+&mdss_mdp {
+	dsi_ssd2080m_720_vid: qcom,mdss_dsi_ssd2080m_720p_video {
+		qcom,mdss-dsi-panel-name = "ssd2080m 720p video mode dsi panel";
+		qcom,mdss-dsi-panel-controller = <&mdss_dsi0>;
+		qcom,mdss-dsi-panel-type = "dsi_video_mode";
+		qcom,mdss-dsi-panel-destination = "display_1";
+		qcom,mdss-dsi-panel-framerate = <60>;
+		qcom,mdss-dsi-virtual-channel-id = <0>;
+		qcom,mdss-dsi-stream = <0>;
+		qcom,mdss-dsi-panel-width = <720>;
+		qcom,mdss-dsi-panel-height = <1280>;
+		qcom,mdss-dsi-h-front-porch = <80>;
+		qcom,mdss-dsi-h-back-porch = <24>;
+		qcom,mdss-dsi-h-pulse-width = <14>;
+		qcom,mdss-dsi-h-sync-skew = <0>;
+		qcom,mdss-dsi-v-back-porch = <15>;
+		qcom,mdss-dsi-v-front-porch = <12>;
+		qcom,mdss-dsi-v-pulse-width = <10>;
+		qcom,mdss-dsi-h-left-border = <0>;
+		qcom,mdss-dsi-h-right-border = <0>;
+		qcom,mdss-dsi-v-top-border = <0>;
+		qcom,mdss-dsi-v-bottom-border = <0>;
+		qcom,mdss-dsi-bpp = <24>;
+		qcom,mdss-dsi-color-order = <0>;
+		qcom,mdss-dsi-underflow-color = <0xff>;
+		qcom,mdss-dsi-border-color = <0>;
+		qcom,mdss-dsi-on-command = [15 01 00 00 00 00 02 FF 01
+			29 01 00 00 00 00 05 C6 63 00 81 31
+			29 01 00 00 00 00 05 CB E7 80 73 33
+			29 01 00 00 00 00 02 EC D2
+			29 01 00 00 00 00 03 B3 04 9F
+			29 01 00 00 00 00 04 B2 16 1E 10
+			29 01 00 00 00 00 02 B4 00
+			29 01 00 00 00 00 02 C1 04
+			29 01 00 00 00 00 04 C2 BE 00 58
+			29 01 00 00 00 00 09 C3 01 22 11 21 0E 80 80 24
+			29 01 00 00 00 00 08 B6 09 16 42 01 13 00 00
+			29 01 00 00 00 00 04 B7 24 26 43
+			29 01 00 00 00 00 06 B8 16 08 25 44 08
+			29 01 00 00 00 00 09 B9 06 08 07 09 00 00 00 00
+			29 01 00 00 00 00 09 BA 0E 10 0A 0C 16 05 00 00
+			29 01 00 00 00 00 09 BB A1 A1 A1 A1 00 00 00 00
+			29 01 00 00 00 00 09 BC 0F 11 0B 0D 16 05 00 00
+			29 01 00 00 00 00 09 BD A1 A1 A1 A1 00 00 00 00
+			29 01 00 00 00 00 04 E6 FF FF 0F
+			29 01 00 00 00 00 02 C7 3F
+			29 01 00 00 00 00 07 B5 47 00 00 08 00 01
+			29 01 00 00 00 00 08 C4 DF 72 12 12 66 E3 99
+			29 01 00 00 00 00 07 D0 0A 00 0D 15 1F 2E
+			29 01 00 00 00 00 06 D1 28 27 14 02 01
+			29 01 00 00 00 00 07 D2 0A 00 0D 15 1F 2E
+			29 01 00 00 00 00 06 D3 28 27 14 02 01
+			29 01 00 00 00 00 07 D4 0A 00 0D 15 1F 2E
+			29 01 00 00 00 00 06 D5 28 27 14 02 01
+			29 01 00 00 00 00 07 D6 0A 00 0D 15 1F 2E
+			29 01 00 00 00 00 06 D7 28 27 14 02 01
+			29 01 00 00 00 00 07 D8 0A 00 0D 15 1F 2E
+			29 01 00 00 00 00 06 D9 28 27 14 02 01
+			29 01 00 00 00 00 07 DA 0A 00 0D 15 1F 2E
+			29 01 00 00 00 00 06 DB 28 27 14 02 01
+			29 01 00 00 00 00 03 CC 10 00
+			29 01 00 00 00 00 04 CE 4E 55 A5
+			29 01 00 00 00 00 04 E0 01 02 02
+			29 01 00 00 00 00 05 F6 00 00 00 00
+			29 01 00 00 00 00 05 F7 00 00 00 00
+			29 01 00 00 00 00 03 E1 90 00
+			29 01 00 00 00 00 03 DE 95 CF
+			29 01 00 00 00 00 02 CF 46
+			29 01 00 00 00 00 03 C5 77 47
+			29 01 00 00 00 00 03 ED 00 20
+			05 01 00 00 B4 00 02 11 00
+			05 01 00 00 82 00 02 29 00
+			15 01 00 00 00 00 02 53 2c];
+
+		qcom,mdss-dsi-off-command = [05 01 00 00 32 00 02 10 00
+			05 01 00 00 32 00 02 53 00
+			05 01 00 00 00 00 02 c2 00
+			39 01 00 00 00 00 02 cf 40
+			05 01 00 00 50 00 03 de 84 00
+			39 01 00 00 00 00 02 cb 22
+			05 01 00 00 00 00 02 c3 00];
+
+		qcom,mdss-dsi-on-command-state = "dsi_lp_mode";
+		qcom,mdss-dsi-off-command-state = "dsi_hs_mode";
+		qcom,mdss-dsi-h-sync-pulse = <1>;
+		qcom,mdss-dsi-traffic-mode = <2>;
+		qcom,mdss-dsi-lane-map = <0>;
+		qcom,mdss-dsi-bllp-eof-power-mode;
+		qcom,mdss-dsi-lane-0-state;
+		qcom,mdss-dsi-lane-1-state;
+		qcom,mdss-dsi-lane-2-state;
+		qcom,mdss-dsi-lane-3-state;
+		qcom,mdss-dsi-panel-timings = [a8 1f 17 00 2f 2d 1c 21 29 03 04 00];
+		qcom,mdss-dsi-t-clk-post = <0x20>;
+		qcom,mdss-dsi-t-clk-pre = <0x2f>;
+		qcom,mdss-dsi-bl-min-level = <1>;
+		qcom,mdss-dsi-bl-max-level = <4095>;
+		qcom,mdss-dsi-dma-trigger = <4>;
+		qcom,mdss-dsi-mdp-trigger = <0>;
+		qcom,mdss-dsi-bl-pmic-control-type = "bl_ctrl_wled";
+	};
+};
diff --git a/arch/arm/boot/dts/dsi-panel-toshiba-720p-video.dtsi b/arch/arm/boot/dts/dsi-panel-toshiba-720p-video.dtsi
index a824d45..0b98db7 100644
--- a/arch/arm/boot/dts/dsi-panel-toshiba-720p-video.dtsi
+++ b/arch/arm/boot/dts/dsi-panel-toshiba-720p-video.dtsi
@@ -15,10 +15,8 @@
  * Update input XML file to add a new entry or update variable in this file
  * VERSION = "1.0"
  *---------------------------------------------------------------------------*/
-&soc {
-	qcom,mdss_dsi_toshiba_720p_video {
-		compatible = "qcom,mdss-dsi-panel";
-		status = "disable";
+&mdss_mdp {
+	dsi_tosh_720_vid: qcom,mdss_dsi_toshiba_720p_video {
 		qcom,mdss-dsi-panel-name = "toshiba 720p video mode dsi panel";
 		qcom,mdss-dsi-panel-controller = <&mdss_dsi0>;
 		qcom,mdss-dsi-panel-type = "dsi_video_mode";
diff --git a/arch/arm/boot/dts/dsi-panel-truly-wvga-cmd.dtsi b/arch/arm/boot/dts/dsi-panel-truly-wvga-cmd.dtsi
new file mode 100644
index 0000000..f6e6df8
--- /dev/null
+++ b/arch/arm/boot/dts/dsi-panel-truly-wvga-cmd.dtsi
@@ -0,0 +1,170 @@
+/* Copyright (c) 2013, The Linux Foundation. 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 and
+ * only 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.
+ */
+
+/*---------------------------------------------------------------------------
+ * This file is autogenerated file using gcdb parser. Please do not edit it.
+ * Update input XML file to add a new entry or update variable in this file
+ * VERSION = "1.0"
+ *---------------------------------------------------------------------------*/
+&mdss_mdp {
+	dsi_truly_wvga_cmd: qcom,mdss_dsi_truly_wvga_cmd {
+		qcom,mdss-dsi-panel-name = "Truly WVGA command mode dsi panel";
+		qcom,mdss-dsi-panel-controller = <&mdss_dsi0>;
+		qcom,mdss-dsi-panel-type = "dsi_cmd_mode";
+		qcom,mdss-dsi-panel-destination = "display_1";
+		qcom,mdss-dsi-panel-mode-gpio-state = "low";
+		qcom,mdss-dsi-panel-framerate = <60>;
+		qcom,mdss-dsi-virtual-channel-id = <0>;
+		qcom,mdss-dsi-stream = <0>;
+		qcom,mdss-dsi-panel-width = <480>;
+		qcom,mdss-dsi-panel-height = <800>;
+		qcom,mdss-dsi-h-front-porch = <160>;
+		qcom,mdss-dsi-h-back-porch = <40>;
+		qcom,mdss-dsi-h-pulse-width = <8>;
+		qcom,mdss-dsi-h-sync-skew = <0>;
+		qcom,mdss-dsi-v-back-porch = <10>;
+		qcom,mdss-dsi-v-front-porch = <12>;
+		qcom,mdss-dsi-v-pulse-width = <2>;
+		qcom,mdss-dsi-h-left-border = <0>;
+		qcom,mdss-dsi-h-right-border = <0>;
+		qcom,mdss-dsi-v-top-border = <0>;
+		qcom,mdss-dsi-v-bottom-border = <0>;
+		qcom,mdss-dsi-bpp = <24>;
+		qcom,mdss-dsi-color-order = <0>;
+		qcom,mdss-dsi-underflow-color = <0xff>;
+		qcom,mdss-dsi-border-color = <0>;
+		qcom,mdss-dsi-on-command = [
+					05 01 00 00 00 00 02
+						01 00
+					23 01 00 00 00 00 02
+						b0 04
+					29 01 00 00 00 00 03
+						b3 02 00
+					29 01 00 00 00 00 03
+						b6 51 83
+					29 01 00 00 00 00 05
+						b7 00 80 15 25
+					29 01 00 00 00 00 14
+						b8 00 07 07 ff c8 c8 01 18 10 10
+						37 5a 87 de ff 00 00 00 00
+					29 01 00 00 00 00 05
+						b9 00 00 00 00
+					23 01 00 00 00 00 02
+						bd 00
+					29 01 00 00 00 00 03
+						c0 02 43
+					29 01 00 00 00 00 10
+						c1 43 31 99 21 20 00 10 28 0c 0c
+						00 00 00 21 01
+					29 01 00 00 00 00 07
+						c2 28 06 06 01 03 00
+					29 01 00 00 00 00 04
+						c3 40 00 03
+					29 01 00 00 00 00 03
+						6f 03 00
+					29 01 00 00 00 00 03
+						c4 00 01
+					29 01 00 00 00 00 03
+						c6 00 00
+					29 01 00 00 00 00 06
+						c7 11 8d a0 f5 27
+					29 01 00 00 00 00 19
+						c8 01 0a 12 1c 2b 45 3f 29 17 13
+						0f 04 01 0a 12 1c 2b 45 3f 29 17 13 0f 04
+					29 01 00 00 00 00 19
+						c9 01 0a 12 1c 2b 45 3f 29 17 13
+						0f 04 01 0a 12 1c 2b 45 3f 29 17 13 0f 04
+					29 01 00 00 00 00 19
+						ca 01 0a 12 1c 2b 45 3f 29 17 13
+						0f 04 01 0a 12 1c 2b 45 3f 29 17 13 0f 04
+					29 01 00 00 00 00 11
+						d0 99 03 ce a6 00 43 20 10 01 00
+						01 01 00 03 01 00
+					29 01 00 00 00 00 08
+						d1 18 0C 23 03 75 02 50
+					23 01 00 00 00 00 02
+						d3 33
+					29 01 00 00 00 00 03
+						d5 2a 2a
+					29 01 00 00 00 00 02
+						d6 28
+					29 01 00 00 00 00 10
+						d7 01 00 aa c0 2a 2c 22	12 71 0a 12 00 a0
+						00 03
+					29 01 00 00 00 00 09
+						d8 44 44 22 44 21 46 42 40
+					29 01 00 00 00 00 04
+						d9 cf 2d 51
+					29 01 00 00 00 00 02
+						da 01
+					29 01 00 00 00 00 03
+						de 01 4f
+					29 01 00 00 00 00 07
+						e1 00 00 00 00 00 00
+					23 01 00 00 00 00 02
+						e6 4f
+					29 01 00 00 00 00 06
+						f3 06 00 00 24 00
+					29 01 00 00 00 00 02
+						f8 00
+					23 01 00 00 00 00 02
+						fa 03
+					29 01 00 00 00 00 04
+						fb 00 00 00
+					29 01 00 00 00 00 06
+						fc 00 00 00 00 00
+					29 01 00 00 00 00 05
+						fd 00 00 70 00
+					39 01 00 00 00 00 05
+						2a 00 00 01 df
+					39 01 00 00 00 00 05
+						2b 00 00 03 1f
+					15 01 00 00 00 00 02
+						35 00
+					39 01 00 00 00 00 03
+						44 00 50
+					15 01 00 00 00 00 02
+						36 41
+					15 01 00 00 00 00 02
+						3a 77
+					05 01 00 00 7D 00 02
+						11 00
+					05 01 00 00 3c 00 02
+						29 00
+					];
+		qcom,mdss-dsi-off-command = [05 01 00 00 32 00 02 28 00
+				05 01 00 00 78 00 02 10 00];
+		qcom,mdss-dsi-on-command-state = "dsi_lp_mode";
+		qcom,mdss-dsi-off-command-state = "dsi_lp_mode";
+		qcom,mdss-dsi-h-sync-pulse = <0>;
+		qcom,mdss-dsi-traffic-mode = <1>;
+		qcom,mdss-dsi-lane-map = <0>;
+		qcom,mdss-dsi-bllp-eof-power-mode;
+		qcom,mdss-dsi-bllp-power-mode;
+		qcom,mdss-dsi-lane-0-state;
+		qcom,mdss-dsi-lane-1-state;
+		qcom,mdss-dsi-te-pin-select = <1>;
+		qcom,mdss-dsi-te-v-sync-rd-ptr-irq-line = <0x2c>;
+		qcom,mdss-dsi-te-v-sync-continues-lines = <0x3c>;
+		qcom,mdss-dsi-te-dcs-command = <1>;
+		qcom,mdss-dsi-te-check-enable;
+		qcom,mdss-dsi-te-using-te-pin;
+		qcom,mdss-dsi-panel-timings = [5D 12 0C 00 33 38 10 16 1E 03 04 00];
+		qcom,mdss-dsi-t-clk-post = <0x04>;
+		qcom,mdss-dsi-t-clk-pre = <0x1b>;
+		qcom,mdss-dsi-bl-min-level = <1>;
+		qcom,mdss-dsi-bl-max-level = <255>;
+		qcom,mdss-dsi-dma-trigger = <4>;
+		qcom,mdss-dsi-mdp-trigger = <2>;
+		qcom,mdss-dsi-bl-pmic-control-type = "bl_ctrl_wled";
+	};
+};
diff --git a/arch/arm/boot/dts/dsi-panel-truly-wvga-video.dtsi b/arch/arm/boot/dts/dsi-panel-truly-wvga-video.dtsi
new file mode 100644
index 0000000..fae4834
--- /dev/null
+++ b/arch/arm/boot/dts/dsi-panel-truly-wvga-video.dtsi
@@ -0,0 +1,168 @@
+/* Copyright (c) 2013, The Linux Foundation. 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 and
+ * only 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.
+ */
+
+/*---------------------------------------------------------------------------
+ * This file is autogenerated file using gcdb parser. Please do not edit it.
+ * Update input XML file to add a new entry or update variable in this file
+ * VERSION = "1.0"
+ *---------------------------------------------------------------------------*/
+&mdss_mdp {
+	dsi_truly_wvga_vid: qcom,mdss_dsi_truly_wvga_video {
+		qcom,mdss-dsi-panel-name = "Truly WVGA video mode dsi panel";
+		qcom,mdss-dsi-panel-controller = <&mdss_dsi0>;
+		qcom,mdss-dsi-panel-type = "dsi_video_mode";
+		qcom,mdss-dsi-panel-destination = "display_1";
+		qcom,mdss-dsi-panel-mode-gpio-state = "high";
+		qcom,mdss-dsi-panel-framerate = <60>;
+		qcom,mdss-dsi-virtual-channel-id = <0>;
+		qcom,mdss-dsi-stream = <0>;
+		qcom,mdss-dsi-panel-width = <480>;
+		qcom,mdss-dsi-panel-height = <800>;
+		qcom,mdss-dsi-h-front-porch = <160>;
+		qcom,mdss-dsi-h-back-porch = <40>;
+		qcom,mdss-dsi-h-pulse-width = <8>;
+		qcom,mdss-dsi-h-sync-skew = <0>;
+		qcom,mdss-dsi-v-back-porch = <10>;
+		qcom,mdss-dsi-v-front-porch = <12>;
+		qcom,mdss-dsi-v-pulse-width = <2>;
+		qcom,mdss-dsi-h-left-border = <0>;
+		qcom,mdss-dsi-h-right-border = <0>;
+		qcom,mdss-dsi-v-top-border = <0>;
+		qcom,mdss-dsi-v-bottom-border = <0>;
+		qcom,mdss-dsi-bpp = <24>;
+		qcom,mdss-dsi-color-order = <0>;
+		qcom,mdss-dsi-underflow-color = <0xff>;
+		qcom,mdss-dsi-border-color = <0>;
+		qcom,mdss-dsi-on-command = [
+					05 01 00 00 00 00 02
+						01 00
+					23 01 00 00 00 00 02
+						b0 04
+					29 01 00 00 00 00 03
+						b3 02 00
+					29 01 00 00 00 00 03
+						b6 51 83
+					29 01 00 00 00 00 05
+						b7 00 80 15 25
+					29 01 00 00 00 00 14
+						b8 00 07 07 ff c8 c8 01 18 10 10
+						37 5a 87 de ff 00 00 00 00
+					29 01 00 00 00 00 05
+						b9 00 00 00 00
+					23 01 00 00 00 00 02
+						bd 00
+					29 01 00 00 00 00 03
+						c0 02 43
+					29 01 00 00 00 00 10
+						c1 43 31 99 21 20 00 10 28 0c 0c
+						00 00 00 21 01
+					29 01 00 00 00 00 07
+						c2 28 06 06 01 03 00
+					29 01 00 00 00 00 04
+						c3 40 00 03
+					29 01 00 00 00 00 03
+						6f 03 00
+					29 01 00 00 00 00 03
+						c4 00 01
+					29 01 00 00 00 00 03
+						c6 00 00
+					29 01 00 00 00 00 06
+						c7 11 8d a0 f5 27
+					29 01 00 00 00 00 19
+						c8 01 0a 12 1c 2b 45 3f 29 17 13
+						0f 04 01 0a 12 1c 2b 45 3f 29 17 13 0f 04
+					29 01 00 00 00 00 19
+						c9 01 0a 12 1c 2b 45 3f 29 17 13
+						0f 04 01 0a 12 1c 2b 45 3f 29 17 13 0f 04
+					29 01 00 00 00 00 19
+						ca 01 0a 12 1c 2b 45 3f 29 17 13
+						0f 04 01 0a 12 1c 2b 45 3f 29 17 13 0f 04
+					29 01 00 00 00 00 11
+						d0 99 03 ce a6 00 43 20 10 01 00
+						01 01 00 03 01 00
+					29 01 00 00 00 00 08
+						d1 18 0C 23 03 75 02 50
+					23 01 00 00 00 00 02
+						d3 33
+					29 01 00 00 00 00 03
+						d5 2a 2a
+					29 01 00 00 00 00 02
+						d6 28
+					29 01 00 00 00 00 10
+						d7 01 00 aa c0 2a 2c 22	12 71 0a 12 00 a0
+						00 03
+					29 01 00 00 00 00 09
+						d8 44 44 22 44 21 46 42 40
+					29 01 00 00 00 00 04
+						d9 cf 2d 51
+					29 01 00 00 00 00 02
+						da 01
+					29 01 00 00 00 00 03
+						de 01 4f
+					29 01 00 00 00 00 07
+						e1 00 00 00 00 00 00
+					23 01 00 00 00 00 02
+						e6 4f
+					29 01 00 00 00 00 06
+						f3 06 00 00 24 00
+					29 01 00 00 00 00 02
+						f8 00
+					23 01 00 00 00 00 02
+						fa 03
+					29 01 00 00 00 00 04
+						fb 00 00 00
+					29 01 00 00 00 00 06
+						fc 00 00 00 00 00
+					29 01 00 00 00 00 05
+						fd 00 00 70 00
+					39 01 00 00 00 00 05
+						2a 00 00 01 df
+					39 01 00 00 00 00 05
+						2b 00 00 03 1f
+					15 01 00 00 00 00 02
+						35 00
+					39 01 00 00 00 00 03
+						44 00 50
+					15 01 00 00 00 00 02
+						36 c1
+					15 01 00 00 00 00 02
+						3a 77
+					05 01 00 00 7D 00 02
+						11 00
+					05 01 00 00 3c 00 02
+						29 00
+					];
+		qcom,mdss-dsi-off-command = [05 01 00 00 32 00 02 28 00
+					05 01 00 00 78 00 02 10 00
+					23 01 00 00 10 00 02
+						b0 04
+					23 01 00 00 20 00 02
+						b1 01];
+		qcom,mdss-dsi-on-command-state = "dsi_lp_mode";
+		qcom,mdss-dsi-off-command-state = "dsi_lp_mode";
+		qcom,mdss-dsi-h-sync-pulse = <0>;
+		qcom,mdss-dsi-traffic-mode = <1>;
+		qcom,mdss-dsi-lane-map = <0>;
+		qcom,mdss-dsi-bllp-eof-power-mode;
+		qcom,mdss-dsi-bllp-power-mode;
+		qcom,mdss-dsi-lane-0-state;
+		qcom,mdss-dsi-lane-1-state;
+		qcom,mdss-dsi-panel-timings = [5D 12 0C 00 33 38 10 16 1E 03 04 00];
+		qcom,mdss-dsi-t-clk-post = <0x04>;
+		qcom,mdss-dsi-t-clk-pre = <0x1b>;
+		qcom,mdss-dsi-bl-min-level = <1>;
+		qcom,mdss-dsi-bl-max-level = <255>;
+		qcom,mdss-dsi-dma-trigger = <4>;
+		qcom,mdss-dsi-mdp-trigger = <0>;
+		qcom,mdss-dsi-bl-pmic-control-type = "bl_ctrl_wled";
+	};
+};
diff --git a/arch/arm/boot/dts/dsi-v2-panel-hx8379a-wvga-video.dtsi b/arch/arm/boot/dts/dsi-v2-panel-hx8379a-wvga-video.dtsi
index befc29c..b2aeed3 100644
--- a/arch/arm/boot/dts/dsi-v2-panel-hx8379a-wvga-video.dtsi
+++ b/arch/arm/boot/dts/dsi-v2-panel-hx8379a-wvga-video.dtsi
@@ -10,7 +10,7 @@
  * GNU General Public License for more details.
  */
 
-/ {
+&soc {
 	qcom,dsi_v2_hx8379a_wvga_video {
 		compatible = "qcom,dsi-panel-v2";
 		label = "HX8379A WVGA video mode dsi panel";
@@ -21,7 +21,7 @@
 		qcom,mdss-pan-res = <480 800>;
 		qcom,mdss-pan-bpp = <24>;
 		qcom,mdss-pan-dest = "display_1";
-		qcom,mdss-pan-porch-values = <90 17 90 2 3 11>;
+		qcom,mdss-pan-porch-values = <100 40 70 6 4 6>;
 		qcom,mdss-pan-underflow-clr = <0xff>;
 		qcom,mdss-pan-bl-levels = <1 255>;
 		qcom,mdss-pan-bl-ctrl = "bl_ctrl_wled";
@@ -41,8 +41,8 @@
 		qcom,mdss-pan-dsi-dma-tr = <0x04>;
 		qcom,mdss-pan-dsi-frame-rate = <60>;
 		qcom,panel-phy-regulatorSettings =[02 08 05 00 20 03];
-		qcom,panel-phy-timingSettings = [5D 12 0C  00 33 39
-						 10 16 15  03 04 00];
+		qcom,panel-phy-timingSettings = [75 1A 11  00 3D 45
+						 15 1D 1C  03 04 00];
 		qcom,panel-phy-strengthCtrl = [ff 06];
 		qcom,panel-phy-bistCtrl = [03 03 00 00 0f 00];
 		qcom,panel-phy-laneConfig =
@@ -54,34 +54,32 @@
 
 		qcom,on-cmds-dsi-state = "DSI_LP_MODE";
 		qcom,panel-on-cmds = [
-					29 01 00 00 01 04
+					39 01 00 00 00 04
 						B9 FF 83 79
-					23 01 00 00 01 02
-						BA 51
-					29 01 00 00 01 14
+					39 01 00 00 00 03
+						BA 51 93
+					39 01 00 00 00 14
 						B1 00 50 44
 						EA 8D 08 11
-						0F 0F 24 2C
+						11 11 27 2F
 						9A 1A 42 0B
 						6E F1 00 E6
-					29 01 00 00 01 0e
+					39 01 00 00 00 0E
 						B2 00 00 3C
 						08 04 19 22
 						00 FF 08 04
 						19 20
-					29 01 00 00 01 20
-						B4 80 08 00
+					39 01 00 00 00 20
+						B4 82 08 00
 						32 10 03 32
 						13 70 32 10
 						08 37 01 28
-						05 37 08 3C
-						20 44 44 08
+						07 37 08 3C
+						08 44 44 08
 						00 40 08 28
 						08 30 30 04
-					23 01 00 00 01 02
-						cc 02
-					29 01 00 00 01 30
-						D5 00 00 08
+					39 01 00 00 00 30
+						D5 00 00 0A
 						00 01 05 00
 						03 00 88 88
 						88 88 23 01
@@ -93,18 +91,20 @@
 						88 88 88 88
 						88 88 00 00
 						00 00 00 00
-					29 01 00 00 01 24
-						E0 79 00 00
-						02 1C 1F 33
-						28 3E 07 0E
-						0F 15 17 16
-						16 13 19 00
-						00 02 1C 1F
-						33 28 3E 07
-						0E 0F 15 17
-						16 16 13 19
-					29 01 00 00 01 05
-						B6 00 A6 00 A6
+					39 01 00 00 00 24
+						E0 79 05 0F
+						14 26 29 3F
+						2B 44 04 0E
+						12 15 18 16
+						16 12 15 05
+						0F 14 26 29
+						3F 2B 44 04
+						0E 12 15 18
+						16 16 12 15
+					23 01 00 00 00 02
+						cc 02
+					39 01 00 00 00 05
+						B6 00 9C 00 9C
 					05 01 00 00 96 02
 						11 00
 					05 01 00 00 78 02
diff --git a/arch/arm/boot/dts/dsi-v2-panel-nt35590-720p-video.dtsi b/arch/arm/boot/dts/dsi-v2-panel-nt35590-720p-video.dtsi
new file mode 100644
index 0000000..7686fc4
--- /dev/null
+++ b/arch/arm/boot/dts/dsi-v2-panel-nt35590-720p-video.dtsi
@@ -0,0 +1,526 @@
+/* Copyright (c) 2013, The Linux Foundation. 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 and
+ * only 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.
+ */
+
+/ {
+	qcom,dsi_v2_nt35590_720p_video {
+		compatible = "qcom,dsi-panel-v2";
+		label = "nt35590 720p video mode dsi panel";
+		qcom,dsi-ctrl-phandle = <&mdss_dsi0>;
+		qcom,rst-gpio = <&msmgpio 41 0>;
+		vdda-supply = <&pm8110_l19>;
+		vddio-supply = <&pm8110_l14>;
+		qcom,mdss-pan-res = <720 1280>;
+		qcom,mdss-pan-bpp = <24>;
+		qcom,mdss-pan-dest = "display_1";
+		qcom,mdss-pan-porch-values = <164 8 140 1 1 6>;
+		qcom,mdss-pan-underflow-clr = <0xff>;
+		qcom,mdss-pan-bl-ctrl = "bl_ctrl_wled";
+		qcom,mdss-pan-bl-levels = <1 255>;
+		qcom,mdss-pan-dsi-mode = <0>;
+		qcom,mdss-pan-dsi-h-pulse-mode = <1>;
+		qcom,mdss-pan-dsi-h-power-stop = <0 0 0>;
+		qcom,mdss-pan-dsi-bllp-power-stop = <1 1>;
+		qcom,mdss-pan-dsi-traffic-mode = <2>;
+		qcom,mdss-pan-dsi-dst-format = <3>;
+		qcom,mdss-pan-dsi-vc = <0>;
+		qcom,mdss-pan-dsi-rgb-swap = <0>;
+		qcom,mdss-pan-dsi-data-lanes = <1 1 1 1>; /* 4 lanes */
+		qcom,mdss-pan-dsi-dlane-swap = <0>;
+		qcom,mdss-pan-dsi-t-clk = <0x2c 0x20>;
+		qcom,mdss-pan-dsi-stream = <0>;
+		qcom,mdss-pan-dsi-mdp-tr = <0x0>;
+		qcom,mdss-pan-dsi-dma-tr = <0x04>;
+		qcom,mdss-pan-dsi-frame-rate = <60>;
+		qcom,panel-phy-regulatorSettings =[02 08 05 00 20 03];
+		qcom,panel-phy-timingSettings = [86 1E 14  00 43 4D
+						 19 21 30 03 04 00];
+		qcom,panel-phy-strengthCtrl = [ff 06];
+		qcom,panel-phy-bistCtrl = [03 03 00 00 0f 00];
+		qcom,panel-phy-laneConfig =
+					[
+					80 45 00 00 01 66 /*lane0**/
+					80 45 00 00 01 66 /*lane1*/
+					80 45 00 00 01 66 /*lane2*/
+					80 45 00 00 01 66 /*lane3*/
+					40 67 00 00 01 88]; /*Clk*/
+		qcom,panel-on-cmds = [
+					29 01 00 00 00 02 FF EE
+					29 01 00 00 00 02 26 08
+					29 01 00 00 00 02 26 00
+					29 01 00 00 10 02 FF 00
+					29 01 00 00 00 02 BA 03
+					29 01 00 00 00 02 C2 03
+					29 01 00 00 00 02 FF 01
+					29 01 00 00 00 02 FB 01
+					29 01 00 00 00 02 00 4A
+					29 01 00 00 00 02 01 33
+					29 01 00 00 00 02 02 53
+					29 01 00 00 00 02 03 55
+					29 01 00 00 00 02 04 55
+					29 01 00 00 00 02 05 33
+					29 01 00 00 00 02 06 22
+					29 01 00 00 00 02 08 56
+					29 01 00 00 00 02 09 8F
+					29 01 00 00 00 02 36 73
+					29 01 00 00 00 02 0B 9F
+					29 01 00 00 00 02 0C 9F
+					29 01 00 00 00 02 0D 2F
+					29 01 00 00 00 02 0E 24
+					29 01 00 00 00 02 11 83
+					29 01 00 00 00 02 12 03
+					29 01 00 00 00 02 71 2C
+					29 01 00 00 00 02 6F 03
+					29 01 00 00 00 02 0F 0A
+					29 01 00 00 00 02 FF 05
+					29 01 00 00 00 02 FB 01
+					29 01 00 00 00 02 01 00
+					29 01 00 00 00 02 02 8B
+					29 01 00 00 00 02 03 82
+					29 01 00 00 00 02 04 82
+					29 01 00 00 00 02 05 30
+					29 01 00 00 00 02 06 33
+					29 01 00 00 00 02 07 01
+					29 01 00 00 00 02 08 00
+					29 01 00 00 00 02 09 46
+					29 01 00 00 00 02 0A 46
+					29 01 00 00 00 02 0D 0B
+					29 01 00 00 00 02 0E 1D
+					29 01 00 00 00 02 0F 08
+					29 01 00 00 00 02 10 53
+					29 01 00 00 00 02 11 00
+					29 01 00 00 00 02 12 00
+					29 01 00 00 00 02 14 01
+					29 01 00 00 00 02 15 00
+					29 01 00 00 00 02 16 05
+					29 01 00 00 00 02 17 00
+					29 01 00 00 00 02 19 7F
+					29 01 00 00 00 02 1A FF
+					29 01 00 00 00 02 1B 0F
+					29 01 00 00 00 02 1C 00
+					29 01 00 00 00 02 1D 00
+					29 01 00 00 00 02 1E 00
+					29 01 00 00 00 02 1F 07
+					29 01 00 00 00 02 20 00
+					29 01 00 00 00 02 21 06
+					29 01 00 00 00 02 22 55
+					29 01 00 00 00 02 23 4D
+					29 01 00 00 00 02 2D 02
+					29 01 00 00 00 02 28 01
+					29 01 00 00 00 02 2F 02
+					29 01 00 00 00 02 83 01
+					29 01 00 00 00 02 9E 58
+					29 01 00 00 00 02 9F 6A
+					29 01 00 00 00 02 A0 01
+					29 01 00 00 00 02 A2 10
+					29 01 00 00 00 02 BB 0A
+					29 01 00 00 00 02 BC 0A
+					29 01 00 00 00 02 32 08
+					29 01 00 00 00 02 33 B8
+					29 01 00 00 00 02 36 01
+					29 01 00 00 00 02 37 00
+					29 01 00 00 00 02 43 00
+					29 01 00 00 00 02 4B 21
+					29 01 00 00 00 02 4C 03
+					29 01 00 00 00 02 50 21
+					29 01 00 00 00 02 51 03
+					29 01 00 00 00 02 58 21
+					29 01 00 00 00 02 59 03
+					29 01 00 00 00 02 5D 21
+					29 01 00 00 00 02 5E 03
+					29 01 00 00 00 02 6C 00
+					29 01 00 00 00 02 6D 00
+					29 01 00 00 00 02 FB 01
+					29 01 00 00 00 02 FF 01
+					29 01 00 00 00 02 FB 01
+					29 01 00 00 00 02 75 00
+					29 01 00 00 00 02 76 7D
+					29 01 00 00 00 02 77 00
+					29 01 00 00 00 02 78 8A
+					29 01 00 00 00 02 79 00
+					29 01 00 00 00 02 7A 9C
+					29 01 00 00 00 02 7B 00
+					29 01 00 00 00 02 7C B1
+					29 01 00 00 00 02 7D 00
+					29 01 00 00 00 02 7E BF
+					29 01 00 00 00 02 7F 00
+					29 01 00 00 00 02 80 CF
+					29 01 00 00 00 02 81 00
+					29 01 00 00 00 02 82 DD
+					29 01 00 00 00 02 83 00
+					29 01 00 00 00 02 84 E8
+					29 01 00 00 00 02 85 00
+					29 01 00 00 00 02 86 F2
+					29 01 00 00 00 02 87 01
+					29 01 00 00 00 02 88 1F
+					29 01 00 00 00 02 89 01
+					29 01 00 00 00 02 8A 41
+					29 01 00 00 00 02 8B 01
+					29 01 00 00 00 02 8C 78
+					29 01 00 00 00 02 8D 01
+					29 01 00 00 00 02 8E A5
+					29 01 00 00 00 02 8F 01
+					29 01 00 00 00 02 90 EE
+					29 01 00 00 00 02 91 02
+					29 01 00 00 00 02 92 29
+					29 01 00 00 00 02 93 02
+					29 01 00 00 00 02 94 2A
+					29 01 00 00 00 02 95 02
+					29 01 00 00 00 02 96 5D
+					29 01 00 00 00 02 97 02
+					29 01 00 00 00 02 98 93
+					29 01 00 00 00 02 99 02
+					29 01 00 00 00 02 9A B8
+					29 01 00 00 00 02 9B 02
+					29 01 00 00 00 02 9C E7
+					29 01 00 00 00 02 9D 03
+					29 01 00 00 00 02 9E 07
+					29 01 00 00 00 02 9F 03
+					29 01 00 00 00 02 A0 37
+					29 01 00 00 00 02 A2 03
+					29 01 00 00 00 02 A3 46
+					29 01 00 00 00 02 A4 03
+					29 01 00 00 00 02 A5 56
+					29 01 00 00 00 02 A6 03
+					29 01 00 00 00 02 A7 66
+					29 01 00 00 00 02 A9 03
+					29 01 00 00 00 02 AA 7A
+					29 01 00 00 00 02 AB 03
+					29 01 00 00 00 02 AC 93
+					29 01 00 00 00 02 AD 03
+					29 01 00 00 00 02 AE A3
+					29 01 00 00 00 02 AF 03
+					29 01 00 00 00 02 B0 B4
+					29 01 00 00 00 02 B1 03
+					29 01 00 00 00 02 B2 CB
+					29 01 00 00 00 02 B3 00
+					29 01 00 00 00 02 B4 7D
+					29 01 00 00 00 02 B5 00
+					29 01 00 00 00 02 B6 8A
+					29 01 00 00 00 02 B7 00
+					29 01 00 00 00 02 B8 9C
+					29 01 00 00 00 02 B9 00
+					29 01 00 00 00 02 BA B1
+					29 01 00 00 00 02 BB 00
+					29 01 00 00 00 02 BC BF
+					29 01 00 00 00 02 BD 00
+					29 01 00 00 00 02 BE CF
+					29 01 00 00 00 02 BF 00
+					29 01 00 00 00 02 C0 DD
+					29 01 00 00 00 02 C1 00
+					29 01 00 00 00 02 C2 E8
+					29 01 00 00 00 02 C3 00
+					29 01 00 00 00 02 C4 F2
+					29 01 00 00 00 02 C5 01
+					29 01 00 00 00 02 C6 1F
+					29 01 00 00 00 02 C7 01
+					29 01 00 00 00 02 C8 41
+					29 01 00 00 00 02 C9 01
+					29 01 00 00 00 02 CA 78
+					29 01 00 00 00 02 CB 01
+					29 01 00 00 00 02 CC A5
+					29 01 00 00 00 02 CD 01
+					29 01 00 00 00 02 CE EE
+					29 01 00 00 00 02 CF 02
+					29 01 00 00 00 02 D0 29
+					29 01 00 00 00 02 D1 02
+					29 01 00 00 00 02 D2 2A
+					29 01 00 00 00 02 D3 02
+					29 01 00 00 00 02 D4 5D
+					29 01 00 00 00 02 D5 02
+					29 01 00 00 00 02 D6 93
+					29 01 00 00 00 02 D7 02
+					29 01 00 00 00 02 D8 B8
+					29 01 00 00 00 02 D9 02
+					29 01 00 00 00 02 DA E7
+					29 01 00 00 00 02 DB 03
+					29 01 00 00 00 02 DC 07
+					29 01 00 00 00 02 DD 03
+					29 01 00 00 00 02 DE 37
+					29 01 00 00 00 02 DF 03
+					29 01 00 00 00 02 E0 46
+					29 01 00 00 00 02 E1 03
+					29 01 00 00 00 02 E2 56
+					29 01 00 00 00 02 E3 03
+					29 01 00 00 00 02 E4 66
+					29 01 00 00 00 02 E5 03
+					29 01 00 00 00 02 E6 7A
+					29 01 00 00 00 02 E7 03
+					29 01 00 00 00 02 E8 93
+					29 01 00 00 00 02 E9 03
+					29 01 00 00 00 02 EA A3
+					29 01 00 00 00 02 EB 03
+					29 01 00 00 00 02 EC B4
+					29 01 00 00 00 02 ED 03
+					29 01 00 00 00 02 EE CB
+					29 01 00 00 00 02 EF 00
+					29 01 00 00 00 02 F0 ED
+					29 01 00 00 00 02 F1 00
+					29 01 00 00 00 02 F2 F3
+					29 01 00 00 00 02 F3 00
+					29 01 00 00 00 02 F4 FE
+					29 01 00 00 00 02 F5 01
+					29 01 00 00 00 02 F6 09
+					29 01 00 00 00 02 F7 01
+					29 01 00 00 00 02 F8 13
+					29 01 00 00 00 02 F9 01
+					29 01 00 00 00 02 FA 1D
+					29 01 00 00 00 02 FF 02
+					29 01 00 00 00 02 FB 01
+					29 01 00 00 00 02 00 01
+					29 01 00 00 00 02 01 26
+					29 01 00 00 00 02 02 01
+					29 01 00 00 00 02 03 2F
+					29 01 00 00 00 02 04 01
+					29 01 00 00 00 02 05 37
+					29 01 00 00 00 02 06 01
+					29 01 00 00 00 02 07 56
+					29 01 00 00 00 02 08 01
+					29 01 00 00 00 02 09 70
+					29 01 00 00 00 02 0A 01
+					29 01 00 00 00 02 0B 9D
+					29 01 00 00 00 02 0C 01
+					29 01 00 00 00 02 0D C2
+					29 01 00 00 00 02 0E 01
+					29 01 00 00 00 02 0F FF
+					29 01 00 00 00 02 10 02
+					29 01 00 00 00 02 11 31
+					29 01 00 00 00 02 12 02
+					29 01 00 00 00 02 13 32
+					29 01 00 00 00 02 14 02
+					29 01 00 00 00 02 15 60
+					29 01 00 00 00 02 16 02
+					29 01 00 00 00 02 17 94
+					29 01 00 00 00 02 18 02
+					29 01 00 00 00 02 19 B5
+					29 01 00 00 00 02 1A 02
+					29 01 00 00 00 02 1B E3
+					29 01 00 00 00 02 1C 03
+					29 01 00 00 00 02 1D 03
+					29 01 00 00 00 02 1E 03
+					29 01 00 00 00 02 1F 2D
+					29 01 00 00 00 02 20 03
+					29 01 00 00 00 02 21 3A
+					29 01 00 00 00 02 22 03
+					29 01 00 00 00 02 23 48
+					29 01 00 00 00 02 24 03
+					29 01 00 00 00 02 25 57
+					29 01 00 00 00 02 26 03
+					29 01 00 00 00 02 27 68
+					29 01 00 00 00 02 28 03
+					29 01 00 00 00 02 29 7B
+					29 01 00 00 00 02 2A 03
+					29 01 00 00 00 02 2B 90
+					29 01 00 00 00 02 2D 03
+					29 01 00 00 00 02 2F A0
+					29 01 00 00 00 02 30 03
+					29 01 00 00 00 02 31 CB
+					29 01 00 00 00 02 32 00
+					29 01 00 00 00 02 33 ED
+					29 01 00 00 00 02 34 00
+					29 01 00 00 00 02 35 F3
+					29 01 00 00 00 02 36 00
+					29 01 00 00 00 02 37 FE
+					29 01 00 00 00 02 38 01
+					29 01 00 00 00 02 39 09
+					29 01 00 00 00 02 3A 01
+					29 01 00 00 00 02 3B 13
+					29 01 00 00 00 02 3D 01
+					29 01 00 00 00 02 3F 1D
+					29 01 00 00 00 02 40 01
+					29 01 00 00 00 02 41 26
+					29 01 00 00 00 02 42 01
+					29 01 00 00 00 02 43 2F
+					29 01 00 00 00 02 44 01
+					29 01 00 00 00 02 45 37
+					29 01 00 00 00 02 46 01
+					29 01 00 00 00 02 47 56
+					29 01 00 00 00 02 48 01
+					29 01 00 00 00 02 49 70
+					29 01 00 00 00 02 4A 01
+					29 01 00 00 00 02 4B 9D
+					29 01 00 00 00 02 4C 01
+					29 01 00 00 00 02 4D C2
+					29 01 00 00 00 02 4E 01
+					29 01 00 00 00 02 4F FF
+					29 01 00 00 00 02 50 02
+					29 01 00 00 00 02 51 31
+					29 01 00 00 00 02 52 02
+					29 01 00 00 00 02 53 32
+					29 01 00 00 00 02 54 02
+					29 01 00 00 00 02 55 60
+					29 01 00 00 00 02 56 02
+					29 01 00 00 00 02 58 94
+					29 01 00 00 00 02 59 02
+					29 01 00 00 00 02 5A B5
+					29 01 00 00 00 02 5B 02
+					29 01 00 00 00 02 5C E3
+					29 01 00 00 00 02 5D 03
+					29 01 00 00 00 02 5E 03
+					29 01 00 00 00 02 5F 03
+					29 01 00 00 00 02 60 2D
+					29 01 00 00 00 02 61 03
+					29 01 00 00 00 02 62 3A
+					29 01 00 00 00 02 63 03
+					29 01 00 00 00 02 64 48
+					29 01 00 00 00 02 65 03
+					29 01 00 00 00 02 66 57
+					29 01 00 00 00 02 67 03
+					29 01 00 00 00 02 68 68
+					29 01 00 00 00 02 69 03
+					29 01 00 00 00 02 6A 7B
+					29 01 00 00 00 02 6B 03
+					29 01 00 00 00 02 6C 90
+					29 01 00 00 00 02 6D 03
+					29 01 00 00 00 02 6E A0
+					29 01 00 00 00 02 6F 03
+					29 01 00 00 00 02 70 CB
+					29 01 00 00 00 02 71 00
+					29 01 00 00 00 02 72 19
+					29 01 00 00 00 02 73 00
+					29 01 00 00 00 02 74 36
+					29 01 00 00 00 02 75 00
+					29 01 00 00 00 02 76 55
+					29 01 00 00 00 02 77 00
+					29 01 00 00 00 02 78 70
+					29 01 00 00 00 02 79 00
+					29 01 00 00 00 02 7A 83
+					29 01 00 00 00 02 7B 00
+					29 01 00 00 00 02 7C 99
+					29 01 00 00 00 02 7D 00
+					29 01 00 00 00 02 7E A8
+					29 01 00 00 00 02 7F 00
+					29 01 00 00 00 02 80 B7
+					29 01 00 00 00 02 81 00
+					29 01 00 00 00 02 82 C5
+					29 01 00 00 00 02 83 00
+					29 01 00 00 00 02 84 F7
+					29 01 00 00 00 02 85 01
+					29 01 00 00 00 02 86 1E
+					29 01 00 00 00 02 87 01
+					29 01 00 00 00 02 88 60
+					29 01 00 00 00 02 89 01
+					29 01 00 00 00 02 8A 95
+					29 01 00 00 00 02 8B 01
+					29 01 00 00 00 02 8C E1
+					29 01 00 00 00 02 8D 02
+					29 01 00 00 00 02 8E 20
+					29 01 00 00 00 02 8F 02
+					29 01 00 00 00 02 90 23
+					29 01 00 00 00 02 91 02
+					29 01 00 00 00 02 92 59
+					29 01 00 00 00 02 93 02
+					29 01 00 00 00 02 94 94
+					29 01 00 00 00 02 95 02
+					29 01 00 00 00 02 96 B4
+					29 01 00 00 00 02 97 02
+					29 01 00 00 00 02 98 E1
+					29 01 00 00 00 02 99 03
+					29 01 00 00 00 02 9A 01
+					29 01 00 00 00 02 9B 03
+					29 01 00 00 00 02 9C 28
+					29 01 00 00 00 02 9D 03
+					29 01 00 00 00 02 9E 30
+					29 01 00 00 00 02 9F 03
+					29 01 00 00 00 02 A0 37
+					29 01 00 00 00 02 A2 03
+					29 01 00 00 00 02 A3 3B
+					29 01 00 00 00 02 A4 03
+					29 01 00 00 00 02 A5 40
+					29 01 00 00 00 02 A6 03
+					29 01 00 00 00 02 A7 50
+					29 01 00 00 00 02 A9 03
+					29 01 00 00 00 02 AA 6D
+					29 01 00 00 00 02 AB 03
+					29 01 00 00 00 02 AC 80
+					29 01 00 00 00 02 AD 03
+					29 01 00 00 00 02 AE CB
+					29 01 00 00 00 02 AF 00
+					29 01 00 00 00 02 B0 19
+					29 01 00 00 00 02 B1 00
+					29 01 00 00 00 02 B2 36
+					29 01 00 00 00 02 B3 00
+					29 01 00 00 00 02 B4 55
+					29 01 00 00 00 02 B5 00
+					29 01 00 00 00 02 B6 70
+					29 01 00 00 00 02 B7 00
+					29 01 00 00 00 02 B8 83
+					29 01 00 00 00 02 B9 00
+					29 01 00 00 00 02 BA 99
+					29 01 00 00 00 02 BB 00
+					29 01 00 00 00 02 BC A8
+					29 01 00 00 00 02 BD 00
+					29 01 00 00 00 02 BE B7
+					29 01 00 00 00 02 BF 00
+					29 01 00 00 00 02 C0 C5
+					29 01 00 00 00 02 C1 00
+					29 01 00 00 00 02 C2 F7
+					29 01 00 00 00 02 C3 01
+					29 01 00 00 00 02 C4 1E
+					29 01 00 00 00 02 C5 01
+					29 01 00 00 00 02 C6 60
+					29 01 00 00 00 02 C7 01
+					29 01 00 00 00 02 C8 95
+					29 01 00 00 00 02 C9 01
+					29 01 00 00 00 02 CA E1
+					29 01 00 00 00 02 CB 02
+					29 01 00 00 00 02 CC 20
+					29 01 00 00 00 02 CD 02
+					29 01 00 00 00 02 CE 23
+					29 01 00 00 00 02 CF 02
+					29 01 00 00 00 02 D0 59
+					29 01 00 00 00 02 D1 02
+					29 01 00 00 00 02 D2 94
+					29 01 00 00 00 02 D3 02
+					29 01 00 00 00 02 D4 B4
+					29 01 00 00 00 02 D5 02
+					29 01 00 00 00 02 D6 E1
+					29 01 00 00 00 02 D7 03
+					29 01 00 00 00 02 D8 01
+					29 01 00 00 00 02 D9 03
+					29 01 00 00 00 02 DA 28
+					29 01 00 00 00 02 DB 03
+					29 01 00 00 00 02 DC 30
+					29 01 00 00 00 02 DD 03
+					29 01 00 00 00 02 DE 37
+					29 01 00 00 00 02 DF 03
+					29 01 00 00 00 02 E0 3B
+					29 01 00 00 00 02 E1 03
+					29 01 00 00 00 02 E2 40
+					29 01 00 00 00 02 E3 03
+					29 01 00 00 00 02 E4 50
+					29 01 00 00 00 02 E5 03
+					29 01 00 00 00 02 E6 6D
+					29 01 00 00 00 02 E7 03
+					29 01 00 00 00 02 E8 80
+					29 01 00 00 00 02 E9 03
+					29 01 00 00 00 02 EA CB
+					29 01 00 00 00 02 FF 01
+					29 01 00 00 00 02 FB 01
+					29 01 00 00 00 02 FF 02
+					29 01 00 00 00 02 FB 01
+					29 01 00 00 00 02 FF 04
+					29 01 00 00 00 02 FB 01
+					29 01 00 00 00 02 FF 00
+					29 01 00 00 64 02 11 00
+					29 01 00 00 00 02 FF EE
+					29 01 00 00 00 02 12 50
+					29 01 00 00 00 02 13 02
+					29 01 00 00 00 02 6A 60
+					29 01 00 00 00 02 FF 00
+					29 01 00 00 78 02 29 00];
+
+		qcom,on-cmds-dsi-state = "DSI_LP_MODE";
+		qcom,panel-off-cmds = [05 01 00 00 32 02 28 00
+					05 01 00 00 78 02 10 00];
+		qcom,off-cmds-dsi-state = "DSI_LP_MODE";
+	};
+};
diff --git a/arch/arm/boot/dts/dsi-v2-panel-otm8018b-fwvga-video.dtsi b/arch/arm/boot/dts/dsi-v2-panel-otm8018b-fwvga-video.dtsi
index c2c64da..b598d6c 100644
--- a/arch/arm/boot/dts/dsi-v2-panel-otm8018b-fwvga-video.dtsi
+++ b/arch/arm/boot/dts/dsi-v2-panel-otm8018b-fwvga-video.dtsi
@@ -10,7 +10,7 @@
  * GNU General Public License for more details.
  */
 
-/ {
+&soc  {
 	qcom,dsi_v2_otm8018b_fwvga_video {
 		compatible = "qcom,dsi-panel-v2";
 		label = "OTM8018B FWVGA video mode dsi panel";
diff --git a/arch/arm/boot/dts/dsi-v2-panel-truly-wvga-cmd.dtsi b/arch/arm/boot/dts/dsi-v2-panel-truly-wvga-cmd.dtsi
index f57a7bd..fd8d218 100644
--- a/arch/arm/boot/dts/dsi-v2-panel-truly-wvga-cmd.dtsi
+++ b/arch/arm/boot/dts/dsi-v2-panel-truly-wvga-cmd.dtsi
@@ -10,8 +10,8 @@
  * GNU General Public License for more details.
  */
 
-/ {
-	qcom,dsi_v2_truly_wvga_video {
+&soc  {
+	qcom,dsi_v2_truly_wvga_cmd {
 		compatible = "qcom,dsi-panel-v2";
 		label = "Truly WVGA command mode dsi panel";
 		qcom,dsi-ctrl-phandle = <&mdss_dsi0>;
@@ -65,43 +65,81 @@
 						b0 04
 					29 01 00 00 00 03
 						b3 02 00
+					29 01 00 00 00 03
+						b6 51 83
+					29 01 00 00 00 05
+						b7 00 80 15 25
+					29 01 00 00 00 14
+						b8 00 07 07 ff c8 c8 01 18 10 10
+						37 5a 87 de ff 00 00 00 00
+					29 01 00 00 00 05
+						b9 00 00 00 00
 					23 01 00 00 00 02
 						bd 00
 					29 01 00 00 00 03
-						c0 18 66
+						c0 02 43
 					29 01 00 00 00 10
-						c1 23 31 99 21 20 00 30 28 0c 0c
+						c1 43 31 99 21 20 00 10 28 0c 0c
 						00 00 00 21 01
 					29 01 00 00 00 07
-						c2 00 06 06 01 03 00
+						c2 28 06 06 01 03 00
+					29 01 00 00 00 04
+						c3 40 00 03
+					29 01 00 00 00 03
+						6f 03 00
+					29 01 00 00 00 03
+						c4 00 01
+					29 01 00 00 00 03
+						c6 00 00
+					29 01 00 00 00 06
+						c7 11 8d a0 f5 27
 					29 01 00 00 00 19
-						c8 04 10 18 20 2e 46 3c 28 1f 18
-						10 04 04 10 18 20 2e 46 3c 28 1f 18 10 04
+						c8 01 0a 12 1c 2b 45 3f 29 17 13
+						0f 04 01 0a 12 1c 2b 45 3f 29 17 13 0f 04
 					29 01 00 00 00 19
-						c9 04 10 18 20 2e 46 3c 28 1f 18
-						10 04 04 10 18 20 2e 46 3c 28 1f 18 10 04
+						c9 01 0a 12 1c 2b 45 3f 29 17 13
+						0f 04 01 0a 12 1c 2b 45 3f 29 17 13 0f 04
 					29 01 00 00 00 19
-						ca 04 10 18 20 2e 46 3c 28 1f 18
-						10 04 04 10 18 20 2e 46 3c 28 1f 18 10 04
+						ca 01 0a 12 1c 2b 45 3f 29 17 13
+						0f 04 01 0a 12 1c 2b 45 3f 29 17 13 0f 04
 					29 01 00 00 00 11
-						d0 29 03 ce a6 00 43 20 10 01 00
+						d0 99 03 ce a6 00 43 20 10 01 00
 						01 01 00 03 01 00
 					29 01 00 00 00 08
 						d1 18 0C 23 03 75 02 50
 					23 01 00 00 00 02
-						d3 11
+						d3 33
 					29 01 00 00 00 03
 						d5 2a 2a
+					29 01 00 00 00 02
+						d6 28
+					29 01 00 00 00 10
+						d7 01 00 aa c0 2a 2c 22	12 71 0a 12 00 a0
+						00 03
+					29 01 00 00 00 09
+						d8 44 44 22 44 21 46 42 40
+					29 01 00 00 00 04
+						d9 cf 2d 51
+					29 01 00 00 00 02
+						da 01
 					29 01 00 00 00 03
-						de 01 51
+						de 01 4f
+					29 01 00 00 00 07
+						e1 00 00 00 00 00 00
 					23 01 00 00 00 02
-						e6 51
+						e6 4f
+					29 01 00 00 00 06
+						f3 06 00 00 24 00
+					29 01 00 00 00 02
+						f8 00
 					23 01 00 00 00 02
 						fa 03
-					23 01 00 00 64 02
-						d6 28
-					15 01 00 00 00 02
-						36 41
+					29 01 00 00 00 04
+						fb 00 00 00
+					29 01 00 00 00 06
+						fc 00 00 00 00 00
+					29 01 00 00 00 05
+						fd 00 00 70 00
 					39 01 00 00 00 05
 						2a 00 00 01 df
 					39 01 00 00 00 05
@@ -111,10 +149,12 @@
 					39 01 00 00 00 03
 						44 00 50
 					15 01 00 00 00 02
+						36 41
+					15 01 00 00 00 02
 						3a 77
 					05 01 00 00 7D 02
 						11 00
-					05 01 00 00 14 02
+					05 01 00 00 3c 02
 						29 00
 					];
 		qcom,panel-off-cmds = [05 01 00 00 32 02 28 00
diff --git a/arch/arm/boot/dts/dsi-v2-panel-truly-wvga-video.dtsi b/arch/arm/boot/dts/dsi-v2-panel-truly-wvga-video.dtsi
index 8be8d71..538f2d8 100644
--- a/arch/arm/boot/dts/dsi-v2-panel-truly-wvga-video.dtsi
+++ b/arch/arm/boot/dts/dsi-v2-panel-truly-wvga-video.dtsi
@@ -10,7 +10,7 @@
  * GNU General Public License for more details.
  */
 
-/ {
+&soc  {
 	qcom,dsi_v2_truly_wvga_video {
 		compatible = "qcom,dsi-panel-v2";
 		label = "Truly WVGA video mode dsi panel";
@@ -61,41 +61,81 @@
 						b0 04
 					29 01 00 00 00 03
 						b3 02 00
+					29 01 00 00 00 03
+						b6 51 83
+					29 01 00 00 00 05
+						b7 00 80 15 25
+					29 01 00 00 00 14
+						b8 00 07 07 ff c8 c8 01 18 10 10
+						37 5a 87 de ff 00 00 00 00
+					29 01 00 00 00 05
+						b9 00 00 00 00
 					23 01 00 00 00 02
 						bd 00
 					29 01 00 00 00 03
-						c0 18 66
+						c0 02 43
 					29 01 00 00 00 10
-						c1 23 31 99 21 20 00 30 28 0c 0c
+						c1 43 31 99 21 20 00 10 28 0c 0c
 						00 00 00 21 01
 					29 01 00 00 00 07
-						c2 00 06 06 01 03 00
+						c2 28 06 06 01 03 00
+					29 01 00 00 00 04
+						c3 40 00 03
+					29 01 00 00 00 03
+						6f 03 00
+					29 01 00 00 00 03
+						c4 00 01
+					29 01 00 00 00 03
+						c6 00 00
+					29 01 00 00 00 06
+						c7 11 8d a0 f5 27
 					29 01 00 00 00 19
-						c8 04 10 18 20 2e 46 3c 28 1f 18
-						10 04 04 10 18 20 2e 46 3c 28 1f 18 10 04
+						c8 01 0a 12 1c 2b 45 3f 29 17 13
+						0f 04 01 0a 12 1c 2b 45 3f 29 17 13 0f 04
 					29 01 00 00 00 19
-						c9 04 10 18 20 2e 46 3c 28 1f 18
-						10 04 04 10 18 20 2e 46 3c 28 1f 18 10 04
+						c9 01 0a 12 1c 2b 45 3f 29 17 13
+						0f 04 01 0a 12 1c 2b 45 3f 29 17 13 0f 04
 					29 01 00 00 00 19
-						ca 04 10 18 20 2e 46 3c 28 1f 18
-						10 04 04 10 18 20 2e 46 3c 28 1f 18 10 04
+						ca 01 0a 12 1c 2b 45 3f 29 17 13
+						0f 04 01 0a 12 1c 2b 45 3f 29 17 13 0f 04
 					29 01 00 00 00 11
-						d0 29 03 ce a6 00 43 20 10 01 00
+						d0 99 03 ce a6 00 43 20 10 01 00
 						01 01 00 03 01 00
 					29 01 00 00 00 08
 						d1 18 0C 23 03 75 02 50
 					23 01 00 00 00 02
-						d3 11
+						d3 33
 					29 01 00 00 00 03
 						d5 2a 2a
+					29 01 00 00 00 02
+						d6 28
+					29 01 00 00 00 10
+						d7 01 00 aa c0 2a 2c 22	12 71 0a 12 00 a0
+						00 03
+					29 01 00 00 00 09
+						d8 44 44 22 44 21 46 42 40
+					29 01 00 00 00 04
+						d9 cf 2d 51
+					29 01 00 00 00 02
+						da 01
 					29 01 00 00 00 03
-						de 01 51
+						de 01 4f
+					29 01 00 00 00 07
+						e1 00 00 00 00 00 00
 					23 01 00 00 00 02
-						e6 51
+						e6 4f
+					29 01 00 00 00 06
+						f3 06 00 00 24 00
+					29 01 00 00 00 02
+						f8 00
 					23 01 00 00 00 02
 						fa 03
-					23 01 00 00 64 02
-						d6 28
+					29 01 00 00 00 04
+						fb 00 00 00
+					29 01 00 00 00 06
+						fc 00 00 00 00 00
+					29 01 00 00 00 05
+						fd 00 00 70 00
 					39 01 00 00 00 05
 						2a 00 00 01 df
 					39 01 00 00 00 05
@@ -110,11 +150,15 @@
 						3a 77
 					05 01 00 00 7D 02
 						11 00
-					05 01 00 00 14 02
+					05 01 00 00 3c 02
 						29 00
 					];
 		qcom,panel-off-cmds = [05 01 00 00 32 02 28 00
-					05 01 00 00 78 02 10 00];
+					05 01 00 00 78 02 10 00
+					23 01 00 00 10 02
+						b0 04
+					23 01 00 00 20 02
+						b1 01];
 		qcom,off-cmds-dsi-state = "DSI_LP_MODE";
 	};
 };
diff --git a/arch/arm/boot/dts/fsm9900.dtsi b/arch/arm/boot/dts/fsm9900.dtsi
index b74e58f..1c48bf0 100644
--- a/arch/arm/boot/dts/fsm9900.dtsi
+++ b/arch/arm/boot/dts/fsm9900.dtsi
@@ -78,8 +78,6 @@
 		compatible = "qcom,cache_dump";
 		qcom,l1-dump-size = <0x100000>;
 		qcom,l2-dump-size = <0x500000>;
-		qcom,memory-reservation-type = "EBI1";
-		qcom,memory-reservation-size = <0x600000>; /* 6M EBI1 buffer */
 	};
 
 	qcom,ion {
diff --git a/arch/arm/boot/dts/mpq8092-iommu.dtsi b/arch/arm/boot/dts/mpq8092-iommu.dtsi
index af8e015..320440c 100644
--- a/arch/arm/boot/dts/mpq8092-iommu.dtsi
+++ b/arch/arm/boot/dts/mpq8092-iommu.dtsi
@@ -27,23 +27,19 @@
 				0x215c
 				0x220c
 				0x22bc
-				0x2008
-				0x200c
-				0x2010>;
+				0x2008>;
 
-	qcom,iommu-bfb-data =  <0x3FFF
+	qcom,iommu-bfb-data =  <0x0F
 				0x4
 				0x4
 				0x0
 				0x0
-				0x10
-				0x50
+				0x4
+				0x14
 				0x0
-				0x2000
-				0x2804
-				0x9614
-				0x0
-				0x0
+				0x800
+				0x800
+				0x3a04
 				0x0
 				0x0>;
 };
@@ -66,21 +62,19 @@
 				0x2008
 				0x200c
 				0x2010
-				0x2014
-				0x2018>;
+				0x2014>;
 
-	qcom,iommu-bfb-data =  <0x7FFFFF
+	qcom,iommu-bfb-data =  <0x3FFFF
 				0x4
-				0x10
+				0x4
 				0x0
-				0x5000
-				0x5a1d
-				0x1822d
+				0x1000
+				0x0e00
+				0x8207
 				0x0
 				0x0
-				0x28
-				0x68
-				0x0
+				0x8
+				0x24
 				0x0
 				0x0
 				0x0
@@ -114,9 +108,9 @@
 				0x4
 				0x8
 				0x0
-				0x13607
-				0x4201
-				0x14221
+				0x13205
+				0x4000
+				0x14020
 				0x0
 				0x0
 				0x94
@@ -184,10 +178,13 @@
 				0x2620
 				0x2624
 				0x2628
-				0x262c>;
+				0x262c
+				0x2630
+				0x2634
+				0x2638>;
 
 	qcom,iommu-bfb-data =  <0x3
-				0x8
+				0x4
 				0x10
 				0x0
 				0x0
@@ -196,26 +193,79 @@
 				0x0
 				0x0
 				0x1
-				0x101
+				0x81
 				0x0
 				0x0
-				0x7
+				0x1f
 				0x4
 				0x8
 				0x14
 				0x0
 				0x0
 				0xc
-				0x6c
+				0x3c
 				0x0
-				0x8
+				0x4
 				0x10
-				0x0>;
+				0x0
+				0x15
+				0x3020100
+				0x04>;
 };
 
 &vpu_iommu {
 	status = "ok";
 
+	qcom,iommu-bfb-regs =  <0x204c
+				0x2050
+				0x2514
+				0x2540
+				0x256c
+				0x2314
+				0x2394
+				0x2414
+				0x2494
+				0x20ac
+				0x215c
+				0x220c
+				0x22bc
+				0x2008
+				0x200c
+				0x2010
+				0x2014
+				0x2018
+				0x201c
+				0x2020
+				0x2024
+				0x2028
+				0x202c
+				0x2030>;
+
+	qcom,iommu-bfb-data =  <0xffffffff
+				0xfffff
+				0x4
+				0x8
+				0x0
+				0x0
+				0x34
+				0x104
+				0x0
+				0x6800
+				0x6800
+				0x18034
+				0x0
+				0x0
+				0x0
+				0x0
+				0x0
+				0x0
+				0x0
+				0x0
+				0x0
+				0x0
+				0x0
+				0x0>;
+
 	interrupts = <0 300 0>;
 	vpu_cb_0: qcom,iommu-ctx@fdeec000 {
 		interrupts = <0 302 0>;
diff --git a/arch/arm/boot/dts/mpq8092-rumi.dts b/arch/arm/boot/dts/mpq8092-rumi.dts
index 1abaf55..3ba2fbc 100644
--- a/arch/arm/boot/dts/mpq8092-rumi.dts
+++ b/arch/arm/boot/dts/mpq8092-rumi.dts
@@ -18,7 +18,7 @@
 / {
 	model = "Qualcomm MPQ8092 RUMI";
 	compatible = "qcom,mpq8092-rumi", "qcom,mpq8092", "qcom,rumi";
-	qcom,msm-id = <146 16 0>;
+	qcom,msm-id = <146 15 0>;
 };
 
 &soc {
diff --git a/arch/arm/boot/dts/mpq8092-sim.dts b/arch/arm/boot/dts/mpq8092-sim.dts
index 676ef3b..2384a45 100644
--- a/arch/arm/boot/dts/mpq8092-sim.dts
+++ b/arch/arm/boot/dts/mpq8092-sim.dts
@@ -17,7 +17,7 @@
 / {
 	model = "Qualcomm MPQ8092 Simulator";
 	compatible = "qcom,mpq8092-sim", "qcom,mpq8092", "qcom,sim";
-	qcom,msm-id = <126 16 0>;
+	qcom,msm-id = <146 16 0>;
 };
 
 &soc {
diff --git a/arch/arm/boot/dts/mpq8092.dtsi b/arch/arm/boot/dts/mpq8092.dtsi
index 2f67f3e..9a37316 100644
--- a/arch/arm/boot/dts/mpq8092.dtsi
+++ b/arch/arm/boot/dts/mpq8092.dtsi
@@ -229,6 +229,15 @@
 		qcom,current-limit = <800>;
 	};
 
+	qcom,sps@f9980000 {
+		compatible = "qcom,msm_sps";
+		reg = <0xf9984000 0x15000>,
+		      <0xf9999000 0xb000>;
+		reg-names = "bam_mem", "core_mem";
+		interrupts = <0 94 0>;
+		qcom,pipe-attr-ee;
+	};
+
 	sata: sata@fc580000 {
 		compatible = "qcom,msm-ahci";
 		reg = <0xfc580000 0x17c>;
@@ -308,5 +317,9 @@
 	status = "ok";
 };
 
+&gdsc_vcap {
+	status = "ok";
+};
+
 /include/ "msm-pma8084.dtsi"
 /include/ "mpq8092-regulator.dtsi"
diff --git a/arch/arm/boot/dts/msm-gdsc.dtsi b/arch/arm/boot/dts/msm-gdsc.dtsi
index 495f65a..2f732a4 100644
--- a/arch/arm/boot/dts/msm-gdsc.dtsi
+++ b/arch/arm/boot/dts/msm-gdsc.dtsi
@@ -109,4 +109,11 @@
 		reg = <0xfc401ec0 0x4>;
 		status = "disabled";
 	};
+
+	gdsc_vcap: qcom,gdsc@fd8c1804 {
+		compatible = "qcom,gdsc";
+		regulator-name = "gdsc_vcap";
+		reg = <0xfd8c1804 0x4>;
+		status = "disabled";
+	};
 };
diff --git a/arch/arm/boot/dts/msm-iommu-v0.dtsi b/arch/arm/boot/dts/msm-iommu-v0.dtsi
index 2cfc5cf..8ab9985 100644
--- a/arch/arm/boot/dts/msm-iommu-v0.dtsi
+++ b/arch/arm/boot/dts/msm-iommu-v0.dtsi
@@ -29,7 +29,6 @@
 						0x80>;
 		qcom,msm-bus,name = "lpass_ebi";
 		qcom,msm-bus,num-cases = <2>;
-		qcom,msm-bus,active-only;
 		qcom,msm-bus,num-paths = <1>;
 		qcom,msm-bus,vectors-KBps =
 				<11 512 0 0>,
@@ -87,7 +86,6 @@
 						0x80>;
 		qcom,msm-bus,name = "copss_ebi";
 		qcom,msm-bus,num-cases = <2>;
-		qcom,msm-bus,active-only;
 		qcom,msm-bus,num-paths = <1>;
 		qcom,msm-bus,vectors-KBps =
 				<88 512 0 0>,
@@ -178,7 +176,6 @@
 						0x80>;
 		qcom,msm-bus,name = "mdpe_ebi";
 		qcom,msm-bus,num-cases = <2>;
-		qcom,msm-bus,active-only;
 		qcom,msm-bus,num-paths = <1>;
 		qcom,msm-bus,vectors-KBps =
 				<92 512 0 0>,
@@ -220,7 +217,6 @@
 						0x80>;
 		qcom,msm-bus,name = "mdps_ebi";
 		qcom,msm-bus,num-cases = <2>;
-		qcom,msm-bus,active-only;
 		qcom,msm-bus,num-paths = <1>;
 		qcom,msm-bus,vectors-KBps =
 				<22 512 0 0>,
@@ -263,7 +259,6 @@
 						0x80>;
 		qcom,msm-bus,name = "gfx_ebi";
 		qcom,msm-bus,num-cases = <2>;
-		qcom,msm-bus,active-only;
 		qcom,msm-bus,num-paths = <1>;
 		qcom,msm-bus,vectors-KBps =
 				<26 512 0 0>,
@@ -315,7 +310,6 @@
 						0x80>;
 		qcom,msm-bus,name = "vfe_ebi";
 		qcom,msm-bus,num-cases = <2>;
-		qcom,msm-bus,active-only;
 		qcom,msm-bus,num-paths = <1>;
 		qcom,msm-bus,vectors-KBps =
 				<29 512 0 0>,
diff --git a/arch/arm/boot/dts/msm-iommu-v1.dtsi b/arch/arm/boot/dts/msm-iommu-v1.dtsi
index cd5adaa..c767b37 100644
--- a/arch/arm/boot/dts/msm-iommu-v1.dtsi
+++ b/arch/arm/boot/dts/msm-iommu-v1.dtsi
@@ -24,7 +24,6 @@
 		status = "disabled";
 		qcom,msm-bus,name = "jpeg_ebi";
 		qcom,msm-bus,num-cases = <2>;
-		qcom,msm-bus,active-only;
 		qcom,msm-bus,num-paths = <1>;
 		qcom,msm-bus,vectors-KBps =
 				<62 512 0 0>,
@@ -119,7 +118,6 @@
 		label = "mdp_iommu";
 		qcom,msm-bus,name = "mdp_ebi";
 		qcom,msm-bus,num-cases = <2>;
-		qcom,msm-bus,active-only;
 		qcom,msm-bus,num-paths = <1>;
 		qcom,msm-bus,vectors-KBps =
 				<22 512 0 0>,
@@ -225,7 +223,6 @@
 		label = "venus_iommu";
 		qcom,msm-bus,name = "venus_ebi";
 		qcom,msm-bus,num-cases = <2>;
-		qcom,msm-bus,active-only;
 		qcom,msm-bus,num-paths = <1>;
 		qcom,msm-bus,vectors-KBps =
 				<63 512 0 0>,
@@ -340,7 +337,6 @@
 		label = "kgsl_iommu";
 		qcom,msm-bus,name = "kgsl_ebi";
 		qcom,msm-bus,num-cases = <2>;
-		qcom,msm-bus,active-only;
 		qcom,msm-bus,num-paths = <1>;
 		qcom,msm-bus,vectors-KBps =
 				<26 512 0 0>,
@@ -431,7 +427,6 @@
 		label = "vfe_iommu";
 		qcom,msm-bus,name = "vfe_ebi";
 		qcom,msm-bus,num-cases = <2>;
-		qcom,msm-bus,active-only;
 		qcom,msm-bus,num-paths = <1>;
 		qcom,msm-bus,vectors-KBps =
 				<29 512 0 0>,
@@ -532,7 +527,6 @@
 		label = "copss_iommu";
 		qcom,msm-bus,name = "copss_ebi";
 		qcom,msm-bus,num-cases = <2>;
-		qcom,msm-bus,active-only;
 		qcom,msm-bus,num-paths = <1>;
 		qcom,msm-bus,vectors-KBps =
 				<88 512 0 0>,
@@ -691,7 +685,6 @@
 		label = "vpu_iommu";
 		qcom,msm-bus,name = "vpu_ebi";
 		qcom,msm-bus,num-cases = <2>;
-		qcom,msm-bus,active-only;
 		qcom,msm-bus,num-paths = <1>;
 		qcom,msm-bus,vectors-KBps =
 				<93 512 0 0>,
@@ -822,7 +815,6 @@
 		label = "lpass_qdsp_iommu";
 		qcom,msm-bus,name = "lpass_qdsp_ebi";
 		qcom,msm-bus,num-cases = <2>;
-		qcom,msm-bus,active-only;
 		qcom,msm-bus,num-paths = <1>;
 		qcom,msm-bus,vectors-KBps =
 				<11 512 0 0>,
@@ -949,7 +941,6 @@
 		label = "lpass_core_iommu";
 		qcom,msm-bus,name = "lpass_core_ebi";
 		qcom,msm-bus,num-cases = <2>;
-		qcom,msm-bus,active-only;
 		qcom,msm-bus,num-paths = <1>;
 		qcom,msm-bus,vectors-KBps =
 				<52 512 0 0>,
@@ -1070,7 +1061,6 @@
 		status = "disabled";
 		qcom,msm-bus,name = "vcap_ebi";
 		qcom,msm-bus,num-cases = <2>;
-		qcom,msm-bus,active-only;
 		qcom,msm-bus,num-paths = <1>;
 		qcom,msm-bus,vectors-KBps =
 			<48 512 0 0>,
diff --git a/arch/arm/boot/dts/msm-pm8110.dtsi b/arch/arm/boot/dts/msm-pm8110.dtsi
index 187599f..6969940 100644
--- a/arch/arm/boot/dts/msm-pm8110.dtsi
+++ b/arch/arm/boot/dts/msm-pm8110.dtsi
@@ -59,16 +59,17 @@
 
 			qcom,vddmax-mv = <4200>;
 			qcom,vddsafe-mv = <4230>;
-			qcom,vinmin-mv = <4200>;
+			qcom,vinmin-mv = <4300>;
 			qcom,vbatdet-mv = <4100>;
 			qcom,ibatmax-ma = <1500>;
 			qcom,ibatterm-ma = <100>;
 			qcom,ibatsafe-ma = <1500>;
 			qcom,thermal-mitigation = <1500 700 600 325>;
-			qcom,vbatdet-delta-mv = <350>;
+			qcom,vbatdet-delta-mv = <100>;
 			qcom,resume-soc = <99>;
 			qcom,tchg-mins = <150>;
 			qcom,chg-vadc = <&pm8110_vadc>;
+			qcom,chg-adc_tm = <&pm8110_adc_tm>;
 
 			qcom,chgr@1000 {
 				status = "disabled";
@@ -217,6 +218,7 @@
 			interrupt-names = "eoc-int-en-set";
 			qcom,adc-bit-resolution = <15>;
 			qcom,adc-vdd-reference = <1800>;
+			qcom,vadc-poll-eoc;
 
 			chan@8 {
 				label = "die_temp";
@@ -252,7 +254,7 @@
 			};
 		};
 
-		iadc@3600 {
+		pm8110_iadc: iadc@3600 {
 			compatible = "qcom,qpnp-iadc";
 			reg = <0x3600 0x100>;
 			#address-cells = <1>;
@@ -262,6 +264,7 @@
 			qcom,adc-bit-resolution = <16>;
 			qcom,adc-vdd-reference = <1800>;
 			qcom,iadc-vadc = <&pm8110_vadc>;
+			qcom,iadc-poll-eoc;
 
 			chan@0 {
 				label = "internal_rsense";
@@ -312,7 +315,7 @@
 			qcom,v-cutoff-uv = <3400000>;
 			qcom,max-voltage-uv = <4200000>;
 			qcom,r-conn-mohm = <0>;
-			qcom,shutdown-soc-valid-limit = <20>;
+			qcom,shutdown-soc-valid-limit = <100>;
 			qcom,adjust-soc-low-threshold = <15>;
 			qcom,ocv-voltage-high-threshold-uv = <3750000>;
 			qcom,ocv-voltage-low-threshold-uv = <3650000>;
@@ -327,6 +330,8 @@
 			qcom,high-ocv-correction-limit-uv = <50>;
 			qcom,hold-soc-est = <3>;
 			qcom,bms-vadc = <&pm8110_vadc>;
+			qcom,bms-iadc = <&pm8110_iadc>;
+			qcom,bms-adc_tm = <&pm8110_adc_tm>;
 
 			qcom,bms-iadc@3800 {
 				reg = <0x3800 0x100>;
@@ -343,14 +348,14 @@
 						<0x0 0x40 0x6>,
 						<0x0 0x40 0x7>;
 
-				interrupt-names = "vsense_for_r",
-						  "vsense_avg",
-						  "sw_cc_thr",
-						  "ocv_thr",
-						  "charge_begin",
-						  "good_ocv",
+				interrupt-names = "cc_thr",
 						  "ocv_for_r",
-						  "cc_thr";
+						  "good_ocv",
+						  "charge_begin",
+						  "ocv_thr",
+						  "sw_cc_thr",
+						  "vsense_avg",
+						  "vsense_for_r";
 			};
 		};
 
diff --git a/arch/arm/boot/dts/msm-pm8226.dtsi b/arch/arm/boot/dts/msm-pm8226.dtsi
index 18b097c..ba1bf08 100644
--- a/arch/arm/boot/dts/msm-pm8226.dtsi
+++ b/arch/arm/boot/dts/msm-pm8226.dtsi
@@ -22,7 +22,7 @@
 		#address-cells = <1>;
 		#size-cells = <1>;
 
-		qcom,revid@100 {
+		pm8226_revid: qcom,revid@100 {
 			compatible = "qcom,qpnp-revid";
 			reg = <0x100 0x100>;
 		};
@@ -48,11 +48,7 @@
 
 			qcom,pon_2 {
 				qcom,pon-type = <1>;
-				qcom,support-reset = <1>;
 				qcom,pull-up = <1>;
-				qcom,s1-timer = <0>;
-				qcom,s2-timer = <2000>;
-				qcom,s2-type = <1>;
 				linux,code = <114>;
 			};
 
@@ -75,8 +71,8 @@
 
 			qcom,vddmax-mv = <4200>;
 			qcom,vddsafe-mv = <4230>;
-			qcom,vinmin-mv = <4200>;
-			qcom,vbatdet-delta-mv = <150>;
+			qcom,vinmin-mv = <4300>;
+			qcom,vbatdet-delta-mv = <100>;
 			qcom,ibatmax-ma = <1500>;
 			qcom,ibatterm-ma = <100>;
 			qcom,ibatsafe-ma = <1500>;
@@ -84,6 +80,14 @@
 			qcom,resume-soc = <99>;
 			qcom,tchg-mins = <150>;
 			qcom,chg-vadc = <&pm8226_vadc>;
+			qcom,chg-adc_tm = <&pm8226_adc_tm>;
+			qcom,pmic-revid = <&pm8226_revid>;
+			qcom,ibatmax-warm-ma = <350>;
+			qcom,warm-bat-decidegc = <450>;
+			qcom,warm-bat-mv = <4100>;
+			qcom,cool-bat-decidegc = <100>;
+			qcom,cool-bat-mv = <4100>;
+			qcom,ibatmax-cool-ma = <350>;
 
 			qcom,chgr@1000 {
 				status = "disabled";
@@ -185,7 +189,7 @@
 			qcom,v-cutoff-uv = <3400000>;
 			qcom,max-voltage-uv = <4200000>;
 			qcom,r-conn-mohm = <0>;
-			qcom,shutdown-soc-valid-limit = <20>;
+			qcom,shutdown-soc-valid-limit = <100>;
 			qcom,adjust-soc-low-threshold = <15>;
 			qcom,ocv-voltage-high-threshold-uv = <3750000>;
 			qcom,ocv-voltage-low-threshold-uv = <3650000>;
@@ -200,6 +204,8 @@
 			qcom,hold-soc-est = <3>;
 			qcom,low-voltage-threshold = <3420000>;
 			qcom,bms-vadc = <&pm8226_vadc>;
+			qcom,bms-iadc = <&pm8226_iadc>;
+			qcom,bms-adc_tm = <&pm8226_adc_tm>;
 
 			qcom,bms-iadc@3800 {
 				reg = <0x3800 0x100>;
@@ -216,14 +222,14 @@
 						<0x0 0x40 0x6>,
 						<0x0 0x40 0x7>;
 
-				interrupt-names = "vsense_for_r",
-						  "vsense_avg",
-						  "sw_cc_thr",
-						  "ocv_thr",
-						  "charge_begin",
-						  "good_ocv",
+				interrupt-names = "cc_thr",
 						  "ocv_for_r",
-						  "cc_thr";
+						  "good_ocv",
+						  "charge_begin",
+						  "ocv_thr",
+						  "sw_cc_thr",
+						  "vsense_avg",
+						  "vsense_for_r";
 			};
 		};
 
@@ -816,43 +822,55 @@
 			status = "disabled";
 		};
 
-                qcom,leds@d300 {
-                        compatible = "qcom,leds-qpnp";
-                        status = "okay";
-                        reg = <0xd300 0x100>;
-                        label = "flash";
-			flash_boost-supply = <&pm8226_chg_boost>;
-                        pm8226_flash0: qcom,flash_0 {
-                                qcom,max-current = <1000>;
-                                qcom,default-state = "off";
-                                qcom,headroom = <0>;
-                                qcom,duration = <1280>;
-                                qcom,clamp-curr = <200>;
-                                qcom,startup-dly = <1>;
-                                qcom,safety-timer;
-                                label = "flash";
-                                linux,default-trigger =
-                                        "flash0_trigger";
-                                qcom,id = <1>;
-                                linux,name = "led:flash_0";
-                                qcom,current = <625>;
-                        };
+		qcom,leds@d300 {
+			compatible = "qcom,leds-qpnp";
+			status = "okay";
+			reg = <0xd300 0x100>;
+			label = "flash";
+			flash-boost-supply = <&pm8226_chg_boost>;
+			pm8226_flash0: qcom,flash_0 {
+				qcom,max-current = <1000>;
+				qcom,default-state = "off";
+				qcom,headroom = <3>;
+				qcom,duration = <1280>;
+				qcom,clamp-curr = <200>;
+				qcom,startup-dly = <3>;
+				qcom,safety-timer;
+				label = "flash";
+				linux,default-trigger =
+						"flash0_trigger";
+				qcom,id = <1>;
+				linux,name = "led:flash_0";
+				qcom,current = <625>;
+			};
 
-                        pm8226_flash1: qcom,flash_1 {
-                                qcom,max-current = <1000>;
-                                qcom,default-state = "off";
-                                qcom,headroom = <0>;
-                                qcom,duration = <1280>;
-                                qcom,clamp-curr = <200>;
-                                qcom,startup-dly = <1>;
-                                qcom,safety-timer;
-                                linux,default-trigger =
-                                        "flash1_trigger";
-                                label = "flash";
-                                qcom,id = <2>;
-                                linux,name = "led:flash_1";
-                                qcom,current = <625>;
-                        };
+			pm8226_flash1: qcom,flash_1 {
+				qcom,max-current = <1000>;
+				qcom,default-state = "off";
+				qcom,headroom = <3>;
+				qcom,duration = <1280>;
+				qcom,clamp-curr = <200>;
+				qcom,startup-dly = <3>;
+				qcom,safety-timer;
+				linux,default-trigger =
+						"flash1_trigger";
+				label = "flash";
+				qcom,id = <2>;
+				linux,name = "led:flash_1";
+				qcom,current = <625>;
+			};
+
+			pm8226_torch: qcom,flash_torch {
+				qcom,max-current = <200>;
+				qcom,default-state = "off";
+				linux,default-trigger =
+						"torch_trigger";
+				label = "flash";
+				qcom,id = <1>;
+				linux,name = "led:flash_torch";
+				qcom,current = <120>;
+				qcom,torch-enable;
+			};
                 };
 	};
 };
diff --git a/arch/arm/boot/dts/msm-pm8841.dtsi b/arch/arm/boot/dts/msm-pm8841.dtsi
index a2d80ec..43bd0c9 100644
--- a/arch/arm/boot/dts/msm-pm8841.dtsi
+++ b/arch/arm/boot/dts/msm-pm8841.dtsi
@@ -238,5 +238,28 @@
 				reg = <0x2b00 0x100>;
 			};
 		};
+
+		krait_regulator_pmic: qcom,krait-regulator-pmic@2000 {
+			spmi-dev-container;
+			compatible = "qcom,krait-regulator-pmic";
+			#address-cells = <1>;
+			#size-cells = <1>;
+			status = "disabled";
+
+			qcom,ctl@2000 {
+				status = "disabled";
+				reg = <0x2000 0x100>;
+			};
+
+			qcom,ps@2100 {
+				status = "disabled";
+				reg = <0x2100 0x100>;
+			};
+
+			qcom,freq@2200 {
+				status = "disabled";
+				reg = <0x2200 0x100>;
+			};
+		};
 	};
 };
diff --git a/arch/arm/boot/dts/msm-pm8941.dtsi b/arch/arm/boot/dts/msm-pm8941.dtsi
index fad57a6..98d2f5e 100644
--- a/arch/arm/boot/dts/msm-pm8941.dtsi
+++ b/arch/arm/boot/dts/msm-pm8941.dtsi
@@ -120,7 +120,7 @@
 		qcom,v-cutoff-uv = <3400000>;
 		qcom,max-voltage-uv = <4200000>;
 		qcom,r-conn-mohm = <0>;
-		qcom,shutdown-soc-valid-limit = <20>;
+		qcom,shutdown-soc-valid-limit = <100>;
 		qcom,adjust-soc-low-threshold = <15>;
 		qcom,ocv-voltage-high-threshold-uv = <3750000>;
 		qcom,ocv-voltage-low-threshold-uv = <3650000>;
@@ -135,6 +135,8 @@
 		qcom,high-ocv-correction-limit-uv = <50>;
 		qcom,hold-soc-est = <3>;
 		qcom,bms-vadc = <&pm8941_vadc>;
+		qcom,bms-iadc = <&pm8941_iadc>;
+		qcom,bms-adc_tm = <&pm8941_adc_tm>;
 
 		qcom,bms-iadc@3800 {
 			reg = <0x3800 0x100>;
@@ -204,6 +206,7 @@
 		qcom,resume-soc = <99>;
 		qcom,tchg-mins = <150>;
 		qcom,chg-vadc = <&pm8941_vadc>;
+		qcom,chg-adc_tm = <&pm8941_adc_tm>;
 
 		qcom,chgr@1000 {
 			status = "disabled";
@@ -568,6 +571,7 @@
 		interrupt-names = "eoc-int-en-set";
 		qcom,adc-bit-resolution = <15>;
 		qcom,adc-vdd-reference = <1800>;
+		qcom,vadc-poll-eoc;
 
 		chan@0 {
 			label = "usb_in";
@@ -811,6 +815,7 @@
 		qcom,adc-bit-resolution = <16>;
 		qcom,adc-vdd-reference = <1800>;
 		qcom,iadc-vadc = <&pm8941_vadc>;
+		qcom,iadc-poll-eoc;
 
 		chan@0 {
 			label = "internal_rsense";
@@ -1248,7 +1253,8 @@
 		compatible = "qcom,leds-qpnp";
 		reg = <0xd300 0x100>;
 		label = "flash";
-		flash_boost-supply = <&pm8941_chg_boost>;
+		flash-boost-supply = <&pm8941_chg_boost>;
+		torch-boost-supply = <&pm8941_boost>;
 	};
 
 	qcom,leds@d400 {
diff --git a/arch/arm/boot/dts/msm-pma8084.dtsi b/arch/arm/boot/dts/msm-pma8084.dtsi
index 3368b36..c070443 100644
--- a/arch/arm/boot/dts/msm-pma8084.dtsi
+++ b/arch/arm/boot/dts/msm-pma8084.dtsi
@@ -264,6 +264,7 @@
 			interrupt-names = "eoc-int-en-set";
 			qcom,adc-bit-resolution = <15>;
 			qcom,adc-vdd-reference = <1800>;
+			qcom,vadc-poll-eoc;
 
 			chan@8 {
 				label = "die_temp";
@@ -323,6 +324,7 @@
 						"low-thr-en-set";
 			qcom,adc-bit-resolution = <15>;
 			qcom,adc-vdd-reference = <1800>;
+			qcom,adc_tm-vadc = <&pma8084_vadc>;
 		};
 
 		qcom,rtc {
@@ -812,5 +814,28 @@
 			compatible = "qcom,qpnp-regulator";
 			status = "disabled";
 		};
+
+		krait_regulator_pmic: qcom,krait-regulator-pmic@2900 {
+			spmi-dev-container;
+			compatible = "qcom,krait-regulator-pmic";
+			#address-cells = <1>;
+			#size-cells = <1>;
+			status = "disabled";
+
+			qcom,ctl@2900 {
+				reg = <0x2900 0x100>;
+				status = "disabled";
+			};
+
+			qcom,ps@2a00 {
+				reg = <0x2a00 0x100>;
+				status = "disabled";
+			};
+
+			qcom,freq@2b00 {
+				reg = <0x2b00 0x100>;
+				status = "disabled";
+			};
+		};
 	};
 };
diff --git a/arch/arm/boot/dts/msm8226-camera-sensor-cdp.dtsi b/arch/arm/boot/dts/msm8226-camera-sensor-cdp.dtsi
index d4b605b..fa5c739 100644
--- a/arch/arm/boot/dts/msm8226-camera-sensor-cdp.dtsi
+++ b/arch/arm/boot/dts/msm8226-camera-sensor-cdp.dtsi
@@ -18,6 +18,7 @@
 		compatible = "qcom,camera-led-flash";
 		qcom,flash-type = <1>;
 		qcom,flash-source = <&pm8226_flash0 &pm8226_flash1>;
+		qcom,torch-source = <&pm8226_torch>;
 	};
 };
 
@@ -30,6 +31,13 @@
 		qcom,cci-master = <0>;
 	};
 
+	actuator1: qcom,actuator@36 {
+		cell-index = <1>;
+		reg = <0x36>;
+		compatible = "qcom,actuator";
+		qcom,cci-master = <0>;
+	};
+
 	qcom,camera@6f {
 		compatible = "qcom,ov8825";
 		reg = <0x6f>;
@@ -38,7 +46,7 @@
 		qcom,csid-sd-index = <0>;
 		qcom,actuator-src = <&actuator0>;
 		qcom,led-flash-src = <&led_flash0>;
-		qcom,mount-angle = <0>;
+		qcom,mount-angle = <180>;
 		qcom,sensor-name = "ov8825";
 		cam_vdig-supply = <&pm8226_l5>;
 		cam_vana-supply = <&pm8226_l19>;
@@ -68,6 +76,48 @@
 		qcom,cci-master = <0>;
 	};
 
+    qcom,camera@20 {
+		compatible = "qcom,imx135";
+		reg = <0x20>;
+		qcom,slave-id = <0x20 0x0016 0x0135>;
+		qcom,csiphy-sd-index = <0>;
+		qcom,csid-sd-index = <0>;
+		qcom,actuator-src = <&actuator1>;
+		qcom,mount-angle = <90>;
+		qcom,sensor-name = "imx135";
+		cam_vdig-supply = <&pm8226_l5>;
+		cam_vana-supply = <&pm8226_l19>;
+		cam_vio-supply = <&pm8226_lvs1>;
+		cam_vaf-supply = <&pm8226_l15>;
+		qcom,cam-vreg-name = "cam_vdig", "cam_vio", "cam_vana",
+				     "cam_vaf";
+		qcom,cam-vreg-type = <0 1 0 0>;
+		qcom,cam-vreg-min-voltage = <1200000 0 2850000 2800000>;
+		qcom,cam-vreg-max-voltage = <1200000 0 2850000 2800000>;
+		qcom,cam-vreg-op-mode = <200000 0 80000 100000>;
+		qcom,gpio-no-mux = <0>;
+		gpios = <&msmgpio 26 0>,
+			<&msmgpio 37 0>,
+			<&msmgpio 36 0>;
+		qcom,gpio-reset = <1>;
+		qcom,gpio-standby = <2>;
+		qcom,gpio-req-tbl-num = <0 1 2>;
+		qcom,gpio-req-tbl-flags = <1 0 0>;
+		qcom,gpio-req-tbl-label = "CAMIF_MCLK",
+			"CAM_RESET1",
+			"CAM_STANDBY";
+		qcom,gpio-set-tbl-num = <1 1>;
+		qcom,gpio-set-tbl-flags = <0 2>;
+		qcom,gpio-set-tbl-delay = <1000 30000>;
+		qcom,csi-lane-assign = <0x4320>;
+		qcom,csi-lane-mask = <0x1F>;
+		qcom,sensor-position = <0>;
+		qcom,sensor-mode = <0>;
+	        qcom,sensor-type = <0>;
+		qcom,cci-master = <0>;
+		status = "ok";
+	};
+
 	qcom,camera@6d {
 		compatible = "qcom,ov9724";
 		reg = <0x6d>;
diff --git a/arch/arm/boot/dts/msm8226-camera-sensor-mtp.dtsi b/arch/arm/boot/dts/msm8226-camera-sensor-mtp.dtsi
index 53860ac..5d1e1c8 100644
--- a/arch/arm/boot/dts/msm8226-camera-sensor-mtp.dtsi
+++ b/arch/arm/boot/dts/msm8226-camera-sensor-mtp.dtsi
@@ -18,6 +18,7 @@
 		compatible = "qcom,camera-led-flash";
 		qcom,flash-type = <1>;
 		qcom,flash-source = <&pm8226_flash0 &pm8226_flash1>;
+		qcom,torch-source = <&pm8226_torch>;
 	};
 };
 
@@ -38,7 +39,7 @@
 		qcom,csid-sd-index = <0>;
 		qcom,actuator-src = <&actuator0>;
 		qcom,led-flash-src = <&led_flash0>;
-		qcom,mount-angle = <0>;
+		qcom,mount-angle = <270>;
 		qcom,sensor-name = "ov8825";
 		cam_vdig-supply = <&pm8226_l5>;
 		cam_vana-supply = <&pm8226_l19>;
diff --git a/arch/arm/boot/dts/msm8226-camera-sensor-qrd.dtsi b/arch/arm/boot/dts/msm8226-camera-sensor-qrd.dtsi
index fb24a25..fd6d618 100644
--- a/arch/arm/boot/dts/msm8226-camera-sensor-qrd.dtsi
+++ b/arch/arm/boot/dts/msm8226-camera-sensor-qrd.dtsi
@@ -18,6 +18,7 @@
 		compatible = "qcom,camera-led-flash";
 		qcom,flash-type = <1>;
 		qcom,flash-source = <&pm8226_flash0 &pm8226_flash1>;
+		qcom,torch-source = <&pm8226_torch>;
 	};
 };
 
@@ -30,6 +31,79 @@
 		qcom,cci-master = <0>;
 	};
 
+	eeprom0: qcom,eeprom@6c {
+		cell-index = <0>;
+		reg = <0x6c 0x0>;
+		qcom,eeprom-name = "truly_cm7700";
+		compatible = "qcom,eeprom";
+		qcom,slave-addr = <0x6c>;
+		qcom,cci-master = <0>;
+		qcom,num-blocks = <9>;
+		qcom,page0 = <1 0x0100 2 0x01 1 1>;
+		qcom,poll0 = <0 0x0 2 0 1 1>;
+		qcom,mem0 = <0 0x0 2 0 1 0>;
+		qcom,page1 = <1 0x3d84 2 0x8 1 1>;
+		qcom,pageen1 = <1 0x3d81 2 0x01 1 10>;
+		qcom,poll1 = <0 0x0 2 0 1 1>;
+		qcom,mem1 = <32 0x3d00 2 0 1 0>;
+		qcom,page2 = <1 0x3d84 2 0x9 1 1>;
+		qcom,pageen2 = <1 0x3d81 2 0x01 1 10>;
+		qcom,poll2 = <0 0x0 2 0 1 1>;
+		qcom,mem2 = <32 0x3d00 2 0 1 0>;
+		qcom,page3 = <1 0x3d84 2 0xa 1 1>;
+		qcom,pageen3 = <1 0x3d81 2 0x01 1 10>;
+		qcom,poll3 = <0 0x0 2 0 1 1>;
+		qcom,mem3 = <32 0x3d00 2 0 1 0>;
+		qcom,page4 = <1 0x3d84 2 0xb 1 1>;
+		qcom,pageen4 = <1 0x3d81 2 0x01 1 10>;
+		qcom,poll4 = <0 0x0 2 0 1 1>;
+		qcom,mem4 = <32 0x3d00 2 0 1 0>;
+		qcom,page5 = <1 0x3d84 2 0xc 1 1>;
+		qcom,pageen5 = <1 0x3d81 2 0x01 1 10>;
+		qcom,poll5 = <0 0x0 2 0 1 1>;
+		qcom,mem5 = <32 0x3d00 2 0 1 0>;
+		qcom,page6 = <1 0x3d84 2 0xd 1 1>;
+		qcom,pageen6 = <1 0x3d81 2 0x01 1 10>;
+		qcom,poll6 = <0 0x0 2 0 1 1>;
+		qcom,mem6 = <32 0x3d00 2 0 1 0>;
+		qcom,page7 = <1 0x3d84 2 0xe 1 1>;
+		qcom,pageen7 = <1 0x3d81 2 0x01 1 10>;
+		qcom,poll7 = <0 0x0 2 0 1 1>;
+		qcom,mem7 = <32 0x3d00 2 0 1 0>;
+		qcom,page8 = <1 0x3d84 2 0xf 1 1>;
+		qcom,pageen8 = <1 0x3d81 2 0x01 1 10>;
+		qcom,poll8 = <0 0x0 2 0 1 1>;
+		qcom,mem8 = <32 0x3d00 2 0 1 0>;
+
+		cam_vdig-supply = <&pm8226_l5>;
+		cam_vio-supply = <&pm8226_lvs1>;
+		qcom,cam-vreg-name = "cam_vdig", "cam_vio";
+		qcom,cam-vreg-type = <0 1>;
+		qcom,cam-vreg-min-voltage = <1200000 0>;
+		qcom,cam-vreg-max-voltage = <1200000 0>;
+		qcom,cam-vreg-op-mode = <200000 0>;
+		qcom,gpio-no-mux = <0>;
+		gpios = <&msmgpio 26 0>,
+			<&msmgpio 37 0>,
+			<&msmgpio 36 0>;
+		qcom,gpio-reset = <1>;
+		qcom,gpio-standby = <2>;
+		qcom,gpio-req-tbl-num = <0 1 2>;
+		qcom,gpio-req-tbl-flags = <1 0 0>;
+		qcom,gpio-req-tbl-label = "CAMIF_MCLK",
+			"CAM_RESET1",
+			"CAM_STANDBY";
+		qcom,cam-power-seq-type = "sensor_vreg",
+			"sensor_vreg", "sensor_clk",
+			"sensor_gpio", "sensor_gpio";
+		qcom,cam-power-seq-val = "cam_vdig",
+			"cam_vio", "sensor_cam_mclk",
+			"sensor_gpio_reset",
+			"sensor_gpio_standby";
+		qcom,cam-power-seq-cfg-val = <1 1 24000000 1 1>;
+		qcom,cam-power-seq-delay = <1 1 5 5 10>;
+	};
+
 	qcom,camera@6f {
 		compatible = "qcom,ov8825";
 		reg = <0x6f>;
@@ -38,7 +112,8 @@
 		qcom,csid-sd-index = <0>;
 		qcom,actuator-src = <&actuator0>;
 		qcom,led-flash-src = <&led_flash0>;
-		qcom,mount-angle = <270>;
+		qcom,eeprom-src = <&eeprom0>;
+		qcom,mount-angle = <90>;
 		qcom,sensor-name = "ov8825";
 		cam_vdig-supply = <&pm8226_l5>;
 		cam_vana-supply = <&pm8226_l19>;
@@ -75,6 +150,108 @@
 		qcom,cci-master = <0>;
 	};
 
+	eeprom1: qcom,eeprom@18{
+		cell-index = <1>;
+		reg = <0x18 0x0>;
+		qcom,eeprom-name = "sunny_p12v01m";
+		compatible = "qcom,eeprom";
+		qcom,slave-addr = <0x20>;
+		qcom,cci-master = <0>;
+		qcom,num-blocks = <16>;
+		qcom,page0 = <1 0x0100 2 0x01 1 1>;
+		qcom,poll0 = <0 0x0 2 0 1 1>;
+		qcom,mem0 = <0 0x0 2 0 1 0>;
+		qcom,page1 = <1 0x3d84 2 0xc1 1 1>;
+		qcom,pageen1 = <1 0x3d81 2 0x01 1 10>;
+		qcom,poll1 = <0 0x0 2 0 1 1>;
+		qcom,mem1 = <16 0x3d00 2 0 1 0>;
+		qcom,page2 = <1 0x3d84 2 0xc2 1 1>;
+		qcom,pageen2 = <1 0x3d81 2 0x01 1 10>;
+		qcom,poll2 = <0 0x0 2 0 1 1>;
+		qcom,mem2 = <16 0x3d00 2 0 1 0>;
+		qcom,page3 = <1 0x3d84 2 0xc3 1 1>;
+		qcom,pageen3 = <1 0x3d81 2 0x01 1 10>;
+		qcom,poll3 = <0 0x0 2 0 1 1>;
+		qcom,mem3 = <16 0x3d00 2 0 1 0>;
+		qcom,page4 = <1 0x3d84 2 0xc4 1 1>;
+		qcom,pageen4 = <1 0x3d81 2 0x01 1 10>;
+		qcom,poll4 = <0 0x0 2 0 1 1>;
+		qcom,mem4 = <16 0x3d00 2 0 1 0>;
+		qcom,page5 = <1 0x3d84 2 0xc5 1 1>;
+		qcom,pageen5 = <1 0x3d81 2 0x01 1 10>;
+		qcom,poll5 = <0 0x0 2 0 1 1>;
+		qcom,mem5 = <16 0x3d00 2 0 1 0>;
+		qcom,page6 = <1 0x3d84 2 0xc6 1 1>;
+		qcom,pageen6 = <1 0x3d81 2 0x01 1 10>;
+		qcom,poll6 = <0 0x0 2 0 1 1>;
+		qcom,mem6 = <16 0x3d00 2 0 1 0>;
+		qcom,page7 = <1 0x3d84 2 0xc7 1 1>;
+		qcom,pageen7 = <1 0x3d81 2 0x01 1 10>;
+		qcom,poll7 = <0 0x0 2 0 1 1>;
+		qcom,mem7 = <16 0x3d00 2 0 1 0>;
+		qcom,page8 = <1 0x3d84 2 0xc8 1 1>;
+		qcom,pageen8 = <1 0x3d81 2 0x01 1 10>;
+		qcom,poll8 = <0 0x0 2 0 1 1>;
+		qcom,mem8 = <16 0x3d00 2 0 1 0>;
+		qcom,page9 = <1 0x3d84 2 0xc9 1 1>;
+		qcom,pageen9 = <1 0x3d81 2 0x01 1 10>;
+		qcom,poll9 = <0 0x0 2 0 1 1>;
+		qcom,mem9 = <16 0x3d00 2 0 1 0>;
+		qcom,page10 = <1 0x3d84 2 0xca 1 1>;
+		qcom,pageen10 = <1 0x3d81 2 0x01 1 10>;
+		qcom,poll10 = <0 0x0 2 0 1 1>;
+		qcom,mem10 = <16 0x3d00 2 0 1 0>;
+		qcom,page11 = <1 0x3d84 2 0xcb 1 1>;
+		qcom,pageen11 = <1 0x3d81 2 0x01 1 10>;
+		qcom,poll11 = <0 0x0 2 0 1 1>;
+		qcom,mem11 = <16 0x3d00 2 0 1 0>;
+		qcom,page12 = <1 0x3d84 2 0xcc 1 1>;
+		qcom,pageen12 = <1 0x3d81 2 0x01 1 10>;
+		qcom,poll12 = <0 0x0 2 0 1 1>;
+		qcom,mem12 = <16 0x3d00 2 0 1 0>;
+		qcom,page13 = <1 0x3d84 2 0xcd 1 1>;
+		qcom,pageen13 = <1 0x3d81 2 0x01 1 10>;
+		qcom,poll13 = <0 0x0 2 0 1 1>;
+		qcom,mem13 = <16 0x3d00 2 0 1 0>;
+		qcom,page14 = <1 0x3d84 2 0xce 1 1>;
+		qcom,pageen14 = <1 0x3d81 2 0x01 1 10>;
+		qcom,poll14 = <0 0x0 2 0 1 1>;
+		qcom,mem14 = <16 0x3d00 2 0 1 0>;
+		qcom,page15 = <1 0x3d84 2 0xcf 1 1>;
+		qcom,pageen15 = <1 0x3d81 2 0x01 1 10>;
+		qcom,poll15 = <0 0x0 2 0 1 1>;
+		qcom,mem15 = <16 0x3d00 2 0 1 0>;
+		cam_vio-supply = <&pm8226_lvs1>;
+		cam_vana-supply = <&pm8226_l19>;
+		qcom,cam-vreg-name = "cam_vio", "cam_vana";
+		qcom,cam-vreg-type = <1 0>;
+		qcom,cam-vreg-min-voltage = <0 2850000>;
+		qcom,cam-vreg-max-voltage = <0 2850000>;
+		qcom,cam-vreg-op-mode = <0 80000>;
+		qcom,gpio-no-mux = <0>;
+		gpios = <&msmgpio 26 0>,
+			<&msmgpio 37 0>,
+			<&msmgpio 36 0>,
+			<&msmgpio 22 0>;
+		qcom,gpio-reset = <1>;
+		qcom,gpio-standby = <2>;
+		qcom,gpio-vdig = <3>;
+		qcom,gpio-req-tbl-num = <0 1 2 3>;
+		qcom,gpio-req-tbl-flags = <1 0 0 0>;
+		qcom,gpio-req-tbl-label = "CAMIF_MCLK",
+			"CAM_RESET1",
+			"CAM_STANDBY",
+			"CAM_VDIG";
+		qcom,cam-power-seq-type = "sensor_vreg",
+			"sensor_vreg", "sensor_gpio",
+			"sensor_gpio", "sensor_gpio" , "sensor_clk";
+		qcom,cam-power-seq-val = "cam_vio", "cam_vana","sensor_gpio_vdig",
+			 "sensor_gpio_reset",
+			"sensor_gpio_standby","sensor_cam_mclk" ;
+		qcom,cam-power-seq-cfg-val = <1 1 1 1 1 24000000>;
+		qcom,cam-power-seq-delay = <1 1 10 10 10 5>;
+	};
+
 	qcom,camera@6c {
 		compatible = "qcom,ov12830";
 		reg = <0x6c>;
@@ -83,7 +260,8 @@
 		qcom,csid-sd-index = <0>;
 		qcom,actuator-src = <&actuator1>;
 		qcom,led-flash-src = <&led_flash0>;
-		qcom,mount-angle = <270>;
+		qcom,eeprom-src = <&eeprom1>;
+		qcom,mount-angle = <90>;
 		qcom,sensor-name = "skuf_ov12830_p12v01c";
 		cam_vdig-supply = <&pm8226_l5>;
 		cam_vana-supply = <&pm8226_l19>;
@@ -157,12 +335,79 @@
 		status = "ok";
 	};
 
+	eeprom2: qcom,eeprom@6b{
+		cell-index = <2>;
+		reg = <0x6b 0x0>;
+		qcom,eeprom-name = "sunny_p5v23c";
+		compatible = "qcom,eeprom";
+		qcom,slave-addr = <0x6c>;
+		qcom,cci-master = <0>;
+		qcom,num-blocks = <7>;
+
+		qcom,page0 = <1 0x0100 2 0x01 1 1>;
+		qcom,poll0 = <0 0x0 2 0 1 1>;
+		qcom,mem0 = <0 0x0 2 0 1 0>;
+
+		qcom,page1 = <1 0x3d84 2 0xc0 1 1>;
+		qcom,poll1 = <0 0x0 2 0 1 1>;
+		qcom,mem1 = <0 0x0 2 0 1 0>;
+		qcom,page2 = <1 0x3d85 2 0x00 1 1>;
+		qcom,poll2 = <0 0x0 2 0 1 1>;
+		qcom,mem2 = <0 0x0 2 0 1 0>;
+		qcom,page3 = <1 0x3d86 2 0x0f 1 1>;
+		qcom,pageen3 = <1 0x3d81 2 0x01 1 10>;
+		qcom,poll3 = <0 0x0 2 0 1 1>;
+		qcom,mem3 = <16 0x3d00 2 0 1 0>;
+
+		qcom,page4 = <1 0x3d84 2 0xc0 1 1>;
+		qcom,poll4 = <0 0x0 2 0 1 1>;
+		qcom,mem4 = <0 0x0 2 0 1 0>;
+		qcom,page5 = <1 0x3d85 2 0x10 1 1>;
+		qcom,poll5 = <0 0x0 2 0 1 1>;
+		qcom,mem5 = <0 0x0 2 0 1 0>;
+		qcom,page6 = <1 0x3d86 2 0x1f 1 1>;
+		qcom,pageen6 = <1 0x3d81 2 0x01 1 10>;
+		qcom,poll6 = <0 0x0 2 0 1 1>;
+		qcom,mem6 = <16 0x3d00 2 0 1 0>;
+
+		cam_vio-supply = <&pm8226_lvs1>;
+		cam_vana-supply = <&pm8226_l19>;
+		qcom,cam-vreg-name = "cam_vdig", "cam_vio", "cam_vana";
+		qcom,cam-vreg-type = <0 1 0>;
+		qcom,cam-vreg-min-voltage = <1200000 0 2850000>;
+		qcom,cam-vreg-max-voltage = <1200000 0 2850000>;
+		qcom,cam-vreg-op-mode = <200000 0 80000>;
+		qcom,gpio-no-mux = <0>;
+		gpios = <&msmgpio 26 0>,
+			<&msmgpio 28 0>,
+			<&msmgpio 35 0>,
+			<&msmgpio 21 0>;
+		qcom,gpio-reset = <1>;
+		qcom,gpio-standby = <2>;
+		qcom,gpio-vdig = <3>;
+		qcom,gpio-req-tbl-num = <0 1 2 3>;
+		qcom,gpio-req-tbl-flags = <1 0 0 0>;
+		qcom,gpio-req-tbl-label = "CAMIF_MCLK",
+			"CAM_RESET",
+			"CAM_STANDBY",
+			"CAM_VDIG";
+		qcom,cam-power-seq-type = "sensor_vreg",
+			"sensor_vreg", "sensor_gpio",
+			"sensor_gpio", "sensor_gpio" , "sensor_clk";
+		qcom,cam-power-seq-val = "cam_vio", "cam_vana","sensor_gpio_vdig",
+			 "sensor_gpio_reset",
+			"sensor_gpio_standby","sensor_cam_mclk" ;
+		qcom,cam-power-seq-cfg-val = <1 1 1 1 1 24000000>;
+		qcom,cam-power-seq-delay = <1 1 10 10 10 5>;
+	};
+
 	qcom,camera@6a {
-		compatible = "qcom,ov5648";
+		compatible = "ovti,ov5648";
 		reg = <0x6a>;
 		qcom,slave-id = <0x6c 0x300a 0x5648>;
 		qcom,csiphy-sd-index = <1>;
 		qcom,csid-sd-index = <1>;
+		qcom,eeprom-src = <&eeprom2>;
 		qcom,mount-angle = <270>;
 		qcom,sensor-name = "skuf_ov5648_p5v23c";
 		cam_vdig-supply = <&pm8226_l5>;
@@ -192,7 +437,7 @@
 		qcom,gpio-set-tbl-delay = <1000 4000>;
 		qcom,csi-lane-assign = <0x4320>;
 		qcom,csi-lane-mask = <0x3>;
-		qcom,sensor-position = <0>;
+		qcom,sensor-position = <1>;
 		qcom,sensor-mode = <1>;
 		qcom,cci-master = <0>;
 		status = "ok";
diff --git a/arch/arm/boot/dts/msm8226-camera.dtsi b/arch/arm/boot/dts/msm8226-camera.dtsi
index 617d738..4987dae 100644
--- a/arch/arm/boot/dts/msm8226-camera.dtsi
+++ b/arch/arm/boot/dts/msm8226-camera.dtsi
@@ -74,8 +74,9 @@
 		cell-index = <0>;
 		compatible = "qcom,vfe40";
 		reg = <0xfda10000 0x1000>,
-		      <0xfda40000 0x200>;
-		reg-names = "vfe", "vfe_vbif";
+			<0xfda40000 0x200>,
+			<0xfd4a8000 0x4>;
+		reg-names = "vfe", "vfe_vbif", "tcsr";
 		interrupts = <0 57 0>;
 		interrupt-names = "vfe";
 		vdd-supply = <&gdsc_vfe>;
@@ -103,7 +104,7 @@
 		compatible = "qcom,cpp";
 		reg = <0xfda04000 0x100>,
 		      <0xfda40000 0x200>,
-		      <0xfda18000 0x008>;
+		      <0xfda18000 0x018>;
 		reg-names = "cpp", "cpp_vbif", "cpp_hw";
 		interrupts = <0 49 0>;
 		interrupt-names = "cpp";
diff --git a/arch/arm/boot/dts/msm8226-cdp.dtsi b/arch/arm/boot/dts/msm8226-cdp.dtsi
index 104cb4c..d377bf0 100644
--- a/arch/arm/boot/dts/msm8226-cdp.dtsi
+++ b/arch/arm/boot/dts/msm8226-cdp.dtsi
@@ -10,7 +10,6 @@
  * GNU General Public License for more details.
  */
 
-/include/ "dsi-panel-nt35590-720p-video.dtsi"
 /include/ "msm8226-camera-sensor-cdp.dtsi"
 
 &soc {
@@ -18,11 +17,6 @@
 		status = "ok";
 	};
 
-	qcom,mdss_dsi_nt35590_720p_video {
-		status = "ok";
-		qcom,cont-splash-enabled;
-	};
-
 	i2c@f9927000 { /* BLSP1 QUP5 */
 		synaptics@20 {
 			compatible = "synaptics,rmi4";
@@ -36,6 +30,7 @@
 			synaptics,button-map = <139 102 158>;
 			synaptics,i2c-pull-up;
 			synaptics,power-down;
+			synaptics,disable-gpios;
 		};
 	};
 
@@ -111,6 +106,24 @@
 		qcom,cdc-vdd-spkr-gpios = <&pm8226_gpios 2 0>;
 		qcom,headset-jack-type-NO;
 	};
+
+	sound-9302 {
+		qcom,audio-routing =
+			"RX_BIAS", "MCLK",
+			"LDO_H", "MCLK",
+			"SPK_OUT", "MCLK",
+			"SPK_OUT", "EXT_VDD_SPKR",
+			"AMIC1", "MIC BIAS1 External",
+			"MIC BIAS1 External", "Handset Mic",
+			"AMIC2", "MIC BIAS2 External",
+			"MIC BIAS2 External", "Headset Mic",
+			"AMIC3", "MIC BIAS1 External",
+			"MIC BIAS1 External", "Handset Mic";
+
+		qcom,cdc-mclk-gpios = <&pm8226_gpios 1 0>;
+		qcom,cdc-vdd-spkr-gpios = <&pm8226_gpios 2 0>;
+		qcom,headset-jack-type-NO;
+	};
 };
 
 &sdcc1 {
@@ -257,7 +270,7 @@
 			qcom,led_mpp_4 {
 				label = "mpp";
 				linux,name = "green";
-				linux,default-trigger = "none";
+				linux,default-trigger = "battery-full";
 				qcom,default-state = "off";
 				qcom,max-current = <40>;
 				qcom,current-setting = <5>;
@@ -283,7 +296,7 @@
 			qcom,led_mpp_6 {
 				label = "mpp";
 				linux,name = "red";
-				linux,default-trigger = "none";
+				linux,default-trigger = "battery-charging";
 				qcom,default-state = "off";
 				qcom,max-current = <40>;
 				qcom,current-setting = <5>;
@@ -325,6 +338,12 @@
 				qcom,id = <0>;
 			};
 		};
+
+		qcom,vibrator@c000 {
+			status = "okay";
+			qcom,vib-timeout-ms = <15000>;
+			qcom,vib-vtg-level-mV = <3100>;
+		};
 	};
 };
 
@@ -439,3 +458,15 @@
 		qcom,fast-avg-setup = <0>;
 	};
 };
+
+&mdss_mdp {
+	qcom,mdss-pref-prim-intf = "dsi";
+};
+
+&mdss_dsi0 {
+	qcom,dsi-pref-prim-pan = <&dsi_nt35590_720_vid>;
+};
+
+&dsi_nt35590_720_vid {
+	qcom,cont-splash-enabled;
+};
diff --git a/arch/arm/boot/dts/msm8226-coresight.dtsi b/arch/arm/boot/dts/msm8226-coresight.dtsi
index cbfdfc9..ec3f248 100644
--- a/arch/arm/boot/dts/msm8226-coresight.dtsi
+++ b/arch/arm/boot/dts/msm8226-coresight.dtsi
@@ -19,8 +19,7 @@
 		interrupts = <0 166 0>;
 		interrupt-names = "byte-cntr-irq";
 
-		qcom,memory-reservation-type = "EBI1";
-		qcom,memory-reservation-size = <0x100000>; /* 1M EBI1 buffer */
+		qcom,memory-size = <0x100000>;
 
 		coresight-id = <0>;
 		coresight-name = "coresight-tmc-etr";
@@ -41,6 +40,11 @@
 
 		qcom,vdd-voltage-level = <2950000 2950000>;
 		qcom,vdd-current-level = <9000 800000>;
+
+		vdd-io-supply = <&pm8226_l21>;
+
+		qcom,vdd-io-voltage-level = <2950000 2950000>;
+		qcom,vdd-io-current-level = <6 22000>;
 	};
 
 	replicator: replicator@fc31c000 {
diff --git a/arch/arm/boot/dts/msm8226-ion.dtsi b/arch/arm/boot/dts/msm8226-ion.dtsi
index 9574b7d..30c3209 100644
--- a/arch/arm/boot/dts/msm8226-ion.dtsi
+++ b/arch/arm/boot/dts/msm8226-ion.dtsi
@@ -55,18 +55,12 @@
 			qcom,memory-reservation-type = "EBI1"; /* reserve EBI memory */
 			qcom,memory-reservation-size = <0x314000>;
 		};
+
 		qcom,ion-heap@23 { /* OTHER PIL HEAP */
 			compatible = "qcom,msm-ion-reserve";
 			reg = <23>;
 			qcom,heap-align = <0x1000>;
-			qcom,memory-fixed = <0x06400000 0x2000000>;
-		};
-		qcom,ion-heap@26 { /* MODEM PIL HEAP */
-			compatible = "qcom,msm-ion-reserve";
-			reg = <26>;
-			qcom,heap-align = <0x1000>;
-			qcom,memory-fixed = <0x08400000 0x4E00000>;
-
+			qcom,memory-fixed = <0x0dc00000 0x1900000>;
 		};
 
 	};
diff --git a/drivers/gpu/msm/adreno_trace.c b/arch/arm/boot/dts/msm8226-mdss-panels.dtsi
similarity index 65%
copy from drivers/gpu/msm/adreno_trace.c
copy to arch/arm/boot/dts/msm8226-mdss-panels.dtsi
index 607ba8c..eeec175 100644
--- a/drivers/gpu/msm/adreno_trace.c
+++ b/arch/arm/boot/dts/msm8226-mdss-panels.dtsi
@@ -8,11 +8,11 @@
  * 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 "adreno.h"
-
-/* Instantiate tracepoints */
-#define CREATE_TRACE_POINTS
-#include "adreno_trace.h"
+/include/ "dsi-panel-hx8394a-720p-video.dtsi"
+/include/ "dsi-panel-nt35590-720p-video.dtsi"
+/include/ "dsi-panel-nt35521-720p-video.dtsi"
+/include/ "dsi-panel-nt35596-1080p-video.dtsi"
+/include/ "dsi-panel-nt35590-720p-cmd.dtsi"
+/include/ "dsi-panel-ssd2080m-720p-video.dtsi"
diff --git a/arch/arm/boot/dts/msm8226-mdss.dtsi b/arch/arm/boot/dts/msm8226-mdss.dtsi
index 5f991fb..2ec7b6c 100644
--- a/arch/arm/boot/dts/msm8226-mdss.dtsi
+++ b/arch/arm/boot/dts/msm8226-mdss.dtsi
@@ -11,7 +11,7 @@
  */
 
 &soc {
-	qcom,mdss_mdp@fd900000 {
+	mdss_mdp: qcom,mdss_mdp@fd900000 {
 		compatible = "qcom,mdss_mdp";
 		reg = <0xfd900000 0x22100>,
 			<0xfd924000 0x1000>;
@@ -41,7 +41,7 @@
 		qcom,vbif-settings = <0x004 0x00000001>,
 				     <0x0D8 0x00000707>,
 				     <0x124 0x00000003>;
-		qcom,mdp-settings = <0x02E0 0x000000A9>,
+		qcom,mdp-settings = <0x02E0 0x000000A5>,
 				    <0x02E4 0x00000055>;
 
 		mdss_fb0: qcom,mdss_fb_primary {
@@ -63,10 +63,11 @@
 		cell-index = <0>;
 		reg = <0xfd922800 0x600>;
 		qcom,mdss-fb-map = <&mdss_fb0>;
+		qcom,mdss-mdp = <&mdss_mdp>;
 		vdd-supply = <&pm8226_l15>;
 		vddio-supply = <&pm8226_l8>;
 		vdda-supply = <&pm8226_l4>;
-		qcom,platform-reset-gpio = <&msmgpio 25 1>;
+		qcom,platform-reset-gpio = <&msmgpio 25 0>;
 		qcom,platform-te-gpio = <&msmgpio 24 0>;
 		qcom,platform-strength-ctrl = [ff 06];
 		qcom,platform-bist-ctrl = [00 00 b1 ff 00 00];
@@ -119,3 +120,5 @@
 		qcom,mdss-fb-map = <&mdss_fb1>;
 	};
 };
+
+/include/ "msm8226-mdss-panels.dtsi"
diff --git a/arch/arm/boot/dts/msm8226-mtp.dtsi b/arch/arm/boot/dts/msm8226-mtp.dtsi
index 977c772..318d4fc 100644
--- a/arch/arm/boot/dts/msm8226-mtp.dtsi
+++ b/arch/arm/boot/dts/msm8226-mtp.dtsi
@@ -10,7 +10,6 @@
  * GNU General Public License for more details.
  */
 
-/include/ "dsi-panel-nt35590-720p-video.dtsi"
 /include/ "msm8226-camera-sensor-mtp.dtsi"
 
 &soc {
@@ -18,11 +17,6 @@
 		status = "ok";
 	};
 
-	qcom,mdss_dsi_nt35590_720p_video {
-		status = "ok";
-		qcom,cont-splash-enabled;
-	};
-
 	i2c@f9927000 { /* BLSP1 QUP5 */
 		synaptics@20 {
 			compatible = "synaptics,rmi4";
@@ -36,6 +30,7 @@
 			synaptics,button-map = <139 102 158>;
 			synaptics,i2c-pull-up;
 			synaptics,power-down;
+			synaptics,disable-gpios;
 		};
 	};
 
@@ -105,14 +100,31 @@
 			"MIC BIAS1 External", "Handset Mic",
 			"AMIC2", "MIC BIAS2 External",
 			"MIC BIAS2 External", "Headset Mic",
-			"AMIC3", "MIC BIAS1 External",
-			"MIC BIAS1 External", "ANCRight Headset Mic",
 			"AMIC4", "MIC BIAS2 External",
+			"MIC BIAS2 External", "ANCRight Headset Mic",
+			"AMIC5", "MIC BIAS2 External",
 			"MIC BIAS2 External", "ANCLeft Headset Mic";
 
 		qcom,cdc-mclk-gpios = <&pm8226_gpios 1 0>;
 		qcom,cdc-vdd-spkr-gpios = <&pm8226_gpios 2 0>;
 	};
+
+	sound-9302 {
+		qcom,audio-routing =
+			"RX_BIAS", "MCLK",
+			"LDO_H", "MCLK",
+			"SPK_OUT", "MCLK",
+			"SPK_OUT", "EXT_VDD_SPKR",
+			"AMIC1", "MIC BIAS1 Internal1",
+			"MIC BIAS1 Internal1", "Handset Mic",
+			"AMIC2", "MIC BIAS2 External",
+			"MIC BIAS2 External", "Headset Mic",
+			"AMIC3", "MIC BIAS1 External",
+			"MIC BIAS1 External", "Handset Mic";
+
+		qcom,cdc-mclk-gpios = <&pm8226_gpios 1 0>;
+		qcom,cdc-vdd-spkr-gpios = <&pm8226_gpios 2 0>;
+	};
 };
 
 &usb_otg {
@@ -261,7 +273,7 @@
 			qcom,led_mpp_4 {
 				label = "mpp";
 				linux,name = "green";
-				linux,default-trigger = "none";
+				linux,default-trigger = "battery-full";
 				qcom,default-state = "off";
 				qcom,max-current = <40>;
 				qcom,current-setting = <5>;
@@ -287,7 +299,7 @@
 			qcom,led_mpp_6 {
 				label = "mpp";
 				linux,name = "red";
-				linux,default-trigger = "none";
+				linux,default-trigger = "battery-charging";
 				qcom,default-state = "off";
 				qcom,max-current = <40>;
 				qcom,current-setting = <5>;
@@ -333,6 +345,12 @@
 				qcom,id = <0>;
 			};
 		};
+
+		qcom,vibrator@c000 {
+			status = "okay";
+			qcom,vib-timeout-ms = <15000>;
+			qcom,vib-vtg-level-mV = <3100>;
+		};
 	};
 };
 
@@ -446,6 +464,11 @@
 
 &pm8226_bms {
 	status = "ok";
+	qcom,enable-fcc-learning;
+	qcom,min-fcc-learning-soc = <20>;
+	qcom,min-fcc-ocv-pc = <30>;
+	qcom,min-fcc-learning-samples = <5>;
+	qcom,fcc-resolution = <10>;
 };
 
 &pm8226_chg {
@@ -457,3 +480,15 @@
 		qcom,cdc-micbias1-ext-cap;
 	};
 };
+
+&mdss_mdp {
+	qcom,mdss-pref-prim-intf = "dsi";
+};
+
+&mdss_dsi0 {
+	qcom,dsi-pref-prim-pan = <&dsi_nt35590_720_vid>;
+};
+
+&dsi_nt35590_720_vid {
+	qcom,cont-splash-enabled;
+};
diff --git a/arch/arm/boot/dts/msm8226-qrd.dtsi b/arch/arm/boot/dts/msm8226-qrd.dtsi
index 10a2dce..18a1aea 100644
--- a/arch/arm/boot/dts/msm8226-qrd.dtsi
+++ b/arch/arm/boot/dts/msm8226-qrd.dtsi
@@ -10,13 +10,11 @@
  * GNU General Public License for more details.
  */
 
-/include/ "dsi-panel-nt35596-1080p-video.dtsi"
 /include/ "msm8226-camera-sensor-qrd.dtsi"
 
 &soc {
 	serial@f991f000 {
 		status = "ok";
-		qcom,cont-splash-enabled;
 	};
 
 	i2c@f9927000 { /* BLSP1 QUP5 */
@@ -32,7 +30,9 @@
 			synaptics,button-map = <139 102 158>;
 			synaptics,i2c-pull-up;
 			synaptics,power-down;
+			synaptics,disable-gpios;
 		};
+
 		focaltech@38 {
 			compatible = "focaltech,5x06";
 			reg = <0x38>;
@@ -118,9 +118,27 @@
 			"AMIC2", "MIC BIAS2 External",
 			"MIC BIAS2 External", "Headset Mic",
 			"AMIC3", "MIC BIAS1 External",
-			"MIC BIAS1 External", "ANCRight Headset Mic",
-			"AMIC4", "MIC BIAS2 External",
-			"MIC BIAS2 External", "ANCLeft Headset Mic";
+			"MIC BIAS1 External", "Analog Mic3",
+			"AMIC4", "MIC BIAS3 External",
+			"MIC BIAS3 External", "Analog Mic4";
+
+		qcom,cdc-mclk-gpios = <&pm8226_gpios 1 0>;
+		qcom,cdc-vdd-spkr-gpios = <&pm8226_gpios 2 0>;
+		qcom,cdc-us-euro-gpios = <&msmgpio 69 0>;
+	};
+
+	sound-9302 {
+		qcom,audio-routing =
+			"RX_BIAS", "MCLK",
+			"LDO_H", "MCLK",
+			"SPK_OUT", "MCLK",
+			"SPK_OUT", "EXT_VDD_SPKR",
+			"AMIC1", "MIC BIAS1 External",
+			"MIC BIAS1 External", "Handset Mic",
+			"AMIC2", "MIC BIAS2 External",
+			"MIC BIAS2 External", "Headset Mic",
+			"AMIC3", "MIC BIAS1 External",
+			"MIC BIAS1 External", "Handset Mic";
 
 		qcom,cdc-mclk-gpios = <&pm8226_gpios 1 0>;
 		qcom,cdc-vdd-spkr-gpios = <&pm8226_gpios 2 0>;
@@ -223,7 +241,7 @@
 	qcom,pad-drv-on = <0x4 0x4 0x4>; /* 10mA, 10mA, 10mA */
 	qcom,pad-drv-off = <0x0 0x0 0x0>; /* 2mA, 2mA, 2mA */
 
-	qcom,clk-rates = <400000 25000000 50000000 100000000 200000000>;
+	qcom,clk-rates = <400000 25000000 50000000>;
 
 	#address-cells = <0>;
 	interrupt-parent = <&sdhc_2>;
@@ -344,16 +362,28 @@
 	};
 };
 
+/ {
+	qrd_batterydata: qcom,battery-data {
+		qcom,rpull-up-kohm = <100>;
+		qcom,vref-batt-therm = <1800000>;
+
+		/include/ "batterydata-qrd-4v35-2000mah.dtsi"
+	};
+};
+
 &pm8226_bms {
 	status = "okay";
-	qcom,batt-type = <4>;
-	qcom,max-voltage-uv = <4350000>;
+	qcom,enable-fcc-learning;
+	qcom,min-fcc-learning-soc = <20>;
+	qcom,min-fcc-ocv-pc = <30>;
+	qcom,min-fcc-learning-samples = <5>;
+	qcom,fcc-resolution = <10>;
+	qcom,battery-data = <&qrd_batterydata>;
 };
 
 &pm8226_chg {
 	status = "okay";
-	qcom,vddmax-mv = <4350>;
-	qcom,vddsafe-mv = <4380>;
+	qcom,battery-data = <&qrd_batterydata>;
 	qcom,tchg-mins = <240>;
 };
 
@@ -427,6 +457,7 @@
 &slim_msm {
 	tapan_codec {
 		qcom,cdc-micbias1-ext-cap;
+		qcom,cdc-micbias3-ext-cap;
 	};
 };
 
@@ -442,3 +473,20 @@
 		qcom,fast-avg-setup = <0>;
 	};
 };
+
+&android_usb {
+	qcom,android-usb-cdrom;
+	qcom,android-usb-internal-ums;
+};
+
+&mdss_mdp {
+	qcom,mdss-pref-prim-intf = "dsi";
+};
+
+&mdss_dsi0 {
+	qcom,dsi-pref-prim-pan = <&dsi_nt35596_1080_vid>;
+};
+
+&dsi_nt35596_1080_vid {
+	qcom,cont-splash-enabled;
+};
diff --git a/arch/arm/boot/dts/msm8226-regulator.dtsi b/arch/arm/boot/dts/msm8226-regulator.dtsi
index 5b3da9b..838592c 100644
--- a/arch/arm/boot/dts/msm8226-regulator.dtsi
+++ b/arch/arm/boot/dts/msm8226-regulator.dtsi
@@ -41,9 +41,14 @@
 		qcom,pvs-fuse = <22 6 5>;
 		qcom,pvs-fuse-redun = <22 27 5>;
 
-		qcom,pvs-bin-process = <0 0 0 0 0 1 1 1 1 1 2 2 2 2 2 2
-					2 2 2 2 3 3 3 3 3 3 3 3 0 0 0 0>;
-		qcom,pvs-corner-ceiling-slow = <1050000 1160000 1275000>;
+		qcom,pvs-init-voltage = <1275000 1275000 1275000 1275000 1275000
+					1275000 1260000 1245000 1230000 1215000
+					1200000 1185000 1170000 1155000 1140000
+					1140000 1140000 1140000 1140000 1140000
+					1150000 1140000 1140000 1140000 1140000
+					1140000 1140000 1140000 1275000 1275000
+					1275000 1275000>;
+		qcom,pvs-corner-ceiling-slow = <1050000 1150000 1275000>;
 		qcom,pvs-corner-ceiling-nom  = <1050000 1075000 1200000>;
 		qcom,pvs-corner-ceiling-fast = <1050000 1050000 1140000>;
 		vdd-apc-supply = <&pm8226_s2>;
diff --git a/arch/arm/boot/dts/msm8226-sim.dts b/arch/arm/boot/dts/msm8226-sim.dts
index 2405646..1da94b3 100644
--- a/arch/arm/boot/dts/msm8226-sim.dts
+++ b/arch/arm/boot/dts/msm8226-sim.dts
@@ -12,7 +12,6 @@
 
 /dts-v1/;
 /include/ "msm8226.dtsi"
-/include/ "msm8226-camera.dtsi"
 
 / {
 	model = "Qualcomm MSM 8226 Simulator";
diff --git a/arch/arm/boot/dts/msm8226-v1-cdp.dts b/arch/arm/boot/dts/msm8226-v1-cdp.dts
index 9c49840..e426a97 100644
--- a/arch/arm/boot/dts/msm8226-v1-cdp.dts
+++ b/arch/arm/boot/dts/msm8226-v1-cdp.dts
@@ -17,9 +17,5 @@
 / {
 	model = "Qualcomm MSM 8226 CDP";
 	compatible = "qcom,msm8226-cdp", "qcom,msm8226", "qcom,cdp";
-	qcom,msm-id = <145 1 0>,
-		      <158 1 0>,
-		      <159 1 0>,
-		      <198 1 0>,
-		      <205 1 0>;
+	qcom,board-id = <1 0>;
 };
diff --git a/arch/arm/boot/dts/msm8226-v1-mtp.dts b/arch/arm/boot/dts/msm8226-v1-mtp.dts
index b1d46b1..08d7cec 100644
--- a/arch/arm/boot/dts/msm8226-v1-mtp.dts
+++ b/arch/arm/boot/dts/msm8226-v1-mtp.dts
@@ -17,9 +17,12 @@
 / {
 	model = "Qualcomm MSM 8226 MTP";
 	compatible = "qcom,msm8226-mtp", "qcom,msm8226", "qcom,mtp";
-	qcom,msm-id = <145 8 0>,
-		      <158 8 0>,
-		      <159 8 0>,
-		      <198 8 0>,
-		      <205 8 0>;
+	qcom,board-id = <8 0>;
+};
+
+&cci {
+	/* Rotate rear camera to 180 degrees */
+	qcom,camera@6f {
+	qcom,mount-angle = <180>;
+	};
 };
diff --git a/arch/arm/boot/dts/msm8610-pm.dtsi b/arch/arm/boot/dts/msm8226-v1-pm.dtsi
similarity index 82%
copy from arch/arm/boot/dts/msm8610-pm.dtsi
copy to arch/arm/boot/dts/msm8226-v1-pm.dtsi
index d31a65c..dcf46e6 100644
--- a/arch/arm/boot/dts/msm8610-pm.dtsi
+++ b/arch/arm/boot/dts/msm8226-v1-pm.dtsi
@@ -24,7 +24,7 @@
 		qcom,saw2-spm-cmd-wfi = [60 03 60 0b 0f];
 		qcom,saw2-spm-cmd-spc = [20 10 80 30 90 5b 60 03 60 3b 76 76
 				0b 94 5b 80 10 26 30 0f];
-		qcom,saw2-spm-cmd-pc = [20 10 80 30 90 5b 60 07 60 3b 76 76
+		qcom,saw2-spm-cmd-pc = [20 10 80 30 90 5b 60 03 60 3b 76 76
 				0b 94 5b 80 10 26 30 0f];
 	};
 
@@ -41,9 +41,9 @@
 		qcom,saw2-spm-cmd-wfi = [60 03 60 0b 0f];
 		qcom,saw2-spm-cmd-spc = [20 10 80 30 90 5b 60 03 60 3b 76 76
 				0b 94 5b 80 10 26 30 0f];
-		qcom,saw2-spm-cmd-pc = [20 10 80 30 90 5b 60 07 60 3b 76 76
+		qcom,saw2-spm-cmd-pc = [20 10 80 30 90 5b 60 03 60 3b 76 76
 				0b 94 5b 80 10 26 30 0f];
-		};
+	};
 
 	qcom,spm@f90a9000 {
 		compatible = "qcom,spm-v2";
@@ -56,10 +56,10 @@
 		qcom,saw2-spm-dly= <0x3c102800>;
 		qcom,saw2-spm-ctl = <0x8>;
 		qcom,saw2-spm-cmd-wfi = [60 03 60 0b 0f];
-		qcom,saw2-spm-cmd-spc = [00 20 10 80 30 90 5b 60 03 60 3b 76 76
-				0b 94 5b 80 10 06 26 30 0f];
-		qcom,saw2-spm-cmd-pc = [00 20 10 80 30 90 5b 60 07 60 3b 76 76
-				0b 94 5b 80 10 06 26 30 0f];
+		qcom,saw2-spm-cmd-spc = [20 10 80 30 90 5b 60 03 60 3b 76 76
+				0b 94 5b 80 10 26 30 0f];
+		qcom,saw2-spm-cmd-pc = [20 10 80 30 90 5b 60 03 60 3b 76 76
+				0b 94 5b 80 10 26 30 0f];
 	};
 
 	qcom,spm@f90b9000 {
@@ -75,7 +75,7 @@
 		qcom,saw2-spm-cmd-wfi = [60 03 60 0b 0f];
 		qcom,saw2-spm-cmd-spc = [20 10 80 30 90 5b 60 03 60 3b 76 76
 				0b 94 5b 80 10 26 30 0f];
-		qcom,saw2-spm-cmd-pc = [20 10 80 30 90 5b 60 07 60 3b 76 76
+		qcom,saw2-spm-cmd-pc = [20 10 80 30 90 5b 60 03 60 3b 76 76
 				0b 94 5b 80 10 26 30 0f];
 	};
 
@@ -99,6 +99,7 @@
 		qcom,saw2-spm-cmd-pc = [00 32 b0 10 e0 d0 6b c0 42 f0
 				11 07 01 b0 50 4e 02 02 c0 d0 12 e0 6b 02 32
 				50 f0 0f]; /*APCS_PMIC_OFF_L2RAM_OFF*/
+		qcom,L2-spm-is-apcs-master;
 	};
 
 	qcom,lpm-levels {
@@ -167,24 +168,40 @@
 			<53 104>, /* mdss_irq */
 			<62 222>, /* ee0_krait_hlos_spmi_periph_irq */
 			<2 216>, /* tsens_upper_lower_int */
+			<0xff 18>,  /* APC_qgicQTmrSecPhysIrptReq */
+			<0xff 19>,  /* APC_qgicQTmrNonSecPhysIrptReq */
+			<0xff 35>,  /* WDT_barkInt */
+			<0xff 40>,  /* qtmr_phy_irq[0] */
+			<0xff 47>,  /* rbif_irq[0] */
 			<0xff 56>,  /* q6_wdog_expired_irq */
 			<0xff 57>,  /* mss_to_apps_irq(0) */
 			<0xff 58>,  /* mss_to_apps_irq(1) */
 			<0xff 59>,  /* mss_to_apps_irq(2) */
 			<0xff 60>,  /* mss_to_apps_irq(3) */
 			<0xff 61>,  /* mss_a2_bam_irq */
+			<0xff 65>,  /* o_gc_sys_irq[0] */
+			<0xff 74>,  /* venus0_mmu_cirpt[1] */
+			<0xff 75>,  /* venus0_mmu_cirpt[0] */
+			<0xff 78>,  /* mdss_mmu_cirpt[0] */
+			<0xff 79>,  /* mdss_mmu_cirpt[1] */
+			<0xff 97>,  /* camss_vfe_mmu_cirpt[1] */
+			<0xff 102>, /* camss_jpeg_mmu_cirpt[1] */
+			<0xff 109>, /* ocmem_dm_nonsec_irq */
+			<0xff 131>, /* blsp1_qup_5_irq */
+			<0xff 141>, /* blsp1_uart_3_irq */
+			<0xff 155>, /* sdc1_irq(0) */
+			<0xff 157>, /* sdc2_irq(0) */
+			<0xff 161>, /* lpass_irq_out_spare[4] */
+			<0xff 162>, /* lpass_irq_out_spare[5]*/
+			<0xff 170>, /* sdc1_pwr_cmd_irq */
 			<0xff 173>, /* o_wcss_apss_smd_hi */
 			<0xff 174>, /* o_wcss_apss_smd_med */
 			<0xff 175>, /* o_wcss_apss_smd_low */
 			<0xff 176>, /* o_wcss_apss_smsm_irq */
 			<0xff 177>, /* o_wcss_apss_wlan_data_xfer_done */
 			<0xff 178>, /* o_wcss_apss_wlan_rx_data_avail */
-			<0xff 179>, /* o_wcss_apss_asic_intr
+			<0xff 179>, /* o_wcss_apss_asic_intr */
 			<0xff 181>, /* o_wcss_apss_wdog_bite_and_reset_rdy */
-			<0xff 161>, /* lpass_irq_out_spare[4] /
-			<0xff 162>, /* lpass_irq_out_spare[5]*/
-			<0xff 234>, /* lpass_irq_out_spare[6]*/
-			<0xff 235>, /* lpass_irq_out_spare[7]*/
 			<0xff 188>, /* lpass_irq_out_apcs(0) */
 			<0xff 189>, /* lpass_irq_out_apcs(1) */
 			<0xff 190>, /* lpass_irq_out_apcs(2) */
@@ -199,12 +216,16 @@
 			<0xff 205>, /* rpm_ipc(25) */
 			<0xff 206>, /* rpm_ipc(26) */
 			<0xff 207>, /* rpm_ipc(27) */
+			<0xff 234>, /* lpass_irq_out_spare[6]*/
+			<0xff 235>, /* lpass_irq_out_spare[7]*/
+			<0xff 240>, /* summary_irq_kpss */
+			<0xff 253>, /* sdc2_pwr_cmd_irq */
 			<0xff 258>, /* rpm_ipc(28) */
 			<0xff 259>, /* rpm_ipc(29) */
-			<0xff 275>, /* rpm_ipc(30) */
-			<0xff 276>, /* rpm_ipc(31) */
 			<0xff 269>, /* rpm_wdog_expired_irq */
-			<0xff 240>; /* summary_irq_kpss */
+			<0xff 270>, /* blsp1_bam_irq[0] */
+			<0xff 275>, /* rpm_ipc(30) */
+			<0xff 276>; /* rpm_ipc(31) */
 
 		qcom,gpio-parent = <&msmgpio>;
 		qcom,gpio-map = <3  1>,
@@ -287,4 +308,12 @@
 		reg = <0xfc000000 0x1a0000>;
 		qcom,start-offset = <0x190010>;
 	};
+
+	qcom,rpm-master-stats@fc428150 {
+		compatible = "qcom,rpm-master-stats";
+		reg = <0xfc428150 0x3200>;
+		qcom,masters = "APSS", "MPSS", "LPSS", "PRONTO";
+		qcom,master-stats-version = <2>;
+		qcom,master-offset = <2560>;
+	};
 };
diff --git a/arch/arm/boot/dts/msm8226-v1-qrd-dvt.dts b/arch/arm/boot/dts/msm8226-v1-qrd-dvt.dts
index 45c26c5..7e9f91b 100644
--- a/arch/arm/boot/dts/msm8226-v1-qrd-dvt.dts
+++ b/arch/arm/boot/dts/msm8226-v1-qrd-dvt.dts
@@ -13,20 +13,17 @@
 /dts-v1/;
 /include/ "msm8226-v1.dtsi"
 /include/ "msm8226-qrd.dtsi"
-/include/ "dsi-panel-hx8394a-720p-video.dtsi"
 
 / {
 	model = "Qualcomm MSM 8226 QRD";
 	compatible = "qcom,msm8226-qrd", "qcom,msm8226", "qcom,qrd";
-	qcom,msm-id = <145 0x2000b 0>,
-		      <158 0x2000b 0>,
-		      <159 0x2000b 0>,
-		      <198 0x2000b 0>;
+	qcom,board-id = <0x2000b 0>;
 };
 
-&soc {
-        qcom,mdss_dsi_hx8394a_720p_video {
-                status = "ok";
-		qcom,cont-splash-enabled;
-        };
+&mdss_dsi0 {
+	qcom,dsi-pref-prim-pan = <&dsi_hx8394a_720_vid>;
+};
+
+&dsi_hx8394a_720_vid {
+	qcom,cont-splash-enabled;
 };
diff --git a/arch/arm/boot/dts/msm8226-v1-qrd-evt.dts b/arch/arm/boot/dts/msm8226-v1-qrd-evt.dts
index a081308..c93d9db 100644
--- a/arch/arm/boot/dts/msm8226-v1-qrd-evt.dts
+++ b/arch/arm/boot/dts/msm8226-v1-qrd-evt.dts
@@ -13,21 +13,17 @@
 /dts-v1/;
 /include/ "msm8226-v1.dtsi"
 /include/ "msm8226-qrd.dtsi"
-/include/ "dsi-panel-nt35590-720p-video.dtsi"
 
 / {
 	model = "Qualcomm MSM 8226 QRD";
 	compatible = "qcom,msm8226-qrd", "qcom,msm8226", "qcom,qrd";
-	qcom,msm-id = <145 11 0>,
-		      <158 11 0>,
-		      <159 11 0>,
-		      <198 11 0>,
-		      <205 11 0>;
+	qcom,board-id = <11 0>;
 };
 
-&soc {
-        qcom,mdss_dsi_nt35590_720p_video {
-                status = "ok";
-		qcom,cont-splash-enabled;
-        };
+&mdss_dsi0 {
+	qcom,dsi-pref-prim-pan = <&dsi_nt35590_720_vid>;
+};
+
+&dsi_nt35590_720_vid {
+	qcom,cont-splash-enabled;
 };
diff --git a/arch/arm/boot/dts/msm8226-v1-qrd-skuf.dts b/arch/arm/boot/dts/msm8226-v1-qrd-skuf.dts
index 936f87f..cbafe80 100644
--- a/arch/arm/boot/dts/msm8226-v1-qrd-skuf.dts
+++ b/arch/arm/boot/dts/msm8226-v1-qrd-skuf.dts
@@ -13,24 +13,14 @@
 /dts-v1/;
 /include/ "msm8226-v1.dtsi"
 /include/ "msm8226-qrd.dtsi"
-/include/ "dsi-panel-nt35590-720p-video.dtsi"
 
 / {
-	model = "Qualcomm MSM 8226 QRD";
-	compatible = "qcom,msm8226-qrd", "qcom,msm8226", "qcom,qrd";
+	model = "Qualcomm MSM 8226v1 QRD";
+	compatible = "qcom,msm8226-qrd", "qcom,msm8226", "qcom,skuf", "qcom,qrd";
 	qcom,board-id = <11 2>;
-	qcom,msm-id = <145 0>,
-		      <158 0>,
-		      <159 0>,
-		      <198 0>;
 };
 
 &soc {
-	qcom,mdss_dsi_nt35590_720p_video {
-		status = "ok";
-		qcom,mdss-pan-bl-ctrl = "bl_ctrl_dcs";
-	};
-
 	sound {
 		qcom,model = "msm8226-tapan-skuf-snd-card";
 
@@ -55,6 +45,52 @@
 		qcom,cdc-vdd-spkr-gpios;
 		qcom,cdc-us-euro-gpios;
 	};
+
+	tp_power: regulator-tp {
+		compatible = "regulator-fixed";
+		regulator-name = "tp_power";
+		regulator-min-microvolt = <2800000>;
+		regulator-max-microvolt = <2800000>;
+		gpio = <&msmgpio 15 0>;
+		startup-delay-us = <20000>;
+		enable-active-high;
+	};
+
+	i2c@f9927000 {
+		goodix@5d {
+			compatible = "goodix,gt9xx";
+			reg = <0x5d>;
+			interrupt-parent = <&msmgpio>;
+			interrupts = <17 0x2008>;
+			reset-gpios = <&msmgpio 16 0x00>;
+			interrupt-gpios = <&msmgpio 17 0x00>;
+			avdd-supply = <&tp_power>;
+			goodix,panel-coords = <0 0 720 1200>;
+			goodix,display-coords = <0 0 720 1080>;
+			goodix,button-map= <158 102 139>;
+			goodix,family-id = <0x0>;
+			goodix,cfg-data = [
+			41 D0 02 00 05 0A 35 01 01 0F
+			2D 08 55 32 03 04 00 00 00 00
+			00 00 05 0A 0C 0F 0A 8C 0E 0E
+			30 2E B8 08 00 00 00 83 03 1D
+			00 00 00 00 00 00 00 00 00 00
+			00 2D 62 94 C5 02 05 00 00 04
+			96 30 00 80 39 00 71 42 00 63
+			4D 00 56 5A 00 56 10 38 68 00
+			56 50 35 AA AA 27 00 00 00 00
+			00 01 1B 14 0C 14 00 00 01 00
+			00 00 00 00 00 00 00 00 00 00
+			00 00 02 04 06 08 0A 0C 0E 10
+			12 14 16 18 1A 1C FF FF FF FF
+			FF FF FF FF FF FF FF FF FF FF
+			FF FF 00 02 04 06 08 0A 0C 0F
+			10 12 13 14 16 18 1C 1D 1E 1F
+			20 21 22 24 26 28 29 2A FF FF
+			FF FF FF FF FF FF FF FF FF FF
+			FF FF FF FF 06 01];
+		};
+	};
 };
 
 &spmi_bus {
@@ -67,6 +103,12 @@
 			status = "disabled";
 		};
 	};
+
+	qcom,pm8226@1 {
+		qcom,leds@d800 {
+			status = "disabled";
+		};
+	};
 };
 
 &pm8226_mpps {
@@ -113,3 +155,26 @@
 		qcom,fast-avg-setup = <0>;
 	};
 };
+
+&qrd_batterydata {
+	qcom,rpull-up-kohm = <100>;
+	qcom,vref-batt-therm = <1800000>;
+
+	/include/ "batterydata-qrd-4v35-2500mah.dtsi"
+};
+
+&pm8226_bms {
+	qcom,battery-data = <&qrd_batterydata>;
+};
+
+&pm8226_chg {
+	qcom,battery-data = <&qrd_batterydata>;
+};
+
+&mdss_dsi0 {
+	qcom,dsi-pref-prim-pan = <&dsi_nt35521_720_vid>;
+};
+
+&dsi_nt35521_720_vid {
+	qcom,cont-splash-enabled;
+};
diff --git a/arch/arm/boot/dts/msm8226-v1.dtsi b/arch/arm/boot/dts/msm8226-v1.dtsi
index 2833673..7f2048f 100644
--- a/arch/arm/boot/dts/msm8226-v1.dtsi
+++ b/arch/arm/boot/dts/msm8226-v1.dtsi
@@ -17,6 +17,19 @@
  */
 
 /include/ "msm8226.dtsi"
+/include/ "msm8226-v1-pm.dtsi"
+
+/ {
+	qcom,msm-id = <145 0>,
+		      <158 0>,
+		      <159 0>,
+		      <198 0>,
+		      <205 0>,
+		      <220 0>,
+		      <221 0>,
+		      <222 0>,
+		      <223 0>;
+};
 
 &tsens {
 	qcom,sensors = <4>;
diff --git a/arch/arm/boot/dts/msm8226-v2-cdp.dts b/arch/arm/boot/dts/msm8226-v2-cdp.dts
index ef14249..3d40180 100644
--- a/arch/arm/boot/dts/msm8226-v2-cdp.dts
+++ b/arch/arm/boot/dts/msm8226-v2-cdp.dts
@@ -18,9 +18,5 @@
 / {
 	model = "Qualcomm MSM 8226v2 CDP";
 	compatible = "qcom,msm8226-cdp", "qcom,msm8226", "qcom,cdp";
-	qcom,msm-id = <145 1 0x20000>,
-		      <158 1 0x20000>,
-		      <159 1 0x20000>,
-		      <198 1 0x20000>,
-		      <205 1 0x20000>;
+	qcom,board-id = <1 0>;
 };
diff --git a/arch/arm/boot/dts/msm8226-v2-mtp.dts b/arch/arm/boot/dts/msm8226-v2-mtp.dts
index 24f822b..6034107 100644
--- a/arch/arm/boot/dts/msm8226-v2-mtp.dts
+++ b/arch/arm/boot/dts/msm8226-v2-mtp.dts
@@ -18,9 +18,5 @@
 / {
 	model = "Qualcomm MSM 8226v2 MTP";
 	compatible = "qcom,msm8226-mtp", "qcom,msm8226", "qcom,mtp";
-	qcom,msm-id = <145 8 0x20000>,
-		      <158 8 0x20000>,
-		      <159 8 0x20000>,
-		      <198 8 0x20000>,
-		      <205 8 0x20000>;
+	qcom,board-id = <8 0>;
 };
diff --git a/arch/arm/boot/dts/msm8226-pm.dtsi b/arch/arm/boot/dts/msm8226-v2-pm.dtsi
similarity index 80%
rename from arch/arm/boot/dts/msm8226-pm.dtsi
rename to arch/arm/boot/dts/msm8226-v2-pm.dtsi
index ef0a55e..9ee47e2 100644
--- a/arch/arm/boot/dts/msm8226-pm.dtsi
+++ b/arch/arm/boot/dts/msm8226-v2-pm.dtsi
@@ -24,7 +24,7 @@
 		qcom,saw2-spm-cmd-wfi = [60 03 60 0b 0f];
 		qcom,saw2-spm-cmd-spc = [20 10 80 30 90 5b 60 03 60 3b 76 76
 				0b 94 5b 80 10 26 30 0f];
-		qcom,saw2-spm-cmd-pc = [20 10 80 30 90 5b 60 07 60 3b 76 76
+		qcom,saw2-spm-cmd-pc = [20 10 80 30 90 5b 60 03 60 3b 76 76
 				0b 94 5b 80 10 26 30 0f];
 	};
 
@@ -41,7 +41,7 @@
 		qcom,saw2-spm-cmd-wfi = [60 03 60 0b 0f];
 		qcom,saw2-spm-cmd-spc = [20 10 80 30 90 5b 60 03 60 3b 76 76
 				0b 94 5b 80 10 26 30 0f];
-		qcom,saw2-spm-cmd-pc = [20 10 80 30 90 5b 60 07 60 3b 76 76
+		qcom,saw2-spm-cmd-pc = [20 10 80 30 90 5b 60 03 60 3b 76 76
 				0b 94 5b 80 10 26 30 0f];
 	};
 
@@ -58,7 +58,7 @@
 		qcom,saw2-spm-cmd-wfi = [60 03 60 0b 0f];
 		qcom,saw2-spm-cmd-spc = [20 10 80 30 90 5b 60 03 60 3b 76 76
 				0b 94 5b 80 10 26 30 0f];
-		qcom,saw2-spm-cmd-pc = [20 10 80 30 90 5b 60 07 60 3b 76 76
+		qcom,saw2-spm-cmd-pc = [20 10 80 30 90 5b 60 03 60 3b 76 76
 				0b 94 5b 80 10 26 30 0f];
 	};
 
@@ -75,7 +75,7 @@
 		qcom,saw2-spm-cmd-wfi = [60 03 60 0b 0f];
 		qcom,saw2-spm-cmd-spc = [20 10 80 30 90 5b 60 03 60 3b 76 76
 				0b 94 5b 80 10 26 30 0f];
-		qcom,saw2-spm-cmd-pc = [20 10 80 30 90 5b 60 07 60 3b 76 76
+		qcom,saw2-spm-cmd-pc = [20 10 80 30 90 5b 60 03 60 3b 76 76
 				0b 94 5b 80 10 26 30 0f];
 	};
 
@@ -96,9 +96,12 @@
 		qcom,phase-port = <0x1>;
 		qcom,pfm-port = <0x2>;
 		qcom,saw2-spm-cmd-ret = [00 03 00 0f];
+		qcom,saw2-spm-cmd-gdhs = [00 20 32 6b c0 e0 d0 42 07 50
+				4e 02 02 d0 e0 c0 22 6b 02 32 50 0f];
 		qcom,saw2-spm-cmd-pc = [00 32 b0 10 e0 d0 6b c0 42 f0
 				11 07 01 b0 50 4e 02 02 c0 d0 12 e0 6b 02 32
 				50 f0 0f]; /*APCS_PMIC_OFF_L2RAM_OFF*/
+		qcom,L2-spm-is-apcs-master;
 	};
 
 	qcom,lpm-levels {
@@ -130,7 +133,7 @@
 		qcom,lpm-level@2 {
 			reg = <0x2>;
 			qcom,mode = "pc";
-			qcom,l2 = "l2_cache_retention";
+			qcom,l2 = "l2_cache_gdhs";
 			qcom,latency-us = <20000>;
 			qcom,ss-power = <138>;
 			qcom,energy-overhead = <1208400>;
@@ -167,28 +170,46 @@
 			<53 104>, /* mdss_irq */
 			<62 222>, /* ee0_krait_hlos_spmi_periph_irq */
 			<2 216>, /* tsens_upper_lower_int */
+			<0xff 18>,  /* APC_qgicQTmrSecPhysIrptReq */
+			<0xff 19>,  /* APC_qgicQTmrNonSecPhysIrptReq */
+			<0xff 35>,  /* WDT_barkInt */
+			<0xff 40>,  /* qtmr_phy_irq[0] */
+			<0xff 47>,  /* rbif_irq[0] */
 			<0xff 56>,  /* q6_wdog_expired_irq */
 			<0xff 57>,  /* mss_to_apps_irq(0) */
 			<0xff 58>,  /* mss_to_apps_irq(1) */
 			<0xff 59>,  /* mss_to_apps_irq(2) */
 			<0xff 60>,  /* mss_to_apps_irq(3) */
 			<0xff 61>,  /* mss_a2_bam_irq */
+			<0xff 65>,  /* o_gc_sys_irq[0] */
+			<0xff 74>,  /* venus0_mmu_cirpt[1] */
+			<0xff 75>,  /* venus0_mmu_cirpt[0] */
+			<0xff 78>,  /* mdss_mmu_cirpt[0] */
+			<0xff 79>,  /* mdss_mmu_cirpt[1] */
+			<0xff 97>,  /* camss_vfe_mmu_cirpt[1] */
+			<0xff 102>, /* camss_jpeg_mmu_cirpt[1] */
+			<0xff 109>, /* ocmem_dm_nonsec_irq */
+			<0xff 131>, /* blsp1_qup_5_irq */
+			<0xff 141>, /* blsp1_uart_3_irq */
+			<0xff 155>, /* sdc1_irq(0) */
+			<0xff 157>, /* sdc2_irq(0) */
+			<0xff 161>, /* lpass_irq_out_spare[4] */
+			<0xff 162>, /* lpass_irq_out_spare[5]*/
+			<0xff 170>, /* sdc1_pwr_cmd_irq */
 			<0xff 173>, /* o_wcss_apss_smd_hi */
 			<0xff 174>, /* o_wcss_apss_smd_med */
 			<0xff 175>, /* o_wcss_apss_smd_low */
 			<0xff 176>, /* o_wcss_apss_smsm_irq */
 			<0xff 177>, /* o_wcss_apss_wlan_data_xfer_done */
 			<0xff 178>, /* o_wcss_apss_wlan_rx_data_avail */
-			<0xff 179>, /* o_wcss_apss_asic_intr
+			<0xff 179>, /* o_wcss_apss_asic_intr */
 			<0xff 181>, /* o_wcss_apss_wdog_bite_and_reset_rdy */
 			<0xff 188>, /* lpass_irq_out_apcs(0) */
 			<0xff 189>, /* lpass_irq_out_apcs(1) */
 			<0xff 190>, /* lpass_irq_out_apcs(2) */
 			<0xff 191>, /* lpass_irq_out_apcs(3) */
 			<0xff 192>, /* lpass_irq_out_apcs(4) */
-			<0xff 194>, /* lpass_irq_out_apcs[6] */
-			<0xff 195>, /* lpass_irq_out_apcs[7] */
-			<0xff 196>, /* lpass_irq_out_apcs[8] */
+			<0xff 194>, /* lpass_irq_out_apcs(6) */
 			<0xff 200>, /* rpm_ipc(4) */
 			<0xff 201>, /* rpm_ipc(5) */
 			<0xff 202>, /* rpm_ipc(6) */
@@ -197,12 +218,16 @@
 			<0xff 205>, /* rpm_ipc(25) */
 			<0xff 206>, /* rpm_ipc(26) */
 			<0xff 207>, /* rpm_ipc(27) */
+			<0xff 234>, /* lpass_irq_out_spare[6]*/
+			<0xff 235>, /* lpass_irq_out_spare[7]*/
+			<0xff 240>, /* summary_irq_kpss */
+			<0xff 253>, /* sdc2_pwr_cmd_irq */
 			<0xff 258>, /* rpm_ipc(28) */
 			<0xff 259>, /* rpm_ipc(29) */
-			<0xff 275>, /* rpm_ipc(30) */
-			<0xff 276>, /* rpm_ipc(31) */
 			<0xff 269>, /* rpm_wdog_expired_irq */
-			<0xff 240>; /* summary_irq_kpss */
+			<0xff 270>, /* blsp1_bam_irq[0] */
+			<0xff 275>, /* rpm_ipc(30) */
+			<0xff 276>; /* rpm_ipc(31) */
 
 		qcom,gpio-parent = <&msmgpio>;
 		qcom,gpio-map = <3  1>,
@@ -285,4 +310,12 @@
 		reg = <0xfc000000 0x1a0000>;
 		qcom,start-offset = <0x190010>;
 	};
+
+	qcom,rpm-master-stats@fc428150 {
+		compatible = "qcom,rpm-master-stats";
+		reg = <0xfc428150 0x3200>;
+		qcom,masters = "APSS", "MPSS", "LPSS", "PRONTO";
+		qcom,master-stats-version = <2>;
+		qcom,master-offset = <2560>;
+	};
 };
diff --git a/arch/arm/boot/dts/msm8226-v2-qrd-dvt.dts b/arch/arm/boot/dts/msm8226-v2-qrd-dvt.dts
index 0a3148b..13402af 100644
--- a/arch/arm/boot/dts/msm8226-v2-qrd-dvt.dts
+++ b/arch/arm/boot/dts/msm8226-v2-qrd-dvt.dts
@@ -13,21 +13,25 @@
 /dts-v1/;
 /include/ "msm8226-v2.dtsi"
 /include/ "msm8226-qrd.dtsi"
-/include/ "dsi-panel-hx8394a-720p-video.dtsi"
 
 / {
 	model = "Qualcomm MSM 8226v2 QRD";
 	compatible = "qcom,msm8226-qrd", "qcom,msm8226", "qcom,qrd";
-	qcom,msm-id = <145 0x2000b 0x20000>,
-		      <158 0x2000b 0x20000>,
-		      <159 0x2000b 0x20000>,
-		      <198 0x2000b 0x20000>,
-		      <205 0x2000b 0x20000>;
+	qcom,board-id = <0x2000b 0>;
 };
 
-&soc {
-        qcom,mdss_dsi_hx8394a_720p_video {
-                status = "ok";
-		qcom,cont-splash-enabled;
-        };
+&mdss_dsi0 {
+	qcom,dsi-pref-prim-pan = <&dsi_hx8394a_720_vid>;
+};
+
+&dsi_hx8394a_720_vid {
+	qcom,cont-splash-enabled;
+};
+
+&pm8226_bms {
+        qcom,use-external-rsense;
+};
+
+&pm8226_iadc {
+	qcom,rsense = <10000000>;
 };
diff --git a/arch/arm/boot/dts/msm8226-v2-qrd-evt.dts b/arch/arm/boot/dts/msm8226-v2-qrd-evt.dts
index cb6c1af..b707d1c 100644
--- a/arch/arm/boot/dts/msm8226-v2-qrd-evt.dts
+++ b/arch/arm/boot/dts/msm8226-v2-qrd-evt.dts
@@ -13,21 +13,17 @@
 /dts-v1/;
 /include/ "msm8226-v2.dtsi"
 /include/ "msm8226-qrd.dtsi"
-/include/ "dsi-panel-nt35590-720p-video.dtsi"
 
 / {
 	model = "Qualcomm MSM 8226v2 QRD";
 	compatible = "qcom,msm8226-qrd", "qcom,msm8226", "qcom,qrd";
-	qcom,msm-id = <145 11 0x20000>,
-		      <158 11 0x20000>,
-		      <159 11 0x20000>,
-		      <198 11 0x20000>,
-		      <205 11 0x20000>;
+	qcom,board-id = <11 0>;
 };
 
-&soc {
-        qcom,mdss_dsi_nt35590_720p_video {
-                status = "ok";
-		qcom,cont-splash-enabled;
-        };
+&mdss_dsi0 {
+	qcom,dsi-pref-prim-pan = <&dsi_nt35590_720_vid>;
+};
+
+&dsi_nt35590_720_vid {
+	qcom,cont-splash-enabled;
 };
diff --git a/arch/arm/boot/dts/msm8226-v2-qrd-skuf.dts b/arch/arm/boot/dts/msm8226-v2-qrd-skuf.dts
index b34fb94..77037be 100644
--- a/arch/arm/boot/dts/msm8226-v2-qrd-skuf.dts
+++ b/arch/arm/boot/dts/msm8226-v2-qrd-skuf.dts
@@ -13,25 +13,14 @@
 /dts-v1/;
 /include/ "msm8226-v2.dtsi"
 /include/ "msm8226-qrd.dtsi"
-/include/ "dsi-panel-nt35590-720p-video.dtsi"
 
 / {
 	model = "Qualcomm MSM 8226v2 QRD";
-	compatible = "qcom,msm8226-qrd", "qcom,msm8226", "qcom,qrd";
+	compatible = "qcom,msm8226-qrd", "qcom,msm8226", "qcom,skuf", "qcom,qrd";
 	qcom,board-id = <0xb 0x2>;
-	qcom,msm-id = <145 0x20000>,
-		      <158 0x20000>,
-		      <159 0x20000>,
-		      <198 0x20000>,
-		      <205 0x20000>;
 };
 
 &soc {
-	qcom,mdss_dsi_nt35590_720p_video {
-		status = "ok";
-		qcom,mdss-pan-bl-ctrl = "bl_ctrl_dcs";
-	};
-
 	sound {
 		qcom,model = "msm8226-tapan-skuf-snd-card";
 
@@ -56,6 +45,52 @@
 		qcom,cdc-vdd-spkr-gpios;
 		qcom,cdc-us-euro-gpios;
 	};
+
+	tp_power: regulator-tp {
+		compatible = "regulator-fixed";
+		regulator-name = "tp_power";
+		regulator-min-microvolt = <2800000>;
+		regulator-max-microvolt = <2800000>;
+		gpio = <&msmgpio 15 0>;
+		startup-delay-us = <20000>;
+		enable-active-high;
+	};
+
+	i2c@f9927000 {
+		goodix@5d {
+			compatible = "goodix,gt9xx";
+			reg = <0x5d>;
+			interrupt-parent = <&msmgpio>;
+			interrupts = <17 0x2008>;
+			reset-gpios = <&msmgpio 16 0x00>;
+			interrupt-gpios = <&msmgpio 17 0x00>;
+			avdd-supply = <&tp_power>;
+			goodix,panel-coords = <0 0 720 1200>;
+			goodix,display-coords = <0 0 720 1080>;
+			goodix,button-map= <158 102 139>;
+			goodix,family-id = <0x0>;
+			goodix,cfg-data = [
+			41 D0 02 00 05 0A 35 01 01 0F
+			2D 08 55 32 03 04 00 00 00 00
+			00 00 05 0A 0C 0F 0A 8C 0E 0E
+			30 2E B8 08 00 00 00 83 03 1D
+			00 00 00 00 00 00 00 00 00 00
+			00 2D 62 94 C5 02 05 00 00 04
+			96 30 00 80 39 00 71 42 00 63
+			4D 00 56 5A 00 56 10 38 68 00
+			56 50 35 AA AA 27 00 00 00 00
+			00 01 1B 14 0C 14 00 00 01 00
+			00 00 00 00 00 00 00 00 00 00
+			00 00 02 04 06 08 0A 0C 0E 10
+			12 14 16 18 1A 1C FF FF FF FF
+			FF FF FF FF FF FF FF FF FF FF
+			FF FF 00 02 04 06 08 0A 0C 0F
+			10 12 13 14 16 18 1C 1D 1E 1F
+			20 21 22 24 26 28 29 2A FF FF
+			FF FF FF FF FF FF FF FF FF FF
+			FF FF FF FF 06 01];
+		};
+	};
 };
 
 &spmi_bus {
@@ -68,6 +103,12 @@
 			status = "disabled";
 		};
 	};
+
+	qcom,pm8226@1 {
+		qcom,leds@d800 {
+			status = "disabled";
+		};
+	};
 };
 
 &pm8226_mpps {
@@ -114,3 +155,31 @@
 		qcom,fast-avg-setup = <0>;
 	};
 };
+
+&qrd_batterydata {
+	qcom,rpull-up-kohm = <100>;
+	qcom,vref-batt-therm = <1800000>;
+
+	/include/ "batterydata-qrd-4v35-2500mah.dtsi"
+};
+
+&pm8226_bms {
+	qcom,use-external-rsense;
+	qcom,battery-data = <&qrd_batterydata>;
+};
+
+&pm8226_chg {
+	qcom,battery-data = <&qrd_batterydata>;
+};
+
+&pm8226_iadc {
+	qcom,rsense = <10000000>;
+};
+
+&mdss_dsi0 {
+	qcom,dsi-pref-prim-pan = <&dsi_nt35521_720_vid>;
+};
+
+&dsi_nt35521_720_vid {
+	qcom,cont-splash-enabled;
+};
diff --git a/arch/arm/boot/dts/msm8226-v2.dtsi b/arch/arm/boot/dts/msm8226-v2.dtsi
index 1dab78a..a57adcd 100644
--- a/arch/arm/boot/dts/msm8226-v2.dtsi
+++ b/arch/arm/boot/dts/msm8226-v2.dtsi
@@ -17,32 +17,49 @@
  */
 
 /include/ "msm8226.dtsi"
-/include/ "msm8226-camera.dtsi"
+/include/ "msm8226-v2-pm.dtsi"
+
+/ {
+	qcom,msm-id = <145 0x20000>,
+		      <158 0x20000>,
+		      <159 0x20000>,
+		      <198 0x20000>,
+		      <205 0x20000>,
+		      <220 0x20000>,
+		      <221 0x20000>,
+		      <222 0x20000>,
+		      <223 0x20000>;
+};
 
 &pm8226_l3 {
 	regulator-min-microvolt = <750000>;
-	regulator-max-microvolt = <1287500>;
+	regulator-max-microvolt = <1337500>;
 };
 
 &pm8226_l3_ao {
 	regulator-min-microvolt = <750000>;
-	regulator-max-microvolt = <1287500>;
+	regulator-max-microvolt = <1337500>;
 };
 
 &pm8226_l3_so {
 	regulator-min-microvolt = <750000>;
-	regulator-max-microvolt = <1287500>;
+	regulator-max-microvolt = <1337500>;
 };
 
 &pm8226_s2 {
 	regulator-min-microvolt = <900000>;
-	regulator-max-microvolt = <1280000>;
+	regulator-max-microvolt = <1330000>;
 };
 
 &apc_vreg_corner {
-	qcom,pvs-bin-process = <1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 2
-				2 2 2 2 2 3 3 3 3 3 3 3 3 3 3 3>;
-	qcom,pvs-corner-ceiling-slow = <1050000 1160000 1280000>;
+	qcom,pvs-init-voltage = <1330000 1330000 1330000 1320000 1310000
+					1300000 1290000 1280000 1270000 1260000
+					1250000 1240000 1230000 1220000 1210000
+					1200000 1190000 1180000 1170000 1160000
+					1150000 1140000 1140000 1140000 1140000
+					1140000 1140000 1140000 1140000 1140000
+					1140000 1140000>;
+	qcom,pvs-corner-ceiling-slow = <1050000 1150000 1280000>;
 	qcom,pvs-corner-ceiling-nom  = <1050000 1080000 1200000>;
 	qcom,pvs-corner-ceiling-fast = <1050000 1050000 1140000>;
 	qcom,cpr-step-quotient = <30>;
diff --git a/arch/arm/boot/dts/msm8226.dtsi b/arch/arm/boot/dts/msm8226.dtsi
index dd4f1f8..cfb6bed 100644
--- a/arch/arm/boot/dts/msm8226.dtsi
+++ b/arch/arm/boot/dts/msm8226.dtsi
@@ -33,7 +33,7 @@
 
 		adsp_mem: adsp_region {
 			linux,contiguous-region;
-			reg = <0 0x2000000>;
+			reg = <0 0x2a00000>;
 			label = "adsp_mem";
 		};
 
@@ -51,7 +51,6 @@
 /include/ "msm8226-camera.dtsi"
 /include/ "msm-gdsc.dtsi"
 /include/ "msm8226-iommu.dtsi"
-/include/ "msm8226-pm.dtsi"
 /include/ "msm8226-smp2p.dtsi"
 /include/ "msm8226-gpu.dtsi"
 /include/ "msm8226-bus.dtsi"
@@ -159,6 +158,7 @@
 		compatible = "qcom,msm-vidc";
 		reg = <0xfdc00000 0xff000>;
 		interrupts = <0 44 0>;
+		vdd-supply = <&gdsc_venus>;
 		qcom,load-freq-tbl = <352800 160000000>,
 			<244800 133330000>,
 			<108000  66700000>;
@@ -201,6 +201,12 @@
 		};
 	};
 
+	qcom,vidc {
+		compatible = "qcom,msm-vidc";
+		qcom,hfi = "q6";
+		qcom,max-hw-load = <108000>; /* 720p @ 30 * 1  */
+	};
+
 	qcom,wfd {
 		compatible = "qcom,msm-wfd";
 	};
@@ -287,10 +293,9 @@
 				<87 512 6000  6000>;
 	};
 
-	android_usb@fe8050c8 {
+	android_usb: android_usb@fe8050c8 {
 		compatible = "qcom,android-usb";
 		reg = <0xfe8050c8 0xc8>;
-		qcom,android-usb-cdrom;
 		qcom,android-usb-swfi-latency = <1>;
 	};
 
@@ -333,20 +338,21 @@
 			qcom,cdc-vdd-px-voltage = <1800000 1800000>;
 			qcom,cdc-vdd-px-current = <25000>;
 
-			cdc-vdd-a-1p2v-supply = <&pm8226_l4>;
-			qcom,cdc-vdd-a-1p2v-voltage = <1200000 1200000>;
-			qcom,cdc-vdd-a-1p2v-current = <10000>;
-
 			cdc-vdd-cx-supply = <&pm8226_l4>;
 			qcom,cdc-vdd-cx-voltage = <1200000 1200000>;
-			qcom,cdc-vdd-cx-current = <10000>;
+			qcom,cdc-vdd-cx-current = <2000>;
 
-			qcom,cdc-static-supplies = "cdc-vdd-buck",
-						   "cdc-vdd-h",
+			cdc-vdd-buckhelper-supply = <&pm8226_l25>;
+			qcom,cdc-vdd-buckhelper-voltage = <1775000 2125000>;
+			qcom,cdc-vdd-buckhelper-current = <10000>;
+
+			qcom,cdc-static-supplies = "cdc-vdd-h",
 						   "cdc-vdd-px",
-						   "cdc-vdd-a-1p2v",
 						   "cdc-vdd-cx";
 
+			qcom,cdc-cp-supplies = "cdc-vdd-buck",
+						"cdc-vdd-buckhelper";
+
 			qcom,cdc-micbias-ldoh-v = <0x3>;
 			qcom,cdc-micbias-cfilt1-mv = <1800>;
 			qcom,cdc-micbias-cfilt2-mv = <2700>;
@@ -378,6 +384,18 @@
 		qcom,prim-auxpcm-gpio-set = "prim-gpio-prim";
 	};
 
+	sound-9302 {
+		compatible = "qcom,msm8226-audio-tapan";
+		qcom,model = "msm8226-tapan9302-snd-card";
+		qcom,tapan-mclk-clk-freq = <9600000>;
+		qcom,prim-auxpcm-gpio-clk  = <&msmgpio 63 0>;
+		qcom,prim-auxpcm-gpio-sync = <&msmgpio 64 0>;
+		qcom,prim-auxpcm-gpio-din  = <&msmgpio 65 0>;
+		qcom,prim-auxpcm-gpio-dout = <&msmgpio 66 0>;
+		qcom,prim-auxpcm-gpio-set = "prim-gpio-prim";
+		qcom,tapan-codec-9302;
+	};
+
 	qcom,msm-pcm {
 		compatible = "qcom,msm-pcm-dsp";
 		qcom,msm-pcm-dsp-id = <0>;
@@ -426,6 +444,10 @@
 		qcom,msm-dai-q6-dev-id = <8>;
 	};
 
+	qcom,msm-lsm-client {
+		compatible = "qcom,msm-lsm-client";
+	};
+
 	qcom,msm-dai-q6 {
 		compatible = "qcom,msm-dai-q6";
 		qcom,msm-dai-q6-sb-0-rx {
@@ -468,6 +490,11 @@
 			qcom,msm-dai-q6-dev-id = <16393>;
 		};
 
+		qcom,msm-dai-q6-sb-5-tx {
+                        compatible = "qcom,msm-dai-q6-dev";
+                        qcom,msm-dai-q6-dev-id = <16395>;
+                };
+
 		qcom,msm-dai-q6-bt-sco-rx {
 			compatible = "qcom,msm-dai-q6-dev";
 			qcom,msm-dai-q6-dev-id = <12288>;
@@ -564,6 +591,7 @@
 		gpios = <&msmgpio 40 0>, <&msmgpio 41 0>, <&msmgpio 42 0>, <&msmgpio 43 0>, <&msmgpio 44 0>;
 		qcom,has-pronto-hw;
 		qcom,has-autodetect-xo;
+		qcom,wcnss-adc_tm = <&pm8226_adc_tm>;
 	};
 
 	qcom,msm-adsp-sensors {
@@ -913,6 +941,8 @@
 		interrupts = <0 99 0>;
 		qcom,i2c-bus-freq = <384000>;
 		qcom,i2c-src-freq = <19200000>;
+		qcom,sda-gpio = <&msmgpio 18 0>;
+		qcom,scl-gpio = <&msmgpio 19 0>;
 	};
 
 	qcom,acpuclk@f9011050 {
@@ -1029,9 +1059,11 @@
 		qcom,gpio-force-stop = <&smp2pgpio_ssr_smp2p_1_out 0 0>;
 	};
 
-	qcom,msm-mem-hole {
+	memory_hole: qcom,msm-mem-hole {
 		compatible = "qcom,msm-mem-hole";
-		qcom,memblock-remove = <0x6400000 0x9b00000>; /* Address and Size of Hole */
+		qcom,memblock-remove = <0x08400000 0x4000000
+					0x0d200000 0x2300000
+					0x0fa00000 0x500000>; /* Address and Size of Hole */
 	};
 
 	tsens: tsens@fc4a8000 {
diff --git a/arch/arm/boot/dts/msm8610-bus.dtsi b/arch/arm/boot/dts/msm8610-bus.dtsi
index cef04ef..6b72e66 100644
--- a/arch/arm/boot/dts/msm8610-bus.dtsi
+++ b/arch/arm/boot/dts/msm8610-bus.dtsi
@@ -952,6 +952,7 @@
 			cell-id = <2048>;
 			label = "fab_mmss_noc";
 			qcom,masterp = <1>;
+			qcom,gateway;
 			qcom,qport = <1>;
 			qcom,buswidth = <8>;
 			qcom,ws = <10000>;
diff --git a/arch/arm/boot/dts/msm8610-camera-sensor-cdp-mtp.dtsi b/arch/arm/boot/dts/msm8610-camera-sensor-cdp-mtp.dtsi
index 1b4a594..e133117 100644
--- a/arch/arm/boot/dts/msm8610-camera-sensor-cdp-mtp.dtsi
+++ b/arch/arm/boot/dts/msm8610-camera-sensor-cdp-mtp.dtsi
@@ -38,6 +38,78 @@
 		qcom,cci-master = <0>;
 	};
 
+	eeprom0: qcom,eeprom@6a {
+		cell-index = <0>;
+		reg = <0x6a 0x0>;
+		qcom,eeprom-name = "truly_cm7700";
+		compatible = "qcom,msm_eeprom";
+		qcom,slave-addr = <0x6c>;
+		qcom,num-blocks = <9>;
+		qcom,page0 = <1 0x0100 2 0x01 1 1>;
+		qcom,poll0 = <0 0x0 2 0 1 1>;
+		qcom,mem0 = <0 0x0 2 0 1 0>;
+		qcom,page1 = <1 0x3d84 2 0x8 1 1>;
+		qcom,pageen1 = <1 0x3d81 2 0x01 1 10>;
+		qcom,poll1 = <0 0x0 2 0 1 1>;
+		qcom,mem1 = <32 0x3d00 2 0 1 0>;
+		qcom,page2 = <1 0x3d84 2 0x9 1 1>;
+		qcom,pageen2 = <1 0x3d81 2 0x01 1 10>;
+		qcom,poll2 = <0 0x0 2 0 1 1>;
+		qcom,mem2 = <32 0x3d00 2 0 1 0>;
+		qcom,page3 = <1 0x3d84 2 0xa 1 1>;
+		qcom,pageen3 = <1 0x3d81 2 0x01 1 10>;
+		qcom,poll3 = <0 0x0 2 0 1 1>;
+		qcom,mem3 = <32 0x3d00 2 0 1 0>;
+		qcom,page4 = <1 0x3d84 2 0xb 1 1>;
+		qcom,pageen4 = <1 0x3d81 2 0x01 1 10>;
+		qcom,poll4 = <0 0x0 2 0 1 1>;
+		qcom,mem4 = <32 0x3d00 2 0 1 0>;
+		qcom,page5 = <1 0x3d84 2 0xc 1 1>;
+		qcom,pageen5 = <1 0x3d81 2 0x01 1 10>;
+		qcom,poll5 = <0 0x0 2 0 1 1>;
+		qcom,mem5 = <32 0x3d00 2 0 1 0>;
+		qcom,page6 = <1 0x3d84 2 0xd 1 1>;
+		qcom,pageen6 = <1 0x3d81 2 0x01 1 10>;
+		qcom,poll6 = <0 0x0 2 0 1 1>;
+		qcom,mem6 = <32 0x3d00 2 0 1 0>;
+		qcom,page7 = <1 0x3d84 2 0xe 1 1>;
+		qcom,pageen7 = <1 0x3d81 2 0x01 1 10>;
+		qcom,poll7 = <0 0x0 2 0 1 1>;
+		qcom,mem7 = <32 0x3d00 2 0 1 0>;
+		qcom,page8 = <1 0x3d84 2 0xf 1 1>;
+		qcom,pageen8 = <1 0x3d81 2 0x01 1 10>;
+		qcom,poll8 = <0 0x0 2 0 1 1>;
+		qcom,mem8 = <32 0x3d00 2 0 1 0>;
+
+		cam_vdig-supply = <&pm8110_l2>;
+		cam_vio-supply = <&pm8110_l14>;
+		qcom,cam-vreg-name = "cam_vdig", "cam_vio";
+		qcom,cam-vreg-type = <0 0 0 0>;
+		qcom,cam-vreg-min-voltage = <1200000 1800000>;
+		qcom,cam-vreg-max-voltage = <1200000 1800000>;
+		qcom,cam-vreg-op-mode = <200000 8000>;
+		qcom,gpio-no-mux = <0>;
+		gpios = <&msmgpio 13 0>,
+			<&msmgpio 21 0>,
+			<&msmgpio 20 0>;
+		qcom,gpio-reset = <1>;
+		qcom,gpio-standby = <2>;
+		qcom,gpio-req-tbl-num = <0 1 2>;
+		qcom,gpio-req-tbl-flags = <1 0 0>;
+		qcom,gpio-req-tbl-label = "CAMIF_MCLK",
+			"CAM_RESET1",
+			"CAM_STANDBY";
+		qcom,cam-power-seq-type = "sensor_vreg",
+			"sensor_vreg", "sensor_clk",
+			"sensor_gpio", "sensor_gpio";
+		qcom,cam-power-seq-val = "cam_vdig",
+			"cam_vio", "sensor_cam_mclk",
+			"sensor_gpio_reset",
+			"sensor_gpio_standby";
+		qcom,cam-power-seq-cfg-val = <1 1 24000000 1 1>;
+		qcom,cam-power-seq-delay = <1 1 5 5 10>;
+	};
+
 	qcom,camera@6f {
 		compatible = "qcom,ov8825";
 		reg = <0x6f>;
@@ -46,6 +118,7 @@
 		qcom,csid-sd-index = <0>;
 		qcom,actuator-src = <&actuator0>;
 		qcom,led-flash-src = <&led_flash0>;
+		qcom,eeprom-src = <&eeprom0>;
 		qcom,mount-angle = <90>;
 		qcom,sensor-name = "ov8825";
 		cam_vdig-supply = <&pm8110_l2>;
diff --git a/arch/arm/boot/dts/msm8610-cdp.dts b/arch/arm/boot/dts/msm8610-cdp.dtsi
similarity index 88%
rename from arch/arm/boot/dts/msm8610-cdp.dts
rename to arch/arm/boot/dts/msm8610-cdp.dtsi
index b0c0191..4e0ee32 100644
--- a/arch/arm/boot/dts/msm8610-cdp.dts
+++ b/arch/arm/boot/dts/msm8610-cdp.dtsi
@@ -10,19 +10,6 @@
  * GNU General Public License for more details.
  */
 
-/dts-v1/;
-
-/include/ "msm8610.dtsi"
-/include/ "dsi-v2-panel-truly-wvga-video.dtsi"
-/include/ "msm8610-camera-sensor-cdp-mtp.dtsi"
-
-/ {
-	model = "Qualcomm MSM 8610 CDP";
-	compatible = "qcom,msm8610-cdp", "qcom,msm8610", "qcom,cdp";
-	qcom,msm-id = <147 1 0>, <165 1 0>, <161 1 0>, <162 1 0>,
-		      <163 1 0>, <164 1 0>, <166 1 0>;
-};
-
 &soc {
 	serial@f991e000 {
 		status = "ok";
@@ -52,7 +39,7 @@
 				/* Object 6, Instance = 0 */
 				00 00 00 00 00 00
 				/* Object 38, Instance = 0 */
-				1D 02 00 0A 06 0D 00 00
+				1D 03 00 1E 07 0D 00 00
 				/* Object 7, Instance = 0 */
 				20 08 32
 				/* Object 8, Instance = 0 */
@@ -60,7 +47,7 @@
 				/* Object 9, Instance = 0 */
 				83 00 00 13 0B 00 20 32 01 03
 				00 32 05 30 0A 05 0A 00 70 03
-				FC 01 00 36 2F D8 00 00 40 00
+				FC 01 04 2F F8 DC 00 00 40 00
 				00 0A 00 00 02
 				/* Object 18, Instance = 0 */
 				00 00
@@ -89,6 +76,21 @@
 				];
 			};
 		};
+
+		synaptics@20 {
+			compatible = "synaptics,rmi4";
+			reg = <0x20>;
+			interrupt-parent = <&msmgpio>;
+			interrupts = <1 0x2008>;
+			vdd-supply = <&pm8110_l19>;
+			vcc_i2c-supply = <&pm8110_l14>;
+			synaptics,reset-gpio = <&msmgpio 0 0x00>;
+			synaptics,irq-gpio = <&msmgpio 1 0x2008>;
+			synaptics,button-map = <139 102 158>;
+			synaptics,i2c-pull-up;
+			synaptics,power-down;
+			synaptics,disable-gpios;
+		};
 	};
 
 	gen-vkeys {
@@ -134,14 +136,15 @@
 		};
 	};
 
-    sound {
-        qcom,audio-routing =
-            "RX_BIAS", "MCLK",
-            "INT_LDO_H", "MCLK",
-            "MIC BIAS External", "Handset Mic",
-            "MIC BIAS Internal2", "Headset Mic",
-            "AMIC1", "MIC BIAS External",
-            "AMIC2", "MIC BIAS Internal2";
+	sound {
+		qcom,audio-routing =
+			"RX_BIAS", "MCLK",
+			"INT_LDO_H", "MCLK",
+			"MIC BIAS External", "Handset Mic",
+			"MIC BIAS Internal2", "Headset Mic",
+			"AMIC1", "MIC BIAS External",
+			"AMIC2", "MIC BIAS Internal2";
+		qcom,headset-jack-type-NC;
     };
 };
 
@@ -149,6 +152,11 @@
 	msm8x10_wcd_codec@0d{
 		compatible = "qcom,msm8x10-wcd-i2c";
 		reg = <0x0d>;
+
+		interrupt-parent = <&wcd9xxx_intc>;
+		interrupts = <0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
+			      17 18 19 20 21 22 23>;
+
 		cdc-vdda-cp-supply = <&pm8110_s4>;
 		qcom,cdc-vdda-cp-voltage = <1800000 2150000>;
 		qcom,cdc-vdda-cp-current = <650000>;
@@ -179,6 +187,7 @@
 
 		qcom,cdc-on-demand-supplies = "cdc-vdda-cp",
 					      "cdc-vdd-mic-bias";
+		qcom,cdc-micbias1-ext-cap;
 	};
 
 	msm8x10_wcd_codec@77{
@@ -226,10 +235,9 @@
 				qcom,source-sel = <8>;
 				qcom,mode-ctrl = <0x10>;
 				qcom,pwm-channel = <0>;
-				qcom,pwm-us = <14>;
+				qcom,pwm-us = <27>;
 				qcom,vin-ctrl = <0x03>;
 				qcom,mode = "pwm";
-				qcom,min-brightness = <19>;
 			};
 		};
 	};
@@ -404,3 +412,19 @@
 	qcom,setb-gpios-pull = <0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0>;
 	qcom,setb-gpios-dir =  <2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2>;
 };
+
+&mdss_mdp {
+	qcom,mdss-pref-prim-intf = "dsi";
+};
+
+&mdss_dsi0 {
+	qcom,dsi-pref-prim-pan = <&dsi_truly_wvga_vid>;
+};
+
+&dsi_truly_wvga_vid {
+	qcom,cont-splash-enabled;
+};
+
+&dsi_truly_wvga_cmd {
+	qcom,cont-splash-enabled;
+};
diff --git a/arch/arm/boot/dts/msm8610-coresight.dtsi b/arch/arm/boot/dts/msm8610-coresight.dtsi
index 2041bf6..78a4b5a 100644
--- a/arch/arm/boot/dts/msm8610-coresight.dtsi
+++ b/arch/arm/boot/dts/msm8610-coresight.dtsi
@@ -16,9 +16,10 @@
 		reg = <0xfc326000 0x1000>,
 		      <0xfc37c000 0x3000>;
 		reg-names = "tmc-base", "bam-base";
+		interrupts = <0 166 0>;
+		interrupt-names = "byte-cntr-irq";
 
-		qcom,memory-reservation-type = "EBI1";
-		qcom,memory-reservation-size = <0x100000>; /* 1M EBI1 buffer */
+		qcom,memory-size = <0x100000>;
 
 		coresight-id = <0>;
 		coresight-name = "coresight-tmc-etr";
@@ -39,6 +40,11 @@
 
 		qcom,vdd-voltage-level = <2950000 2950000>;
 		qcom,vdd-current-level = <15000 400000>;
+
+		vdd-io-supply = <&pm8110_l21>;
+
+		qcom,vdd-io-voltage-level = <2950000 2950000>;
+		qcom,vdd-io-current-level = <200 50000>;
 	};
 
 	replicator: replicator@fc324000 {
diff --git a/drivers/gpu/msm/adreno_trace.c b/arch/arm/boot/dts/msm8610-mdss-panels.dtsi
similarity index 69%
copy from drivers/gpu/msm/adreno_trace.c
copy to arch/arm/boot/dts/msm8610-mdss-panels.dtsi
index 607ba8c..243d7e8 100644
--- a/drivers/gpu/msm/adreno_trace.c
+++ b/arch/arm/boot/dts/msm8610-mdss-panels.dtsi
@@ -8,11 +8,10 @@
  * 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 "adreno.h"
-
-/* Instantiate tracepoints */
-#define CREATE_TRACE_POINTS
-#include "adreno_trace.h"
+/include/ "dsi-panel-truly-wvga-video.dtsi"
+/include/ "dsi-panel-truly-wvga-cmd.dtsi"
+/include/ "dsi-panel-nt35590-720p-video.dtsi"
+/include/ "dsi-panel-otm8018b-fwvga-video.dtsi"
+/include/ "dsi-panel-hx8379a-wvga-video.dtsi"
diff --git a/arch/arm/boot/dts/msm8610-mdss.dtsi b/arch/arm/boot/dts/msm8610-mdss.dtsi
index d0fc1dc..f37a42b 100644
--- a/arch/arm/boot/dts/msm8610-mdss.dtsi
+++ b/arch/arm/boot/dts/msm8610-mdss.dtsi
@@ -11,7 +11,7 @@
  */
 
 &soc {
-	qcom,mdss_mdp@fd900000 {
+	mdss_mdp: qcom,mdss_mdp@fd900000 {
 		compatible = "qcom,mdss_mdp3";
 		reg = <0xfd900000 0x100000>;
 		reg-names = "mdp_phys";
@@ -29,7 +29,62 @@
 		cell-index = <0>;
 		reg = <0xfdd00000 0x100000>;
 		interrupts = <0 30 0>;
-		vdda-supply = <&pm8110_l4>;
+		vdd-supply = <&pm8110_l4>;
+		vdda-supply = <&pm8110_l19>;
+		vddio-supply = <&pm8110_l14>;
 		qcom,mdss-fb-map = <&mdss_fb0>;
+		qcom,mdss-mdp = <&mdss_mdp>;
+		qcom,platform-reset-gpio = <&msmgpio 41 0>;
+		qcom,platform-te-gpio = <&msmgpio 12 0>;
+		qcom,platform-mode-gpio = <&msmgpio 7 0>;
+
+		qcom,platform-reset-sequence = <1 20 0 2 1 20 2>;
+
+		qcom,platform-strength-ctrl = [ff 06];
+		qcom,platform-bist-ctrl = [03 03 00 00 0f 00];
+		qcom,platform-regulator-settings = [02 08 05 00 20 03];
+		qcom,platform-lane-config = [80 45 00 00 01 66
+		80 45 00 00 01 66
+		80 45 00 00 01 66
+		80 45 00 00 01 66
+		40 67 00 00 01 88];
+
+		qcom,platform-supply-entry1 {
+			qcom,supply-name = "vdd";
+			qcom,supply-min-voltage = <1200000>;
+			qcom,supply-max-voltage = <1200000>;
+			qcom,supply-enable-load = <100000>;
+			qcom,supply-disable-load = <100>;
+			qcom,supply-pre-on-sleep = <0>;
+			qcom,supply-post-on-sleep = <20>;
+			qcom,supply-pre-off-sleep = <0>;
+			qcom,supply-post-off-sleep = <20>;
+		};
+
+		qcom,platform-supply-entry2 {
+			qcom,supply-name = "vddio";
+			qcom,supply-min-voltage = <1800000>;
+			qcom,supply-max-voltage = <1800000>;
+			qcom,supply-enable-load = <100000>;
+			qcom,supply-disable-load = <100>;
+			qcom,supply-pre-on-sleep = <0>;
+			qcom,supply-post-on-sleep = <0>;
+			qcom,supply-pre-off-sleep = <0>;
+			qcom,supply-post-off-sleep = <0>;
+		};
+
+		qcom,platform-supply-entry3 {
+			qcom,supply-name = "vdda";
+			qcom,supply-min-voltage = <2850000>;
+			qcom,supply-max-voltage = <2850000>;
+			qcom,supply-enable-load = <100000>;
+			qcom,supply-disable-load = <100>;
+			qcom,supply-pre-on-sleep = <0>;
+			qcom,supply-post-on-sleep = <0>;
+			qcom,supply-pre-off-sleep = <0>;
+			qcom,supply-post-off-sleep = <0>;
+		};
 	};
 };
+
+/include/ "msm8610-mdss-panels.dtsi"
diff --git a/arch/arm/boot/dts/msm8610-mtp.dts b/arch/arm/boot/dts/msm8610-mtp.dtsi
similarity index 84%
rename from arch/arm/boot/dts/msm8610-mtp.dts
rename to arch/arm/boot/dts/msm8610-mtp.dtsi
index 221ace4..82f5aea 100644
--- a/arch/arm/boot/dts/msm8610-mtp.dts
+++ b/arch/arm/boot/dts/msm8610-mtp.dtsi
@@ -10,19 +10,6 @@
  * GNU General Public License for more details.
  */
 
-/dts-v1/;
-
-/include/ "msm8610.dtsi"
-/include/ "dsi-v2-panel-truly-wvga-video.dtsi"
-/include/ "msm8610-camera-sensor-cdp-mtp.dtsi"
-
-/ {
-	model = "Qualcomm MSM 8610 MTP";
-	compatible = "qcom,msm8610-mtp", "qcom,msm8610", "qcom,mtp";
-	qcom,msm-id = <147 8 0>, <165 8 0>, <161 8 0>, <162 8 0>,
-		      <163 8 0>, <164 8 0>, <166 8 0>;
-};
-
 &soc {
 	serial@f991e000 {
 		status = "ok";
@@ -52,7 +39,7 @@
 				/* Object 6, Instance = 0 */
 				00 00 00 00 00 00
 				/* Object 38, Instance = 0 */
-				1D 02 00 0A 06 0D 00 00
+				1D 03 00 1E 07 0D 00 00
 				/* Object 7, Instance = 0 */
 				20 08 32
 				/* Object 8, Instance = 0 */
@@ -60,7 +47,7 @@
 				/* Object 9, Instance = 0 */
 				83 00 00 13 0B 00 20 32 01 03
 				00 32 05 30 0A 05 0A 00 70 03
-				FC 01 00 36 2F D8 00 00 40 00
+				FC 01 04 2F F8 DC 00 00 40 00
 				00 0A 00 00 02
 				/* Object 18, Instance = 0 */
 				00 00
@@ -89,6 +76,21 @@
 				];
 			};
 		};
+
+		synaptics@20 {
+			compatible = "synaptics,rmi4";
+			reg = <0x20>;
+			interrupt-parent = <&msmgpio>;
+			interrupts = <1 0x2008>;
+			vdd-supply = <&pm8110_l19>;
+			vcc_i2c-supply = <&pm8110_l14>;
+			synaptics,reset-gpio = <&msmgpio 0 0x00>;
+			synaptics,irq-gpio = <&msmgpio 1 0x2008>;
+			synaptics,button-map = <139 102 158>;
+			synaptics,i2c-pull-up;
+			synaptics,power-down;
+			synaptics,disable-gpios;
+		};
 	};
 
 	i2c@f9925000 {
@@ -127,6 +129,23 @@
 			fsl,irq-gpio = <&msmgpio 81 0x00>;
 			fsl,sensors-position = <5>;
 		};
+		capella@60 {
+			compatible = "capella,cm36283";
+			reg = <0x60>;
+			interrupt-parent = <&msmgpio>;
+			interrupts = <80 0x2>;
+			vdd-supply = <&pm8110_l19>;
+			vio-supply = <&pm8110_l14>;
+			capella,use-polling;
+			capella,interrupt-gpio = <&msmgpio 80 0x2>;
+			capella,levels = <0x0A 0xA0 0xE1 0x140 0x280 0x500 0xA28 0x16A8 0x1F40
+				0x2800>;
+			capella,ps_close_thd_set = <0xa>;
+			capella,ps_away_thd_set = <0x5>;
+			capella,ls_cmd = <0x44>; /* PS_IT=160ms, INT_PERS=2*/
+			capella,ps_conf1_val = <0x0006>;
+			capella,ps_conf3_val = <0x3010>;
+		};
 	};
 
 	gen-vkeys {
@@ -178,8 +197,10 @@
             "INT_LDO_H", "MCLK",
             "MIC BIAS External", "Handset Mic",
             "MIC BIAS Internal2", "Headset Mic",
+            "MIC BIAS External", "Secondary Mic",
             "AMIC1", "MIC BIAS External",
-            "AMIC2", "MIC BIAS Internal2";
+            "AMIC2", "MIC BIAS Internal2",
+            "AMIC3", "MIC BIAS External";
     };
 };
 
@@ -187,6 +208,11 @@
 	msm8x10_wcd_codec@0d{
 		compatible = "qcom,msm8x10-wcd-i2c";
 		reg = <0x0d>;
+
+		interrupt-parent = <&wcd9xxx_intc>;
+		interrupts = <0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
+			      17 18 19 20 21 22 23>;
+
 		cdc-vdda-cp-supply = <&pm8110_s4>;
 		qcom,cdc-vdda-cp-voltage = <1800000 2150000>;
 		qcom,cdc-vdda-cp-current = <650000>;
@@ -217,6 +243,7 @@
 
 		qcom,cdc-on-demand-supplies = "cdc-vdda-cp",
 					      "cdc-vdd-mic-bias";
+		qcom,cdc-micbias1-ext-cap;
 	};
 
 	msm8x10_wcd_codec@77{
@@ -264,10 +291,9 @@
 				qcom,source-sel = <8>;
 				qcom,mode-ctrl = <0x10>;
 				qcom,pwm-channel = <0>;
-				qcom,pwm-us = <14>;
+				qcom,pwm-us = <27>;
 				qcom,vin-ctrl = <0x03>;
 				qcom,mode = "pwm";
-				qcom,min-brightness = <19>;
 			};
 		};
 	};
@@ -400,3 +426,19 @@
 &pm8110_bms {
 	status = "ok";
 };
+
+&mdss_mdp {
+	qcom,mdss-pref-prim-intf = "dsi";
+};
+
+&mdss_dsi0 {
+	qcom,dsi-pref-prim-pan = <&dsi_truly_wvga_vid>;
+};
+
+&dsi_truly_wvga_vid {
+	qcom,cont-splash-enabled;
+};
+
+&dsi_truly_wvga_cmd {
+	qcom,cont-splash-enabled;
+};
diff --git a/arch/arm/boot/dts/msm8610-qrd-camera-sensor.dtsi b/arch/arm/boot/dts/msm8610-qrd-camera-sensor.dtsi
index e73573a..fc3087a 100644
--- a/arch/arm/boot/dts/msm8610-qrd-camera-sensor.dtsi
+++ b/arch/arm/boot/dts/msm8610-qrd-camera-sensor.dtsi
@@ -18,16 +18,16 @@
                 qcom,slave-id = <0x40 0x04 0xc0>;
                 qcom,csiphy-sd-index = <0>;
                 qcom,csid-sd-index = <0>;
-                qcom,mount-angle = <270>;
+                qcom,mount-angle = <90>;
                 qcom,sensor-name = "hi256";
-                cam_vdig-supply = <&pm8110_l2>;
+                cam_vdig-supply = <&pm8110_l14>;
                 cam_vana-supply = <&pm8110_l19>;
                 cam_vio-supply = <&pm8110_l14>;
                 qcom,cam-vreg-name = "cam_vdig", "cam_vio", "cam_vana";
                 qcom,cam-vreg-type = <0 0 0>;
-                qcom,cam-vreg-min-voltage = <1200000 1800000 2850000>;
-                qcom,cam-vreg-max-voltage = <1200000 1800000 2850000>;
-                qcom,cam-vreg-op-mode = <200000 8000 80000>;
+                qcom,cam-vreg-min-voltage = <1800000 1800000 2850000>;
+                qcom,cam-vreg-max-voltage = <1800000 1800000 2850000>;
+                qcom,cam-vreg-op-mode = <200000 0 80000>;
                 qcom,gpio-no-mux = <0>;
                 gpios = <&msmgpio 13 0>,
                         <&msmgpio 21 0>,
diff --git a/arch/arm/boot/dts/msm8610-qrd-skuaa.dts b/arch/arm/boot/dts/msm8610-qrd-skuaa.dtsi
similarity index 62%
rename from arch/arm/boot/dts/msm8610-qrd-skuaa.dts
rename to arch/arm/boot/dts/msm8610-qrd-skuaa.dtsi
index aeaf8ca..86f1210 100644
--- a/arch/arm/boot/dts/msm8610-qrd-skuaa.dts
+++ b/arch/arm/boot/dts/msm8610-qrd-skuaa.dtsi
@@ -10,19 +10,7 @@
  * GNU General Public License for more details.
  */
 
-/dts-v1/;
-
 /include/ "msm8610-qrd.dtsi"
-/include/ "dsi-v2-panel-hx8379a-wvga-video.dtsi"
-/include/ "msm8610-qrd-camera-sensor.dtsi"
-
-/ {
-	model = "Qualcomm MSM 8610 QRD";
-	compatible = "qcom,msm8610-qrd", "qcom,msm8610", "qcom,qrd";
-	qcom,board-id = <11 1>, <11 0>;
-	qcom,msm-id = <147 0>, <165 0>, <161 0>, <162 0>,
-				  <163 0>, <164 0>, <166 0>;
-};
 
 &soc {
     sound {
@@ -39,9 +27,46 @@
 
         qcom,ext-spk-amp-gpio = <&msmgpio 92 0x0>;
     };
+
+	usb@f9a55000 {
+		qcom,hsusb-otg-phy-init-seq =
+		<0x44 0x80 0x6a 0x81 0x34 0x82 0x13 0x83 0xffffffff>;
+	};
+};
+
+/ {
+	qrd_batterydata: qcom,battery-data {
+		qcom,rpull-up-kohm = <100>;
+		qcom,vref-batt-therm = <1800000>;
+
+		/include/ "batterydata-qrd-4v2-1300mah.dtsi"
+	};
 };
 
 &pm8110_bms {
 	status = "ok";
-	qcom,batt-type = <5>;
+	qcom,battery-data = <&qrd_batterydata>;
+};
+
+&pm8110_chg {
+	qcom,battery-data = <&qrd_batterydata>;
+};
+
+&pm8110_vadc {
+	chan@30 {
+		label = "batt_therm";
+		qcom,scale-function = <7>;
+	};
+};
+
+&mdss_mdp {
+	qcom,mdss-pref-prim-intf = "dsi";
+};
+
+&mdss_dsi0 {
+	qcom,dsi-pref-prim-pan = <&dsi_hx8379a_wvga_vid>;
+};
+
+&dsi_hx8379a_wvga_vid {
+	qcom,cont-splash-enabled;
 };
diff --git a/arch/arm/boot/dts/msm8610-qrd-skuab.dts b/arch/arm/boot/dts/msm8610-qrd-skuab.dtsi
similarity index 65%
rename from arch/arm/boot/dts/msm8610-qrd-skuab.dts
rename to arch/arm/boot/dts/msm8610-qrd-skuab.dtsi
index 947a312..17bf329 100644
--- a/arch/arm/boot/dts/msm8610-qrd-skuab.dts
+++ b/arch/arm/boot/dts/msm8610-qrd-skuab.dtsi
@@ -10,19 +10,7 @@
  * GNU General Public License for more details.
  */
 
-/dts-v1/;
-
 /include/ "msm8610-qrd.dtsi"
-/include/ "dsi-v2-panel-otm8018b-fwvga-video.dtsi"
-/include/ "msm8612-qrd-camera-sensor.dtsi"
-
-/ {
-	model = "Qualcomm MSM 8610 QRD";
-	compatible = "qcom,msm8610-qrd", "qcom,msm8610", "qcom,qrd";
-	qcom,board-id = <11 3>;
-	qcom,msm-id = <147 0>, <165 0>, <161 0>, <162 0>,
-				  <163 0>, <164 0>, <166 0>;
-};
 
 &soc {
     sound {
@@ -78,9 +66,58 @@
 			fsl,irq-gpio = <&msmgpio 81 0x00>;
 			fsl,sensors-position = <1>;
 		};
+		stk@48 {
+			compatible = "stk,stk3x1x";
+			reg = <0x48>;
+			interrupt-parent = <&msmgpio>;
+			interrupts = <80 0x2>;
+			vdd-supply = <&pm8110_l19>;
+			vio-supply = <&pm8110_l14>;
+			stk,irq-gpio = <&msmgpio 80 0x02>;
+			stk,transmittance = <340>;
+			stk,state-reg = <0x00>;
+			stk,psctrl-reg = <0x71>;
+			stk,alsctrl-reg = <0x38>;
+			stk,ledctrl-reg = <0xFF>;
+			stk,wait-reg = <0x07>;
+			stk,ps-thdh = <150>;
+			stk,ps-thdl = <100>;
+			stk,use-fir;
+		};
 	};
 
-	qcom,dsi_v2_otm8018b_fwvga_video {
-		status = "ok";
+	usb@f9a55000 {
+               qcom,hsusb-otg-phy-init-seq =
+                       <0x44 0x80 0x6a 0x81 0x34 0x82 0x23 0x83 0xffffffff>;
 	};
 };
+
+/ {
+	qrd_batterydata: qcom,battery-data {
+		qcom,rpull-up-kohm = <100>;
+		qcom,vref-batt-therm = <1800000>;
+
+		/include/ "batterydata-qrd-4v2-1800mah.dtsi"
+	};
+};
+
+&pm8110_bms {
+	status = "ok";
+	qcom,battery-data = <&qrd_batterydata>;
+};
+
+&pm8110_chg {
+	qcom,battery-data = <&qrd_batterydata>;
+};
+
+&mdss_mdp {
+	qcom,mdss-pref-prim-intf = "dsi";
+};
+
+&mdss_dsi0 {
+	qcom,dsi-pref-prim-pan = <&dsi_otm8018b_fwvga_vid>;
+};
+
+&dsi_otm8018b_fwvga_vid {
+	qcom,cont-splash-enabled;
+};
diff --git a/arch/arm/boot/dts/msm8610-qrd.dtsi b/arch/arm/boot/dts/msm8610-qrd.dtsi
index ea47d45..83d84c0 100644
--- a/arch/arm/boot/dts/msm8610-qrd.dtsi
+++ b/arch/arm/boot/dts/msm8610-qrd.dtsi
@@ -26,8 +26,6 @@
  * };
  */
 
-/include/ "msm8610.dtsi"
-
 &soc {
 	i2c@f9923000{
 		focaltech@38{
@@ -37,6 +35,7 @@
 			interrupts = <1 0x2>;
 			vdd-supply = <&pm8110_l19>;
 			vcc_i2c-supply = <&pm8110_l14>;
+			focaltech,name = "ft6x06";
 			focaltech,family-id = <0x06>;
 			focaltech,reset-gpio = <&msmgpio 0 0x00>;
 			focaltech,irq-gpio = <&msmgpio 1 0x00>;
@@ -45,6 +44,17 @@
 			focaltech,button-map= <139 102 158>;
 			focaltech,no-force-update;
 			focaltech,i2c-pull-up;
+			focaltech,group-id = <1>;
+			focaltech,hard-reset-delay-ms = <20>;
+			focaltech,soft-reset-delay-ms = <150>;
+			focaltech,num-max-touches = <2>;
+			focaltech,fw-name = "ft_8610_qrd_fw.bin";
+			focaltech,fw-delay-aa-ms = <100>;
+			focaltech,fw-delay-55-ms = <30>;
+			focaltech,fw-upgrade-id1 = <0x79>;
+			focaltech,fw-upgrade-id2 = <0x08>;
+			focaltech,fw-delay-readid-ms = <10>;
+			focaltech,fw-delay-era-flsh-ms = <2000>;
 		};
 	};
 
@@ -125,13 +135,14 @@
 	};
 
     sound {
-        qcom,audio-routing =
-            "RX_BIAS", "MCLK",
-            "INT_LDO_H", "MCLK",
-            "MIC BIAS Internal1", "Handset Mic",
-            "MIC BIAS Internal2", "Headset Mic",
-            "AMIC1", "MIC BIAS Internal1",
-            "AMIC2", "MIC BIAS Internal2";
+	qcom,audio-routing =
+		"RX_BIAS", "MCLK",
+		"INT_LDO_H", "MCLK",
+		"MIC BIAS Internal1", "Handset Mic",
+		"MIC BIAS Internal2", "Headset Mic",
+		"AMIC1", "MIC BIAS Internal1",
+		"AMIC2", "MIC BIAS Internal2";
+	qcom,mbhc-bias-internal;
     };
 };
 
@@ -139,6 +150,11 @@
 	msm8x10_wcd_codec@0d{
 		compatible = "qcom,msm8x10-wcd-i2c";
 		reg = <0x0d>;
+
+		interrupt-parent = <&wcd9xxx_intc>;
+		interrupts = <0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
+			     17 18 19 20 21 22 23>;
+
 		cdc-vdda-cp-supply = <&pm8110_s4>;
 		qcom,cdc-vdda-cp-voltage = <1800000 2150000>;
 		qcom,cdc-vdda-cp-current = <650000>;
@@ -216,10 +232,9 @@
 				qcom,source-sel = <8>;
 				qcom,mode-ctrl = <0x10>;
 				qcom,pwm-channel = <0>;
-				qcom,pwm-us = <14>;
+				qcom,pwm-us = <27>;
 				qcom,vin-ctrl = <0x03>;
 				qcom,mode = "pwm";
-				qcom,min-brightness = <19>;
 			};
 		};
 	};
@@ -263,8 +278,6 @@
 	qcom,vdd-current-level = <15000 400000>;
 
 	vdd-io-supply = <&pm8110_l21>;
-	qcom,vdd-io-always-on;
-	qcom,vdd-io-lpm-sup;
 	qcom,vdd-io-voltage-level = <1800000 2950000>;
 	qcom,vdd-io-current-level = <200 50000>;
 
@@ -342,3 +355,15 @@
 	mpp@a300 { /* MPP 4 */
 	};
 };
+
+&pm8110_vadc {
+	chan@30 {
+		label = "batt_therm";
+		qcom,scale-function = <6>;
+	};
+};
+
+&android_usb {
+	qcom,android-usb-cdrom;
+	qcom,android-usb-internal-ums;
+};
diff --git a/arch/arm/boot/dts/msm8610-regulator.dtsi b/arch/arm/boot/dts/msm8610-regulator.dtsi
index 34cbd99..eb69678 100644
--- a/arch/arm/boot/dts/msm8610-regulator.dtsi
+++ b/arch/arm/boot/dts/msm8610-regulator.dtsi
@@ -20,6 +20,7 @@
 			reg = <0x1700 0x100>;
 			regulator-min-microvolt = <900000>;
 			regulator-max-microvolt = <1350000>;
+			qcom,mode = "auto";
 		};
 	};
 };
@@ -41,10 +42,15 @@
 		qcom,pvs-fuse = <23 6 5>;
 		qcom,pvs-fuse-redun = <61 47 5>;
 
-		qcom,pvs-bin-process = <1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1
-					1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1>;
-		qcom,pvs-corner-ceiling-slow = <1050000 1150000 1275000>;
-		qcom,pvs-corner-ceiling-nom  = <1050000 1075000 1200000>;
+		qcom,pvs-init-voltage = <1275000 1275000 1275000 1275000 1275000
+					1275000 1275000 1275000 1275000 1275000
+					1275000 1275000 1275000 1275000 1275000
+					1275000 1275000 1275000 1275000 1275000
+					1275000 1275000 1275000 1275000 1275000
+					1275000 1275000 1275000 1275000 1275000
+					1275000 1275000>;
+		qcom,pvs-corner-ceiling-slow = <1150000 1150000 1275000>;
+		qcom,pvs-corner-ceiling-nom  = <1075000 1075000 1200000>;
 		qcom,pvs-corner-ceiling-fast = <1050000 1050000 1140000>;
 		vdd-apc-supply = <&pm8110_s2>;
 
@@ -79,6 +85,7 @@
 		qcom,cpr-fuse-redun-ro-sel = <44 26 29>;
 
 		qcom,cpr-enable;
+		qcom,use-tz-api;
 	};
 };
 
diff --git a/arch/arm/boot/dts/msm8610-sim.dts b/arch/arm/boot/dts/msm8610-sim.dts
index 7c57fe6..33176b9 100644
--- a/arch/arm/boot/dts/msm8610-sim.dts
+++ b/arch/arm/boot/dts/msm8610-sim.dts
@@ -30,6 +30,11 @@
 	msm8x10_wcd_codec@0d{
 		compatible = "qcom,msm8x10-wcd-i2c";
 		reg = <0x0d>;
+
+		interrupt-parent = <&wcd9xxx_intc>;
+		interrupts = <0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
+			      17 18 19 20 21 22 23>;
+
 		cdc-vdda-cp-supply = <&pm8110_s4>;
 		qcom,cdc-vdda-cp-voltage = <2150000 2150000>;
 		qcom,cdc-vdda-cp-current = <650000>;
diff --git a/drivers/gpu/msm/adreno_trace.c b/arch/arm/boot/dts/msm8610-v1-cdp.dts
similarity index 61%
copy from drivers/gpu/msm/adreno_trace.c
copy to arch/arm/boot/dts/msm8610-v1-cdp.dts
index 607ba8c..beb3976 100644
--- a/drivers/gpu/msm/adreno_trace.c
+++ b/arch/arm/boot/dts/msm8610-v1-cdp.dts
@@ -8,11 +8,19 @@
  * 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 "adreno.h"
+/dts-v1/;
 
-/* Instantiate tracepoints */
-#define CREATE_TRACE_POINTS
-#include "adreno_trace.h"
+/include/ "msm8610-v1.dtsi"
+/include/ "msm8610-cdp.dtsi"
+/include/ "msm8610-camera-sensor-cdp-mtp.dtsi"
+
+/ {
+	model = "Qualcomm MSM 8610 CDP";
+	compatible = "qcom,msm8610-cdp", "qcom,msm8610", "qcom,cdp";
+	qcom,msm-id = <147 1 0>, <165 1 0>, <161 1 0>, <162 1 0>,
+		      <163 1 0>, <164 1 0>, <166 1 0>;
+};
+
+
diff --git a/drivers/gpu/msm/adreno_trace.c b/arch/arm/boot/dts/msm8610-v1-mtp.dts
similarity index 61%
copy from drivers/gpu/msm/adreno_trace.c
copy to arch/arm/boot/dts/msm8610-v1-mtp.dts
index 607ba8c..82992a3 100644
--- a/drivers/gpu/msm/adreno_trace.c
+++ b/arch/arm/boot/dts/msm8610-v1-mtp.dts
@@ -8,11 +8,19 @@
  * 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 "adreno.h"
+/dts-v1/;
 
-/* Instantiate tracepoints */
-#define CREATE_TRACE_POINTS
-#include "adreno_trace.h"
+/include/ "msm8610-v1.dtsi"
+/include/ "msm8610-mtp.dtsi"
+/include/ "msm8610-camera-sensor-cdp-mtp.dtsi"
+
+/ {
+	model = "Qualcomm MSM 8610 MTP";
+	compatible = "qcom,msm8610-mtp", "qcom,msm8610", "qcom,mtp";
+	qcom,msm-id = <147 8 0>, <165 8 0>, <161 8 0>, <162 8 0>,
+		      <163 8 0>, <164 8 0>, <166 8 0>;
+};
+
+
diff --git a/arch/arm/boot/dts/msm8610-pm.dtsi b/arch/arm/boot/dts/msm8610-v1-pm.dtsi
similarity index 77%
copy from arch/arm/boot/dts/msm8610-pm.dtsi
copy to arch/arm/boot/dts/msm8610-v1-pm.dtsi
index d31a65c..4a2de1c 100644
--- a/arch/arm/boot/dts/msm8610-pm.dtsi
+++ b/arch/arm/boot/dts/msm8610-v1-pm.dtsi
@@ -24,7 +24,7 @@
 		qcom,saw2-spm-cmd-wfi = [60 03 60 0b 0f];
 		qcom,saw2-spm-cmd-spc = [20 10 80 30 90 5b 60 03 60 3b 76 76
 				0b 94 5b 80 10 26 30 0f];
-		qcom,saw2-spm-cmd-pc = [20 10 80 30 90 5b 60 07 60 3b 76 76
+		qcom,saw2-spm-cmd-pc = [20 10 80 30 90 5b 60 03 60 3b 76 76
 				0b 94 5b 80 10 26 30 0f];
 	};
 
@@ -41,7 +41,7 @@
 		qcom,saw2-spm-cmd-wfi = [60 03 60 0b 0f];
 		qcom,saw2-spm-cmd-spc = [20 10 80 30 90 5b 60 03 60 3b 76 76
 				0b 94 5b 80 10 26 30 0f];
-		qcom,saw2-spm-cmd-pc = [20 10 80 30 90 5b 60 07 60 3b 76 76
+		qcom,saw2-spm-cmd-pc = [20 10 80 30 90 5b 60 03 60 3b 76 76
 				0b 94 5b 80 10 26 30 0f];
 		};
 
@@ -58,7 +58,7 @@
 		qcom,saw2-spm-cmd-wfi = [60 03 60 0b 0f];
 		qcom,saw2-spm-cmd-spc = [00 20 10 80 30 90 5b 60 03 60 3b 76 76
 				0b 94 5b 80 10 06 26 30 0f];
-		qcom,saw2-spm-cmd-pc = [00 20 10 80 30 90 5b 60 07 60 3b 76 76
+		qcom,saw2-spm-cmd-pc = [00 20 10 80 30 90 5b 60 03 60 3b 76 76
 				0b 94 5b 80 10 06 26 30 0f];
 	};
 
@@ -75,7 +75,7 @@
 		qcom,saw2-spm-cmd-wfi = [60 03 60 0b 0f];
 		qcom,saw2-spm-cmd-spc = [20 10 80 30 90 5b 60 03 60 3b 76 76
 				0b 94 5b 80 10 26 30 0f];
-		qcom,saw2-spm-cmd-pc = [20 10 80 30 90 5b 60 07 60 3b 76 76
+		qcom,saw2-spm-cmd-pc = [20 10 80 30 90 5b 60 03 60 3b 76 76
 				0b 94 5b 80 10 26 30 0f];
 	};
 
@@ -99,6 +99,7 @@
 		qcom,saw2-spm-cmd-pc = [00 32 b0 10 e0 d0 6b c0 42 f0
 				11 07 01 b0 50 4e 02 02 c0 d0 12 e0 6b 02 32
 				50 f0 0f]; /*APCS_PMIC_OFF_L2RAM_OFF*/
+		qcom,L2-spm-is-apcs-master;
 	};
 
 	qcom,lpm-levels {
@@ -167,24 +168,42 @@
 			<53 104>, /* mdss_irq */
 			<62 222>, /* ee0_krait_hlos_spmi_periph_irq */
 			<2 216>, /* tsens_upper_lower_int */
+			<41 63>,  /* dino_gen_purpose_irq35 */
+			<0xff 18>,  /* APC_qgicQTmrSecPhysIrptReq */
+			<0xff 19>,  /* APC_qgicQTmrNonSecPhysIrptReq */
+			<0xff 35>,  /* WDT_barkInt */
+			<0xff 40>,  /* qtmr_phy_irq[0] */
+			<0xff 47>,  /* rbif_irq[0] */
 			<0xff 56>,  /* q6_wdog_expired_irq */
 			<0xff 57>,  /* mss_to_apps_irq(0) */
 			<0xff 58>,  /* mss_to_apps_irq(1) */
 			<0xff 59>,  /* mss_to_apps_irq(2) */
 			<0xff 60>,  /* mss_to_apps_irq(3) */
 			<0xff 61>,  /* mss_a2_bam_irq */
+			<0xff 63>,  /* wcd9xxx_irq */
+			<0xff 65>,  /* o_gc_sys_irq[0] */
+			<0xff 74>,  /* venus0_mmu_cirpt[1] */
+			<0xff 75>,  /* venus0_mmu_cirpt[0] */
+			<0xff 78>,  /* mdss_mmu_cirpt[0] */
+			<0xff 79>,  /* mdss_mmu_cirpt[1] */
+			<0xff 97>,  /* camss_vfe_mmu_cirpt[1] */
+			<0xff 102>, /* camss_jpeg_mmu_cirpt[1] */
+			<0xff 109>, /* ocmem_dm_nonsec_irq */
+			<0xff 131>, /* blsp1_qup_5_irq */
+			<0xff 141>, /* blsp1_uart_3_irq */
+			<0xff 155>, /* sdc1_irq(0) */
+			<0xff 157>, /* sdc2_irq(0) */
+			<0xff 161>, /* lpass_irq_out_spare[4] */
+			<0xff 162>, /* lpass_irq_out_spare[5]*/
+			<0xff 170>, /* sdc1_pwr_cmd_irq */
 			<0xff 173>, /* o_wcss_apss_smd_hi */
 			<0xff 174>, /* o_wcss_apss_smd_med */
 			<0xff 175>, /* o_wcss_apss_smd_low */
 			<0xff 176>, /* o_wcss_apss_smsm_irq */
 			<0xff 177>, /* o_wcss_apss_wlan_data_xfer_done */
 			<0xff 178>, /* o_wcss_apss_wlan_rx_data_avail */
-			<0xff 179>, /* o_wcss_apss_asic_intr
+			<0xff 179>, /* o_wcss_apss_asic_intr */
 			<0xff 181>, /* o_wcss_apss_wdog_bite_and_reset_rdy */
-			<0xff 161>, /* lpass_irq_out_spare[4] /
-			<0xff 162>, /* lpass_irq_out_spare[5]*/
-			<0xff 234>, /* lpass_irq_out_spare[6]*/
-			<0xff 235>, /* lpass_irq_out_spare[7]*/
 			<0xff 188>, /* lpass_irq_out_apcs(0) */
 			<0xff 189>, /* lpass_irq_out_apcs(1) */
 			<0xff 190>, /* lpass_irq_out_apcs(2) */
@@ -199,54 +218,56 @@
 			<0xff 205>, /* rpm_ipc(25) */
 			<0xff 206>, /* rpm_ipc(26) */
 			<0xff 207>, /* rpm_ipc(27) */
+			<0xff 234>, /* lpass_irq_out_spare[6]*/
+			<0xff 235>, /* lpass_irq_out_spare[7]*/
+			<0xff 240>, /* summary_irq_kpss */
+			<0xff 253>, /* sdc2_pwr_cmd_irq */
 			<0xff 258>, /* rpm_ipc(28) */
 			<0xff 259>, /* rpm_ipc(29) */
-			<0xff 275>, /* rpm_ipc(30) */
-			<0xff 276>, /* rpm_ipc(31) */
 			<0xff 269>, /* rpm_wdog_expired_irq */
-			<0xff 240>; /* summary_irq_kpss */
+			<0xff 270>, /* blsp1_bam_irq[0] */
+			<0xff 275>, /* rpm_ipc(30) */
+			<0xff 276>; /* rpm_ipc(31) */
 
 		qcom,gpio-parent = <&msmgpio>;
 		qcom,gpio-map = <3  1>,
-			<4  4 >,
-			<5  5 >,
-			<6  9 >,
-			<7  13>,
-			<8  17>,
-			<9  21>,
-			<10  27>,
-			<11  29>,
-			<12  31>,
-			<13  33>,
-			<14  35>,
-			<15  37>,
-			<16  38>,
-			<17  39>,
-			<18  41>,
-			<19  46>,
-			<20  48>,
-			<21  49>,
-			<22  50>,
-			<23  51>,
-			<24  52>,
-			<25  54>,
-			<26  62>,
-			<27  63>,
-			<28  64>,
-			<29  65>,
-			<30  66>,
-			<31  67>,
-			<32  68>,
-			<33  69>,
-			<34  71>,
-			<35  72>,
-			<36  106>,
-			<37  107>,
-			<38  108>,
-			<39  109>,
-			<40  110>,
-			<54  111>,
-			<55  113>;
+			<4  5 >,
+			<5  9 >,
+			<6  14>,
+			<7  15>,
+			<8  32>,
+			<9  33>,
+			<10  34>,
+			<11  35>,
+			<12  41>,
+			<13  42>,
+			<14  72>,
+			<15  73>,
+			<16  74>,
+			<17  75>,
+			<18  76>,
+			<19  77>,
+			<20  78>,
+			<21  79>,
+			<22  80>,
+			<23  81>,
+			<24  82>,
+			<25  83>,
+			<26  84>,
+			<27  85>,
+			<28  87>,
+			<29  90>,
+			<30  91>,
+			<31  92>,
+			<32  93>,
+			<33  94>,
+			<34  95>,
+			<35  96>,
+			<36  97>,
+			<37  98>,
+			<38  99>,
+			<39  100>,
+			<40  101>;
 	};
 
 	qcom,pm-8x60@fe805664 {
@@ -287,4 +308,12 @@
 		reg = <0xfc000000 0x1a0000>;
 		qcom,start-offset = <0x190010>;
 	};
+
+	qcom,rpm-master-stats@fc428150 {
+		compatible = "qcom,rpm-master-stats";
+		reg = <0xfc428150 0x3200>;
+		qcom,masters = "APSS", "MPSS", "LPSS", "PRONTO";
+		qcom,master-stats-version = <2>;
+		qcom,master-offset = <2560>;
+	};
 };
diff --git a/drivers/gpu/msm/adreno_trace.c b/arch/arm/boot/dts/msm8610-v1-qrd-skuaa.dts
similarity index 66%
copy from drivers/gpu/msm/adreno_trace.c
copy to arch/arm/boot/dts/msm8610-v1-qrd-skuaa.dts
index 607ba8c..ec8c4c6 100644
--- a/drivers/gpu/msm/adreno_trace.c
+++ b/arch/arm/boot/dts/msm8610-v1-qrd-skuaa.dts
@@ -8,11 +8,16 @@
  * 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 "adreno.h"
+/dts-v1/;
 
-/* Instantiate tracepoints */
-#define CREATE_TRACE_POINTS
-#include "adreno_trace.h"
+/include/ "msm8610-v1.dtsi"
+/include/ "msm8610-qrd-skuaa.dtsi"
+/include/ "msm8610-qrd-camera-sensor.dtsi"
+
+/ {
+	model = "Qualcomm MSM 8610v1 QRD SKUAA";
+	compatible = "qcom,msm8610-qrd", "qcom,msm8610", "qcom,qrd";
+	qcom,board-id = <11 1>, <11 0>;
+};
diff --git a/drivers/gpu/msm/adreno_trace.c b/arch/arm/boot/dts/msm8610-v1-qrd-skuab.dts
similarity index 67%
copy from drivers/gpu/msm/adreno_trace.c
copy to arch/arm/boot/dts/msm8610-v1-qrd-skuab.dts
index 607ba8c..b3350bb 100644
--- a/drivers/gpu/msm/adreno_trace.c
+++ b/arch/arm/boot/dts/msm8610-v1-qrd-skuab.dts
@@ -8,11 +8,16 @@
  * 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 "adreno.h"
+/dts-v1/;
 
-/* Instantiate tracepoints */
-#define CREATE_TRACE_POINTS
-#include "adreno_trace.h"
+/include/ "msm8610-v1.dtsi"
+/include/ "msm8610-qrd-skuab.dtsi"
+/include/ "msm8612-qrd-camera-sensor.dtsi"
+
+/ {
+	model = "Qualcomm MSM 8610v1 QRD SKUAB";
+	compatible = "qcom,msm8610-qrd", "qcom,msm8610", "qcom,qrd";
+	qcom,board-id = <11 3>;
+};
diff --git a/drivers/gpu/msm/adreno_trace.c b/arch/arm/boot/dts/msm8610-v1.dtsi
similarity index 60%
copy from drivers/gpu/msm/adreno_trace.c
copy to arch/arm/boot/dts/msm8610-v1.dtsi
index 607ba8c..9d8c411 100644
--- a/drivers/gpu/msm/adreno_trace.c
+++ b/arch/arm/boot/dts/msm8610-v1.dtsi
@@ -8,11 +8,18 @@
  * 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 "adreno.h"
+/*
+ * As a general rule, only version-specific property overrides should be placed
+ * inside this file. However, device definitions should be placed inside the
+ * msm8610.dtsi file.
+ */
 
-/* Instantiate tracepoints */
-#define CREATE_TRACE_POINTS
-#include "adreno_trace.h"
+/include/ "msm8610.dtsi"
+/include/ "msm8610-v1-pm.dtsi"
+
+/ {
+	qcom,msm-id = <147 0>, <165 0>, <161 0>, <162 0>,
+			<163 0>, <164 0>, <166 0>;
+};
diff --git a/arch/arm/boot/dts/msm8610-v2-cdp.dts b/arch/arm/boot/dts/msm8610-v2-cdp.dts
new file mode 100644
index 0000000..a6d1d9c
--- /dev/null
+++ b/arch/arm/boot/dts/msm8610-v2-cdp.dts
@@ -0,0 +1,26 @@
+/* Copyright (c) 2013, The Linux Foundation. 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 and
+ * only 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.
+ */
+
+/dts-v1/;
+
+/include/ "msm8610-v2.dtsi"
+/include/ "msm8610-cdp.dtsi"
+/include/ "msm8610-camera-sensor-cdp-mtp.dtsi"
+
+/ {
+	model = "Qualcomm MSM 8610v2 CDP";
+	compatible = "qcom,msm8610-cdp", "qcom,msm8610", "qcom,cdp";
+	qcom,msm-id = <147 1 0x10001>, <165 1 0x10001>, <161 1 0x10001>, <162 1 0x10001>,
+		      <163 1 0x10001>, <164 1 0x10001>, <166 1 0x10001>;
+};
+
+
diff --git a/arch/arm/boot/dts/msm8610-v2-mtp.dts b/arch/arm/boot/dts/msm8610-v2-mtp.dts
new file mode 100644
index 0000000..405a775
--- /dev/null
+++ b/arch/arm/boot/dts/msm8610-v2-mtp.dts
@@ -0,0 +1,26 @@
+/* Copyright (c) 2013, The Linux Foundation. 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 and
+ * only 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.
+ */
+
+/dts-v1/;
+
+/include/ "msm8610-v2.dtsi"
+/include/ "msm8610-mtp.dtsi"
+/include/ "msm8610-camera-sensor-cdp-mtp.dtsi"
+
+/ {
+	model = "Qualcomm MSM 8610v2 MTP";
+	compatible = "qcom,msm8610-mtp", "qcom,msm8610", "qcom,mtp";
+	qcom,msm-id = <147 8 0x10001>, <165 8 0x10001>, <161 8 0x10001>, <162 8 0x10001>,
+		      <163 8 0x10001>, <164 8 0x10001>, <166 8 0x10001>;
+};
+
+
diff --git a/arch/arm/boot/dts/msm8610-pm.dtsi b/arch/arm/boot/dts/msm8610-v2-pm.dtsi
similarity index 87%
rename from arch/arm/boot/dts/msm8610-pm.dtsi
rename to arch/arm/boot/dts/msm8610-v2-pm.dtsi
index d31a65c..079f0b1 100644
--- a/arch/arm/boot/dts/msm8610-pm.dtsi
+++ b/arch/arm/boot/dts/msm8610-v2-pm.dtsi
@@ -24,7 +24,7 @@
 		qcom,saw2-spm-cmd-wfi = [60 03 60 0b 0f];
 		qcom,saw2-spm-cmd-spc = [20 10 80 30 90 5b 60 03 60 3b 76 76
 				0b 94 5b 80 10 26 30 0f];
-		qcom,saw2-spm-cmd-pc = [20 10 80 30 90 5b 60 07 60 3b 76 76
+		qcom,saw2-spm-cmd-pc = [20 10 80 30 90 5b 60 03 60 3b 76 76
 				0b 94 5b 80 10 26 30 0f];
 	};
 
@@ -41,7 +41,7 @@
 		qcom,saw2-spm-cmd-wfi = [60 03 60 0b 0f];
 		qcom,saw2-spm-cmd-spc = [20 10 80 30 90 5b 60 03 60 3b 76 76
 				0b 94 5b 80 10 26 30 0f];
-		qcom,saw2-spm-cmd-pc = [20 10 80 30 90 5b 60 07 60 3b 76 76
+		qcom,saw2-spm-cmd-pc = [20 10 80 30 90 5b 60 03 60 3b 76 76
 				0b 94 5b 80 10 26 30 0f];
 		};
 
@@ -58,7 +58,7 @@
 		qcom,saw2-spm-cmd-wfi = [60 03 60 0b 0f];
 		qcom,saw2-spm-cmd-spc = [00 20 10 80 30 90 5b 60 03 60 3b 76 76
 				0b 94 5b 80 10 06 26 30 0f];
-		qcom,saw2-spm-cmd-pc = [00 20 10 80 30 90 5b 60 07 60 3b 76 76
+		qcom,saw2-spm-cmd-pc = [00 20 10 80 30 90 5b 60 03 60 3b 76 76
 				0b 94 5b 80 10 06 26 30 0f];
 	};
 
@@ -75,7 +75,7 @@
 		qcom,saw2-spm-cmd-wfi = [60 03 60 0b 0f];
 		qcom,saw2-spm-cmd-spc = [20 10 80 30 90 5b 60 03 60 3b 76 76
 				0b 94 5b 80 10 26 30 0f];
-		qcom,saw2-spm-cmd-pc = [20 10 80 30 90 5b 60 07 60 3b 76 76
+		qcom,saw2-spm-cmd-pc = [20 10 80 30 90 5b 60 03 60 3b 76 76
 				0b 94 5b 80 10 26 30 0f];
 	};
 
@@ -96,9 +96,12 @@
 		qcom,phase-port = <0x1>;
 		qcom,pfm-port = <0x2>;
 		qcom,saw2-spm-cmd-ret = [00 03 00 0f];
+		qcom,saw2-spm-cmd-gdhs = [00 20 32 6b c0 e0 d0 42 07 50
+				4e 02 02 d0 e0 c0 22 6b 02 32 50 0f];
 		qcom,saw2-spm-cmd-pc = [00 32 b0 10 e0 d0 6b c0 42 f0
 				11 07 01 b0 50 4e 02 02 c0 d0 12 e0 6b 02 32
 				50 f0 0f]; /*APCS_PMIC_OFF_L2RAM_OFF*/
+		qcom,L2-spm-is-apcs-master;
 	};
 
 	qcom,lpm-levels {
@@ -130,7 +133,7 @@
 		qcom,lpm-level@2 {
 			reg = <0x2>;
 			qcom,mode = "pc";
-			qcom,l2 = "l2_cache_retention";
+			qcom,l2 = "l2_cache_gdhs";
 			qcom,latency-us = <20000>;
 			qcom,ss-power = <138>;
 			qcom,energy-overhead = <1208400>;
@@ -167,12 +170,14 @@
 			<53 104>, /* mdss_irq */
 			<62 222>, /* ee0_krait_hlos_spmi_periph_irq */
 			<2 216>, /* tsens_upper_lower_int */
+			<41 63>,  /* dino_gen_purpose_irq35 */
 			<0xff 56>,  /* q6_wdog_expired_irq */
 			<0xff 57>,  /* mss_to_apps_irq(0) */
 			<0xff 58>,  /* mss_to_apps_irq(1) */
 			<0xff 59>,  /* mss_to_apps_irq(2) */
 			<0xff 60>,  /* mss_to_apps_irq(3) */
 			<0xff 61>,  /* mss_a2_bam_irq */
+			<0xff 63>,  /* wcd9xxx_irq */
 			<0xff 173>, /* o_wcss_apss_smd_hi */
 			<0xff 174>, /* o_wcss_apss_smd_med */
 			<0xff 175>, /* o_wcss_apss_smd_low */
@@ -208,45 +213,43 @@
 
 		qcom,gpio-parent = <&msmgpio>;
 		qcom,gpio-map = <3  1>,
-			<4  4 >,
-			<5  5 >,
-			<6  9 >,
-			<7  13>,
-			<8  17>,
-			<9  21>,
-			<10  27>,
-			<11  29>,
-			<12  31>,
-			<13  33>,
-			<14  35>,
-			<15  37>,
-			<16  38>,
-			<17  39>,
-			<18  41>,
-			<19  46>,
-			<20  48>,
-			<21  49>,
-			<22  50>,
-			<23  51>,
-			<24  52>,
-			<25  54>,
-			<26  62>,
-			<27  63>,
-			<28  64>,
-			<29  65>,
-			<30  66>,
-			<31  67>,
-			<32  68>,
-			<33  69>,
-			<34  71>,
-			<35  72>,
-			<36  106>,
-			<37  107>,
-			<38  108>,
-			<39  109>,
-			<40  110>,
-			<54  111>,
-			<55  113>;
+			<4  5 >,
+			<5  9 >,
+			<6  14>,
+			<7  15>,
+			<8  32>,
+			<9  33>,
+			<10  34>,
+			<11  35>,
+			<12  41>,
+			<13  42>,
+			<14  72>,
+			<15  73>,
+			<16  74>,
+			<17  75>,
+			<18  76>,
+			<19  77>,
+			<20  78>,
+			<21  79>,
+			<22  80>,
+			<23  81>,
+			<24  82>,
+			<25  83>,
+			<26  84>,
+			<27  85>,
+			<28  87>,
+			<29  90>,
+			<30  91>,
+			<31  92>,
+			<32  93>,
+			<33  94>,
+			<34  95>,
+			<35  96>,
+			<36  97>,
+			<37  98>,
+			<38  99>,
+			<39  100>,
+			<40  101>;
 	};
 
 	qcom,pm-8x60@fe805664 {
diff --git a/drivers/gpu/msm/adreno_trace.c b/arch/arm/boot/dts/msm8610-v2-qrd-skuaa.dts
similarity index 66%
copy from drivers/gpu/msm/adreno_trace.c
copy to arch/arm/boot/dts/msm8610-v2-qrd-skuaa.dts
index 607ba8c..44df025 100644
--- a/drivers/gpu/msm/adreno_trace.c
+++ b/arch/arm/boot/dts/msm8610-v2-qrd-skuaa.dts
@@ -8,11 +8,17 @@
  * 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 "adreno.h"
+/dts-v1/;
 
-/* Instantiate tracepoints */
-#define CREATE_TRACE_POINTS
-#include "adreno_trace.h"
+/include/ "msm8610-v2.dtsi"
+/include/ "msm8610-qrd-skuaa.dtsi"
+/include/ "msm8610-qrd-camera-sensor.dtsi"
+
+/ {
+	model = "Qualcomm MSM 8610v2 QRD SKUAA";
+	compatible = "qcom,msm8610-qrd", "qcom,msm8610", "qcom,qrd";
+	qcom,board-id = <11 1>, <11 0>;
+};
+
diff --git a/drivers/gpu/msm/adreno_trace.c b/arch/arm/boot/dts/msm8610-v2-qrd-skuab.dts
similarity index 67%
copy from drivers/gpu/msm/adreno_trace.c
copy to arch/arm/boot/dts/msm8610-v2-qrd-skuab.dts
index 607ba8c..92908fb 100644
--- a/drivers/gpu/msm/adreno_trace.c
+++ b/arch/arm/boot/dts/msm8610-v2-qrd-skuab.dts
@@ -8,11 +8,16 @@
  * 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 "adreno.h"
+/dts-v1/;
 
-/* Instantiate tracepoints */
-#define CREATE_TRACE_POINTS
-#include "adreno_trace.h"
+/include/ "msm8610-v2.dtsi"
+/include/ "msm8610-qrd-skuab.dtsi"
+/include/ "msm8612-qrd-camera-sensor.dtsi"
+
+/ {
+	model = "Qualcomm MSM 8610v2 QRD SKUAB";
+	compatible = "qcom,msm8610-qrd", "qcom,msm8610", "qcom,qrd";
+	qcom,board-id = <11 3>;
+};
diff --git a/arch/arm/boot/dts/msm8610-v2.dtsi b/arch/arm/boot/dts/msm8610-v2.dtsi
new file mode 100644
index 0000000..a1f466a
--- /dev/null
+++ b/arch/arm/boot/dts/msm8610-v2.dtsi
@@ -0,0 +1,25 @@
+/* Copyright (c) 2013, The Linux Foundation. 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 and
+ * only 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.
+ */
+
+/*
+ * As a general rule, only version-specific property overrides should be placed
+ * inside this file. However, device definitions should be placed inside the
+ * msm8610.dtsi file.
+ */
+
+/include/ "msm8610.dtsi"
+/include/ "msm8610-v2-pm.dtsi"
+
+/ {
+	qcom,msm-id = <147 0x10001>, <165 0x10001>, <161 0x10001>, <162 0x10001>,
+				  <163 0x10001>, <164 0x10001>, <166 0x10001>;
+};
diff --git a/arch/arm/boot/dts/msm8610.dtsi b/arch/arm/boot/dts/msm8610.dtsi
index 60528ee..7dcb985 100644
--- a/arch/arm/boot/dts/msm8610.dtsi
+++ b/arch/arm/boot/dts/msm8610.dtsi
@@ -40,7 +40,6 @@
 /include/ "msm8610-gpu.dtsi"
 /include/ "msm-gdsc.dtsi"
 /include/ "msm8610-coresight.dtsi"
-/include/ "msm8610-pm.dtsi"
 /include/ "msm8610-smp2p.dtsi"
 /include/ "msm8610-bus.dtsi"
 /include/ "msm8610-mdss.dtsi"
@@ -70,6 +69,15 @@
 		qcom,direct-connect-irqs = <8>;
 	};
 
+	wcd9xxx_intc: wcd9xxx_irq {
+		compatible = "qcom,wcd9xxx-irq";
+		interrupt-controller;
+		#interrupt-cells = <1>;
+		interrupt-parent = <&intc>;
+		interrupts = <0 31 0>;
+		interrupt-names = "cdc-int";
+	};
+
 	qcom,mpm2-sleep-counter@fc4a3000 {
 		compatible = "qcom,mpm2-sleep-counter";
 		reg = <0xfc4a3000 0x1000>;
@@ -176,7 +184,7 @@
 		qcom,buffer-type-tz-usage-map = <0x1 0x1>,
 						<0x1fe 0x2>;
 		qcom,hfi = "q6";
-		qcom,max-hw-load = <108000>; /* 720p @ 30 * 1 */
+		qcom,max-hw-load = <244800>; /* 1080p @ 30 * 1 */
 		qcom,vidc-iommu-domains {
 			qcom,domain-ns {
 				qcom,vidc-domain-phandle = <&q6_domain_ns>;
@@ -241,7 +249,7 @@
 				<87 512 60000 960000>;
 	};
 
-	android_usb@fe8050c8 {
+	android_usb: android_usb@fe8050c8 {
 		compatible = "qcom,android-usb";
 		reg = <0xfe8050c8 0xc8>;
 		qcom,android-usb-swfi-latency = <1>;
@@ -470,6 +478,7 @@
 		qcom,i2c-src-freq = <19200000>;
 		qcom,sda-gpio = <&msmgpio 2 0>;
 		qcom,scl-gpio = <&msmgpio 3 0>;
+                qcom,master-id = <86>;
 	};
 
 	i2c_cdc: i2c@f9927000 { /* BLSP1 QUP5 */
@@ -482,6 +491,8 @@
                 interrupt-names = "qup_err_intr";
                 interrupts = <0 99 0>;
                 qcom,i2c-bus-freq = <100000>;
+                qcom,i2c-src-freq = <19200000>;
+                qcom,master-id = <86>;
         };
 
 	i2c: i2c@f9928000 { /* BLSP1 QUP6 */
@@ -497,6 +508,7 @@
 		qcom,i2c-src-freq = <19200000>;
 		qcom,sda-gpio = <&msmgpio 16 0>;
 		qcom,scl-gpio = <&msmgpio 17 0>;
+                qcom,master-id = <86>;
 	};
 
 	i2c@f9925000 { /* BLSP-1 QUP-3 */
@@ -509,6 +521,10 @@
 		interrupt-names = "qup_err_intr";
 		interrupts = <0 97 0>;
 		qcom,i2c-bus-freq = <100000>;
+                qcom,i2c-src-freq = <19200000>;
+                qcom,sda-gpio = <&msmgpio 10 0>;
+                qcom,scl-gpio = <&msmgpio 11 0>;
+                qcom,master-id = <86>;
 	};
 
 	spi_4: spi@f9926000 { /* BLSP1 QUP4 */
@@ -927,10 +943,12 @@
 };
 
 &gdsc_vfe {
+	qcom,clock-names = "core_clk", "iface_clk", "bus_clk";
 	status = "ok";
 };
 
 &gdsc_oxili_cx {
+	qcom,clock-names = "core_clk", "iface_clk", "mem_clk";
 	status = "ok";
 };
 
diff --git a/arch/arm/boot/dts/msm8612-qrd-camera-sensor.dtsi b/arch/arm/boot/dts/msm8612-qrd-camera-sensor.dtsi
index 25554eb..b060abe 100644
--- a/arch/arm/boot/dts/msm8612-qrd-camera-sensor.dtsi
+++ b/arch/arm/boot/dts/msm8612-qrd-camera-sensor.dtsi
@@ -53,7 +53,7 @@
 		qcom,slave-id = <0x42 0x00 0xc8>;
 		qcom,csiphy-sd-index = <1>;
 		qcom,csid-sd-index = <1>;
-		qcom,mount-angle = <90>;
+		qcom,mount-angle = <270>;
 		qcom,sensor-name = "skuab_shinetech_gc0339";
 		cam_vdig-supply = <&pm8110_l14>;
 		cam_vana-supply = <&pm8110_l19>;
diff --git a/arch/arm/boot/dts/msm8926-camera-sensor-qrd.dtsi b/arch/arm/boot/dts/msm8926-camera-sensor-qrd.dtsi
new file mode 100644
index 0000000..a85e048
--- /dev/null
+++ b/arch/arm/boot/dts/msm8926-camera-sensor-qrd.dtsi
@@ -0,0 +1,115 @@
+/*
+ * Copyright (c) 2013, The Linux Foundation. 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 and
+ * only 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.
+ */
+
+&soc {
+
+	led_flash0: qcom,camera-led-flash {
+		cell-index = <0>;
+		compatible = "qcom,camera-led-flash";
+		qcom,flash-type = <1>;
+		qcom,flash-source = <&pm8226_flash0 &pm8226_flash1>;
+		qcom,torch-source = <&pm8226_torch>;
+	};
+};
+
+&cci {
+
+	actuator0: qcom,actuator@6e {
+		cell-index = <5>;
+		reg = <0x18>;
+		compatible = "qcom,actuator";
+		qcom,cci-master = <0>;
+	};
+
+	qcom,camera@20 {
+		compatible = "ovti,ov8865";
+		reg = <0x20>;
+		qcom,slave-id = <0x20 0x300b 0x8865>;
+		qcom,csiphy-sd-index = <0>;
+		qcom,csid-sd-index = <0>;
+		qcom,actuator-src = <&actuator0>;
+		qcom,led-flash-src = <&led_flash0>;
+		qcom,mount-angle = <90>;
+		qcom,sensor-name = "ov8865_q8v18a";
+		cam_vdig-supply = <&pm8226_l5>;
+		cam_vana-supply = <&pm8226_l19>;
+		cam_vio-supply = <&pm8226_lvs1>;
+		cam_vaf-supply = <&pm8226_l15>;
+		qcom,cam-vreg-name = "cam_vdig", "cam_vio", "cam_vana",
+		                                         "cam_vaf";
+		qcom,cam-vreg-type = <0 1 0 0>;
+		qcom,cam-vreg-min-voltage = <1200000 0 2850000 2800000>;
+		qcom,cam-vreg-max-voltage = <1200000 0 2850000 2800000>;
+		qcom,cam-vreg-op-mode = <200000 0 80000 100000>;
+		qcom,gpio-no-mux = <0>;
+		gpios = <&msmgpio 26 0>,
+		        <&msmgpio 37 0>,
+		        <&msmgpio 36 0>,
+		        <&msmgpio 15 0>;
+		qcom,gpio-reset = <1>;
+		qcom,gpio-standby = <2>;
+		qcom,gpio-af-pwdm = <3>;
+		qcom,gpio-req-tbl-num = <0 1 2 3>;
+		qcom,gpio-req-tbl-flags = <1 0 0 0>;
+		qcom,gpio-req-tbl-label = "CAMIF_MCLK",
+		        "CAM_RESET1",
+		        "CAM_STANDBY",
+		        "CAM_AF_PWDM";
+		qcom,csi-lane-assign = <0x4320>;
+		qcom,csi-lane-mask = <0x1F>;
+		qcom,sensor-position = <0>;
+		qcom,sensor-mode = <1>;
+		qcom,cci-master = <0>;
+	};
+
+	qcom,camera@6a {
+		compatible = "ovti,ov5648";
+		reg = <0x6a>;
+		qcom,slave-id = <0x6c 0x300a 0x5648>;
+		qcom,csiphy-sd-index = <1>;
+		qcom,csid-sd-index = <1>;
+		qcom,mount-angle = <270>;
+		qcom,sensor-name = "ov5648_oty5f03";
+		cam_vdig-supply = <&pm8226_l5>;
+		cam_vana-supply = <&pm8226_l19>;
+		cam_vio-supply = <&pm8226_lvs1>;
+		qcom,cam-vreg-name = "cam_vdig", "cam_vio", "cam_vana";
+		qcom,cam-vreg-type = <0 1 0>;
+		qcom,cam-vreg-min-voltage = <1200000 0 2850000>;
+		qcom,cam-vreg-max-voltage = <1200000 0 2850000>;
+		qcom,cam-vreg-op-mode = <200000 0 80000>;
+		qcom,gpio-no-mux = <0>;
+		gpios = <&msmgpio 26 0>,
+				<&msmgpio 28 0>,
+				<&msmgpio 35 0>,
+				<&msmgpio 23 0>;
+		qcom,gpio-reset = <1>;
+		qcom,gpio-standby = <2>;
+		qcom,gpio-vdig = <3>;
+		qcom,gpio-req-tbl-num = <0 1 2 3>;
+		qcom,gpio-req-tbl-flags = <1 0 0 0>;
+		qcom,gpio-req-tbl-label = "CAMIF_MCLK",
+				"CAM_RESET",
+				"CAM_STANDBY",
+				"CAM_VDIG";
+		qcom,gpio-set-tbl-num = <1 1>;
+		qcom,gpio-set-tbl-flags = <0 2>;
+		qcom,gpio-set-tbl-delay = <1000 4000>;
+		qcom,csi-lane-assign = <0x4320>;
+		qcom,csi-lane-mask = <0x3>;
+		qcom,sensor-position = <1>;
+		qcom,sensor-mode = <1>;
+		qcom,cci-master = <0>;
+		status = "ok";
+	};
+};
diff --git a/arch/arm/boot/dts/msm8926-cdp.dts b/arch/arm/boot/dts/msm8926-cdp.dts
index 48d3ea9..7d8d6cf 100644
--- a/arch/arm/boot/dts/msm8926-cdp.dts
+++ b/arch/arm/boot/dts/msm8926-cdp.dts
@@ -19,7 +19,7 @@
 / {
 	model = "Qualcomm MSM 8926 CDP";
 	compatible = "qcom,msm8926-cdp", "qcom,msm8926", "qcom,cdp";
-	qcom,msm-id = <200 1 0>;
+	qcom,board-id = <1 0>;
 };
 
 &pm8226_chg {
diff --git a/arch/arm/boot/dts/msm8926-mtp.dts b/arch/arm/boot/dts/msm8926-mtp.dts
index dc6e60e..624781b 100644
--- a/arch/arm/boot/dts/msm8926-mtp.dts
+++ b/arch/arm/boot/dts/msm8926-mtp.dts
@@ -19,5 +19,5 @@
 / {
 	model = "Qualcomm MSM 8926 MTP";
 	compatible = "qcom,msm8926-mtp", "qcom,msm8926", "qcom,mtp";
-	qcom,msm-id = <200 8 0>;
+	qcom,board-id = <8 0>;
 };
diff --git a/arch/arm/boot/dts/msm8926-qrd-skug.dts b/arch/arm/boot/dts/msm8926-qrd-skug.dts
new file mode 100644
index 0000000..a366205
--- /dev/null
+++ b/arch/arm/boot/dts/msm8926-qrd-skug.dts
@@ -0,0 +1,90 @@
+/* Copyright (c) 2013, The Linux Foundation. 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 and
+ * only 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.
+ */
+
+/dts-v1/;
+/include/ "msm8926.dtsi"
+/include/ "msm8226-qrd.dtsi"
+/include/ "msm8926-camera-sensor-qrd.dtsi"
+
+/ {
+	model = "Qualcomm MSM 8926 QRD SKUG";
+	compatible = "qcom,msm8926-qrd", "qcom,msm8926", "qcom,qrd";
+	qcom,board-id = <11 5>;
+};
+
+&qrd_batterydata {
+	qcom,rpull-up-kohm = <100>;
+	qcom,vref-batt-therm = <1800000>;
+
+	/include/ "batterydata-qrd-4v2-2000mah.dtsi"
+};
+
+&pm8226_bms {
+	qcom,battery-data = <&qrd_batterydata>;
+};
+
+&pm8226_chg {
+	qcom,battery-data = <&qrd_batterydata>;
+};
+
+&soc {
+	i2c@f9927000 { /* BLSP1 QUP5 */
+		focaltech@38 {
+			compatible = "focaltech,5x06";
+			reg = <0x38>;
+			interrupt-parent = <&msmgpio>;
+			interrupts = <17 0x2>;
+			vdd-supply = <&pm8226_l19>;
+			vcc_i2c-supply = <&pm8226_lvs1>;
+			focaltech,name = "ft5336";
+			focaltech,family-id = <0x14>;
+			focaltech,reset-gpio = <&msmgpio 16 0x00>;
+			focaltech,irq-gpio = <&msmgpio 17 0x00>;
+			focaltech,display-coords = <0 0 720 1280>;
+			focaltech,panel-coords = <0 0 720 1400>;
+			focaltech,button-map= <139 102 158>;
+			focaltech,no-force-update;
+			focaltech,i2c-pull-up;
+			focaltech,group-id = <1>;
+			focaltech,hard-reset-delay-ms = <20>;
+			focaltech,soft-reset-delay-ms = <200>;
+			focaltech,num-max-touches = <5>;
+			focaltech,fw-name = "ft_8926_qrd_fw.bin";
+			focaltech,fw-delay-aa-ms = <30>;
+			focaltech,fw-delay-55-ms = <30>;
+			focaltech,fw-upgrade-id1 = <0x79>;
+			focaltech,fw-upgrade-id2 = <0x08>;
+			focaltech,fw-delay-readid-ms = <10>;
+			focaltech,fw-delay-era-flsh-ms = <2000>;
+			focaltech,fw-auto-cal;
+		};
+	};
+
+	gen-vkeys {
+		compatible = "qcom,gen-vkeys";
+		label = "ft5x06_ts";
+		qcom,disp-maxx = <720>;
+		qcom,disp-maxy = <1280>;
+		qcom,panel-maxx = <720>;
+		qcom,panel-maxy = <1404>;
+		qcom,key-codes = <139 172 158>;
+		qcom,y-offset = <0>;
+	};
+};
+
+&mdss_dsi0 {
+	qcom,dsi-pref-prim-pan = <&dsi_ssd2080m_720_vid>;
+};
+
+&dsi_ssd2080m_720_vid {
+	qcom,cont-splash-enabled;
+};
diff --git a/arch/arm/boot/dts/msm8926-qrd.dts b/arch/arm/boot/dts/msm8926-qrd.dts
index e056b7e..8ee8828 100644
--- a/arch/arm/boot/dts/msm8926-qrd.dts
+++ b/arch/arm/boot/dts/msm8926-qrd.dts
@@ -17,5 +17,5 @@
 / {
 	model = "Qualcomm MSM 8926 QRD";
 	compatible = "qcom,msm8926-qrd", "qcom,msm8926", "qcom,qrd";
-	qcom,msm-id = <200 11 0>;
+	qcom,board-id = <11 0>;
 };
diff --git a/arch/arm/boot/dts/msm8926.dtsi b/arch/arm/boot/dts/msm8926.dtsi
index f46b714..2ab272a 100644
--- a/arch/arm/boot/dts/msm8926.dtsi
+++ b/arch/arm/boot/dts/msm8926.dtsi
@@ -17,11 +17,15 @@
  */
 
 /include/ "msm8226.dtsi"
-/include/ "msm8226-camera.dtsi"
+/include/ "msm8226-v2-pm.dtsi"
 
 / {
 	model = "Qualcomm MSM 8926";
 	compatible = "qcom,msm8926";
+	qcom,msm-id = <200 0>,
+		      <224 0>,
+		      <200 0x10001>,
+		      <224 0x10001>;
 };
 
 &soc {
@@ -44,30 +48,35 @@
 
 &pm8226_l3 {
 	regulator-min-microvolt = <750000>;
-	regulator-max-microvolt = <1287500>;
+	regulator-max-microvolt = <1350000>;
 };
 
 &pm8226_l3_ao {
 	regulator-min-microvolt = <750000>;
-	regulator-max-microvolt = <1287500>;
+	regulator-max-microvolt = <1350000>;
 };
 
 &pm8226_l3_so {
 	regulator-min-microvolt = <750000>;
-	regulator-max-microvolt = <1287500>;
+	regulator-max-microvolt = <1350000>;
 };
 
 &pm8226_s2 {
 	regulator-min-microvolt = <900000>;
-	regulator-max-microvolt = <1280000>;
+	regulator-max-microvolt = <1350000>;
 };
 
 &apc_vreg_corner {
-	qcom,pvs-bin-process = <1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 2
-				2 2 2 2 2 3 3 3 3 3 3 3 3 3 3 3>;
-	qcom,pvs-corner-ceiling-slow = <1160000 1160000 1280000>;
-	qcom,pvs-corner-ceiling-nom  =  <980000 1080000 1200000>;
-	qcom,pvs-corner-ceiling-fast =  <900000 1000000 1140000>;
+	qcom,pvs-init-voltage = <1350000 1340000 1330000 1320000 1310000
+					1300000 1290000 1280000 1270000 1260000
+					1250000 1240000 1230000 1220000 1210000
+					1200000 1190000 1180000 1170000 1160000
+					1150000 1140000 1140000 1140000 1140000
+					1140000 1140000 1140000 1140000 1140000
+					1140000 1140000>;
+	qcom,pvs-corner-ceiling-slow = <1050000 1150000 1280000>;
+	qcom,pvs-corner-ceiling-nom  = <1050000 1080000 1200000>;
+	qcom,pvs-corner-ceiling-fast = <1050000 1050000 1140000>;
 	qcom,cpr-step-quotient = <30>;
 	qcom,cpr-up-threshold = <0>;
 	qcom,cpr-down-threshold = <5>;
@@ -78,3 +87,12 @@
 	qcom,sensors = <6>;
 	qcom,slope = <2901 2846 3038 2955 2901 2846>;
 };
+
+&msmgpio {
+	ngpio = <120>;
+};
+
+&memory_hole {
+	qcom,memblock-remove = <0x08000000 0x7500000
+				0x0fa00000 0x500000>; /* Address and size of the hole */
+};
diff --git a/arch/arm/boot/dts/msm8974-camera-sensor-cdp.dtsi b/arch/arm/boot/dts/msm8974-camera-sensor-cdp.dtsi
index 26c5b8f..9948833 100644
--- a/arch/arm/boot/dts/msm8974-camera-sensor-cdp.dtsi
+++ b/arch/arm/boot/dts/msm8974-camera-sensor-cdp.dtsi
@@ -36,8 +36,6 @@
 		qcom,actuator-src = <&actuator0>;
 		qcom,mount-angle = <90>;
 		qcom,sensor-name = "s5k3l1yx";
-		qcom,vdd-cx-supply = <&pm8841_s2>;
-		qcom,vdd-cx-name = "qcom,vdd-cx";
 		cam_vdig-supply = <&pm8941_l3>;
 		cam_vana-supply = <&pm8941_l17>;
 		cam_vio-supply = <&pm8941_lvs3>;
@@ -79,8 +77,6 @@
 		qcom,mount-angle = <90>;
 		qcom,sensor-name = "imx135";
 		qcom,actuator-src = <&actuator1>;
-		qcom,vdd-cx-supply = <&pm8841_s2>;
-		qcom,vdd-cx-name = "qcom,vdd-cx";
 		cam_vdig-supply = <&pm8941_l3>;
 		cam_vana-supply = <&pm8941_l17>;
 		cam_vio-supply = <&pm8941_lvs3>;
@@ -122,8 +118,6 @@
 		qcom,csid-sd-index = <2>;
 		qcom,mount-angle = <90>;
 		qcom,sensor-name = "ov2720";
-		qcom,vdd-cx-supply = <&pm8841_s2>;
-		qcom,vdd-cx-name = "qcom,vdd-cx";
 		cam_vdig-supply = <&pm8941_l3>;
 		cam_vana-supply = <&pm8941_l17>;
 		cam_vio-supply = <&pm8941_lvs3>;
@@ -159,8 +153,6 @@
 		qcom,csid-sd-index = <0>;
 		qcom,mount-angle = <0>;
 		qcom,sensor-name = "mt9m114";
-		qcom,vdd-cx-supply = <&pm8841_s2>;
-		qcom,vdd-cx-name = "qcom,vdd-cx";
 		cam_vdig-supply = <&pm8941_l3>;
 		cam_vana-supply = <&pm8941_l17>;
 		cam_vio-supply = <&pm8941_lvs3>;
diff --git a/arch/arm/boot/dts/msm8974-camera-sensor-fluid.dtsi b/arch/arm/boot/dts/msm8974-camera-sensor-fluid.dtsi
index f61b83a..9cbd45c 100644
--- a/arch/arm/boot/dts/msm8974-camera-sensor-fluid.dtsi
+++ b/arch/arm/boot/dts/msm8974-camera-sensor-fluid.dtsi
@@ -37,8 +37,6 @@
 		qcom,led-flash-src = <&led_flash0>;
 		qcom,mount-angle = <270>;
 		qcom,sensor-name = "s5k3l1yx";
-		qcom,vdd-cx-supply = <&pm8841_s2>;
-		qcom,vdd-cx-name = "qcom,vdd-cx";
 		cam_vdig-supply = <&pm8941_l3>;
 		cam_vana-supply = <&pm8941_l17>;
 		cam_vio-supply = <&pm8941_lvs3>;
@@ -80,8 +78,6 @@
 		qcom,mount-angle = <270>;
 		qcom,sensor-name = "imx135";
 		qcom,actuator-src = <&actuator1>;
-		qcom,vdd-cx-supply = <&pm8841_s2>;
-		qcom,vdd-cx-name = "qcom,vdd-cx";
 		cam_vdig-supply = <&pm8941_l3>;
 		cam_vana-supply = <&pm8941_l17>;
 		cam_vio-supply = <&pm8941_lvs3>;
@@ -123,8 +119,6 @@
 		qcom,csid-sd-index = <2>;
 		qcom,mount-angle = <90>;
 		qcom,sensor-name = "ov2720";
-		qcom,vdd-cx-supply = <&pm8841_s2>;
-		qcom,vdd-cx-name = "qcom,vdd-cx";
 		cam_vdig-supply = <&pm8941_l3>;
 		cam_vana-supply = <&pm8941_l17>;
 		cam_vio-supply = <&pm8941_lvs3>;
@@ -160,8 +154,6 @@
 		qcom,csid-sd-index = <0>;
 		qcom,mount-angle = <0>;
 		qcom,sensor-name = "mt9m114";
-		qcom,vdd-cx-supply = <&pm8841_s2>;
-		qcom,vdd-cx-name = "qcom,vdd-cx";
 		cam_vdig-supply = <&pm8941_l3>;
 		cam_vana-supply = <&pm8941_l17>;
 		cam_vio-supply = <&pm8941_lvs3>;
diff --git a/arch/arm/boot/dts/msm8974-camera-sensor-liquid.dtsi b/arch/arm/boot/dts/msm8974-camera-sensor-liquid.dtsi
index cf968d2..bf7f492 100644
--- a/arch/arm/boot/dts/msm8974-camera-sensor-liquid.dtsi
+++ b/arch/arm/boot/dts/msm8974-camera-sensor-liquid.dtsi
@@ -37,8 +37,6 @@
 		qcom,mount-angle = <0>;
 		qcom,actuator-src = <&actuator0>;
 		qcom,sensor-name = "s5k3l1yx";
-		qcom,vdd-cx-supply = <&pm8841_s2>;
-		qcom,vdd-cx-name = "qcom,vdd-cx";
 		cam_vdig-supply = <&pm8941_l3>;
 		cam_vana-supply = <&pm8941_l17>;
 		cam_vio-supply = <&pm8941_lvs2>;
@@ -79,8 +77,6 @@
 		qcom,csid-sd-index = <0>;
 		qcom,mount-angle = <0>;
 		qcom,sensor-name = "imx135";
-		qcom,vdd-cx-supply = <&pm8841_s2>;
-		qcom,vdd-cx-name = "qcom,vdd-cx";
 		qcom,actuator-src = <&actuator1>;
 		cam_vdig-supply = <&pm8941_l3>;
 		cam_vana-supply = <&pm8941_l17>;
@@ -123,8 +119,6 @@
 		qcom,csid-sd-index = <0>;
 		qcom,mount-angle = <180>;
 		qcom,sensor-name = "ov2720";
-		qcom,vdd-cx-supply = <&pm8841_s2>;
-		qcom,vdd-cx-name = "qcom,vdd-cx";
 		cam_vdig-supply = <&pm8941_l3>;
 		cam_vana-supply = <&pm8941_l17>;
 		cam_vio-supply = <&pm8941_lvs2>;
@@ -159,8 +153,6 @@
 		qcom,csiphy-sd-index = <1>;
 		qcom,csid-sd-index = <0>;
 		qcom,mount-angle = <0>;
-		qcom,vdd-cx-supply = <&pm8841_s2>;
-		qcom,vdd-cx-name = "qcom,vdd-cx";
 		qcom,sensor-name = "mt9m114";
 		cam_vdig-supply = <&pm8941_l3>;
 		cam_vana-supply = <&pm8941_l17>;
diff --git a/arch/arm/boot/dts/msm8974-camera-sensor-mtp.dtsi b/arch/arm/boot/dts/msm8974-camera-sensor-mtp.dtsi
index 6ad6213..68af4a6 100644
--- a/arch/arm/boot/dts/msm8974-camera-sensor-mtp.dtsi
+++ b/arch/arm/boot/dts/msm8974-camera-sensor-mtp.dtsi
@@ -37,8 +37,6 @@
 		qcom,led-flash-src = <&led_flash0>;
 		qcom,mount-angle = <90>;
 		qcom,sensor-name = "s5k3l1yx";
-		qcom,vdd-cx-supply = <&pm8841_s2>;
-		qcom,vdd-cx-name = "qcom,vdd-cx";
 		cam_vdig-supply = <&pm8941_l3>;
 		cam_vana-supply = <&pm8941_l17>;
 		cam_vio-supply = <&pm8941_lvs3>;
@@ -79,8 +77,6 @@
 		qcom,csid-sd-index = <0>;
 		qcom,mount-angle = <90>;
 		qcom,sensor-name = "imx135";
-		qcom,vdd-cx-supply = <&pm8841_s2>;
-		qcom,vdd-cx-name = "qcom,vdd-cx";
 		qcom,actuator-src = <&actuator1>;
 		cam_vdig-supply = <&pm8941_l3>;
 		cam_vana-supply = <&pm8941_l17>;
@@ -124,8 +120,6 @@
 		qcom,csid-sd-index = <2>;
 		qcom,mount-angle = <90>;
 		qcom,sensor-name = "ov2720";
-		qcom,vdd-cx-supply = <&pm8841_s2>;
-		qcom,vdd-cx-name = "qcom,vdd-cx";
 		cam_vdig-supply = <&pm8941_l3>;
 		cam_vana-supply = <&pm8941_l17>;
 		cam_vio-supply = <&pm8941_lvs3>;
@@ -161,8 +155,6 @@
 		qcom,csid-sd-index = <0>;
 		qcom,mount-angle = <0>;
 		qcom,sensor-name = "mt9m114";
-		qcom,vdd-cx-supply = <&pm8841_s2>;
-		qcom,vdd-cx-name = "qcom,vdd-cx";
 		cam_vdig-supply = <&pm8941_l3>;
 		cam_vana-supply = <&pm8941_l17>;
 		cam_vio-supply = <&pm8941_lvs3>;
diff --git a/arch/arm/boot/dts/msm8974-camera.dtsi b/arch/arm/boot/dts/msm8974-camera.dtsi
index 1413e0c..610f237 100644
--- a/arch/arm/boot/dts/msm8974-camera.dtsi
+++ b/arch/arm/boot/dts/msm8974-camera.dtsi
@@ -107,8 +107,9 @@
 		cell-index = <0>;
 		compatible = "qcom,vfe40";
 		reg = <0xfda10000 0x1000>,
-			<0xfda40000 0x200>;
-		reg-names = "vfe", "vfe_vbif";
+			<0xfda40000 0x200>,
+			<0xfd4a8000 0x4>;
+		reg-names = "vfe", "vfe_vbif", "tcsr";
 		interrupts = <0 57 0>;
 		interrupt-names = "vfe";
 		vdd-supply = <&gdsc_vfe>;
@@ -118,8 +119,9 @@
 		cell-index = <1>;
 		compatible = "qcom,vfe40";
 		reg = <0xfda14000 0x1000>,
-			<0xfda40000 0x200>;
-		reg-names = "vfe", "vfe_vbif";
+			<0xfda40000 0x200>,
+			<0xfd4a8000 0x4>;
+		reg-names = "vfe", "vfe_vbif", "tcsr";
 		interrupts = <0 58 0>;
 		interrupt-names = "vfe";
 		vdd-supply = <&gdsc_vfe>;
@@ -167,7 +169,7 @@
 		compatible = "qcom,cpp";
 		reg = <0xfda04000 0x100>,
 			<0xfda40000 0x200>,
-			<0xfda18000 0x008>;
+			<0xfda18000 0x018>;
 		reg-names = "cpp", "cpp_vbif", "cpp_hw";
 		interrupts = <0 49 0>;
 		interrupt-names = "cpp";
@@ -179,6 +181,7 @@
 		compatible = "qcom,camera-led-flash";
 		qcom,flash-type = <1>;
 		qcom,flash-source = <&pm8941_flash0 &pm8941_flash1>;
+		qcom,torch-source = <&pm8941_torch>;
 	};
 
 	cci: qcom,cci@fda0C000 {
diff --git a/arch/arm/boot/dts/msm8974-cdp.dtsi b/arch/arm/boot/dts/msm8974-cdp.dtsi
index a4f512a..9e7b2e6 100644
--- a/arch/arm/boot/dts/msm8974-cdp.dtsi
+++ b/arch/arm/boot/dts/msm8974-cdp.dtsi
@@ -10,8 +10,6 @@
  * GNU General Public License for more details.
  */
 
-/include/ "dsi-panel-toshiba-720p-video.dtsi"
-/include/ "dsi-panel-orise-720p-video.dtsi"
 /include/ "msm8974-leds.dtsi"
 /include/ "msm8974-camera-sensor-cdp.dtsi"
 
@@ -26,9 +24,12 @@
 		status = "ok";
 	};
 
-	qcom,mdss_dsi_toshiba_720p_video {
-		status = "ok";
-		qcom,cont-splash-enabled;
+	qcom,mdss_dsi@fd922800 {
+		qcom,dsi-pref-prim-pan = <&dsi_tosh_720_vid>;
+	};
+
+	qcom,mdss_mdp@fd900000 {
+		qcom,mdss-pref-prim-intf = "dsi";
 	};
 
 	qcom,mdss_dsi_orise_720p_video {
@@ -40,6 +41,22 @@
 	};
 
 	i2c@f9924000 {
+		synaptics@20 {
+			compatible = "synaptics,rmi4";
+			reg = <0x20>;
+			interrupt-parent = <&msmgpio>;
+			interrupts = <61 0x2008>;
+			vdd-supply = <&pm8941_l18>;
+			vcc_i2c-supply = <&pm8941_lvs1>;
+			synaptics,reset-gpio = <&msmgpio 60 0x00>;
+			synaptics,irq-gpio = <&msmgpio 61 0x2008>;
+			synaptics,display-coords = <0 0 1079 1919>;
+			synaptics,i2c-pull-up;
+			synaptics,power-down;
+			synaptics,disable-gpios;
+			synaptics,do-lockdown;
+		};
+
 		atmel_mxt_ts@4a {
 			compatible = "atmel,mxt-ts";
 			reg = <0x4a>;
@@ -226,7 +243,7 @@
 			1 &intc 0 148 0
 			2 &msmgpio 144 0x8>;
 		interrupt-names = "core_irq", "async_irq", "wakeup";
-		HSIC_VDDCX-supply = <&pm8841_s2>;
+		hsic_vdd_dig-supply = <&pm8841_s2_corner>;
 		HSIC_GDSC-supply = <&gdsc_usb_hsic>;
 		hsic,strobe-gpio = <&msmgpio 144 0x00>;
 		hsic,data-gpio = <&msmgpio 145 0x00>;
@@ -234,6 +251,8 @@
 		hsic,ignore-cal-pad-config;
 		hsic,strobe-pad-offset = <0x2050>;
 		hsic,data-pad-offset = <0x2054>;
+		qcom,phy-susp-sof-workaround;
+		hsic,vdd-voltage-level = <1 5 7>;
 
 		qcom,msm-bus,name = "hsic";
 		qcom,msm-bus,num-cases = <2>;
@@ -270,11 +289,11 @@
 			qcom,default-state = "on";
 			qcom,max-current = <25>;
 			qcom,ctrl-delay-us = <0>;
-			qcom,boost-curr-lim = <3>;
+			qcom,boost-curr-lim = <5>;
 			qcom,cp-sel = <0>;
 			qcom,switch-freq = <11>;
 			qcom,ovp-val = <2>;
-			qcom,num-strings = <1>;
+			qcom,num-strings = <3>;
 			qcom,id = <0>;
 		};
 	};
@@ -734,3 +753,7 @@
 		qcom,cdc-on-demand-supplies = "cdc-vdd-spkdrv";
 	};
 };
+
+&dsi_tosh_720_vid {
+       qcom,cont-splash-enabled;
+};
diff --git a/arch/arm/boot/dts/msm8974-coresight.dtsi b/arch/arm/boot/dts/msm8974-coresight.dtsi
index 9fd0cd9..a809c2b 100644
--- a/arch/arm/boot/dts/msm8974-coresight.dtsi
+++ b/arch/arm/boot/dts/msm8974-coresight.dtsi
@@ -19,8 +19,7 @@
 		interrupts = <0 166 0>;
 		interrupt-names = "byte-cntr-irq";
 
-		qcom,memory-reservation-type = "EBI1";
-		qcom,memory-reservation-size = <0x100000>; /* 1M EBI1 buffer */
+		qcom,memory-size = <0x100000>;
 
 		coresight-id = <0>;
 		coresight-name = "coresight-tmc-etr";
@@ -41,6 +40,11 @@
 
 		qcom,vdd-voltage-level = <2950000 2950000>;
 		qcom,vdd-current-level = <9000 800000>;
+
+		vdd-io-supply = <&pm8941_l13>;
+
+		qcom,vdd-io-voltage-level = <2950000 2950000>;
+		qcom,vdd-io-current-level = <6 22000>;
 	};
 
 	replicator: replicator@fc31c000 {
diff --git a/arch/arm/boot/dts/msm8974-fluid.dtsi b/arch/arm/boot/dts/msm8974-fluid.dtsi
index 3d20f7c..c112bea 100644
--- a/arch/arm/boot/dts/msm8974-fluid.dtsi
+++ b/arch/arm/boot/dts/msm8974-fluid.dtsi
@@ -10,7 +10,6 @@
  * GNU General Public License for more details.
  */
 
-/include/ "dsi-panel-toshiba-720p-video.dtsi"
 /include/ "msm8974-camera-sensor-fluid.dtsi"
 /include/ "msm8974-leds.dtsi"
 
@@ -25,9 +24,12 @@
 		status = "ok";
 	};
 
-	qcom,mdss_dsi_toshiba_720p_video {
-		status = "ok";
-		qcom,cont-splash-enabled;
+	qcom,mdss_dsi@fd922800{
+		qcom,dsi-pref-prim-pan = <&dsi_tosh_720_vid>;
+	};
+
+	qcom,mdss_mdp@fd900000 {
+		qcom,mdss-pref-prim-intf = "dsi";
 	};
 
 	qcom,hdmi_tx@fd922100 {
@@ -35,6 +37,22 @@
 	};
 
 	i2c@f9924000 {
+		synaptics@20 {
+			compatible = "synaptics,rmi4";
+			reg = <0x20>;
+			interrupt-parent = <&msmgpio>;
+			interrupts = <61 0x2008>;
+			vdd-supply = <&pm8941_l18>;
+			vcc_i2c-supply = <&pm8941_lvs1>;
+			synaptics,reset-gpio = <&msmgpio 60 0x00>;
+			synaptics,irq-gpio = <&msmgpio 61 0x2008>;
+			synaptics,display-coords = <0 0 1079 1919>;
+			synaptics,i2c-pull-up;
+			synaptics,power-down;
+			synaptics,disable-gpios;
+			synaptics,do-lockdown;
+		};
+
 		atmel_mxt_ts@4a {
 			compatible = "atmel,mxt-ts";
 			reg = <0x4a>;
@@ -269,11 +287,11 @@
 			qcom,default-state = "on";
 			qcom,max-current = <25>;
 			qcom,ctrl-delay-us = <0>;
-			qcom,boost-curr-lim = <3>;
+			qcom,boost-curr-lim = <5>;
 			qcom,cp-sel = <0>;
 			qcom,switch-freq = <11>;
 			qcom,ovp-val = <2>;
-			qcom,num-strings = <1>;
+			qcom,num-strings = <3>;
 			qcom,id = <0>;
 		};
 	};
@@ -675,3 +693,7 @@
 		qcom,channel-type = <0xf0000000>;
 	};
 };
+
+&dsi_tosh_720_vid {
+       qcom,cont-splash-enabled;
+};
diff --git a/arch/arm/boot/dts/msm8974-ion.dtsi b/arch/arm/boot/dts/msm8974-ion.dtsi
index 63f6d59..455ed2d 100644
--- a/arch/arm/boot/dts/msm8974-ion.dtsi
+++ b/arch/arm/boot/dts/msm8974-ion.dtsi
@@ -55,5 +55,12 @@
 			qcom,memory-reservation-type = "EBI1"; /* reserve EBI memory */
 			qcom,memory-reservation-size = <0x614000>;
 		};
+
+		qcom,ion-heap@23 { /* OTHER PIL HEAP */
+			compatible = "qcom,msm-ion-reserve";
+			reg = <23>;
+			qcom,heap-align = <0x1000>;
+			qcom,memory-fixed = <0x05d00000 0x1e00000>;
+		};
 	};
 };
diff --git a/arch/arm/boot/dts/msm8974-liquid.dtsi b/arch/arm/boot/dts/msm8974-liquid.dtsi
index 51cb226..67e1802 100644
--- a/arch/arm/boot/dts/msm8974-liquid.dtsi
+++ b/arch/arm/boot/dts/msm8974-liquid.dtsi
@@ -24,9 +24,9 @@
 		status = "ok";
 	};
 
-	qcom,mdss_edp@fd923400 {
-		status = "ok";
-	};
+        qcom,mdss_mdp@fd900000 {
+                qcom,mdss-pref-prim-intf = "edp";
+        };
 
 	i2c@f9967000 {
 		battery@b {
@@ -375,6 +375,7 @@
 
 	hsic_hub {
 		compatible = "qcom,hsic-smsc-hub";
+		smsc,model-id = <3503>;
 		#address-cells = <1>;
 		#size-cells = <1>;
 		ranges;
@@ -396,13 +397,15 @@
 		                1 &intc 0 148 0
 		                2 &msmgpio 144 0x8>;
 			interrupt-names = "core_irq", "async_irq", "wakeup";
-			HSIC_VDDCX-supply = <&pm8841_s2>;
+			hsic_vdd_dig-supply = <&pm8841_s2_corner>;
 			HSIC_GDSC-supply = <&gdsc_usb_hsic>;
 			hsic,strobe-gpio = <&msmgpio 144 0x00>;
 			hsic,data-gpio = <&msmgpio 145 0x00>;
 			hsic,ignore-cal-pad-config;
 			hsic,strobe-pad-offset = <0x2050>;
 			hsic,data-pad-offset = <0x2054>;
+			qcom,phy-susp-sof-workaround;
+			hsic,vdd-voltage-level = <1 5 7>;
 
 			qcom,msm-bus,name = "hsic";
 			qcom,msm-bus,num-cases = <2>;
diff --git a/drivers/gpu/msm/adreno_trace.c b/arch/arm/boot/dts/msm8974-mdss-panels.dtsi
similarity index 74%
copy from drivers/gpu/msm/adreno_trace.c
copy to arch/arm/boot/dts/msm8974-mdss-panels.dtsi
index 607ba8c..00fc779 100644
--- a/drivers/gpu/msm/adreno_trace.c
+++ b/arch/arm/boot/dts/msm8974-mdss-panels.dtsi
@@ -8,11 +8,9 @@
  * 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 "adreno.h"
-
-/* Instantiate tracepoints */
-#define CREATE_TRACE_POINTS
-#include "adreno_trace.h"
+/include/ "dsi-panel-orise-720p-video.dtsi"
+/include/ "dsi-panel-toshiba-720p-video.dtsi"
+/include/ "dsi-panel-sharp-qhd-video.dtsi"
+/include/ "dsi-panel-generic-720p-cmd.dtsi"
diff --git a/arch/arm/boot/dts/msm8974-mdss.dtsi b/arch/arm/boot/dts/msm8974-mdss.dtsi
index f8a8fa6..24b5860 100644
--- a/arch/arm/boot/dts/msm8974-mdss.dtsi
+++ b/arch/arm/boot/dts/msm8974-mdss.dtsi
@@ -86,9 +86,11 @@
 		vddio-supply = <&pm8941_l12>;
 		vdda-supply = <&pm8941_l2>;
 		qcom,mdss-fb-map = <&mdss_fb0>;
-		qcom,platform-reset-gpio = <&pm8941_gpios 19 1>;
-		qcom,platform-enable-gpio = <&msmgpio 58 1>;
+		qcom,mdss-mdp = <&mdss_mdp>;
+		qcom,platform-reset-gpio = <&pm8941_gpios 19 0>;
+		qcom,platform-enable-gpio = <&msmgpio 58 0>;
 		qcom,platform-reset-sequence = <1 20 0 200 1 20 2>;
+		qcom,platform-te-gpio = <&msmgpio 12 0>;
 		qcom,platform-strength-ctrl = [ff 06];
 		qcom,platform-bist-ctrl = [00 00 b1 ff 00 00];
 		qcom,platform-regulator-settings = [07 09 03 00 20 00 01];
@@ -141,6 +143,7 @@
 		vddio-supply = <&pm8941_l12>;
 		vdda-supply = <&pm8941_l2>;
 		qcom,mdss-fb-map = <&mdss_fb0>;
+		qcom,mdss-mdp = <&mdss_mdp>;
 	};
 
 	mdss_hdmi_tx: qcom,hdmi_tx@fd922100 {
@@ -158,7 +161,7 @@
 		qcom,hdmi-tx-supply-names = "hpd-gdsc", "hpd-5v", "core-vdda", "core-vcc";
 		qcom,hdmi-tx-min-voltage-level = <0 0 1800000 1800000>;
 		qcom,hdmi-tx-max-voltage-level = <0 0 1800000 1800000>;
-		qcom,hdmi-tx-peak-current = <0 0 1800000 0>;
+		qcom,hdmi-tx-peak-current = <0 0 300000 0>;
 
 		qcom,hdmi-tx-cec = <&msmgpio 31 0>;
 		qcom,hdmi-tx-ddc-clk = <&msmgpio 32 0>;
@@ -187,8 +190,9 @@
 		gpio-panel-pwm = <&pm8941_gpios 36 0>;
 		qcom,panel-lpg-channel = <7>; /* LPG Channel 8 */
 		qcom,panel-pwm-period = <53>;
-		status = "disable";
 		qcom,mdss-fb-map = <&mdss_fb0>;
 		gpio-panel-hpd = <&msmgpio 102 0>;
 	};
 };
+
+/include/ "msm8974-mdss-panels.dtsi"
diff --git a/arch/arm/boot/dts/msm8974-mtp.dtsi b/arch/arm/boot/dts/msm8974-mtp.dtsi
index c1a8792..7a81e64 100644
--- a/arch/arm/boot/dts/msm8974-mtp.dtsi
+++ b/arch/arm/boot/dts/msm8974-mtp.dtsi
@@ -10,7 +10,6 @@
  * GNU General Public License for more details.
  */
 
-/include/ "dsi-panel-toshiba-720p-video.dtsi"
 /include/ "msm8974-camera-sensor-mtp.dtsi"
 /include/ "msm8974-leds.dtsi"
 
@@ -25,9 +24,12 @@
 		status = "ok";
 	};
 
-	qcom,mdss_dsi_toshiba_720p_video {
-		status = "ok";
-		qcom,cont-splash-enabled;
+	qcom,mdss_dsi@fd922800 {
+		qcom,dsi-pref-prim-pan = <&dsi_tosh_720_vid>;
+	};
+
+	qcom,mdss_mdp@fd900000 {
+		qcom,mdss-pref-prim-intf = "dsi";
 	};
 
 	qcom,hdmi_tx@fd922100 {
@@ -35,6 +37,22 @@
 	};
 
 	i2c@f9924000 {
+		synaptics@20 {
+			compatible = "synaptics,rmi4";
+			reg = <0x20>;
+			interrupt-parent = <&msmgpio>;
+			interrupts = <61 0x2008>;
+			vdd-supply = <&pm8941_l18>;
+			vcc_i2c-supply = <&pm8941_lvs1>;
+			synaptics,reset-gpio = <&msmgpio 60 0x00>;
+			synaptics,irq-gpio = <&msmgpio 61 0x2008>;
+			synaptics,display-coords = <0 0 1079 1919>;
+			synaptics,i2c-pull-up;
+			synaptics,power-down;
+			synaptics,disable-gpios;
+			synaptics,do-lockdown;
+		};
+
 		atmel_mxt_ts@4a {
 			compatible = "atmel,mxt-ts";
 			reg = <0x4a>;
@@ -210,11 +228,11 @@
 			qcom,default-state = "on";
 			qcom,max-current = <25>;
 			qcom,ctrl-delay-us = <0>;
-			qcom,boost-curr-lim = <3>;
+			qcom,boost-curr-lim = <5>;
 			qcom,cp-sel = <0>;
 			qcom,switch-freq = <11>;
 			qcom,ovp-val = <2>;
-			qcom,num-strings = <1>;
+			qcom,num-strings = <3>;
 			qcom,id = <0>;
 		};
 	};
@@ -698,3 +716,7 @@
 		qcom,channel-type = <0x1540>;
 	};
 };
+
+&dsi_tosh_720_vid {
+       qcom,cont-splash-enabled;
+};
diff --git a/arch/arm/boot/dts/msm8974-regulator.dtsi b/arch/arm/boot/dts/msm8974-regulator.dtsi
index eae9032..a88a709 100644
--- a/arch/arm/boot/dts/msm8974-regulator.dtsi
+++ b/arch/arm/boot/dts/msm8974-regulator.dtsi
@@ -463,7 +463,7 @@
 		#address-cells = <1>;
 		#size-cells = <1>;
 		ranges;
-		qcom,pfm-threshold = <73>;
+		qcom,pfm-threshold = <76>;
 		qcom,use-phase-scaling-factor;
 
 		krait0_vreg: regulator@f9088000 {
diff --git a/arch/arm/boot/dts/msm8974-v1-cdp.dts b/arch/arm/boot/dts/msm8974-v1-cdp.dts
index c3fd98d..071c7c9 100644
--- a/arch/arm/boot/dts/msm8974-v1-cdp.dts
+++ b/arch/arm/boot/dts/msm8974-v1-cdp.dts
@@ -26,6 +26,8 @@
 &ehci {
 	status = "ok";
 	vbus-supply = <&usb2_otg_sw>;
+	hsusb_vdd_dig-supply = <&pm8841_s2_corner>;
+	qcom,vdd-voltage-level = <1 2 3 5 7>;
 };
 
 &hsic_host {
diff --git a/arch/arm/boot/dts/msm8974-v1-pm.dtsi b/arch/arm/boot/dts/msm8974-v1-pm.dtsi
index 7362b64..0115d89 100644
--- a/arch/arm/boot/dts/msm8974-v1-pm.dtsi
+++ b/arch/arm/boot/dts/msm8974-v1-pm.dtsi
@@ -127,6 +127,7 @@
 		qcom,saw2-spm-cmd-gdhs = [00 20 32 42 07 44 22 50 02 32 50 0f];
 		qcom,saw2-spm-cmd-pc = [00 10 32 b0 11 42 07 01 b0 12 44
 				50 02 32 50 0f];
+		qcom,L2-spm-is-apcs-master;
 	};
 
 	qcom,lpm-levels {
@@ -217,7 +218,7 @@
 			<0xff 176>, /* o_wcss_apss_smsm_irq */
 			<0xff 177>, /* o_wcss_apss_wlan_data_xfer_done */
 			<0xff 178>, /* o_wcss_apss_wlan_rx_data_avail */
-			<0xff 179>, /* o_wcss_apss_asic_intr
+			<0xff 179>, /* o_wcss_apss_asic_intr */
 
 			<0xff 188>, /* lpass_irq_out_apcs(0) */
 			<0xff 189>, /* lpass_irq_out_apcs(1) */
@@ -315,4 +316,13 @@
 		reg-names = "phys_addr_base";
 		qcom,sleep-stats-version = <2>;
 	};
+
+	qcom,rpm-master-stats@fc428150 {
+		compatible = "qcom,rpm-master-stats";
+		reg = <0xfc428150 0x3200>;
+		qcom,masters = "APSS", "MPSS", "LPSS", "PRONTO";
+		qcom,master-stats-version = <2>;
+		qcom,master-offset = <2560>;
+	};
+
 };
diff --git a/arch/arm/boot/dts/msm8974-v1.dtsi b/arch/arm/boot/dts/msm8974-v1.dtsi
index 86a61cd..249c963 100644
--- a/arch/arm/boot/dts/msm8974-v1.dtsi
+++ b/arch/arm/boot/dts/msm8974-v1.dtsi
@@ -165,3 +165,19 @@
 	qcom,retain-mem;
 	qcom,retain-periph;
 };
+
+&krait_regulator_pmic {
+	status = "ok";
+
+	qcom,ctl@2000 {
+		status = "ok";
+	};
+
+	qcom,ps@2100 {
+		status = "ok";
+	};
+
+	qcom,freq@2200 {
+		status = "ok";
+	};
+};
diff --git a/arch/arm/boot/dts/msm8974-v2-pm.dtsi b/arch/arm/boot/dts/msm8974-v2-pm.dtsi
index 1235c6e..8836975 100644
--- a/arch/arm/boot/dts/msm8974-v2-pm.dtsi
+++ b/arch/arm/boot/dts/msm8974-v2-pm.dtsi
@@ -123,6 +123,7 @@
 		qcom,saw2-spm-cmd-gdhs = [00 32 42 07 44 50 02 32 50 0f];
 		qcom,saw2-spm-cmd-pc = [00 10 32 b0 11 42 07 01 b0 12 44
 				50 02 32 50 0f];
+		qcom,L2-spm-is-apcs-master;
 	};
 
 	qcom,lpm-levels {
@@ -219,6 +220,7 @@
 			<0xff 58>,  /* mss_to_apps_irq(1) */
 			<0xff 59>,  /* mss_to_apps_irq(2) */
 			<0xff 60>,  /* mss_to_apps_irq(3) */
+			<0xff 61>,  /* mss_a2_bam_irq */
 			<0xff 70>,  /* iommu_pmon_nonsecure_irq */
 			<0xff 97>,  /* iommu_nonsecure_irq */
 			<0xff 105>, /* iommu_pmon_nonsecure_irq */
@@ -345,4 +347,12 @@
 		reg = <0xfc000000 0x1a0000>;
 		qcom,start-offset = <0x190010>;
 	};
+
+	qcom,rpm-master-stats@fc428150 {
+		compatible = "qcom,rpm-master-stats";
+		reg = <0xfc428150 0x3200>;
+		qcom,masters = "APSS", "MPSS", "LPSS", "PRONTO";
+		qcom,master-stats-version = <2>;
+		qcom,master-offset = <2560>;
+	};
 };
diff --git a/arch/arm/boot/dts/msm8974-v2.dtsi b/arch/arm/boot/dts/msm8974-v2.dtsi
index 9d5e50b..f2f73e9 100644
--- a/arch/arm/boot/dts/msm8974-v2.dtsi
+++ b/arch/arm/boot/dts/msm8974-v2.dtsi
@@ -168,3 +168,42 @@
 &tspp {
 	vdd_cx-supply = <&pm8841_s2_corner>;
 };
+
+&krait_regulator_pmic {
+	status = "ok";
+
+	qcom,ctl@2000 {
+		status = "ok";
+	};
+
+	qcom,ps@2100 {
+		status = "ok";
+	};
+
+	qcom,freq@2200 {
+		status = "ok";
+	};
+};
+
+&cci {
+
+	qcom,camera@6e {
+		qcom,vdd-cx-supply = <&pm8841_s2>;
+		qcom,vdd-cx-name = "qcom,vdd-cx";
+	};
+
+	qcom,camera@20 {
+		qcom,vdd-cx-supply = <&pm8841_s2>;
+		qcom,vdd-cx-name = "qcom,vdd-cx";
+	};
+
+	qcom,camera@6c {
+		qcom,vdd-cx-supply = <&pm8841_s2>;
+		qcom,vdd-cx-name = "qcom,vdd-cx";
+	};
+
+	qcom,camera@90 {
+		qcom,vdd-cx-supply = <&pm8841_s2>;
+		qcom,vdd-cx-name = "qcom,vdd-cx";
+	};
+};
diff --git a/arch/arm/boot/dts/msm8974.dtsi b/arch/arm/boot/dts/msm8974.dtsi
index 725cfaf..0283bfd 100644
--- a/arch/arm/boot/dts/msm8974.dtsi
+++ b/arch/arm/boot/dts/msm8974.dtsi
@@ -24,6 +24,19 @@
 		sdhc2 = &sdhc_2; /* SDC2 SD card slot */
 		sdhc3 = &sdhc_3; /* SDC3 SDIO slot */
 		sdhc4 = &sdhc_4; /* SDC4 SDIO slot */
+
+		/* smdtty devices */
+		smd1 = &smdtty_apps_fm;
+		smd2 = &smdtty_apps_riva_bt_acl;
+		smd3 = &smdtty_apps_riva_bt_cmd;
+		smd4 = &smdtty_mbalbridge;
+		smd5 = &smdtty_apps_riva_ant_cmd;
+		smd6 = &smdtty_apps_riva_ant_data;
+		smd7 = &smdtty_data1;
+		smd11 = &smdtty_data11;
+		smd21 = &smdtty_data21;
+		smd27 = &smdtty_gps_nmea;
+		smd36 = &smdtty_loopback;
 	};
 
 	cpus {
@@ -198,6 +211,7 @@
 		compatible = "qcom,msm-vidc";
 		reg = <0xfdc00000 0xff000>;
 		interrupts = <0 44 0>;
+		vdd-supply = <&gdsc_venus>;
 		qcom,hfi = "venus";
 		qcom,has-ocmem;
 		qcom,max-hw-load = <1224450>; /* 4k @ 30 + 1080p @ 30*/
@@ -821,9 +835,11 @@
 		reg-names = "qup_phys_addr";
 		interrupts = <0 96 0>;
 		interrupt-names = "qup_err_intr";
-		qcom,i2c-bus-freq = <100000>;
-		qcom,i2c-src-freq = <50000000>;
+		qcom,i2c-bus-freq = <384000>;
+		qcom,i2c-src-freq = <19200000>;
 		qcom,master-id = <86>;
+		qcom,scl-gpio = <&msmgpio 7 0>;
+		qcom,sda-gpio = <&msmgpio 6 0>;
 	};
 
 	spi_0: spi@f9923000 { /* BLSP1 QUP1 */
@@ -897,6 +913,9 @@
 		qcom,vdd-voltage-level = <1 5 7>;
 		qcom,dwc-hsphy-init = <0x00D191A4>;
 		qcom,misc-ref = <&pm8941_misc>;
+		dwc_usb3-adc_tm = <&pm8941_adc_tm>;
+		qcom,dwc-usb3-msm-tx-fifo-size = <29696>;
+		qcom,dwc-usb3-msm-qdss-tx-fifo-size = <16384>;
 
 		qcom,msm-bus,name = "usb3";
 		qcom,msm-bus,num-cases = <2>;
@@ -910,6 +929,7 @@
 			interrupt-parent = <&intc>;
 			interrupts = <0 131 0>, <0 179 0>;
 			interrupt-names = "irq", "otg_irq";
+			tx-fifo-resize;
 		};
 	};
 
@@ -1377,8 +1397,6 @@
 		compatible = "qcom,cache_dump";
 		qcom,l1-dump-size = <0x100000>;
 		qcom,l2-dump-size = <0x500000>;
-		qcom,memory-reservation-type = "EBI1";
-		qcom,memory-reservation-size = <0x600000>; /* 6M EBI1 buffer */
 	};
 
 	tsens: tsens@fc4a8000 {
@@ -1467,7 +1485,7 @@
 			qcom,src-bam-pipe-index = <0>;
 			qcom,dst-bam-physical-address = <0xf9304000>;
 			qcom,dst-bam-pipe-index = <2>;
-			qcom,data-fifo-offset = <0xf0000>;
+			qcom,data-fifo-offset = <0xf2000>;
 			qcom,data-fifo-size = <0x1800>;
 			qcom,descriptor-fifo-offset = <0xf4000>;
 			qcom,descriptor-fifo-size = <0x1400>;
@@ -1503,6 +1521,10 @@
 		qcom,core-limit-temp = <80>;
 		qcom,core-temp-hysteresis = <10>;
 		qcom,core-control-mask = <0xe>;
+		qcom,hotplug-temp = <110>;
+		qcom,hotplug-temp-hysteresis = <20>;
+		qcom,cpu-sensors = "tsens_tz_sensor5", "tsens_tz_sensor6",
+				"tsens_tz_sensor7", "tsens_tz_sensor8";
 		qcom,vdd-restriction-temp = <5>;
 		qcom,vdd-restriction-temp-hysteresis = <10>;
 		qcom,pmic-sw-mode-temp = <85>;
@@ -1539,7 +1561,7 @@
 
         memory_hole: qcom,msm-mem-hole {
                 compatible = "qcom,msm-mem-hole";
-                qcom,memblock-remove = <0x7b00000 0x8400000>; /* Address and Size of Hole */
+                qcom,memblock-remove = <0x5d00000 0xa200000>; /* Address and Size of Hole */
         };
 
 	uart7: uart@f995d000 { /*BLSP #2, UART #7 */
@@ -1667,6 +1689,66 @@
 		compatible = "qcom,l2-pmu";
 		interrupts = <0 1 0>;
 	};
+
+	qcom,smdtty {
+		compatible = "qcom,smdtty";
+
+		smdtty_apps_fm: qcom,smdtty-apps-fm {
+			qcom,smdtty-remote = "wcnss";
+			qcom,smdtty-port-name = "APPS_FM";
+		};
+
+		smdtty_apps_riva_bt_acl: smdtty-apps-riva-bt-acl {
+			qcom,smdtty-remote = "wcnss";
+			qcom,smdtty-port-name = "APPS_RIVA_BT_ACL";
+		};
+
+		smdtty_apps_riva_bt_cmd: qcom,smdtty-apps-riva-bt-cmd {
+			qcom,smdtty-remote = "wcnss";
+			qcom,smdtty-port-name = "APPS_RIVA_BT_CMD";
+		};
+
+		smdtty_mbalbridge: qcom,smdtty-mbalbridge {
+			qcom,smdtty-remote = "modem";
+			qcom,smdtty-port-name = "MBALBRIDGE";
+		};
+
+		smdtty_apps_riva_ant_cmd: smdtty-apps-riva-ant-cmd {
+			qcom,smdtty-remote = "wcnss";
+			qcom,smdtty-port-name = "APPS_RIVA_ANT_CMD";
+		};
+
+		smdtty_apps_riva_ant_data: smdtty-apps-riva-ant-data {
+			qcom,smdtty-remote = "wcnss";
+			qcom,smdtty-port-name = "APPS_RIVA_ANT_DATA";
+		};
+
+		smdtty_data1: qcom,smdtty-data1 {
+			qcom,smdtty-remote = "modem";
+			qcom,smdtty-port-name = "DATA1";
+		};
+
+		smdtty_data11: qcom,smdtty-data11 {
+			qcom,smdtty-remote = "modem";
+			qcom,smdtty-port-name = "DATA11";
+		};
+
+		smdtty_data21: qcom,smdtty-data21 {
+			qcom,smdtty-remote = "modem";
+			qcom,smdtty-port-name = "DATA21";
+		};
+
+		smdtty_gps_nmea: smdtty-gpsnmea {
+			qcom,smdtty-remote = "modem";
+			qcom,smdtty-port-name = "GPSNMEA";
+		};
+
+		smdtty_loopback: smdtty-loopback {
+			qcom,smdtty-remote = "modem";
+			qcom,smdtty-port-name = "LOOPBACK";
+			qcom,smdtty-dev-name = "LOOPBACK_TTY";
+		};
+	};
 };
 
 &gdsc_venus {
diff --git a/arch/arm/boot/dts/msm8974pro-ab-cdp.dts b/arch/arm/boot/dts/msm8974pro-ab-cdp.dts
index 74bd23d..fae72fa 100644
--- a/arch/arm/boot/dts/msm8974pro-ab-cdp.dts
+++ b/arch/arm/boot/dts/msm8974pro-ab-cdp.dts
@@ -24,5 +24,9 @@
 		      <214 1 0x10000>,
 		      <215 1 0x10000>,
 		      <217 1 0x10000>,
-		      <218 1 0x10000>;
+		      <218 1 0x10000>,
+		      <194 1 0x10000>,	/* 8974Pro-AC IDs */
+		      <210 1 0x10000>,
+		      <213 1 0x10000>,
+		      <216 1 0x10000>;
 };
diff --git a/arch/arm/boot/dts/msm8974pro-ab-mtp.dts b/arch/arm/boot/dts/msm8974pro-ab-mtp.dts
index d1566ae..002baf7 100644
--- a/arch/arm/boot/dts/msm8974pro-ab-mtp.dts
+++ b/arch/arm/boot/dts/msm8974pro-ab-mtp.dts
@@ -26,7 +26,3 @@
 		      <217 8 0x10000>,
 		      <218 8 0x10000>;
 };
-
-&sdhc_1 {
-	qcom,clk-rates = <400000 20000000 25000000 50000000 100000000>;
-};
diff --git a/arch/arm/boot/dts/msm8974pro-ab.dtsi b/arch/arm/boot/dts/msm8974pro-ab.dtsi
index 88687bd..5809069 100644
--- a/arch/arm/boot/dts/msm8974pro-ab.dtsi
+++ b/arch/arm/boot/dts/msm8974pro-ab.dtsi
@@ -39,3 +39,19 @@
 &tspp {
 	vdd_cx-supply = <&pm8841_s2_corner>;
 };
+
+&krait_regulator_pmic {
+	status = "ok";
+
+	qcom,ctl@2000 {
+		status = "ok";
+	};
+
+	qcom,ps@2100 {
+		status = "ok";
+	};
+
+	qcom,freq@2200 {
+		status = "ok";
+	};
+};
diff --git a/arch/arm/boot/dts/msm8974pro-ac-mtp.dts b/arch/arm/boot/dts/msm8974pro-ac-mtp.dts
index b8df576..237c9f9 100644
--- a/arch/arm/boot/dts/msm8974pro-ac-mtp.dts
+++ b/arch/arm/boot/dts/msm8974pro-ac-mtp.dts
@@ -24,6 +24,111 @@
 		      <216 8 0x10000>;
 };
 
+&pma8084_vadc {
+	chan@73 {
+		label = "msm_therm";
+		reg = <0x73>;
+		qcom,decimation = <0>;
+		qcom,pre-div-channel-scaling = <0>;
+		qcom,calibration-type = "ratiometric";
+		qcom,scale-function = <2>;
+		qcom,hw-settle-time = <2>;
+		qcom,fast-avg-setup = <0>;
+	};
+
+	chan@75 {
+		label = "pa_therm0";
+		reg = <0x75>;
+		qcom,decimation = <0>;
+		qcom,pre-div-channel-scaling = <0>;
+		qcom,calibration-type = "ratiometric";
+		qcom,scale-function = <2>;
+		qcom,hw-settle-time = <2>;
+		qcom,fast-avg-setup = <0>;
+	};
+
+	chan@77 {
+		label = "pa_therm1";
+		reg = <0x77>;
+		qcom,decimation = <0>;
+		qcom,pre-div-channel-scaling = <0>;
+		qcom,calibration-type = "ratiometric";
+		qcom,scale-function = <2>;
+		qcom,hw-settle-time = <2>;
+		qcom,fast-avg-setup = <0>;
+	};
+
+	chan@78 {
+		label = "quiet_therm";
+		reg = <0x78>;
+		qcom,decimation = <0>;
+		qcom,pre-div-channel-scaling = <0>;
+		qcom,calibration-type = "ratiometric";
+		qcom,scale-function = <2>;
+		qcom,hw-settle-time = <2>;
+		qcom,fast-avg-setup = <0>;
+	};
+};
+
+&pma8084_adc_tm {
+	chan@73 {
+		label = "msm_therm";
+		reg = <0x73>;
+		qcom,decimation = <0>;
+		qcom,pre-div-channel-scaling = <0>;
+		qcom,calibration-type = "ratiometric";
+		qcom,scale-function = <2>;
+		qcom,hw-settle-time = <2>;
+		qcom,fast-avg-setup = <0>;
+		qcom,btm-channel-number = <0x48>;
+		qcom,thermal-node;
+	};
+
+	chan@75 {
+		label = "pa_therm0";
+		reg = <0x75>;
+		qcom,decimation = <0>;
+		qcom,pre-div-channel-scaling = <0>;
+		qcom,calibration-type = "ratiometric";
+		qcom,scale-function = <2>;
+		qcom,hw-settle-time = <2>;
+		qcom,fast-avg-setup = <0>;
+		qcom,btm-channel-number = <0x68>;
+		qcom,thermal-node;
+	};
+
+	chan@77 {
+		label = "pa_therm1";
+		reg = <0x77>;
+		qcom,decimation = <0>;
+		qcom,pre-div-channel-scaling = <0>;
+		qcom,calibration-type = "ratiometric";
+		qcom,scale-function = <2>;
+		qcom,hw-settle-time = <2>;
+		qcom,fast-avg-setup = <0>;
+		qcom,btm-channel-number = <0x70>;
+		qcom,thermal-node;
+	};
+
+	chan@78 {
+		label = "quiet_therm";
+		reg = <0x78>;
+		qcom,decimation = <0>;
+		qcom,pre-div-channel-scaling = <0>;
+		qcom,calibration-type = "ratiometric";
+		qcom,scale-function = <2>;
+		qcom,hw-settle-time = <2>;
+		qcom,fast-avg-setup = <0>;
+		qcom,btm-channel-number = <0x78>;
+		qcom,thermal-node;
+	};
+};
+
 &sdhc_1 {
-	qcom,clk-rates = <400000 20000000 25000000 50000000 100000000>;
+	reg = <0xf9824900 0x1a0>, <0xf9824000 0x800>;
+	qcom,clk-rates = <400000 20000000 25000000 50000000 100000000 200000000 400000000>;
+	qcom,bus-speed-mode = "HS400_1p8v", "HS200_1p8v", "DDR_1p8v";
+
+	qcom,pad-pull-on = <0x0 0x3 0x3 0x1>; /* no-pull, pull-up, pull-up, pull-down */
+	qcom,pad-pull-off = <0x0 0x3 0x3 0x1>; /* no-pull, pull-up, pull-up, pull-down */
 };
diff --git a/arch/arm/boot/dts/msm8974pro-ac-mtp.dtsi b/arch/arm/boot/dts/msm8974pro-ac-mtp.dtsi
index 250afd2..cdb4ed0 100644
--- a/arch/arm/boot/dts/msm8974pro-ac-mtp.dtsi
+++ b/arch/arm/boot/dts/msm8974pro-ac-mtp.dtsi
@@ -46,6 +46,11 @@
 
 &soc {
 	i2c@f9924000 {
+		synaptics@20 {
+			vdd-supply = <&pma8084_l18>;
+			vcc_i2c-supply = <&pma8084_lvs1>;
+		};
+
 		atmel_mxt_ts@4a {
 			vdd_ana-supply = <&pma8084_l18>;
 			vcc_i2c-supply = <&pma8084_lvs1>;
@@ -62,10 +67,6 @@
 		vbus_dwc3-supply = <&pm8941_mvs1>;
 	};
 
-	qcom,mdss_dsi_toshiba_720p_video {
-		qcom,rst-gpio = <&pma8084_gpios 20 0>;
-	};
-
 	gpio_keys {
 		camera_snapshot {
 			gpios = <&pma8084_gpios 3 0x1>;
diff --git a/arch/arm/boot/dts/msm8974pro-ac-pm8941.dtsi b/arch/arm/boot/dts/msm8974pro-ac-pm8941.dtsi
index 4d10ded..cc4b6ed 100644
--- a/arch/arm/boot/dts/msm8974pro-ac-pm8941.dtsi
+++ b/arch/arm/boot/dts/msm8974pro-ac-pm8941.dtsi
@@ -21,14 +21,6 @@
 };
 /include/ "msm-pm8941.dtsi"
 
-&pma8084_vadc {
-	status = "disabled";
-};
-
-&pma8084_adc_tm {
-	status = "disabled";
-};
-
 &pm8941_lsid0 {
 	qcom,power-on@800 {
 		status = "disabled";
@@ -102,6 +94,16 @@
 	regulator-name = "8941_smbb_otg";
 };
 
+&usb3 {
+	vbus_dwc3-supply = <&pm8941_mvs1>;
+	qcom,misc-ref = <&pm8941_misc>;
+	dwc_usb3-adc_tm = <&pm8941_adc_tm>;
+	interrupt-map-mask = <0x0 0xffffffff>;
+	interrupt-map = <0x0 0 &intc 0 133 0
+			0x0 1 &spmi_bus 0x0 0x2 0x9 0x0>;
+	interrupt-names = "hs_phy_irq", "pmic_id_irq";
+};
+
 /* Correct PM8941 local slave ID 0 to use global SID 4 for all interrupts. */
 &pm8941_lsid0 {
 	qcom,temp-alarm@2400 {
diff --git a/arch/arm/boot/dts/msm8974pro-ac-regulator.dtsi b/arch/arm/boot/dts/msm8974pro-ac-regulator.dtsi
index 9d7f316..e0473b7 100644
--- a/arch/arm/boot/dts/msm8974pro-ac-regulator.dtsi
+++ b/arch/arm/boot/dts/msm8974pro-ac-regulator.dtsi
@@ -479,7 +479,7 @@
 		#address-cells = <1>;
 		#size-cells = <1>;
 		ranges;
-		qcom,pfm-threshold = <73>;
+		qcom,pfm-threshold = <76>;
 
 		krait0_vreg: regulator@f9088000 {
 			compatible = "qcom,krait-regulator";
diff --git a/arch/arm/boot/dts/msm8974pro-ac.dtsi b/arch/arm/boot/dts/msm8974pro-ac.dtsi
index 032c256..f8a371d 100644
--- a/arch/arm/boot/dts/msm8974pro-ac.dtsi
+++ b/arch/arm/boot/dts/msm8974pro-ac.dtsi
@@ -46,12 +46,14 @@
 
 	tpiu@fc318000 {
 		vdd-supply = <&pma8084_l21>;
+		vdd-io-supply = <&pma8084_l13>;
 	};
 
 	qcom,mdss_dsi@fd922800 {
 		vdd-supply = <&pma8084_l22>;
 		vddio-supply = <&pma8084_l12>;
 		vdda-supply = <&pma8084_l2>;
+		qcom,platform-reset-gpio = <&pma8084_gpios 20 0>;
 	};
 
 	qcom,mdss_dsi@fd922e00 {
@@ -160,6 +162,9 @@
 	qcom,msm-thermal {
 		vdd-dig-supply = <&pma8084_s2_floor_corner>;
 		vdd-gfx-supply = <&pma8084_s7_floor_corner>;
+		/delete-property/ qcom,pmic-sw-mode-temp;
+		/delete-property/ qcom,pmic-sw-mode-temp-hysteresis;
+		/delete-property/ qcom,pmic-sw-mode-regs;
 	};
 
 	qcom,lpm-resources {
@@ -188,3 +193,19 @@
 &tspp {
 	vdd_cx-supply = <&pma8084_s2_corner>;
 };
+
+&krait_regulator_pmic {
+	status = "ok";
+
+	qcom,ctl@2900 {
+		status = "ok";
+	};
+
+	qcom,ps@2a00 {
+		status = "ok";
+	};
+
+	qcom,freq@2b00 {
+		status = "ok";
+	};
+};
diff --git a/arch/arm/boot/dts/msm8974pro-ion.dtsi b/arch/arm/boot/dts/msm8974pro-ion.dtsi
new file mode 100644
index 0000000..7faee21
--- /dev/null
+++ b/arch/arm/boot/dts/msm8974pro-ion.dtsi
@@ -0,0 +1,30 @@
+/* Copyright (c) 2013, The Linux Foundation. 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 and
+ * only 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.
+ */
+
+&soc {
+	qcom,ion {
+
+		qcom,ion-heap@23 { /* OTHER PIL HEAP */
+			compatible = "qcom,msm-ion-reserve";
+			reg = <23>;
+			qcom,heap-align = <0x1000>;
+			qcom,memory-fixed = <0x05400000 0x2700000>;
+		};
+
+		qcom,ion-heap@26 { /* MODEM HEAP */
+			compatible = "qcom,msm-ion-reserve";
+			reg = <26>;
+			qcom,heap-align = <0x1000>;
+			qcom,memory-fixed = <0x08000000 0x5000000>;
+		};
+	};
+};
diff --git a/arch/arm/boot/dts/msm8974pro-pm.dtsi b/arch/arm/boot/dts/msm8974pro-pm.dtsi
new file mode 100644
index 0000000..9e1f83f
--- /dev/null
+++ b/arch/arm/boot/dts/msm8974pro-pm.dtsi
@@ -0,0 +1,341 @@
+/* Copyright (c) 2013, The Linux Foundation. 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 and
+ * only 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.
+ */
+
+&soc {
+	qcom,spm@f9089000 {
+		compatible = "qcom,spm-v2";
+	#address-cells = <1>;
+	#size-cells = <1>;
+		reg = <0xf9089000 0x1000>;
+		qcom,core-id = <0>;
+		qcom,saw2-ver-reg = <0xfd0>;
+		qcom,saw2-cfg = <0x01>;
+		qcom,saw2-avs-ctl = <0>;
+		qcom,saw2-avs-hysteresis = <0>;
+		qcom,saw2-avs-limit = <0>;
+		qcom,saw2-avs-dly= <0>;
+		qcom,saw2-spm-dly= <0x3C102800>;
+		qcom,saw2-spm-ctl = <0x1>;
+		qcom,saw2-spm-cmd-wfi = [03 0b 0f];
+		qcom,saw2-spm-cmd-ret = [42 1b 00 d8 5B 03 d8 5b 0b 00 42 1b 0f];
+		qcom,saw2-spm-cmd-spc = [00 20 80 10 E8 5B 03 3B E8 5B 82 10 0B
+			30 06 26 30 0F];
+		qcom,saw2-spm-cmd-pc = [00 20 80 10 E8 5B 03 3B E8 5B 82 10 0B
+			30 06 26 30 0F];
+	};
+
+	qcom,spm@f9099000 {
+		compatible = "qcom,spm-v2";
+		#address-cells = <1>;
+		#size-cells = <1>;
+		reg = <0xf9099000 0x1000>;
+		qcom,core-id = <1>;
+		qcom,saw2-ver-reg = <0xfd0>;
+		qcom,saw2-cfg = <0x01>;
+		qcom,saw2-avs-ctl = <0>;
+		qcom,saw2-avs-hysteresis = <0>;
+		qcom,saw2-avs-limit = <0>;
+		qcom,saw2-avs-dly= <0>;
+		qcom,saw2-spm-dly= <0x3C102800>;
+		qcom,saw2-spm-ctl = <0x1>;
+		qcom,saw2-spm-cmd-wfi = [03 0b 0f];
+		qcom,saw2-spm-cmd-ret = [42 1b 00 d8 5B 03 d8 5b 0b 00 42 1b 0f];
+		qcom,saw2-spm-cmd-spc = [00 20 80 10 E8 5B 03 3B E8 5B 82 10 0B
+			30 06 26 30 0F];
+		qcom,saw2-spm-cmd-pc = [00 20 80 10 E8 5B 03 3B E8 5B 82 10 0B
+			30 06 26 30 0F];
+	};
+
+	qcom,spm@f90a9000 {
+		compatible = "qcom,spm-v2";
+		#address-cells = <1>;
+		#size-cells = <1>;
+		reg = <0xf90a9000 0x1000>;
+		qcom,core-id = <2>;
+		qcom,saw2-ver-reg = <0xfd0>;
+		qcom,saw2-cfg = <0x01>;
+		qcom,saw2-avs-ctl = <0>;
+		qcom,saw2-avs-hysteresis = <0>;
+		qcom,saw2-avs-limit = <0>;
+		qcom,saw2-avs-dly= <0>;
+		qcom,saw2-spm-dly= <0x3C102800>;
+		qcom,saw2-spm-ctl = <0x1>;
+		qcom,saw2-spm-cmd-wfi = [03 0b 0f];
+		qcom,saw2-spm-cmd-ret = [42 1b 00 d8 5B 03 d8 5b 0b 00 42 1b 0f];
+		qcom,saw2-spm-cmd-spc = [00 20 80 10 E8 5B 03 3B E8 5B 82 10 0B
+			30 06 26 30 0F];
+		qcom,saw2-spm-cmd-pc = [00 20 80 10 E8 5B 03 3B E8 5B 82 10 0B
+			30 06 26 30 0F];
+	};
+
+	qcom,spm@f90b9000 {
+		compatible = "qcom,spm-v2";
+		#address-cells = <1>;
+		#size-cells = <1>;
+		reg = <0xf90b9000 0x1000>;
+		qcom,core-id = <3>;
+		qcom,saw2-ver-reg = <0xfd0>;
+		qcom,saw2-cfg = <0x01>;
+		qcom,saw2-avs-ctl = <0>;
+		qcom,saw2-avs-hysteresis = <0>;
+		qcom,saw2-avs-limit = <0>;
+		qcom,saw2-avs-dly= <0>;
+		qcom,saw2-spm-dly= <0x3C102800>;
+		qcom,saw2-spm-ctl = <0x1>;
+		qcom,saw2-spm-cmd-wfi = [03 0b 0f];
+		qcom,saw2-spm-cmd-ret = [42 1b 00 d8 5B 03 d8 5b 0b 00 42 1b 0f];
+		qcom,saw2-spm-cmd-spc = [00 20 80 10 E8 5B 03 3B E8 5B 82 10 0B
+			30 06 26 30 0F];
+		qcom,saw2-spm-cmd-pc = [00 20 80 10 E8 5B 03 3B E8 5B 82 10 0B
+			30 06 26 30 0F];
+	};
+
+	qcom,spm@f9012000 {
+		compatible = "qcom,spm-v2";
+		#address-cells = <1>;
+		#size-cells = <1>;
+		reg = <0xf9012000 0x1000>;
+		qcom,core-id = <0xffff>; /* L2/APCS SAW */
+		qcom,saw2-ver-reg = <0xfd0>;
+		qcom,saw2-cfg = <0x14>;
+		qcom,saw2-avs-ctl = <0>;
+		qcom,saw2-avs-hysteresis = <0>;
+		qcom,saw2-avs-limit = <0>;
+		qcom,saw2-avs-dly= <0>;
+		qcom,saw2-spm-dly= <0x3C102800>;
+		qcom,saw2-spm-ctl = <0x1>;
+		qcom,saw2-pmic-data0 = <0x02030080>;
+		qcom,saw2-pmic-data1 = <0x00030000>;
+		qcom,vctl-timeout-us = <50>;
+		qcom,vctl-port = <0x0>;
+		qcom,phase-port = <0x1>;
+		qcom,pfm-port = <0x2>;
+		qcom,saw2-spm-cmd-ret = [1f 00 03 00 0f];
+		qcom,saw2-spm-cmd-gdhs = [00 32 42 07 44 50 02 32 50 0f];
+		qcom,saw2-spm-cmd-pc = [00 10 32 b0 11 42 07 01 b0 12 44
+				50 02 32 50 0f];
+		qcom,L2-spm-is-apcs-master;
+	};
+
+	qcom,lpm-levels {
+		compatible = "qcom,lpm-levels";
+		qcom,default-l2-state = "l2_cache_retention";
+		#address-cells = <1>;
+		#size-cells = <0>;
+
+		qcom,lpm-level@0 {
+			reg = <0x0>;
+			qcom,mode = "wfi";
+			qcom,l2 = "l2_cache_retention";
+			qcom,latency-us = <1>;
+			qcom,ss-power = <715>;
+			qcom,energy-overhead = <17700>;
+			qcom,time-overhead = <2>;
+		};
+
+		qcom,lpm-level@1 {
+			reg = <0x1>;
+			qcom,mode = "retention";
+			qcom,l2 = "l2_cache_retention";
+			qcom,latency-us = <35>;
+			qcom,ss-power = <542>;
+			qcom,energy-overhead = <34920>;
+			qcom,time-overhead = <40>;
+		};
+
+
+		qcom,lpm-level@2 {
+			reg = <0x2>;
+			qcom,mode = "standalone_pc";
+			qcom,l2 = "l2_cache_retention";
+			qcom,latency-us = <300>;
+			qcom,ss-power = <476>;
+			qcom,energy-overhead = <225300>;
+			qcom,time-overhead = <350>;
+		};
+
+		qcom,lpm-level@3 {
+			reg = <0x3>;
+			qcom,mode = "pc";
+			qcom,l2 = "l2_cache_gdhs";
+			qcom,gpio-detectable;
+			qcom,latency-us = <20000>;
+			qcom,ss-power = <163>;
+			qcom,energy-overhead = <1577736>;
+			qcom,time-overhead = <5067>;
+		};
+
+		qcom,lpm-level@4 {
+			reg = <0x4>;
+			qcom,mode = "pc";
+			qcom,l2 = "l2_cache_pc";
+			qcom,latency-us = <30000>;
+			qcom,ss-power = <83>;
+			qcom,energy-overhead = <2274420>;
+			qcom,time-overhead = <6605>;
+		};
+	};
+
+	qcom,pm-boot {
+		compatible = "qcom,pm-boot";
+		qcom,mode = "tz";
+	};
+
+	qcom,mpm@fc4281d0 {
+		compatible = "qcom,mpm-v2";
+		reg = <0xfc4281d0 0x1000>, /* MSM_RPM_MPM_BASE 4K */
+		    <0xf9011008 0x4>;   /* MSM_APCS_GCC_BASE 4K */
+		reg-names = "vmpm", "ipc";
+		interrupts = <0 171 1>;
+
+		qcom,ipc-bit-offset = <1>;
+
+		qcom,gic-parent = <&intc>;
+		qcom,gic-map = <2 216>, /* tsens_upper_lower_int */
+			<47 165>, /* usb30_hs_phy_irq */
+			<50 172>, /* usb1_hs_async_wakeup_irq */
+			<53 104>, /* mdss_irq */
+			<62 222>, /* ee0_krait_hlos_spmi_periph_irq */
+			<0xff 56>,  /* modem_watchdog */
+			<0xff 57>,  /* mss_to_apps_irq(0) */
+			<0xff 58>,  /* mss_to_apps_irq(1) */
+			<0xff 59>,  /* mss_to_apps_irq(2) */
+			<0xff 60>,  /* mss_to_apps_irq(3) */
+			<0xff 61>,  /* mss_a2_bam_irq */
+			<0xff 70>,  /* iommu_pmon_nonsecure_irq */
+			<0xff 97>,  /* iommu_nonsecure_irq */
+			<0xff 105>, /* iommu_pmon_nonsecure_irq */
+			<0xff 173>, /* o_wcss_apss_smd_hi */
+			<0xff 174>, /* o_wcss_apss_smd_med */
+			<0xff 175>, /* o_wcss_apss_smd_low */
+			<0xff 176>, /* o_wcss_apss_smsm_irq */
+			<0xff 177>, /* o_wcss_apss_wlan_data_xfer_done */
+			<0xff 178>, /* o_wcss_apss_wlan_rx_data_avail */
+			<0xff 179>, /* o_wcss_apss_asic_intr */
+
+			<0xff 181>, /* wcnss watchdog */
+			<0xff 188>, /* lpass_irq_out_apcs(0) */
+			<0xff 189>, /* lpass_irq_out_apcs(1) */
+			<0xff 190>, /* lpass_irq_out_apcs(2) */
+			<0xff 191>, /* lpass_irq_out_apcs(3) */
+			<0xff 192>, /* lpass_irq_out_apcs(4) */
+			<0xff 193>, /* lpass_irq_out_apcs(5) */
+			<0xff 194>, /* lpass_irq_out_apcs(6) */
+			<0xff 195>, /* lpass_irq_out_apcs(7) */
+			<0xff 196>, /* lpass_irq_out_apcs(8) */
+			<0xff 197>, /* lpass_irq_out_apcs(9) */
+			<0xff 200>, /* rpm_ipc(4) */
+			<0xff 201>, /* rpm_ipc(5) */
+			<0xff 202>, /* rpm_ipc(6) */
+			<0xff 203>, /* rpm_ipc(7) */
+			<0xff 204>, /* rpm_ipc(24) */
+			<0xff 205>, /* rpm_ipc(25) */
+			<0xff 206>, /* rpm_ipc(26) */
+			<0xff 207>, /* rpm_ipc(27) */
+			<0xff 211>, /* usb_dwc3_otg */
+			<0xff 240>; /* summary_irq_kpss */
+
+		qcom,gpio-parent = <&msmgpio>;
+		qcom,gpio-map = <3  102>,
+			<4  1 >,
+			<5  5 >,
+			<6  9 >,
+			<7  18>,
+			<8  20>,
+			<9  24>,
+			<10  27>,
+			<11  28>,
+			<12  34>,
+			<13  35>,
+			<14  37>,
+			<15  42>,
+			<16  44>,
+			<17  46>,
+			<18  50>,
+			<19  54>,
+			<20  59>,
+			<21  61>,
+			<22  62>,
+			<23  64>,
+			<24  65>,
+			<25  66>,
+			<26  67>,
+			<27  68>,
+			<28  71>,
+			<29  72>,
+			<30  73>,
+			<31  74>,
+			<32  75>,
+			<33  77>,
+			<34  79>,
+			<35  80>,
+			<36  82>,
+			<37  86>,
+			<38  92>,
+			<39  93>,
+			<40  95>,
+			<41  144>;
+	};
+
+	qcom,pm-8x60@fe805664 {
+		compatible = "qcom,pm-8x60";
+		#address-cells = <1>;
+		#size-cells = <1>;
+		ranges;
+		reg = <0xfe805664 0x40>;
+		qcom,pc-mode = "tz_l2_int";
+		qcom,use-sync-timer;
+		qcom,cpus-as-clocks;
+
+		qcom,pm-snoc-client {
+			compatible = "qcom,pm-snoc-client";
+			qcom,msm-bus,name = "ocimem_snoc";
+			qcom,msm-bus,num-cases = <2>;
+			qcom,msm-bus,num-paths = <1>;
+			qcom,msm-bus,active-only;
+			qcom,msm-bus,vectors-KBps =
+				<54 585 0 0>,
+				<54 585 0 800000>;
+		};
+	};
+
+	qcom,cpu-sleep-status@f9088008{
+		compatible = "qcom,cpu-sleep-status";
+		reg = <0xf9088008 0x100>;
+		qcom,cpu-alias-addr = <0x10000>;
+		qcom,sleep-status-mask= <0x80000>;
+	};
+
+	qcom,rpm-log@fc19dc00 {
+		compatible = "qcom,rpm-log";
+		reg = <0xfc19dc00 0x4000>;
+		qcom,rpm-addr-phys = <0xfc000000>;
+		qcom,offset-version = <4>;
+		qcom,offset-page-buffer-addr = <36>;
+		qcom,offset-log-len = <40>;
+		qcom,offset-log-len-mask = <44>;
+		qcom,offset-page-indices = <56>;
+	};
+
+	qcom,rpm-stats@fc19dba0 {
+		compatible = "qcom,rpm-stats";
+		reg = <0xfc19dba0 0x1000>;
+		reg-names = "phys_addr_base";
+		qcom,sleep-stats-version = <2>;
+	};
+
+	qcom,rpm-rbcpr-stats@fc000000 {
+		compatible = "qcom,rpmrbcpr-stats";
+		reg = <0xfc000000 0x1a0000>;
+		qcom,start-offset = <0x190010>;
+	};
+};
diff --git a/arch/arm/boot/dts/msm8974pro.dtsi b/arch/arm/boot/dts/msm8974pro.dtsi
index b80eb0f..86f0058 100644
--- a/arch/arm/boot/dts/msm8974pro.dtsi
+++ b/arch/arm/boot/dts/msm8974pro.dtsi
@@ -19,7 +19,8 @@
 /include/ "msm8974.dtsi"
 /include/ "msm8974-v2-iommu.dtsi"
 /include/ "msm8974-v2-iommu-domains.dtsi"
-/include/ "msm8974-v2-pm.dtsi"
+/include/ "msm8974pro-pm.dtsi"
+/include/ "msm8974pro-ion.dtsi"
 
 &soc {
 	android_usb@fe8050c8 {
@@ -32,6 +33,12 @@
 		compatible = "qcom,msm-imem";
 		reg = <0xfe805000 0x1000>; /* Address and size of IMEM */
 	};
+
+	qcom,msm-thermal {
+		/delete-property/ qcom,pmic-sw-mode-temp;
+		/delete-property/ qcom,pmic-sw-mode-temp-hysteresis;
+		/delete-property/ qcom,pmic-sw-mode-regs;
+	};
 };
 
 /* GPU overrides */
@@ -126,7 +133,7 @@
 
 &msm_vidc {
 	qcom,vidc-ns-map = <0x40000000 0x40000000>;
-	qcom,load-freq-tbl = <979200 465000000>,
+	qcom,load-freq-tbl = <1036800 465000000>,
 		<783360 465000000>,
 		<489600 266670000>,
 		<244800 133330000>;
@@ -161,19 +168,40 @@
 		<1608000 604000>,
 		<2576000 967000>,
 		<4680000 1404000>,
-		<49880000 1496000>;
+		<4988000 1496000>;
 	qcom,dec-ddr-ab-ib = <0 0>,
 		<208000 303000>,
-		<536000 303000>,
-		<1012000 303000>,
-		<2024000 606000>,
-		<3240000 970000>,
-		<4048000 1212000>,
-		<4264000 1279000>;
-	qcom,iommu-groups = <&venus_domain_ns &venus_domain_sec_bitstream
-			&venus_domain_sec_pixel &venus_domain_sec_non_pixel>;
-	qcom,iommu-group-buffer-types = <0xfff 0x91 0x42 0x120>;
+		<536000 1600000>,
+		<1012000 1600000>,
+		<2024000 1600000>,
+		<3240000 1600000>,
+		<4048000 1600000>,
+		<4264000 1600000>;
+	qcom,max-hw-load = <1281600>; /* max(4k X 2304 @ 24, 4k X 2160 @ 30) + 1080p @ 30 */
 	qcom,buffer-type-tz-usage-table = <0x91 0x1>,
 					<0x42 0x2>,
 					<0x120 0x3>;
+	qcom,vidc-iommu-domains {
+		qcom,domain-ns {
+			qcom,vidc-domain-phandle = <&venus_domain_ns>;
+			qcom,vidc-partition-buffer-types = <0x1ff>,
+							<0x200>;
+		};
+		qcom,domain-sec-bs {
+			qcom,vidc-domain-phandle = <&venus_domain_sec_bitstream>;
+			qcom,vidc-partition-buffer-types = <0x91>;
+		};
+		qcom,domain-sec-px {
+			qcom,vidc-domain-phandle = <&venus_domain_sec_pixel>;
+			qcom,vidc-partition-buffer-types = <0x42>;
+		};
+		qcom,domain-sec-np {
+			qcom,vidc-domain-phandle = <&venus_domain_sec_non_pixel>;
+			qcom,vidc-partition-buffer-types = <0x120>;
+		};
+	};
+};
+
+&memory_hole {
+	qcom,memblock-remove = <0x05400000 0xab00000>; /* Address and size of the hole */
 };
diff --git a/arch/arm/boot/dts/msm9625-coresight.dtsi b/arch/arm/boot/dts/msm9625-coresight.dtsi
index 4a903b7..4880f96 100644
--- a/arch/arm/boot/dts/msm9625-coresight.dtsi
+++ b/arch/arm/boot/dts/msm9625-coresight.dtsi
@@ -19,8 +19,7 @@
 		interrupts = <0 166 0>;
 		interrupt-names = "byte-cntr-irq";
 
-		qcom,memory-reservation-type = "EBI1";
-		qcom,memory-reservation-size = <0x20000>; /* 128K EBI1 buffer */
+		qcom,memory-size = <0x20000>;
 
 		coresight-id = <0>;
 		coresight-name = "coresight-tmc-etr";
@@ -121,13 +120,13 @@
 		coresight-child-ports = <7>;
 	};
 
-	etm: etm@fc332000 {
+	etm0: etm@fc332000 {
 		compatible = "arm,coresight-etm";
 		reg = <0xfc332000 0x1000>;
 		reg-names = "etm-base";
 
 		coresight-id = <8>;
-		coresight-name = "coresight-etm";
+		coresight-name = "coresight-etm0";
 		coresight-nr-inports = <0>;
 		coresight-outports = <0>;
 		coresight-child-list = <&funnel_in0>;
diff --git a/arch/arm/boot/dts/msm9625-pm.dtsi b/arch/arm/boot/dts/msm9625-pm.dtsi
index 7989f2b..1e6cdf2 100644
--- a/arch/arm/boot/dts/msm9625-pm.dtsi
+++ b/arch/arm/boot/dts/msm9625-pm.dtsi
@@ -192,4 +192,12 @@
 		reg = <0xfc000000 0x1a0000>;
 		qcom,start-offset = <0x190010>;
 	};
+
+	qcom,rpm-master-stats@fc428150 {
+		compatible = "qcom,rpm-master-stats";
+		reg = <0xfc428150 0x3200>;
+		qcom,masters = "APSS", "MPSS", "LPSS";
+		qcom,master-stats-version = <2>;
+		qcom,master-offset = <2560>;
+	};
 };
diff --git a/arch/arm/boot/dts/msmsamarium-regulator.dtsi b/arch/arm/boot/dts/msmsamarium-regulator.dtsi
new file mode 100644
index 0000000..ae4dc8d
--- /dev/null
+++ b/arch/arm/boot/dts/msmsamarium-regulator.dtsi
@@ -0,0 +1,374 @@
+/*
+ * Copyright (c) 2013, The Linux Foundation. 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 and
+ * only 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.
+ */
+
+/* QPNP controlled regulators: */
+
+&spmi_bus {
+	qcom,pma8084@1 {
+		pma8084_s1: regulator@1400 {
+			regulator-min-microvolt = <1050000>;
+			regulator-max-microvolt = <1050000>;
+			qcom,enable-time = <500>;
+			qcom,pull-down-enable = <1>;
+			regulator-always-on;
+			qcom,system-load = <100000>;
+			status = "okay";
+		};
+
+		/* PMA8084 S2 + S12 = 2 phase VDD_CX supply */
+		pma8084_s2: regulator@1700 {
+			regulator-min-microvolt = <1050000>;
+			regulator-max-microvolt = <1050000>;
+			qcom,enable-time = <500>;
+			qcom,pull-down-enable = <1>;
+			regulator-always-on;
+			qcom,system-load = <100000>;
+			status = "okay";
+		};
+
+		pma8084_s3: regulator@1a00 {
+			regulator-min-microvolt = <1300000>;
+			regulator-max-microvolt = <1300000>;
+			qcom,enable-time = <500>;
+			qcom,pull-down-enable = <1>;
+			regulator-always-on;
+			qcom,system-load = <100000>;
+			status = "okay";
+		};
+
+		pma8084_s4: regulator@1d00 {
+			regulator-min-microvolt = <1800000>;
+			regulator-max-microvolt = <1800000>;
+			qcom,enable-time = <500>;
+			qcom,pull-down-enable = <1>;
+			regulator-always-on;
+			qcom,system-load = <100000>;
+			status = "okay";
+		};
+
+		/* Output of PMA8084 S5 and L25 is tied together. */
+		pma8084_s5: regulator@2000 {
+			regulator-min-microvolt = <2150000>;
+			regulator-max-microvolt = <2150000>;
+			qcom,enable-time = <500>;
+			qcom,pull-down-enable = <1>;
+			status = "okay";
+		};
+
+		pma8084_s6: regulator@2300 {
+			regulator-min-microvolt = <500000>;
+			regulator-max-microvolt = <1050000>;
+			qcom,enable-time = <500>;
+			qcom,pull-down-enable = <1>;
+			status = "okay";
+		};
+
+		pma8084_s7: regulator@2600 {
+			regulator-min-microvolt = <815000>;
+			regulator-max-microvolt = <900000>;
+			qcom,enable-time = <500>;
+			qcom,pull-down-enable = <1>;
+			status = "okay";
+		};
+
+		pma8084_s8: regulator@2900 {
+			regulator-min-microvolt = <500000>;
+			regulator-max-microvolt = <1100000>;
+			qcom,enable-time = <500>;
+			qcom,pull-down-enable = <1>;
+			regulator-always-on;
+			qcom,system-load = <100000>;
+			status = "okay";
+		};
+
+		pma8084_s9: regulator@2c00 {
+			regulator-min-microvolt = <500000>;
+			regulator-max-microvolt = <1100000>;
+			qcom,enable-time = <500>;
+			qcom,pull-down-enable = <1>;
+			regulator-always-on;
+			qcom,system-load = <100000>;
+			status = "okay";
+		};
+
+		pma8084_s10: regulator@2f00 {
+			regulator-min-microvolt = <500000>;
+			regulator-max-microvolt = <1100000>;
+			qcom,enable-time = <500>;
+			qcom,pull-down-enable = <1>;
+			regulator-always-on;
+			qcom,system-load = <100000>;
+			status = "okay";
+		};
+
+		pma8084_s11: regulator@3200 {
+			regulator-min-microvolt = <500000>;
+			regulator-max-microvolt = <1100000>;
+			qcom,enable-time = <500>;
+			qcom,pull-down-enable = <1>;
+			regulator-always-on;
+			qcom,system-load = <100000>;
+			status = "okay";
+		};
+
+		pma8084_l1: regulator@4000 {
+			parent-supply = <&pma8084_s3>;
+			regulator-min-microvolt = <1225000>;
+			regulator-max-microvolt = <1225000>;
+			qcom,enable-time = <200>;
+			qcom,pull-down-enable = <1>;
+			regulator-always-on;
+			qcom,system-load = <10000>;
+			status = "okay";
+		};
+
+		pma8084_l2: regulator@4100 {
+			parent-supply = <&pma8084_s3>;
+			regulator-min-microvolt = <1175000>;
+			regulator-max-microvolt = <1175000>;
+			qcom,enable-time = <200>;
+			qcom,pull-down-enable = <1>;
+			status = "okay";
+		};
+
+		pma8084_l3: regulator@4200 {
+			parent-supply = <&pma8084_s3>;
+			regulator-min-microvolt = <1200000>;
+			regulator-max-microvolt = <1200000>;
+			qcom,enable-time = <200>;
+			qcom,pull-down-enable = <1>;
+			status = "okay";
+		};
+
+		pma8084_l4: regulator@4300 {
+			parent-supply = <&pma8084_s3>;
+			regulator-min-microvolt = <1225000>;
+			regulator-max-microvolt = <1225000>;
+			qcom,enable-time = <200>;
+			qcom,pull-down-enable = <1>;
+			status = "okay";
+		};
+
+		pma8084_l6: regulator@4500 {
+			parent-supply = <&pma8084_s5>;
+			regulator-min-microvolt = <1800000>;
+			regulator-max-microvolt = <1800000>;
+			qcom,enable-time = <200>;
+			qcom,pull-down-enable = <1>;
+			status = "okay";
+		};
+
+		pma8084_l8: regulator@4700 {
+			regulator-min-microvolt = <1800000>;
+			regulator-max-microvolt = <1800000>;
+			qcom,enable-time = <200>;
+			qcom,pull-down-enable = <1>;
+			status = "okay";
+		};
+
+		pma8084_l9: regulator@4800 {
+			regulator-min-microvolt = <1800000>;
+			regulator-max-microvolt = <1800000>;
+			qcom,enable-time = <200>;
+			qcom,pull-down-enable = <1>;
+			status = "okay";
+		};
+
+		pma8084_l10: regulator@4900 {
+			regulator-min-microvolt = <1800000>;
+			regulator-max-microvolt = <1800000>;
+			qcom,enable-time = <200>;
+			qcom,pull-down-enable = <1>;
+			status = "okay";
+		};
+
+		pma8084_l11: regulator@4a00 {
+			parent-supply = <&pma8084_s3>;
+			regulator-min-microvolt = <1300000>;
+			regulator-max-microvolt = <1300000>;
+			qcom,enable-time = <200>;
+			qcom,pull-down-enable = <1>;
+			status = "okay";
+		};
+
+		pma8084_l12: regulator@4b00 {
+			parent-supply = <&pma8084_s5>;
+			regulator-min-microvolt = <1800000>;
+			regulator-max-microvolt = <1800000>;
+			qcom,enable-time = <200>;
+			qcom,pull-down-enable = <1>;
+			status = "okay";
+		};
+
+		pma8084_l13: regulator@4c00 {
+			regulator-min-microvolt = <1800000>;
+			regulator-max-microvolt = <2950000>;
+			qcom,enable-time = <200>;
+			qcom,pull-down-enable = <1>;
+			status = "okay";
+		};
+
+		pma8084_l14: regulator@4d00 {
+			parent-supply = <&pma8084_s5>;
+			regulator-min-microvolt = <1800000>;
+			regulator-max-microvolt = <1800000>;
+			qcom,enable-time = <200>;
+			qcom,pull-down-enable = <1>;
+			status = "okay";
+		};
+
+		pma8084_l15: regulator@4e00 {
+			parent-supply = <&pma8084_s5>;
+			regulator-min-microvolt = <2050000>;
+			regulator-max-microvolt = <2050000>;
+			qcom,enable-time = <200>;
+			qcom,pull-down-enable = <1>;
+			status = "okay";
+		};
+
+		pma8084_l16: regulator@4f00 {
+			regulator-min-microvolt = <2700000>;
+			regulator-max-microvolt = <2700000>;
+			qcom,enable-time = <200>;
+			qcom,pull-down-enable = <1>;
+			status = "okay";
+		};
+
+		pma8084_l17: regulator@5000 {
+			regulator-min-microvolt = <2850000>;
+			regulator-max-microvolt = <2850000>;
+			qcom,enable-time = <200>;
+			qcom,pull-down-enable = <1>;
+			status = "okay";
+		};
+
+		pma8084_l18: regulator@5100 {
+			regulator-min-microvolt = <2850000>;
+			regulator-max-microvolt = <2850000>;
+			qcom,enable-time = <200>;
+			qcom,pull-down-enable = <1>;
+			status = "okay";
+		};
+
+		pma8084_l19: regulator@5200 {
+			regulator-min-microvolt = <2900000>;
+			regulator-max-microvolt = <2900000>;
+			qcom,enable-time = <200>;
+			qcom,pull-down-enable = <1>;
+			status = "okay";
+		};
+
+		pma8084_l20: regulator@5300 {
+			regulator-min-microvolt = <2950000>;
+			regulator-max-microvolt = <2950000>;
+			qcom,enable-time = <200>;
+			qcom,pull-down-enable = <1>;
+			status = "okay";
+		};
+
+		pma8084_l21: regulator@5400 {
+			regulator-min-microvolt = <2950000>;
+			regulator-max-microvolt = <2950000>;
+			qcom,enable-time = <200>;
+			qcom,pull-down-enable = <1>;
+			status = "okay";
+		};
+
+		pma8084_l22: regulator@5500 {
+			regulator-min-microvolt = <3000000>;
+			regulator-max-microvolt = <3000000>;
+			qcom,enable-time = <200>;
+			qcom,pull-down-enable = <1>;
+			status = "okay";
+		};
+
+		pma8084_l23: regulator@5600 {
+			regulator-min-microvolt = <2850000>;
+			regulator-max-microvolt = <2850000>;
+			qcom,enable-time = <200>;
+			qcom,pull-down-enable = <1>;
+			status = "okay";
+		};
+
+		pma8084_l24: regulator@5700 {
+			regulator-min-microvolt = <3075000>;
+			regulator-max-microvolt = <3075000>;
+			qcom,enable-time = <200>;
+			qcom,pull-down-enable = <1>;
+			status = "okay";
+		};
+
+		pma8084_l26: regulator@5900 {
+			parent-supply = <&pma8084_s5>;
+			regulator-min-microvolt = <2050000>;
+			regulator-max-microvolt = <2050000>;
+			qcom,enable-time = <200>;
+			qcom,pull-down-enable = <1>;
+			status = "okay";
+		};
+
+		pma8084_l27: regulator@5a00 {
+			parent-supply = <&pma8084_s3>;
+			regulator-min-microvolt = <1050000>;
+			regulator-max-microvolt = <1050000>;
+			qcom,enable-time = <200>;
+			qcom,pull-down-enable = <1>;
+			status = "okay";
+		};
+
+		pma8084_lvs1: regulator@8000 {
+			parent-supply = <&pma8084_s4>;
+			qcom,enable-time = <200>;
+			qcom,pull-down-enable = <1>;
+			status = "okay";
+		};
+
+		pma8084_lvs2: regulator@8100 {
+			parent-supply = <&pma8084_s4>;
+			qcom,enable-time = <200>;
+			qcom,pull-down-enable = <1>;
+			status = "okay";
+		};
+
+		pma8084_lvs3: regulator@8200 {
+			parent-supply = <&pma8084_s4>;
+			qcom,enable-time = <200>;
+			qcom,pull-down-enable = <1>;
+			status = "okay";
+		};
+
+		pma8084_lvs4: regulator@8300 {
+			parent-supply = <&pma8084_s4>;
+			qcom,enable-time = <200>;
+			qcom,pull-down-enable = <1>;
+			status = "okay";
+		};
+
+		pma8084_mvs1: regulator@8400 {
+			qcom,enable-time = <200>;
+			qcom,pull-down-enable = <1>;
+			status = "okay";
+		};
+	};
+};
+
+&soc {
+	pma8084_s2_corner: s2_corner_vreg {
+		compatible = "qcom,stub-regulator";
+		regulator-name = "8084_s2_corner";
+		regulator-min-microvolt = <1>;
+		regulator-max-microvolt = <7>;
+		qcom,hpm-min-load = <100000>;
+		qcom,consumer-supplies = "vdd_dig", "";
+	};
+};
diff --git a/arch/arm/boot/dts/msmsamarium.dtsi b/arch/arm/boot/dts/msmsamarium.dtsi
index 8b79f3b..a492561 100644
--- a/arch/arm/boot/dts/msmsamarium.dtsi
+++ b/arch/arm/boot/dts/msmsamarium.dtsi
@@ -42,7 +42,7 @@
 		interrupt-controller;
 		#interrupt-cells = <2>;
 		reg = <0xfd510000 0x4000>;
-		ngpio = <145>;
+		ngpio = <146>;
 		interrupts = <0 208 0>;
 		qcom,direct-connect-irqs = <8>;
 	};
@@ -242,6 +242,19 @@
 		cell-index = <0>;
 		qcom,not-wakeup;     /* Needed until MPM is fully configured. */
 	};
+
+	tsens: tsens@fc4a8000 {
+		compatible = "qcom,msm-tsens";
+		reg = <0xfc4a8000 0x2000>,
+		      <0xfc4bc000 0x1000>;
+		reg-names = "tsens_physical", "tsens_eeprom_physical";
+		interrupts = <0 184 0>;
+		qcom,sensors = <11>;
+		qcom,slope = <3200 3200 3200 3200 3200 3200 3200 3200 3200
+				3200 3200>;
+		qcom,calib-mode = "fuse_map1";
+	};
 };
 
 /include/ "msm-pma8084.dtsi"
+/include/ "msmsamarium-regulator.dtsi"
diff --git a/arch/arm/configs/apq8084_defconfig b/arch/arm/configs/apq8084_defconfig
index 4315d3f..66d66fc 100644
--- a/arch/arm/configs/apq8084_defconfig
+++ b/arch/arm/configs/apq8084_defconfig
@@ -1,6 +1,7 @@
 # CONFIG_ARM_PATCH_PHYS_VIRT is not set
 CONFIG_EXPERIMENTAL=y
 CONFIG_SYSVIPC=y
+CONFIG_AUDIT=y
 CONFIG_RCU_FAST_NO_HZ=y
 CONFIG_IKCONFIG=y
 CONFIG_IKCONFIG_PROC=y
@@ -129,6 +130,7 @@
 CONFIG_NETFILTER=y
 CONFIG_NETFILTER_NETLINK_LOG=y
 CONFIG_NF_CONNTRACK=y
+CONFIG_NF_CONNTRACK_SECMARK=y
 CONFIG_NF_CONNTRACK_EVENTS=y
 CONFIG_NF_CT_PROTO_DCCP=y
 CONFIG_NF_CT_PROTO_SCTP=y
@@ -146,9 +148,11 @@
 CONFIG_NETFILTER_TPROXY=y
 CONFIG_NETFILTER_XT_TARGET_CLASSIFY=y
 CONFIG_NETFILTER_XT_TARGET_CONNMARK=y
+CONFIG_NETFILTER_XT_TARGET_CONNSECMARK=y
 CONFIG_NETFILTER_XT_TARGET_LOG=y
 CONFIG_NETFILTER_XT_TARGET_MARK=y
 CONFIG_NETFILTER_XT_TARGET_NFQUEUE=y
+CONFIG_NETFILTER_XT_TARGET_SECMARK=y
 CONFIG_NETFILTER_XT_MATCH_COMMENT=y
 CONFIG_NETFILTER_XT_MATCH_CONNLIMIT=y
 CONFIG_NETFILTER_XT_MATCH_CONNMARK=y
@@ -182,6 +186,7 @@
 CONFIG_IP_NF_TARGET_REJECT=y
 CONFIG_IP_NF_MANGLE=y
 CONFIG_IP_NF_RAW=y
+CONFIG_IP_NF_SECURITY=y
 CONFIG_IP_NF_ARPTABLES=y
 CONFIG_IP_NF_ARPFILTER=y
 CONFIG_IP_NF_ARP_MANGLE=y
@@ -359,6 +364,7 @@
 CONFIG_EXT3_FS=y
 # CONFIG_EXT3_DEFAULTS_TO_ORDERED is not set
 CONFIG_EXT4_FS=y
+CONFIG_EXT4_FS_SECURITY=y
 CONFIG_FUSE_FS=y
 CONFIG_VFAT_FS=y
 CONFIG_TMPFS=y
@@ -393,6 +399,10 @@
 CONFIG_EARLY_PRINTK=y
 CONFIG_PID_IN_CONTEXTIDR=y
 CONFIG_KEYS=y
+CONFIG_SECURITY=y
+CONFIG_SECURITY_NETWORK=y
+CONFIG_LSM_MMAP_MIN_ADDR=4096
+CONFIG_SECURITY_SELINUX=y
 CONFIG_CRYPTO_MD4=y
 CONFIG_CRYPTO_SHA256=y
 CONFIG_CRYPTO_ARC4=y
@@ -402,9 +412,11 @@
 CONFIG_CRYPTO_DEV_QCEDEV=m
 CONFIG_CRC_CCITT=y
 CONFIG_CORESIGHT=y
+CONFIG_CORESIGHT_FUSE=y
 CONFIG_CORESIGHT_TMC=y
 CONFIG_CORESIGHT_FUNNEL=y
 CONFIG_CORESIGHT_REPLICATOR=y
 CONFIG_CORESIGHT_STM=y
+CONFIG_CORESIGHT_HWEVENT=y
 CONFIG_CORESIGHT_ETM=y
 CONFIG_USB_BAM=y
diff --git a/arch/arm/configs/msm8226-perf_defconfig b/arch/arm/configs/msm8226-perf_defconfig
index 31d133a..d11634b 100644
--- a/arch/arm/configs/msm8226-perf_defconfig
+++ b/arch/arm/configs/msm8226-perf_defconfig
@@ -1,7 +1,7 @@
 # CONFIG_ARM_PATCH_PHYS_VIRT is not set
 CONFIG_EXPERIMENTAL=y
-# CONFIG_LOCALVERSION_AUTO is not set
 CONFIG_SYSVIPC=y
+CONFIG_AUDIT=y
 CONFIG_RCU_FAST_NO_HZ=y
 CONFIG_IKCONFIG=y
 CONFIG_IKCONFIG_PROC=y
@@ -61,7 +61,7 @@
 CONFIG_MSM_WATCHDOG_V2=y
 CONFIG_MSM_MEMORY_DUMP=y
 CONFIG_MSM_DLOAD_MODE=y
-CONFIG_MSM_ADSP_LOADER=m
+CONFIG_MSM_ADSP_LOADER=y
 CONFIG_MSM_OCMEM=y
 CONFIG_MSM_OCMEM_LOCAL_POWER_CTRL=y
 CONFIG_MSM_OCMEM_DEBUG=y
@@ -72,6 +72,7 @@
 CONFIG_MSM_RTB_SEPARATE_CPUS=y
 CONFIG_MSM_ENABLE_WDOG_DEBUG_CONTROL=y
 CONFIG_MSM_BOOT_STATS=y
+CONFIG_STRICT_MEMORY_RWX=y
 CONFIG_NO_HZ=y
 CONFIG_HIGH_RES_TIMERS=y
 CONFIG_SMP=y
@@ -98,14 +99,17 @@
 CONFIG_NET=y
 CONFIG_PACKET=y
 CONFIG_UNIX=y
+CONFIG_XFRM_USER=y
 CONFIG_INET=y
 CONFIG_IP_ADVANCED_ROUTER=y
 CONFIG_IP_MULTIPLE_TABLES=y
 CONFIG_IP_ROUTE_VERBOSE=y
 CONFIG_IP_PNP=y
 CONFIG_IP_PNP_DHCP=y
-# CONFIG_INET_XFRM_MODE_TRANSPORT is not set
-# CONFIG_INET_XFRM_MODE_TUNNEL is not set
+CONFIG_INET_AH=y
+CONFIG_INET_ESP=y
+CONFIG_INET_XFRM_MODE_TRANSPORT=y
+CONFIG_INET_XFRM_MODE_TUNNEL=y
 # CONFIG_INET_XFRM_MODE_BEET is not set
 # CONFIG_INET_LRO is not set
 CONFIG_IPV6=y
@@ -122,6 +126,7 @@
 CONFIG_NETFILTER=y
 CONFIG_NETFILTER_NETLINK_LOG=y
 CONFIG_NF_CONNTRACK=y
+CONFIG_NF_CONNTRACK_SECMARK=y
 CONFIG_NF_CONNTRACK_EVENTS=y
 CONFIG_NF_CT_PROTO_DCCP=y
 CONFIG_NF_CT_PROTO_SCTP=y
@@ -139,9 +144,12 @@
 CONFIG_NETFILTER_TPROXY=y
 CONFIG_NETFILTER_XT_TARGET_CLASSIFY=y
 CONFIG_NETFILTER_XT_TARGET_CONNMARK=y
+CONFIG_NETFILTER_XT_TARGET_CONNSECMARK=y
 CONFIG_NETFILTER_XT_TARGET_LOG=y
 CONFIG_NETFILTER_XT_TARGET_MARK=y
 CONFIG_NETFILTER_XT_TARGET_NFQUEUE=y
+CONFIG_NETFILTER_XT_TARGET_NOTRACK=y
+CONFIG_NETFILTER_XT_TARGET_SECMARK=y
 CONFIG_NETFILTER_XT_MATCH_COMMENT=y
 CONFIG_NETFILTER_XT_MATCH_CONNLIMIT=y
 CONFIG_NETFILTER_XT_MATCH_CONNMARK=y
@@ -179,6 +187,7 @@
 CONFIG_IP_NF_TARGET_REDIRECT=y
 CONFIG_IP_NF_MANGLE=y
 CONFIG_IP_NF_RAW=y
+CONFIG_IP_NF_SECURITY=y
 CONFIG_IP_NF_ARPTABLES=y
 CONFIG_IP_NF_ARPFILTER=y
 CONFIG_IP_NF_ARP_MANGLE=y
@@ -223,6 +232,7 @@
 CONFIG_DM_CRYPT=y
 CONFIG_NETDEVICES=y
 CONFIG_DUMMY=y
+CONFIG_TUN=y
 CONFIG_KS8851=y
 # CONFIG_MSM_RMNET is not set
 CONFIG_MSM_RMNET_BAM=y
@@ -290,6 +300,8 @@
 # CONFIG_MSM_CAMERA is not set
 CONFIG_OV8825=y
 CONFIG_OV12830=y
+CONFIG_IMX135=y
+CONFIG_OV8865=y
 CONFIG_MSM_CAMERA_SENSOR=y
 CONFIG_MSM_EEPROM=y
 CONFIG_MSM_CPP=y
@@ -313,6 +325,7 @@
 CONFIG_ION=y
 CONFIG_ION_MSM=y
 CONFIG_MSM_KGSL=y
+CONFIG_KGSL_PER_PROCESS_PAGE_TABLE=y
 CONFIG_FB=y
 CONFIG_FB_MSM=y
 # CONFIG_FB_MSM_BACKLIGHT is not set
@@ -398,6 +411,7 @@
 CONFIG_EXT3_FS=y
 # CONFIG_EXT3_DEFAULTS_TO_ORDERED is not set
 CONFIG_EXT4_FS=y
+CONFIG_EXT4_FS_SECURITY=y
 CONFIG_FUSE_FS=y
 CONFIG_VFAT_FS=y
 CONFIG_TMPFS=y
@@ -415,8 +429,14 @@
 CONFIG_DEBUG_USER=y
 CONFIG_DEBUG_SET_MODULE_RONX=y
 CONFIG_KEYS=y
+CONFIG_CRYPTO_NULL=y
+CONFIG_SECURITY=y
+CONFIG_SECURITY_NETWORK=y
+CONFIG_LSM_MMAP_MIN_ADDR=4096
+CONFIG_SECURITY_SELINUX=y
 CONFIG_CRYPTO_MD4=y
 CONFIG_CRYPTO_ARC4=y
+CONFIG_CRYPTO_XCBC=y
 CONFIG_CRYPTO_TWOFISH=y
 CONFIG_NFC_QNCI=y
 CONFIG_CRYPTO_DEV_QCRYPTO=m
@@ -425,3 +445,5 @@
 CONFIG_MOBICORE_SUPPORT=m
 CONFIG_MOBICORE_API=m
 CONFIG_MSM_RPM_RBCPR_STATS_V2_LOG=y
+CONFIG_TOUCHSCREEN_GT9XX=y
+CONFIG_GT9XX_TOUCHPANEL_DRIVER=y
diff --git a/arch/arm/configs/msm8226_defconfig b/arch/arm/configs/msm8226_defconfig
index 24ac0d8..b03e4cd 100644
--- a/arch/arm/configs/msm8226_defconfig
+++ b/arch/arm/configs/msm8226_defconfig
@@ -1,7 +1,7 @@
 # CONFIG_ARM_PATCH_PHYS_VIRT is not set
 CONFIG_EXPERIMENTAL=y
-# CONFIG_LOCALVERSION_AUTO is not set
 CONFIG_SYSVIPC=y
+CONFIG_AUDIT=y
 CONFIG_RCU_FAST_NO_HZ=y
 CONFIG_IKCONFIG=y
 CONFIG_IKCONFIG_PROC=y
@@ -61,7 +61,7 @@
 CONFIG_MSM_WATCHDOG_V2=y
 CONFIG_MSM_MEMORY_DUMP=y
 CONFIG_MSM_DLOAD_MODE=y
-CONFIG_MSM_ADSP_LOADER=m
+CONFIG_MSM_ADSP_LOADER=y
 CONFIG_MSM_OCMEM=y
 CONFIG_MSM_OCMEM_LOCAL_POWER_CTRL=y
 CONFIG_MSM_OCMEM_DEBUG=y
@@ -73,6 +73,7 @@
 CONFIG_MSM_ENABLE_WDOG_DEBUG_CONTROL=y
 CONFIG_MSM_BOOT_STATS=y
 CONFIG_MSM_XPU_ERR_FATAL=y
+CONFIG_STRICT_MEMORY_RWX=y
 CONFIG_NO_HZ=y
 CONFIG_HIGH_RES_TIMERS=y
 CONFIG_SMP=y
@@ -99,14 +100,17 @@
 CONFIG_NET=y
 CONFIG_PACKET=y
 CONFIG_UNIX=y
+CONFIG_XFRM_USER=y
 CONFIG_INET=y
 CONFIG_IP_ADVANCED_ROUTER=y
 CONFIG_IP_MULTIPLE_TABLES=y
 CONFIG_IP_ROUTE_VERBOSE=y
 CONFIG_IP_PNP=y
 CONFIG_IP_PNP_DHCP=y
-# CONFIG_INET_XFRM_MODE_TRANSPORT is not set
-# CONFIG_INET_XFRM_MODE_TUNNEL is not set
+CONFIG_INET_AH=y
+CONFIG_INET_ESP=y
+CONFIG_INET_XFRM_MODE_TRANSPORT=y
+CONFIG_INET_XFRM_MODE_TUNNEL=y
 # CONFIG_INET_XFRM_MODE_BEET is not set
 # CONFIG_INET_LRO is not set
 CONFIG_IPV6=y
@@ -123,6 +127,7 @@
 CONFIG_NETFILTER=y
 CONFIG_NETFILTER_NETLINK_LOG=y
 CONFIG_NF_CONNTRACK=y
+CONFIG_NF_CONNTRACK_SECMARK=y
 CONFIG_NF_CONNTRACK_EVENTS=y
 CONFIG_NF_CT_PROTO_DCCP=y
 CONFIG_NF_CT_PROTO_SCTP=y
@@ -140,9 +145,12 @@
 CONFIG_NETFILTER_TPROXY=y
 CONFIG_NETFILTER_XT_TARGET_CLASSIFY=y
 CONFIG_NETFILTER_XT_TARGET_CONNMARK=y
+CONFIG_NETFILTER_XT_TARGET_CONNSECMARK=y
 CONFIG_NETFILTER_XT_TARGET_LOG=y
 CONFIG_NETFILTER_XT_TARGET_MARK=y
 CONFIG_NETFILTER_XT_TARGET_NFQUEUE=y
+CONFIG_NETFILTER_XT_TARGET_NOTRACK=y
+CONFIG_NETFILTER_XT_TARGET_SECMARK=y
 CONFIG_NETFILTER_XT_MATCH_COMMENT=y
 CONFIG_NETFILTER_XT_MATCH_CONNLIMIT=y
 CONFIG_NETFILTER_XT_MATCH_CONNMARK=y
@@ -180,6 +188,7 @@
 CONFIG_IP_NF_TARGET_REDIRECT=y
 CONFIG_IP_NF_MANGLE=y
 CONFIG_IP_NF_RAW=y
+CONFIG_IP_NF_SECURITY=y
 CONFIG_IP_NF_ARPTABLES=y
 CONFIG_IP_NF_ARPFILTER=y
 CONFIG_IP_NF_ARP_MANGLE=y
@@ -205,6 +214,7 @@
 CONFIG_BT_HIDP=y
 CONFIG_BT_HCISMD=y
 CONFIG_CFG80211=y
+CONFIG_CFG80211_INTERNAL_REGDB=y
 CONFIG_NL80211_TESTMODE=y
 CONFIG_CMA=y
 CONFIG_BLK_DEV_LOOP=y
@@ -294,6 +304,8 @@
 # CONFIG_MSM_CAMERA is not set
 CONFIG_OV8825=y
 CONFIG_OV12830=y
+CONFIG_IMX135=y
+CONFIG_OV8865=y
 CONFIG_MSM_CAMERA_SENSOR=y
 CONFIG_MSM_EEPROM=y
 CONFIG_MSM_CPP=y
@@ -339,6 +351,7 @@
 CONFIG_ION=y
 CONFIG_ION_MSM=y
 CONFIG_MSM_KGSL=y
+CONFIG_KGSL_PER_PROCESS_PAGE_TABLE=y
 CONFIG_FB=y
 CONFIG_FB_MSM=y
 # CONFIG_FB_MSM_BACKLIGHT is not set
@@ -434,6 +447,7 @@
 CONFIG_EXT3_FS=y
 # CONFIG_EXT3_DEFAULTS_TO_ORDERED is not set
 CONFIG_EXT4_FS=y
+CONFIG_EXT4_FS_SECURITY=y
 CONFIG_FUSE_FS=y
 CONFIG_VFAT_FS=y
 CONFIG_TMPFS=y
@@ -466,8 +480,14 @@
 CONFIG_EARLY_PRINTK=y
 CONFIG_DEBUG_SET_MODULE_RONX=y
 CONFIG_KEYS=y
+CONFIG_CRYPTO_NULL=y
+CONFIG_SECURITY=y
+CONFIG_SECURITY_NETWORK=y
+CONFIG_LSM_MMAP_MIN_ADDR=4096
+CONFIG_SECURITY_SELINUX=y
 CONFIG_CRYPTO_MD4=y
 CONFIG_CRYPTO_ARC4=y
+CONFIG_CRYPTO_XCBC=y
 CONFIG_CRYPTO_TWOFISH=y
 CONFIG_NFC_QNCI=y
 CONFIG_CRYPTO_DEV_QCRYPTO=m
@@ -476,3 +496,5 @@
 CONFIG_MOBICORE_SUPPORT=m
 CONFIG_MOBICORE_API=m
 CONFIG_MSM_RPM_RBCPR_STATS_V2_LOG=y
+CONFIG_TOUCHSCREEN_GT9XX=y
+CONFIG_GT9XX_TOUCHPANEL_DRIVER=y
diff --git a/arch/arm/configs/msm8610-perf_defconfig b/arch/arm/configs/msm8610-perf_defconfig
index 0db08db..1a197a3 100644
--- a/arch/arm/configs/msm8610-perf_defconfig
+++ b/arch/arm/configs/msm8610-perf_defconfig
@@ -2,6 +2,7 @@
 CONFIG_EXPERIMENTAL=y
 CONFIG_LOCALVERSION="-perf"
 CONFIG_SYSVIPC=y
+CONFIG_AUDIT=y
 CONFIG_RCU_FAST_NO_HZ=y
 CONFIG_IKCONFIG=y
 CONFIG_IKCONFIG_PROC=y
@@ -62,15 +63,13 @@
 CONFIG_MSM_WATCHDOG_V2=y
 CONFIG_MSM_MEMORY_DUMP=y
 CONFIG_MSM_DLOAD_MODE=y
-CONFIG_MSM_ADSP_LOADER=m
+CONFIG_MSM_ADSP_LOADER=y
 CONFIG_MSM_OCMEM=y
 CONFIG_MSM_OCMEM_LOCAL_POWER_CTRL=y
 CONFIG_MSM_OCMEM_DEBUG=y
 CONFIG_MSM_OCMEM_NONSECURE=y
 CONFIG_MSM_OCMEM_POWER_DISABLE=y
 CONFIG_SENSORS_ADSP=y
-CONFIG_MSM_RTB=y
-CONFIG_MSM_RTB_SEPARATE_CPUS=y
 CONFIG_MSM_ENABLE_WDOG_DEBUG_CONTROL=y
 CONFIG_MSM_BOOT_STATS=y
 CONFIG_NO_HZ=y
@@ -123,6 +122,7 @@
 CONFIG_NETFILTER=y
 CONFIG_NETFILTER_NETLINK_LOG=y
 CONFIG_NF_CONNTRACK=y
+CONFIG_NF_CONNTRACK_SECMARK=y
 CONFIG_NF_CONNTRACK_EVENTS=y
 CONFIG_NF_CT_PROTO_DCCP=y
 CONFIG_NF_CT_PROTO_SCTP=y
@@ -140,9 +140,11 @@
 CONFIG_NETFILTER_TPROXY=y
 CONFIG_NETFILTER_XT_TARGET_CLASSIFY=y
 CONFIG_NETFILTER_XT_TARGET_CONNMARK=y
+CONFIG_NETFILTER_XT_TARGET_CONNSECMARK=y
 CONFIG_NETFILTER_XT_TARGET_LOG=y
 CONFIG_NETFILTER_XT_TARGET_MARK=y
 CONFIG_NETFILTER_XT_TARGET_NFQUEUE=y
+CONFIG_NETFILTER_XT_TARGET_SECMARK=y
 CONFIG_NETFILTER_XT_MATCH_COMMENT=y
 CONFIG_NETFILTER_XT_MATCH_CONNLIMIT=y
 CONFIG_NETFILTER_XT_MATCH_CONNMARK=y
@@ -180,6 +182,7 @@
 CONFIG_IP_NF_TARGET_REDIRECT=y
 CONFIG_IP_NF_MANGLE=y
 CONFIG_IP_NF_RAW=y
+CONFIG_IP_NF_SECURITY=y
 CONFIG_IP_NF_ARPTABLES=y
 CONFIG_IP_NF_ARPFILTER=y
 CONFIG_IP_NF_ARP_MANGLE=y
@@ -234,6 +237,7 @@
 CONFIG_INPUT_MISC=y
 CONFIG_INPUT_UINPUT=y
 CONFIG_INPUT_GPIO=m
+# CONFIG_INPUT_MOUSEDEV is not set
 CONFIG_SERIAL_MSM_HSL=y
 CONFIG_SERIAL_MSM_HSL_CONSOLE=y
 CONFIG_DIAG_CHAR=y
@@ -282,6 +286,7 @@
 CONFIG_OV5648=y
 CONFIG_MSM_CAMERA_SENSOR=y
 # CONFIG_MSM_CPP is not set
+CONFIG_MSM_EEPROM=y
 CONFIG_MSM_CCI=y
 CONFIG_MSM_CSI22_HEADER=y
 CONFIG_MSM_CSIPHY=y
@@ -366,6 +371,7 @@
 CONFIG_EXT3_FS=y
 # CONFIG_EXT3_DEFAULTS_TO_ORDERED is not set
 CONFIG_EXT4_FS=y
+CONFIG_EXT4_FS_SECURITY=y
 CONFIG_FUSE_FS=y
 CONFIG_VFAT_FS=y
 CONFIG_TMPFS=y
@@ -382,12 +388,26 @@
 CONFIG_DEBUG_USER=y
 CONFIG_DEBUG_SET_MODULE_RONX=y
 CONFIG_KEYS=y
+CONFIG_SECURITY=y
+CONFIG_SECURITY_NETWORK=y
+CONFIG_LSM_MMAP_MIN_ADDR=4096
+CONFIG_SECURITY_SELINUX=y
 CONFIG_CRYPTO_MD4=y
 CONFIG_CRYPTO_ARC4=y
 CONFIG_CRYPTO_TWOFISH=y
 # CONFIG_CRYPTO_HW is not set
 CONFIG_CRC_CCITT=y
+CONFIG_PPP=y
+CONFIG_PPP_ASYNC=y
+CONFIG_PPP_SYNC_TTY=y
+CONFIG_PPP_DEFLATE=y
+CONFIG_PPP_BSDCOMP=y
+CONFIG_PPPOE=y
+CONFIG_N_HDLC=y
+CONFIG_UNIX98_PTYS=y
 CONFIG_INPUT_KXTJ9=y
 CONFIG_MSM_RPM_RBCPR_STATS_V2_LOG=y
 CONFIG_SENSORS_STK3X1X=y
 CONFIG_SENSORS_MMA8X5X=y
+CONFIG_LOGCAT_SIZE=64
+CONFIG_SENSORS_CAPELLA_CM36283=y
diff --git a/arch/arm/configs/msm8610_defconfig b/arch/arm/configs/msm8610_defconfig
index a5f0704..8238414 100644
--- a/arch/arm/configs/msm8610_defconfig
+++ b/arch/arm/configs/msm8610_defconfig
@@ -1,7 +1,7 @@
 # CONFIG_ARM_PATCH_PHYS_VIRT is not set
 CONFIG_EXPERIMENTAL=y
-# CONFIG_LOCALVERSION_AUTO is not set
 CONFIG_SYSVIPC=y
+CONFIG_AUDIT=y
 CONFIG_RCU_FAST_NO_HZ=y
 CONFIG_IKCONFIG=y
 CONFIG_IKCONFIG_PROC=y
@@ -60,7 +60,7 @@
 CONFIG_MSM_WATCHDOG_V2=y
 CONFIG_MSM_MEMORY_DUMP=y
 CONFIG_MSM_DLOAD_MODE=y
-CONFIG_MSM_ADSP_LOADER=m
+CONFIG_MSM_ADSP_LOADER=y
 CONFIG_MSM_OCMEM=y
 CONFIG_MSM_OCMEM_LOCAL_POWER_CTRL=y
 CONFIG_MSM_OCMEM_DEBUG=y
@@ -71,6 +71,8 @@
 CONFIG_MSM_RTB_SEPARATE_CPUS=y
 CONFIG_MSM_ENABLE_WDOG_DEBUG_CONTROL=y
 CONFIG_MSM_BOOT_STATS=y
+CONFIG_MSM_XPU_ERR_FATAL=y
+CONFIG_STRICT_MEMORY_RWX=y
 CONFIG_NO_HZ=y
 CONFIG_HIGH_RES_TIMERS=y
 CONFIG_SMP=y
@@ -121,6 +123,7 @@
 CONFIG_NETFILTER=y
 CONFIG_NETFILTER_NETLINK_LOG=y
 CONFIG_NF_CONNTRACK=y
+CONFIG_NF_CONNTRACK_SECMARK=y
 CONFIG_NF_CONNTRACK_EVENTS=y
 CONFIG_NF_CT_PROTO_DCCP=y
 CONFIG_NF_CT_PROTO_SCTP=y
@@ -138,9 +141,11 @@
 CONFIG_NETFILTER_TPROXY=y
 CONFIG_NETFILTER_XT_TARGET_CLASSIFY=y
 CONFIG_NETFILTER_XT_TARGET_CONNMARK=y
+CONFIG_NETFILTER_XT_TARGET_CONNSECMARK=y
 CONFIG_NETFILTER_XT_TARGET_LOG=y
 CONFIG_NETFILTER_XT_TARGET_MARK=y
 CONFIG_NETFILTER_XT_TARGET_NFQUEUE=y
+CONFIG_NETFILTER_XT_TARGET_SECMARK=y
 CONFIG_NETFILTER_XT_MATCH_COMMENT=y
 CONFIG_NETFILTER_XT_MATCH_CONNLIMIT=y
 CONFIG_NETFILTER_XT_MATCH_CONNMARK=y
@@ -178,6 +183,7 @@
 CONFIG_IP_NF_TARGET_REDIRECT=y
 CONFIG_IP_NF_MANGLE=y
 CONFIG_IP_NF_RAW=y
+CONFIG_IP_NF_SECURITY=y
 CONFIG_IP_NF_ARPTABLES=y
 CONFIG_IP_NF_ARPFILTER=y
 CONFIG_IP_NF_ARP_MANGLE=y
@@ -203,6 +209,7 @@
 CONFIG_BT_HIDP=y
 CONFIG_BT_HCISMD=y
 CONFIG_CFG80211=y
+CONFIG_CFG80211_INTERNAL_REGDB=y
 CONFIG_NL80211_TESTMODE=y
 CONFIG_CMA=y
 CONFIG_BLK_DEV_LOOP=y
@@ -232,6 +239,7 @@
 CONFIG_INPUT_MISC=y
 CONFIG_INPUT_UINPUT=y
 CONFIG_INPUT_GPIO=m
+# CONFIG_INPUT_MOUSEDEV is not set
 CONFIG_SERIAL_MSM_HSL=y
 CONFIG_SERIAL_MSM_HSL_CONSOLE=y
 CONFIG_DIAG_CHAR=y
@@ -278,6 +286,7 @@
 CONFIG_HI256=y
 CONFIG_OV12830=y
 CONFIG_MSM_CAMERA_SENSOR=y
+CONFIG_MSM_EEPROM=y
 CONFIG_MSM_CCI=y
 CONFIG_MSM_CSIPHY=y
 CONFIG_MSM_CSID=y
@@ -395,6 +404,7 @@
 CONFIG_EXT3_FS=y
 # CONFIG_EXT3_DEFAULTS_TO_ORDERED is not set
 CONFIG_EXT4_FS=y
+CONFIG_EXT4_FS_SECURITY=y
 CONFIG_FUSE_FS=y
 CONFIG_VFAT_FS=y
 CONFIG_TMPFS=y
@@ -425,6 +435,10 @@
 CONFIG_DEBUG_USER=y
 CONFIG_DEBUG_SET_MODULE_RONX=y
 CONFIG_KEYS=y
+CONFIG_SECURITY=y
+CONFIG_SECURITY_NETWORK=y
+CONFIG_LSM_MMAP_MIN_ADDR=4096
+CONFIG_SECURITY_SELINUX=y
 CONFIG_CRYPTO_MD4=y
 CONFIG_CRYPTO_ARC4=y
 CONFIG_CRYPTO_TWOFISH=y
@@ -432,7 +446,16 @@
 CONFIG_CRYPTO_DEV_QCE=y
 CONFIG_CRYPTO_DEV_QCEDEV=m
 CONFIG_CRC_CCITT=y
+CONFIG_PPP=y
+CONFIG_PPP_ASYNC=y
+CONFIG_PPP_SYNC_TTY=y
+CONFIG_PPP_DEFLATE=y
+CONFIG_PPP_BSDCOMP=y
+CONFIG_PPPOE=y
+CONFIG_N_HDLC=y
+CONFIG_UNIX98_PTYS=y
 CONFIG_INPUT_KXTJ9=y
 CONFIG_MSM_RPM_RBCPR_STATS_V2_LOG=y
 CONFIG_SENSORS_STK3X1X=y
 CONFIG_SENSORS_MMA8X5X=y
+CONFIG_SENSORS_CAPELLA_CM36283=y
diff --git a/arch/arm/configs/msm8960_defconfig b/arch/arm/configs/msm8960_defconfig
index 9b55c3b..c668cb2 100644
--- a/arch/arm/configs/msm8960_defconfig
+++ b/arch/arm/configs/msm8960_defconfig
@@ -240,19 +240,20 @@
 CONFIG_NET_EMATCH_TEXT=y
 CONFIG_NET_CLS_ACT=y
 CONFIG_BT=y
-CONFIG_BT_RFCOMM=y
-CONFIG_BT_RFCOMM_TTY=y
-CONFIG_BT_BNEP=y
-CONFIG_BT_BNEP_MC_FILTER=y
-CONFIG_BT_BNEP_PROTO_FILTER=y
+# CONFIG_BT_RFCOMM is not set
+# CONFIG_BT_RFCOMM_TTY is not set
+# CONFIG_BT_BNEP is not set
+# CONFIG_BT_BNEP_MC_FILTER is not set
+# CONFIG_BT_BNEP_PROTO_FILTER is not set
 CONFIG_BT_HIDP=y
-CONFIG_BT_HCISMD=y
-CONFIG_BT_HCIUART=y
-CONFIG_BT_HCIUART_H4=y
-CONFIG_BT_HCIUART_ATH3K=y
-CONFIG_BT_HCIUART_IBS=y
-CONFIG_MSM_BT_POWER=y
+# CONFIG_BT_HCISMD is not set
+# CONFIG_BT_HCIUART is not set
+# CONFIG_BT_HCIUART_H4 is not set
+# CONFIG_BT_HCIUART_ATH3K is not set
+# CONFIG_BT_HCIUART_IBS is not set
+# CONFIG_MSM_BT_POWER is not set
 CONFIG_CFG80211=m
+CONFIG_CFG80211_INTERNAL_REGDB=y
 # CONFIG_CFG80211_WEXT is not set
 CONFIG_RFKILL=y
 CONFIG_GENLOCK=y
diff --git a/arch/arm/configs/msm8974-perf_defconfig b/arch/arm/configs/msm8974-perf_defconfig
index f2f6558..6683409 100644
--- a/arch/arm/configs/msm8974-perf_defconfig
+++ b/arch/arm/configs/msm8974-perf_defconfig
@@ -2,6 +2,7 @@
 CONFIG_EXPERIMENTAL=y
 CONFIG_LOCALVERSION="-perf"
 CONFIG_SYSVIPC=y
+CONFIG_AUDIT=y
 CONFIG_RCU_FAST_NO_HZ=y
 CONFIG_IKCONFIG=y
 CONFIG_IKCONFIG_PROC=y
@@ -68,7 +69,7 @@
 CONFIG_MSM_WATCHDOG_V2=y
 CONFIG_MSM_MEMORY_DUMP=y
 CONFIG_MSM_DLOAD_MODE=y
-CONFIG_MSM_ADSP_LOADER=m
+CONFIG_MSM_ADSP_LOADER=y
 CONFIG_MSM_OCMEM=y
 CONFIG_MSM_OCMEM_LOCAL_POWER_CTRL=y
 CONFIG_MSM_OCMEM_DEBUG=y
@@ -139,6 +140,7 @@
 CONFIG_NETFILTER=y
 CONFIG_NETFILTER_NETLINK_LOG=y
 CONFIG_NF_CONNTRACK=y
+CONFIG_NF_CONNTRACK_SECMARK=y
 CONFIG_NF_CONNTRACK_EVENTS=y
 CONFIG_NF_CT_PROTO_DCCP=y
 CONFIG_NF_CT_PROTO_SCTP=y
@@ -156,9 +158,12 @@
 CONFIG_NETFILTER_TPROXY=y
 CONFIG_NETFILTER_XT_TARGET_CLASSIFY=y
 CONFIG_NETFILTER_XT_TARGET_CONNMARK=y
+CONFIG_NETFILTER_XT_TARGET_CONNSECMARK=y
 CONFIG_NETFILTER_XT_TARGET_LOG=y
 CONFIG_NETFILTER_XT_TARGET_MARK=y
 CONFIG_NETFILTER_XT_TARGET_NFQUEUE=y
+CONFIG_NETFILTER_XT_TARGET_NOTRACK=y
+CONFIG_NETFILTER_XT_TARGET_SECMARK=y
 CONFIG_NETFILTER_XT_MATCH_COMMENT=y
 CONFIG_NETFILTER_XT_MATCH_CONNLIMIT=y
 CONFIG_NETFILTER_XT_MATCH_CONNMARK=y
@@ -196,6 +201,7 @@
 CONFIG_IP_NF_TARGET_REDIRECT=y
 CONFIG_IP_NF_MANGLE=y
 CONFIG_IP_NF_RAW=y
+CONFIG_IP_NF_SECURITY=y
 CONFIG_IP_NF_ARPTABLES=y
 CONFIG_IP_NF_ARPFILTER=y
 CONFIG_IP_NF_ARP_MANGLE=y
@@ -280,6 +286,8 @@
 CONFIG_INPUT_TOUCHSCREEN=y
 CONFIG_TOUCHSCREEN_ATMEL_MXT=y
 CONFIG_TOUCHSCREEN_GEN_VKEYS=y
+CONFIG_TOUCHSCREEN_SYNAPTICS_I2C_RMI4=y
+CONFIG_TOUCHSCREEN_SYNAPTICS_DSX_FW_UPDATE=y
 CONFIG_INPUT_MISC=y
 CONFIG_INPUT_UINPUT=y
 CONFIG_SERIAL_MSM_HS=y
@@ -452,6 +460,7 @@
 CONFIG_EXT3_FS=y
 # CONFIG_EXT3_DEFAULTS_TO_ORDERED is not set
 CONFIG_EXT4_FS=y
+CONFIG_EXT4_FS_SECURITY=y
 CONFIG_FUSE_FS=y
 CONFIG_VFAT_FS=y
 CONFIG_TMPFS=y
@@ -471,6 +480,10 @@
 CONFIG_PID_IN_CONTEXTIDR=y
 CONFIG_DEBUG_SET_MODULE_RONX=y
 CONFIG_KEYS=y
+CONFIG_SECURITY=y
+CONFIG_SECURITY_NETWORK=y
+CONFIG_LSM_MMAP_MIN_ADDR=4096
+CONFIG_SECURITY_SELINUX=y
 CONFIG_CRYPTO_NULL=y
 CONFIG_CRYPTO_XCBC=y
 CONFIG_CRYPTO_MD4=y
@@ -480,3 +493,4 @@
 CONFIG_CRYPTO_DEV_QCE=y
 CONFIG_CRYPTO_DEV_QCEDEV=y
 CONFIG_SND_SOC_MSM_HDMI_CODEC_RX=y
+CONFIG_BUILD_ARM_APPENDED_DTB_IMAGE=y
diff --git a/arch/arm/configs/msm8974_defconfig b/arch/arm/configs/msm8974_defconfig
index 71742a5..02494b2 100644
--- a/arch/arm/configs/msm8974_defconfig
+++ b/arch/arm/configs/msm8974_defconfig
@@ -1,6 +1,7 @@
 # CONFIG_ARM_PATCH_PHYS_VIRT is not set
 CONFIG_EXPERIMENTAL=y
 CONFIG_SYSVIPC=y
+CONFIG_AUDIT=y
 CONFIG_RCU_FAST_NO_HZ=y
 CONFIG_IKCONFIG=y
 CONFIG_IKCONFIG_PROC=y
@@ -68,7 +69,7 @@
 CONFIG_MSM_WATCHDOG_V2=y
 CONFIG_MSM_MEMORY_DUMP=y
 CONFIG_MSM_DLOAD_MODE=y
-CONFIG_MSM_ADSP_LOADER=m
+CONFIG_MSM_ADSP_LOADER=y
 CONFIG_MSM_OCMEM=y
 CONFIG_MSM_OCMEM_LOCAL_POWER_CTRL=y
 CONFIG_MSM_OCMEM_DEBUG=y
@@ -145,6 +146,7 @@
 CONFIG_NETFILTER=y
 CONFIG_NETFILTER_NETLINK_LOG=y
 CONFIG_NF_CONNTRACK=y
+CONFIG_NF_CONNTRACK_SECMARK=y
 CONFIG_NF_CONNTRACK_EVENTS=y
 CONFIG_NF_CT_PROTO_DCCP=y
 CONFIG_NF_CT_PROTO_SCTP=y
@@ -162,9 +164,12 @@
 CONFIG_NETFILTER_TPROXY=y
 CONFIG_NETFILTER_XT_TARGET_CLASSIFY=y
 CONFIG_NETFILTER_XT_TARGET_CONNMARK=y
+CONFIG_NETFILTER_XT_TARGET_CONNSECMARK=y
 CONFIG_NETFILTER_XT_TARGET_LOG=y
 CONFIG_NETFILTER_XT_TARGET_MARK=y
 CONFIG_NETFILTER_XT_TARGET_NFQUEUE=y
+CONFIG_NETFILTER_XT_TARGET_NOTRACK=y
+CONFIG_NETFILTER_XT_TARGET_SECMARK=y
 CONFIG_NETFILTER_XT_MATCH_COMMENT=y
 CONFIG_NETFILTER_XT_MATCH_CONNLIMIT=y
 CONFIG_NETFILTER_XT_MATCH_CONNMARK=y
@@ -202,6 +207,7 @@
 CONFIG_IP_NF_TARGET_REDIRECT=y
 CONFIG_IP_NF_MANGLE=y
 CONFIG_IP_NF_RAW=y
+CONFIG_IP_NF_SECURITY=y
 CONFIG_IP_NF_ARPTABLES=y
 CONFIG_IP_NF_ARPFILTER=y
 CONFIG_IP_NF_ARP_MANGLE=y
@@ -240,6 +246,7 @@
 CONFIG_BT_HCIUART_ATH3K=y
 CONFIG_MSM_BT_POWER=y
 CONFIG_CFG80211=y
+CONFIG_CFG80211_INTERNAL_REGDB=y
 CONFIG_NL80211_TESTMODE=y
 CONFIG_RFKILL=y
 CONFIG_GENLOCK=y
@@ -287,6 +294,8 @@
 CONFIG_INPUT_TOUCHSCREEN=y
 CONFIG_TOUCHSCREEN_ATMEL_MXT=y
 CONFIG_TOUCHSCREEN_GEN_VKEYS=y
+CONFIG_TOUCHSCREEN_SYNAPTICS_I2C_RMI4=y
+CONFIG_TOUCHSCREEN_SYNAPTICS_DSX_FW_UPDATE=y
 CONFIG_INPUT_MISC=y
 CONFIG_INPUT_UINPUT=y
 CONFIG_SERIAL_MSM_HS=y
@@ -470,6 +479,7 @@
 CONFIG_EXT3_FS=y
 # CONFIG_EXT3_DEFAULTS_TO_ORDERED is not set
 CONFIG_EXT4_FS=y
+CONFIG_EXT4_FS_SECURITY=y
 CONFIG_FUSE_FS=y
 CONFIG_VFAT_FS=y
 CONFIG_TMPFS=y
@@ -505,6 +515,10 @@
 CONFIG_PID_IN_CONTEXTIDR=y
 CONFIG_DEBUG_SET_MODULE_RONX=y
 CONFIG_KEYS=y
+CONFIG_SECURITY=y
+CONFIG_SECURITY_NETWORK=y
+CONFIG_LSM_MMAP_MIN_ADDR=4096
+CONFIG_SECURITY_SELINUX=y
 CONFIG_CRYPTO_NULL=y
 CONFIG_CRYPTO_XCBC=y
 CONFIG_CRYPTO_MD4=y
@@ -514,3 +528,4 @@
 CONFIG_CRYPTO_DEV_QCE=y
 CONFIG_CRYPTO_DEV_QCEDEV=y
 CONFIG_SND_SOC_MSM_HDMI_CODEC_RX=y
+CONFIG_BUILD_ARM_APPENDED_DTB_IMAGE=y
diff --git a/drivers/gpu/msm/adreno_trace.c b/arch/arm/include/asm/archrandom.h
similarity index 75%
rename from drivers/gpu/msm/adreno_trace.c
rename to arch/arm/include/asm/archrandom.h
index 607ba8c..5530d45 100644
--- a/drivers/gpu/msm/adreno_trace.c
+++ b/arch/arm/include/asm/archrandom.h
@@ -11,8 +11,10 @@
  *
  */
 
-#include "adreno.h"
+#ifndef ARM_ASM_ARCHRANDOM_H
+#define ARM_ASM_ARCHRANDOM_H
 
-/* Instantiate tracepoints */
-#define CREATE_TRACE_POINTS
-#include "adreno_trace.h"
+extern int arch_get_random_long(unsigned long *v);
+extern int arch_get_random_int(unsigned int *v);
+
+#endif
diff --git a/arch/arm/include/asm/pgtable.h b/arch/arm/include/asm/pgtable.h
index 6bbe966..e0376d1 100644
--- a/arch/arm/include/asm/pgtable.h
+++ b/arch/arm/include/asm/pgtable.h
@@ -101,7 +101,7 @@
 	__pgprot_modify(prot, L_PTE_MT_MASK, L_PTE_MT_BUFFERABLE)
 
 #define pgprot_stronglyordered(prot) \
-	__pgprot_modify(prot, L_PTE_MT_MASK, L_PTE_MT_UNCACHED)
+	__pgprot_modify(prot, L_PTE_MT_MASK, L_PTE_MT_UNCACHED | L_PTE_XN)
 
 #define pgprot_device(prot) \
 	__pgprot_modify(prot, L_PTE_MT_MASK, L_PTE_MT_DEV_NONSHARED)
diff --git a/arch/arm/kernel/arch_timer.c b/arch/arm/kernel/arch_timer.c
index ac4c7a3..9e27592 100644
--- a/arch/arm/kernel/arch_timer.c
+++ b/arch/arm/kernel/arch_timer.c
@@ -291,7 +291,7 @@
 	return 0;
 }
 
-static inline cycle_t counter_get_cntpct_mem(void)
+static inline cycle_t notrace counter_get_cntpct_mem(void)
 {
 	u32 cvall, cvalh, thigh;
 
@@ -304,7 +304,7 @@
 	return ((cycle_t) cvalh << 32) | cvall;
 }
 
-static inline cycle_t counter_get_cntpct_cp15(void)
+static inline cycle_t notrace counter_get_cntpct_cp15(void)
 {
 	u32 cvall, cvalh;
 
@@ -312,7 +312,7 @@
 	return ((cycle_t) cvalh << 32) | cvall;
 }
 
-static inline cycle_t counter_get_cntvct_mem(void)
+static inline cycle_t notrace counter_get_cntvct_mem(void)
 {
 	u32 cvall, cvalh, thigh;
 
@@ -325,7 +325,7 @@
 	return ((cycle_t) cvalh << 32) | cvall;
 }
 
-static inline cycle_t counter_get_cntvct_cp15(void)
+static inline cycle_t notrace counter_get_cntvct_cp15(void)
 {
 	u32 cvall, cvalh;
 
diff --git a/arch/arm/kernel/sched_clock.c b/arch/arm/kernel/sched_clock.c
index ad9dfb2..bb97140 100644
--- a/arch/arm/kernel/sched_clock.c
+++ b/arch/arm/kernel/sched_clock.c
@@ -68,7 +68,9 @@
 		smp_rmb();
 	} while (epoch_cyc != cd.epoch_cyc_copy);
 
-	return epoch_ns + cyc_to_ns((cyc - epoch_cyc) & mask, cd.mult, cd.shift);
+	cyc = read_sched_clock();
+	cyc = (cyc - epoch_cyc) & sched_clock_mask;
+	return epoch_ns + cyc_to_ns(cyc, cd.mult, cd.shift);
 }
 
 /*
diff --git a/arch/arm/kernel/smp.c b/arch/arm/kernel/smp.c
index a70b300..5bca467 100644
--- a/arch/arm/kernel/smp.c
+++ b/arch/arm/kernel/smp.c
@@ -555,13 +555,15 @@
 
 static DEFINE_RAW_SPINLOCK(stop_lock);
 
+DEFINE_PER_CPU(struct pt_regs, regs_before_stop);
 /*
  * ipi_cpu_stop - handle IPI from smp_send_stop()
  */
-static void ipi_cpu_stop(unsigned int cpu)
+static void ipi_cpu_stop(unsigned int cpu, struct pt_regs *regs)
 {
 	if (system_state == SYSTEM_BOOTING ||
 	    system_state == SYSTEM_RUNNING) {
+		per_cpu(regs_before_stop, cpu) = *regs;
 		raw_spin_lock(&stop_lock);
 		printk(KERN_CRIT "CPU%u: stopping\n", cpu);
 		dump_stack();
@@ -676,7 +678,7 @@
 
 	case IPI_CPU_STOP:
 		irq_enter();
-		ipi_cpu_stop(cpu);
+		ipi_cpu_stop(cpu, regs);
 		irq_exit();
 		break;
 
diff --git a/arch/arm/kernel/vmlinux.lds.S b/arch/arm/kernel/vmlinux.lds.S
index ae59e5a..0bf55ae 100644
--- a/arch/arm/kernel/vmlinux.lds.S
+++ b/arch/arm/kernel/vmlinux.lds.S
@@ -93,6 +93,9 @@
 		_text = .;
 		HEAD_TEXT
 	}
+#ifdef CONFIG_STRICT_MEMORY_RWX
+	. = ALIGN(1<<SECTION_SHIFT);
+#endif
 
 	.text : {			/* Real text segment		*/
 		_stext = .;		/* Text and read-only data	*/
@@ -115,10 +118,10 @@
 		*(.got)			/* Global offset table		*/
 			ARM_CPU_KEEP(PROC_INFO)
 	}
+
 #ifdef CONFIG_STRICT_MEMORY_RWX
 	. = ALIGN(1<<SECTION_SHIFT);
 #endif
-
 	RO_DATA(PAGE_SIZE)
 
 #ifdef CONFIG_ARM_UNWIND
@@ -156,6 +159,9 @@
 	.init.proc.info : {
 		ARM_CPU_DISCARD(PROC_INFO)
 	}
+#ifdef CONFIG_STRICT_MEMORY_RWX
+	. = ALIGN(1<<SECTION_SHIFT);
+#endif
 	.init.arch.info : {
 		__arch_info_begin = .;
 		*(.arch.info.init)
@@ -190,10 +196,6 @@
 		INIT_RAM_FS
 	}
 #ifndef CONFIG_XIP_KERNEL
-#ifdef CONFIG_STRICT_MEMORY_RWX
-	. = ALIGN(1<<SECTION_SHIFT);
-#endif
-	__init_data = .;
 	.exit.data : {
 		ARM_EXIT_KEEP(EXIT_DATA)
 	}
diff --git a/arch/arm/mach-msm/Kconfig b/arch/arm/mach-msm/Kconfig
index 5c0d2cf..696ddf9 100644
--- a/arch/arm/mach-msm/Kconfig
+++ b/arch/arm/mach-msm/Kconfig
@@ -1761,6 +1761,16 @@
 	help
 	  SMD Transport Layer for IPC Router
 
+config MSM_IPC_ROUTER_HSIC_XPRT
+	depends on USB_QCOM_IPC_BRIDGE
+	depends on MSM_IPC_ROUTER
+	bool "MSM HSIC XPRT Layer"
+	help
+	  HSIC Transport Layer that enables off-chip communication of
+	  IPC Router. When the HSIC endpoint becomes available, this layer
+	  registers the transport with IPC Router and enable message
+	  exchange.
+
 config MSM_IPC_ROUTER_SECURITY
 	depends on MSM_IPC_ROUTER
 	bool "MSM IPC Router Security support"
@@ -2626,7 +2636,7 @@
 config MSM_ADSP_LOADER
         tristate "ADSP loader support"
         select SND_SOC_MSM_APRV2_INTF
-	depends on MSM_AUDIO_QDSP6V2 && m
+	depends on MSM_AUDIO_QDSP6V2
         help
           Enable ADSP image loader.
 	  The ADSP loader brings ADSP out of reset
diff --git a/arch/arm/mach-msm/Makefile b/arch/arm/mach-msm/Makefile
index cd71104..dd533f4 100644
--- a/arch/arm/mach-msm/Makefile
+++ b/arch/arm/mach-msm/Makefile
@@ -24,7 +24,7 @@
 
 obj-y += acpuclock.o
 obj-$(CONFIG_HW_PERF_EVENTS) += perf_trace_counters.o
-obj-$(CONFIG_ARCH_MSM_KRAIT) += acpuclock-krait.o
+obj-$(CONFIG_ARCH_MSM_KRAIT) += acpuclock-krait.o clock-krait.o
 ifdef CONFIG_ARCH_MSM_KRAIT
 obj-$(CONFIG_DEBUG_FS) += acpuclock-krait-debug.o
 endif
@@ -75,7 +75,7 @@
 $(obj)/smd_rpc_sym.c: $(src)/smd_rpc_sym $(src)/mkrpcsym.pl
 	$(call if_changed,mkrpcsym)
 
-obj-$(CONFIG_MSM_SMD) += smd.o smd_debug.o remote_spinlock.o smd_private.o smem.o
+obj-$(CONFIG_MSM_SMD) += smd.o smd_debug.o remote_spinlock.o smd_private.o smem.o smd_init_dt.o smd_init_plat.o
 obj-$(CONFIG_MSM_SMP2P) += smp2p.o smp2p_debug.o smp2p_gpio.o
 obj-$(CONFIG_MSM_SMP2P_TEST) += smp2p_loopback.o smp2p_test.o smp2p_gpio_test.o smp2p_spinlock_test.o
 obj-$(CONFIG_MSM_SCM) += scm.o scm-boot.o
@@ -130,6 +130,7 @@
 obj-$(CONFIG_MSM_SMD_NMEA) += smd_nmea.o
 obj-$(CONFIG_MSM_RESET_MODEM) += reset_modem.o
 obj-$(CONFIG_MSM_IPC_ROUTER_SMD_XPRT) += ipc_router_smd_xprt.o
+obj-$(CONFIG_MSM_IPC_ROUTER_HSIC_XPRT) += ipc_router_hsic_xprt.o
 obj-$(CONFIG_MSM_ONCRPCROUTER) += smd_rpcrouter.o
 obj-$(CONFIG_MSM_ONCRPCROUTER) += smd_rpcrouter_device.o
 obj-$(CONFIG_MSM_IPC_ROUTER) += ipc_router.o
@@ -296,7 +297,7 @@
 obj-$(CONFIG_ARCH_MSM8610) += gdsc.o
 obj-$(CONFIG_ARCH_MPQ8092) += gdsc.o
 obj-$(CONFIG_ARCH_APQ8084) += gdsc.o
-obj-$(CONFIG_KRAIT_REGULATOR) += krait-regulator.o
+obj-$(CONFIG_KRAIT_REGULATOR) += krait-regulator.o  krait-regulator-pmic.o
 obj-$(CONFIG_ARCH_MSMKRYPTON) += board-krypton.o board-krypton-gpiomux.o
 obj-$(CONFIG_ARCH_MSMSAMARIUM) += board-samarium.o board-samarium-gpiomux.o
 obj-$(CONFIG_ARCH_MSM9625) += board-9625.o board-9625-gpiomux.o
@@ -431,3 +432,4 @@
 
 obj-$(CONFIG_WALL_CLK) += wallclk.o
 obj-$(CONFIG_WALL_CLK_SYSFS) += wallclk_sysfs.o
+obj-$(CONFIG_ARCH_RANDOM) += early_random.o
diff --git a/arch/arm/mach-msm/Makefile.boot b/arch/arm/mach-msm/Makefile.boot
index 9296515..910264e 100644
--- a/arch/arm/mach-msm/Makefile.boot
+++ b/arch/arm/mach-msm/Makefile.boot
@@ -109,6 +109,7 @@
         dtb-$(CONFIG_ARCH_MSM8226)	+= msm8926-cdp.dtb
         dtb-$(CONFIG_ARCH_MSM8226)	+= msm8926-mtp.dtb
         dtb-$(CONFIG_ARCH_MSM8226)	+= msm8926-qrd.dtb
+        dtb-$(CONFIG_ARCH_MSM8226)	+= msm8926-qrd-skug.dtb
         dtb-$(CONFIG_ARCH_MSM8226)	+= msm8226-v1-qrd-skuf.dtb
         dtb-$(CONFIG_ARCH_MSM8226)	+= msm8226-v2-qrd-skuf.dtb
         dtb-$(CONFIG_ARCH_MSM8226)	+= apq8026-v1-xpm.dtb
@@ -133,12 +134,16 @@
 
 # MSM8610
    zreladdr-$(CONFIG_ARCH_MSM8610)	:= 0x00008000
-        dtb-$(CONFIG_ARCH_MSM8610)	+= msm8610-cdp.dtb
-        dtb-$(CONFIG_ARCH_MSM8610)	+= msm8610-mtp.dtb
+        dtb-$(CONFIG_ARCH_MSM8610)	+= msm8610-v1-cdp.dtb
+        dtb-$(CONFIG_ARCH_MSM8610)	+= msm8610-v2-cdp.dtb
+        dtb-$(CONFIG_ARCH_MSM8610)	+= msm8610-v1-mtp.dtb
+        dtb-$(CONFIG_ARCH_MSM8610)	+= msm8610-v2-mtp.dtb
         dtb-$(CONFIG_ARCH_MSM8610)	+= msm8610-rumi.dtb
         dtb-$(CONFIG_ARCH_MSM8610)	+= msm8610-sim.dtb
-        dtb-$(CONFIG_ARCH_MSM8610)	+= msm8610-qrd-skuaa.dtb
-        dtb-$(CONFIG_ARCH_MSM8610)	+= msm8610-qrd-skuab.dtb
+        dtb-$(CONFIG_ARCH_MSM8610)	+= msm8610-v1-qrd-skuaa.dtb
+        dtb-$(CONFIG_ARCH_MSM8610)	+= msm8610-v1-qrd-skuab.dtb
+        dtb-$(CONFIG_ARCH_MSM8610)	+= msm8610-v2-qrd-skuaa.dtb
+        dtb-$(CONFIG_ARCH_MSM8610)	+= msm8610-v2-qrd-skuab.dtb
 
 # MSMSAMARIUM
    zreladdr-$(CONFIG_ARCH_MSMSAMARIUM)	:= 0x00008000
diff --git a/arch/arm/mach-msm/acpuclock-8226.c b/arch/arm/mach-msm/acpuclock-8226.c
index 59c682f..65e22ae 100644
--- a/arch/arm/mach-msm/acpuclock-8226.c
+++ b/arch/arm/mach-msm/acpuclock-8226.c
@@ -95,7 +95,7 @@
 	{ 0 }
 };
 
-static struct clkctl_acpu_speed acpu_freq_tbl_8226_1p5[] = {
+static struct clkctl_acpu_speed acpu_freq_tbl_8226_1p6[] = {
 	{ 1,  300000, PLL0,    4, 2,   CPR_CORNER_SVS,    0, 4 },
 	{ 1,  384000, ACPUPLL, 5, 2,   CPR_CORNER_SVS,    0, 4 },
 	{ 1,  600000, PLL0,    4, 0,   CPR_CORNER_NORMAL, 0, 6 },
@@ -106,7 +106,8 @@
 	{ 1, 1305600, ACPUPLL, 5, 0,   CPR_CORNER_TURBO,  0, 7 },
 	{ 1, 1344000, ACPUPLL, 5, 0,   CPR_CORNER_TURBO,  0, 7 },
 	{ 1, 1401600, ACPUPLL, 5, 0,   CPR_CORNER_TURBO,  0, 7 },
-	/* No support for 1p5 GHz yet */
+	{ 1, 1497600, ACPUPLL, 5, 0,   CPR_CORNER_TURBO,  0, 7 },
+	{ 1, 1593600, ACPUPLL, 5, 0,   CPR_CORNER_TURBO,  0, 7 },
 	{ 0 }
 };
 
@@ -125,8 +126,9 @@
 	[6] = acpu_freq_tbl_8226_1p2,
 	[2] = acpu_freq_tbl_8226_1p4,
 	[5] = acpu_freq_tbl_8226_1p4,
-	[3] = acpu_freq_tbl_8226_1p5,
-	[4] = acpu_freq_tbl_8226_1p5,
+	[4] = acpu_freq_tbl_8226_1p4,
+	[7] = acpu_freq_tbl_8226_1p4,
+	[1] = acpu_freq_tbl_8226_1p6,
 };
 
 static struct acpuclk_drv_data drv_data = {
diff --git a/arch/arm/mach-msm/acpuclock-8974.c b/arch/arm/mach-msm/acpuclock-8974.c
index 6d848d2..8410019 100644
--- a/arch/arm/mach-msm/acpuclock-8974.c
+++ b/arch/arm/mach-msm/acpuclock-8974.c
@@ -899,38 +899,460 @@
 	{ 0, { 0 } }
 };
 
-static struct acpu_level acpu_freq_tbl_pro_pvs0[] __initdata = {
-	{ 1, {  300000, PLL_0, 0,   0 },  L2(0),  800000, 999 },
-	{ 0, {  345600, HFPLL, 2,  36 },  L2(1),  800000, 999 },
-	{ 1, {  422400, HFPLL, 2,  44 },  L2(2),  800000, 999 },
-	{ 0, {  499200, HFPLL, 2,  52 },  L2(2),  805000, 999 },
-	{ 0, {  576000, HFPLL, 1,  30 },  L2(3),  815000, 999 },
-	{ 1, {  652800, HFPLL, 1,  34 },  L2(3),  825000, 999 },
-	{ 1, {  729600, HFPLL, 1,  38 },  L2(4),  835000, 999 },
-	{ 0, {  806400, HFPLL, 1,  42 },  L2(4),  845000, 999 },
-	{ 1, {  883200, HFPLL, 1,  46 },  L2(4),  855000, 999 },
-	{ 1, {  960000, HFPLL, 1,  50 },  L2(9),  865000, 999 },
-	{ 1, { 1036800, HFPLL, 1,  54 }, L2(10),  875000, 999 },
-	{ 0, { 1113600, HFPLL, 1,  58 }, L2(10),  890000, 999 },
-	{ 1, { 1190400, HFPLL, 1,  62 }, L2(10),  900000, 999 },
-	{ 1, { 1267200, HFPLL, 1,  66 }, L2(13),  915000, 999 },
-	{ 0, { 1344000, HFPLL, 1,  70 }, L2(14),  925000, 999 },
-	{ 0, { 1420800, HFPLL, 1,  74 }, L2(15),  940000, 999 },
-	{ 1, { 1497600, HFPLL, 1,  78 }, L2(16),  950000, 999 },
-	{ 1, { 1574400, HFPLL, 1,  82 }, L2(17),  965000, 999 },
-	{ 0, { 1651200, HFPLL, 1,  86 }, L2(17),  980000, 999 },
-	{ 1, { 1728000, HFPLL, 1,  90 }, L2(18),  995000, 999 },
-	{ 0, { 1804800, HFPLL, 1,  94 }, L2(18), 1010000, 999 },
-	{ 0, { 1881600, HFPLL, 1,  98 }, L2(18), 1025000, 999 },
-	{ 1, { 1958400, HFPLL, 1, 102 }, L2(19), 1040000, 999 },
-	{ 0, { 2035200, HFPLL, 1, 106 }, L2(19), 1055000, 999 },
-	{ 0, { 2112000, HFPLL, 1, 110 }, L2(19), 1070000, 999 },
-	{ 0, { 2188800, HFPLL, 1, 114 }, L2(19), 1085000, 999 },
-	{ 1, { 2265600, HFPLL, 1, 118 }, L2(19), 1100000, 999 },
-	/* higher frequencies aren't available for bring up */
+static struct acpu_level acpu_ftbl_pro_2p3g_pvs0[] __initdata = {
+	{ 1, {  300000, PLL_0, 0,   0 },  L2(0),  775000,  72 },
+	{ 0, {  345600, HFPLL, 2,  36 },  L2(1),  775000,  83 },
+	{ 1, {  422400, HFPLL, 2,  44 },  L2(2),  775000, 101 },
+	{ 0, {  499200, HFPLL, 2,  52 },  L2(2),  780000, 120 },
+	{ 0, {  576000, HFPLL, 1,  30 },  L2(3),  790000, 139 },
+	{ 1, {  652800, HFPLL, 1,  34 },  L2(3),  800000, 159 },
+	{ 1, {  729600, HFPLL, 1,  38 },  L2(4),  810000, 180 },
+	{ 0, {  806400, HFPLL, 1,  42 },  L2(4),  820000, 200 },
+	{ 1, {  883200, HFPLL, 1,  46 },  L2(4),  830000, 221 },
+	{ 1, {  960000, HFPLL, 1,  50 },  L2(9),  840000, 242 },
+	{ 1, { 1036800, HFPLL, 1,  54 }, L2(10),  850000, 264 },
+	{ 0, { 1113600, HFPLL, 1,  58 }, L2(10),  865000, 287 },
+	{ 1, { 1190400, HFPLL, 1,  62 }, L2(10),  875000, 308 },
+	{ 1, { 1267200, HFPLL, 1,  66 }, L2(13),  890000, 333 },
+	{ 0, { 1344000, HFPLL, 1,  70 }, L2(14),  900000, 356 },
+	{ 0, { 1420800, HFPLL, 1,  74 }, L2(15),  915000, 380 },
+	{ 1, { 1497600, HFPLL, 1,  78 }, L2(16),  925000, 404 },
+	{ 1, { 1574400, HFPLL, 1,  82 }, L2(17),  940000, 430 },
+	{ 0, { 1651200, HFPLL, 1,  86 }, L2(17),  955000, 456 },
+	{ 1, { 1728000, HFPLL, 1,  90 }, L2(18),  970000, 482 },
+	{ 0, { 1804800, HFPLL, 1,  94 }, L2(18),  985000, 510 },
+	{ 0, { 1881600, HFPLL, 1,  98 }, L2(18), 1000000, 538 },
+	{ 1, { 1958400, HFPLL, 1, 102 }, L2(19), 1015000, 565 },
+	{ 0, { 2035200, HFPLL, 1, 106 }, L2(19), 1030000, 596 },
+	{ 0, { 2112000, HFPLL, 1, 110 }, L2(19), 1045000, 627 },
+	{ 0, { 2188800, HFPLL, 1, 114 }, L2(19), 1060000, 659 },
+	{ 1, { 2265600, HFPLL, 1, 118 }, L2(19), 1075000, 691 },
 	{ 0, { 0 } }
 };
 
+static struct acpu_level acpu_ftbl_pro_2p3g_pvs1[] __initdata = {
+	{ 1, {  300000, PLL_0, 0,   0 },  L2(0),  775000,  72},
+	{ 0, {  345600, HFPLL, 2,  36 },  L2(1),  775000,  83},
+	{ 1, {  422400, HFPLL, 2,  44 },  L2(2),  775000, 101},
+	{ 0, {  499200, HFPLL, 2,  52 },  L2(2),  775000, 120},
+	{ 0, {  576000, HFPLL, 1,  30 },  L2(3),  775000, 139},
+	{ 1, {  652800, HFPLL, 1,  34 },  L2(3),  785000, 159},
+	{ 1, {  729600, HFPLL, 1,  38 },  L2(4),  795000, 180},
+	{ 0, {  806400, HFPLL, 1,  42 },  L2(4),  805000, 200},
+	{ 1, {  883200, HFPLL, 1,  46 },  L2(4),  815000, 221},
+	{ 1, {  960000, HFPLL, 1,  50 },  L2(9),  825000, 242},
+	{ 1, { 1036800, HFPLL, 1,  54 }, L2(10),  835000, 264},
+	{ 0, { 1113600, HFPLL, 1,  58 }, L2(10),  850000, 287},
+	{ 1, { 1190400, HFPLL, 1,  62 }, L2(10),  860000, 308},
+	{ 1, { 1267200, HFPLL, 1,  66 }, L2(13),  870000, 333},
+	{ 0, { 1344000, HFPLL, 1,  70 }, L2(14),  885000, 356},
+	{ 0, { 1420800, HFPLL, 1,  74 }, L2(15),  895000, 380},
+	{ 1, { 1497600, HFPLL, 1,  78 }, L2(16),  905000, 404},
+	{ 1, { 1574400, HFPLL, 1,  82 }, L2(17),  920000, 430},
+	{ 0, { 1651200, HFPLL, 1,  86 }, L2(17),  935000, 456},
+	{ 1, { 1728000, HFPLL, 1,  90 }, L2(18),  950000, 482},
+	{ 0, { 1804800, HFPLL, 1,  94 }, L2(18),  965000, 510},
+	{ 0, { 1881600, HFPLL, 1,  98 }, L2(18),  980000, 538},
+	{ 1, { 1958400, HFPLL, 1, 102 }, L2(19),  995000, 565},
+	{ 0, { 2035200, HFPLL, 1, 106 }, L2(19), 1005000, 596},
+	{ 0, { 2112000, HFPLL, 1, 110 }, L2(19), 1020000, 627},
+	{ 0, { 2188800, HFPLL, 1, 114 }, L2(19), 1035000, 659},
+	{ 1, { 2265600, HFPLL, 1, 118 }, L2(19), 1050000, 691},
+	{ 0, { 0 } }
+};
+
+static struct acpu_level acpu_ftbl_pro_2p3g_pvs2[] __initdata = {
+	{ 1, {  300000, PLL_0, 0,   0 },  L2(0),  750000,  72 },
+	{ 0, {  345600, HFPLL, 2,  36 },  L2(1),  750000,  83 },
+	{ 1, {  422400, HFPLL, 2,  44 },  L2(2),  750000, 101 },
+	{ 0, {  499200, HFPLL, 2,  52 },  L2(2),  750000, 120 },
+	{ 0, {  576000, HFPLL, 1,  30 },  L2(3),  760000, 139 },
+	{ 1, {  652800, HFPLL, 1,  34 },  L2(3),  770000, 159 },
+	{ 1, {  729600, HFPLL, 1,  38 },  L2(4),  780000, 180 },
+	{ 0, {  806400, HFPLL, 1,  42 },  L2(4),  790000, 200 },
+	{ 1, {  883200, HFPLL, 1,  46 },  L2(4),  800000, 221 },
+	{ 1, {  960000, HFPLL, 1,  50 },  L2(9),  810000, 242 },
+	{ 1, { 1036800, HFPLL, 1,  54 }, L2(10),  820000, 264 },
+	{ 0, { 1113600, HFPLL, 1,  58 }, L2(10),  830000, 287 },
+	{ 1, { 1190400, HFPLL, 1,  62 }, L2(10),  840000, 308 },
+	{ 1, { 1267200, HFPLL, 1,  66 }, L2(13),  850000, 333 },
+	{ 0, { 1344000, HFPLL, 1,  70 }, L2(14),  865000, 356 },
+	{ 0, { 1420800, HFPLL, 1,  74 }, L2(15),  875000, 380 },
+	{ 1, { 1497600, HFPLL, 1,  78 }, L2(16),  885000, 404 },
+	{ 1, { 1574400, HFPLL, 1,  82 }, L2(17),  900000, 430 },
+	{ 0, { 1651200, HFPLL, 1,  86 }, L2(17),  915000, 456 },
+	{ 1, { 1728000, HFPLL, 1,  90 }, L2(18),  930000, 482 },
+	{ 0, { 1804800, HFPLL, 1,  94 }, L2(18),  945000, 510 },
+	{ 0, { 1881600, HFPLL, 1,  98 }, L2(18),  955000, 538 },
+	{ 1, { 1958400, HFPLL, 1, 102 }, L2(19),  970000, 565 },
+	{ 0, { 2035200, HFPLL, 1, 106 }, L2(19),  980000, 596 },
+	{ 0, { 2112000, HFPLL, 1, 110 }, L2(19),  995000, 627 },
+	{ 0, { 2188800, HFPLL, 1, 114 }, L2(19), 1010000, 659 },
+	{ 1, { 2265600, HFPLL, 1, 118 }, L2(19), 1025000, 691 },
+	{ 0, { 0 } }
+};
+
+static struct acpu_level acpu_ftbl_pro_2p3g_pvs3[] __initdata = {
+	{ 1, {  300000, PLL_0, 0,   0 },  L2(0),  750000,  72},
+	{ 0, {  345600, HFPLL, 2,  36 },  L2(1),  750000,  83},
+	{ 1, {  422400, HFPLL, 2,  44 },  L2(2),  750000, 101},
+	{ 0, {  499200, HFPLL, 2,  52 },  L2(2),  750000, 120},
+	{ 0, {  576000, HFPLL, 1,  30 },  L2(3),  750000, 139},
+	{ 1, {  652800, HFPLL, 1,  34 },  L2(3),  755000, 159},
+	{ 1, {  729600, HFPLL, 1,  38 },  L2(4),  765000, 180},
+	{ 0, {  806400, HFPLL, 1,  42 },  L2(4),  775000, 200},
+	{ 1, {  883200, HFPLL, 1,  46 },  L2(4),  785000, 221},
+	{ 1, {  960000, HFPLL, 1,  50 },  L2(9),  795000, 242},
+	{ 1, { 1036800, HFPLL, 1,  54 }, L2(10),  805000, 264},
+	{ 0, { 1113600, HFPLL, 1,  58 }, L2(10),  815000, 287},
+	{ 1, { 1190400, HFPLL, 1,  62 }, L2(10),  825000, 308},
+	{ 1, { 1267200, HFPLL, 1,  66 }, L2(13),  835000, 333},
+	{ 0, { 1344000, HFPLL, 1,  70 }, L2(14),  850000, 356},
+	{ 0, { 1420800, HFPLL, 1,  74 }, L2(15),  860000, 380},
+	{ 1, { 1497600, HFPLL, 1,  78 }, L2(16),  870000, 404},
+	{ 1, { 1574400, HFPLL, 1,  82 }, L2(17),  885000, 430},
+	{ 0, { 1651200, HFPLL, 1,  86 }, L2(17),  900000, 456},
+	{ 1, { 1728000, HFPLL, 1,  90 }, L2(18),  910000, 482},
+	{ 0, { 1804800, HFPLL, 1,  94 }, L2(18),  925000, 510},
+	{ 0, { 1881600, HFPLL, 1,  98 }, L2(18),  935000, 538},
+	{ 1, { 1958400, HFPLL, 1, 102 }, L2(19),  945000, 565},
+	{ 0, { 2035200, HFPLL, 1, 106 }, L2(19),  960000, 596},
+	{ 0, { 2112000, HFPLL, 1, 110 }, L2(19),  970000, 627},
+	{ 0, { 2188800, HFPLL, 1, 114 }, L2(19),  985000, 659},
+	{ 1, { 2265600, HFPLL, 1, 118 }, L2(19), 1000000, 691},
+	{ 0, { 0 } }
+};
+
+static struct acpu_level acpu_ftbl_pro_2p3g_pvs4[] __initdata = {
+	{ 1, {  300000, PLL_0, 0,   0 },  L2(0),  750000,  72},
+	{ 0, {  345600, HFPLL, 2,  36 },  L2(1),  750000,  83},
+	{ 1, {  422400, HFPLL, 2,  44 },  L2(2),  750000, 101},
+	{ 0, {  499200, HFPLL, 2,  52 },  L2(2),  750000, 120},
+	{ 0, {  576000, HFPLL, 1,  30 },  L2(3),  750000, 139},
+	{ 1, {  652800, HFPLL, 1,  34 },  L2(3),  750000, 159},
+	{ 1, {  729600, HFPLL, 1,  38 },  L2(4),  755000, 180},
+	{ 0, {  806400, HFPLL, 1,  42 },  L2(4),  765000, 200},
+	{ 1, {  883200, HFPLL, 1,  46 },  L2(4),  775000, 221},
+	{ 1, {  960000, HFPLL, 1,  50 },  L2(9),  785000, 242},
+	{ 1, { 1036800, HFPLL, 1,  54 }, L2(10),  795000, 264},
+	{ 0, { 1113600, HFPLL, 1,  58 }, L2(10),  805000, 287},
+	{ 1, { 1190400, HFPLL, 1,  62 }, L2(10),  815000, 308},
+	{ 1, { 1267200, HFPLL, 1,  66 }, L2(13),  825000, 333},
+	{ 0, { 1344000, HFPLL, 1,  70 }, L2(14),  835000, 356},
+	{ 0, { 1420800, HFPLL, 1,  74 }, L2(15),  845000, 380},
+	{ 1, { 1497600, HFPLL, 1,  78 }, L2(16),  855000, 404},
+	{ 1, { 1574400, HFPLL, 1,  82 }, L2(17),  870000, 430},
+	{ 0, { 1651200, HFPLL, 1,  86 }, L2(17),  885000, 456},
+	{ 1, { 1728000, HFPLL, 1,  90 }, L2(18),  895000, 482},
+	{ 0, { 1804800, HFPLL, 1,  94 }, L2(18),  905000, 510},
+	{ 0, { 1881600, HFPLL, 1,  98 }, L2(18),  915000, 538},
+	{ 1, { 1958400, HFPLL, 1, 102 }, L2(19),  925000, 565},
+	{ 0, { 2035200, HFPLL, 1, 106 }, L2(19),  935000, 596},
+	{ 0, { 2112000, HFPLL, 1, 110 }, L2(19),  950000, 627},
+	{ 0, { 2188800, HFPLL, 1, 114 }, L2(19),  960000, 659},
+	{ 1, { 2265600, HFPLL, 1, 118 }, L2(19),  975000, 691},
+	{ 0, { 0 } }
+};
+
+static struct acpu_level acpu_ftbl_pro_2p3g_pvs5[] __initdata = {
+	{ 1, {  300000, PLL_0, 0,   0 },  L2(0),  725000,  72},
+	{ 0, {  345600, HFPLL, 2,  36 },  L2(1),  725000,  83},
+	{ 1, {  422400, HFPLL, 2,  44 },  L2(2),  725000, 101},
+	{ 0, {  499200, HFPLL, 2,  52 },  L2(2),  725000, 120},
+	{ 0, {  576000, HFPLL, 1,  30 },  L2(3),  725000, 139},
+	{ 1, {  652800, HFPLL, 1,  34 },  L2(3),  735000, 159},
+	{ 1, {  729600, HFPLL, 1,  38 },  L2(4),  745000, 180},
+	{ 0, {  806400, HFPLL, 1,  42 },  L2(4),  755000, 200},
+	{ 1, {  883200, HFPLL, 1,  46 },  L2(4),  765000, 221},
+	{ 1, {  960000, HFPLL, 1,  50 },  L2(9),  775000, 242},
+	{ 1, { 1036800, HFPLL, 1,  54 }, L2(10),  785000, 264},
+	{ 0, { 1113600, HFPLL, 1,  58 }, L2(10),  795000, 287},
+	{ 1, { 1190400, HFPLL, 1,  62 }, L2(10),  805000, 308},
+	{ 1, { 1267200, HFPLL, 1,  66 }, L2(13),  815000, 333},
+	{ 0, { 1344000, HFPLL, 1,  70 }, L2(14),  825000, 356},
+	{ 0, { 1420800, HFPLL, 1,  74 }, L2(15),  835000, 380},
+	{ 1, { 1497600, HFPLL, 1,  78 }, L2(16),  845000, 404},
+	{ 1, { 1574400, HFPLL, 1,  82 }, L2(17),  855000, 430},
+	{ 0, { 1651200, HFPLL, 1,  86 }, L2(17),  865000, 456},
+	{ 1, { 1728000, HFPLL, 1,  90 }, L2(18),  875000, 482},
+	{ 0, { 1804800, HFPLL, 1,  94 }, L2(18),  885000, 510},
+	{ 0, { 1881600, HFPLL, 1,  98 }, L2(18),  895000, 538},
+	{ 1, { 1958400, HFPLL, 1, 102 }, L2(19),  905000, 565},
+	{ 0, { 2035200, HFPLL, 1, 106 }, L2(19),  915000, 596},
+	{ 0, { 2112000, HFPLL, 1, 110 }, L2(19),  930000, 627},
+	{ 0, { 2188800, HFPLL, 1, 114 }, L2(19),  940000, 659},
+	{ 1, { 2265600, HFPLL, 1, 118 }, L2(19),  950000, 691},
+	{ 0, { 0 } }
+};
+
+static struct acpu_level acpu_ftbl_pro_2p3g_pvs6[] __initdata = {
+	{ 1, {  300000, PLL_0, 0,   0 },  L2(0),  725000,  72},
+	{ 0, {  345600, HFPLL, 2,  36 },  L2(1),  725000,  83},
+	{ 1, {  422400, HFPLL, 2,  44 },  L2(2),  725000, 101},
+	{ 0, {  499200, HFPLL, 2,  52 },  L2(2),  725000, 120},
+	{ 0, {  576000, HFPLL, 1,  30 },  L2(3),  725000, 139},
+	{ 1, {  652800, HFPLL, 1,  34 },  L2(3),  725000, 159},
+	{ 1, {  729600, HFPLL, 1,  38 },  L2(4),  735000, 180},
+	{ 0, {  806400, HFPLL, 1,  42 },  L2(4),  745000, 200},
+	{ 1, {  883200, HFPLL, 1,  46 },  L2(4),  755000, 221},
+	{ 1, {  960000, HFPLL, 1,  50 },  L2(9),  765000, 242},
+	{ 1, { 1036800, HFPLL, 1,  54 }, L2(10),  775000, 264},
+	{ 0, { 1113600, HFPLL, 1,  58 }, L2(10),  785000, 287},
+	{ 1, { 1190400, HFPLL, 1,  62 }, L2(10),  795000, 308},
+	{ 1, { 1267200, HFPLL, 1,  66 }, L2(13),  805000, 333},
+	{ 0, { 1344000, HFPLL, 1,  70 }, L2(14),  815000, 356},
+	{ 0, { 1420800, HFPLL, 1,  74 }, L2(15),  825000, 380},
+	{ 1, { 1497600, HFPLL, 1,  78 }, L2(16),  835000, 404},
+	{ 1, { 1574400, HFPLL, 1,  82 }, L2(17),  845000, 430},
+	{ 0, { 1651200, HFPLL, 1,  86 }, L2(17),  850000, 456},
+	{ 1, { 1728000, HFPLL, 1,  90 }, L2(18),  860000, 482},
+	{ 0, { 1804800, HFPLL, 1,  94 }, L2(18),  870000, 510},
+	{ 0, { 1881600, HFPLL, 1,  98 }, L2(18),  880000, 538},
+	{ 1, { 1958400, HFPLL, 1, 102 }, L2(19),  890000, 565},
+	{ 0, { 2035200, HFPLL, 1, 106 }, L2(19),  895000, 596},
+	{ 0, { 2112000, HFPLL, 1, 110 }, L2(19),  905000, 627},
+	{ 0, { 2188800, HFPLL, 1, 114 }, L2(19),  915000, 659},
+	{ 1, { 2265600, HFPLL, 1, 118 }, L2(19),  925000, 691},
+	{ 0, { 0 } }
+};
+
+static struct acpu_level acpu_ftbl_pro_2p5g_pvs0[] __initdata = {
+	{ 1, {  300000, PLL_0, 0,   0 },  L2(0),  800000,  76},
+	{ 0, {  345600, HFPLL, 2,  36 },  L2(1),  800000,  87},
+	{ 1, {  422400, HFPLL, 2,  44 },  L2(2),  800000, 106},
+	{ 0, {  499200, HFPLL, 2,  52 },  L2(2),  800000, 125},
+	{ 0, {  576000, HFPLL, 1,  30 },  L2(3),  800000, 145},
+	{ 1, {  652800, HFPLL, 1,  34 },  L2(3),  800000, 164},
+	{ 1, {  729600, HFPLL, 1,  38 },  L2(4),  800000, 183},
+	{ 0, {  806400, HFPLL, 1,  42 },  L2(4),  800000, 202},
+	{ 1, {  883200, HFPLL, 1,  46 },  L2(4),  800000, 222},
+	{ 1, {  960000, HFPLL, 1,  50 },  L2(9),  800000, 241},
+	{ 1, { 1036800, HFPLL, 1,  54 }, L2(10),  805000, 261},
+	{ 0, { 1113600, HFPLL, 1,  58 }, L2(10),  815000, 282},
+	{ 1, { 1190400, HFPLL, 1,  62 }, L2(10),  825000, 305},
+	{ 1, { 1267200, HFPLL, 1,  66 }, L2(13),  835000, 327},
+	{ 0, { 1344000, HFPLL, 1,  70 }, L2(14),  845000, 350},
+	{ 0, { 1420800, HFPLL, 1,  74 }, L2(15),  855000, 373},
+	{ 1, { 1497600, HFPLL, 1,  78 }, L2(16),  870000, 398},
+	{ 1, { 1574400, HFPLL, 1,  82 }, L2(17),  885000, 424},
+	{ 0, { 1651200, HFPLL, 1,  86 }, L2(17),  900000, 449},
+	{ 1, { 1728000, HFPLL, 1,  90 }, L2(18),  915000, 476},
+	{ 0, { 1804800, HFPLL, 1,  94 }, L2(18),  930000, 503},
+	{ 0, { 1881600, HFPLL, 1,  98 }, L2(18),  945000, 530},
+	{ 1, { 1958400, HFPLL, 1, 102 }, L2(19),  960000, 559},
+	{ 0, { 2035200, HFPLL, 1, 106 }, L2(19),  980000, 590},
+	{ 0, { 2112000, HFPLL, 1, 110 }, L2(19), 1000000, 621},
+	{ 0, { 2188800, HFPLL, 1, 114 }, L2(19), 1020000, 654},
+	{ 1, { 2265600, HFPLL, 1, 118 }, L2(19), 1040000, 686},
+	{ 0, { 2342400, HFPLL, 1, 122 }, L2(19), 1060000, 723},
+	{ 0, { 2419200, HFPLL, 1, 126 }, L2(19), 1080000, 761},
+	{ 1, { 2496000, HFPLL, 1, 130 }, L2(19), 1100000, 800},
+	{ 0, { 0 } }
+};
+
+static struct acpu_level acpu_ftbl_pro_2p5g_pvs1[] __initdata = {
+	{ 1, {  300000, PLL_0, 0,   0 },  L2(0),  800000,  76},
+	{ 0, {  345600, HFPLL, 2,  36 },  L2(1),  800000,  87},
+	{ 1, {  422400, HFPLL, 2,  44 },  L2(2),  800000, 106},
+	{ 0, {  499200, HFPLL, 2,  52 },  L2(2),  800000, 125},
+	{ 0, {  576000, HFPLL, 1,  30 },  L2(3),  800000, 145},
+	{ 1, {  652800, HFPLL, 1,  34 },  L2(3),  800000, 164},
+	{ 1, {  729600, HFPLL, 1,  38 },  L2(4),  800000, 183},
+	{ 0, {  806400, HFPLL, 1,  42 },  L2(4),  800000, 202},
+	{ 1, {  883200, HFPLL, 1,  46 },  L2(4),  800000, 222},
+	{ 1, {  960000, HFPLL, 1,  50 },  L2(9),  800000, 241},
+	{ 1, { 1036800, HFPLL, 1,  54 }, L2(10),  800000, 261},
+	{ 0, { 1113600, HFPLL, 1,  58 }, L2(10),  805000, 282},
+	{ 1, { 1190400, HFPLL, 1,  62 }, L2(10),  815000, 305},
+	{ 1, { 1267200, HFPLL, 1,  66 }, L2(13),  825000, 327},
+	{ 0, { 1344000, HFPLL, 1,  70 }, L2(14),  835000, 350},
+	{ 0, { 1420800, HFPLL, 1,  74 }, L2(15),  845000, 373},
+	{ 1, { 1497600, HFPLL, 1,  78 }, L2(16),  855000, 398},
+	{ 1, { 1574400, HFPLL, 1,  82 }, L2(17),  870000, 424},
+	{ 0, { 1651200, HFPLL, 1,  86 }, L2(17),  885000, 449},
+	{ 1, { 1728000, HFPLL, 1,  90 }, L2(18),  900000, 476},
+	{ 0, { 1804800, HFPLL, 1,  94 }, L2(18),  915000, 503},
+	{ 0, { 1881600, HFPLL, 1,  98 }, L2(18),  930000, 530},
+	{ 1, { 1958400, HFPLL, 1, 102 }, L2(19),  945000, 559},
+	{ 0, { 2035200, HFPLL, 1, 106 }, L2(19),  960000, 590},
+	{ 0, { 2112000, HFPLL, 1, 110 }, L2(19),  975000, 621},
+	{ 0, { 2188800, HFPLL, 1, 114 }, L2(19),  995000, 654},
+	{ 1, { 2265600, HFPLL, 1, 118 }, L2(19), 1015000, 686},
+	{ 0, { 2342400, HFPLL, 1, 122 }, L2(19), 1035000, 723},
+	{ 0, { 2419200, HFPLL, 1, 126 }, L2(19), 1055000, 761},
+	{ 1, { 2496000, HFPLL, 1, 130 }, L2(19), 1075000, 800},
+	{ 0, { 0 } }
+};
+
+static struct acpu_level acpu_ftbl_pro_2p5g_pvs2[] __initdata = {
+	{ 1, {  300000, PLL_0, 0,   0 },  L2(0),  775000,  76},
+	{ 0, {  345600, HFPLL, 2,  36 },  L2(1),  775000,  87},
+	{ 1, {  422400, HFPLL, 2,  44 },  L2(2),  775000, 106},
+	{ 0, {  499200, HFPLL, 2,  52 },  L2(2),  775000, 125},
+	{ 0, {  576000, HFPLL, 1,  30 },  L2(3),  775000, 145},
+	{ 1, {  652800, HFPLL, 1,  34 },  L2(3),  775000, 164},
+	{ 1, {  729600, HFPLL, 1,  38 },  L2(4),  775000, 183},
+	{ 0, {  806400, HFPLL, 1,  42 },  L2(4),  775000, 202},
+	{ 1, {  883200, HFPLL, 1,  46 },  L2(4),  775000, 222},
+	{ 1, {  960000, HFPLL, 1,  50 },  L2(9),  775000, 241},
+	{ 1, { 1036800, HFPLL, 1,  54 }, L2(10),  780000, 261},
+	{ 0, { 1113600, HFPLL, 1,  58 }, L2(10),  790000, 282},
+	{ 1, { 1190400, HFPLL, 1,  62 }, L2(10),  800000, 305},
+	{ 1, { 1267200, HFPLL, 1,  66 }, L2(13),  810000, 327},
+	{ 0, { 1344000, HFPLL, 1,  70 }, L2(14),  820000, 350},
+	{ 0, { 1420800, HFPLL, 1,  74 }, L2(15),  830000, 373},
+	{ 1, { 1497600, HFPLL, 1,  78 }, L2(16),  840000, 398},
+	{ 1, { 1574400, HFPLL, 1,  82 }, L2(17),  850000, 424},
+	{ 0, { 1651200, HFPLL, 1,  86 }, L2(17),  865000, 449},
+	{ 1, { 1728000, HFPLL, 1,  90 }, L2(18),  880000, 476},
+	{ 0, { 1804800, HFPLL, 1,  94 }, L2(18),  895000, 503},
+	{ 0, { 1881600, HFPLL, 1,  98 }, L2(18),  910000, 530},
+	{ 1, { 1958400, HFPLL, 1, 102 }, L2(19),  925000, 559},
+	{ 0, { 2035200, HFPLL, 1, 106 }, L2(19),  940000, 590},
+	{ 0, { 2112000, HFPLL, 1, 110 }, L2(19),  955000, 621},
+	{ 0, { 2188800, HFPLL, 1, 114 }, L2(19),  970000, 654},
+	{ 1, { 2265600, HFPLL, 1, 118 }, L2(19),  990000, 686},
+	{ 0, { 2342400, HFPLL, 1, 122 }, L2(19), 1010000, 723},
+	{ 0, { 2419200, HFPLL, 1, 126 }, L2(19), 1030000, 761},
+	{ 1, { 2496000, HFPLL, 1, 130 }, L2(19), 1050000, 800},
+	{ 0, { 0 } }
+};
+
+static struct acpu_level acpu_ftbl_pro_2p5g_pvs3[] __initdata = {
+	{ 1, {  300000, PLL_0, 0,   0 },  L2(0),  775000,  76},
+	{ 0, {  345600, HFPLL, 2,  36 },  L2(1),  775000,  87},
+	{ 1, {  422400, HFPLL, 2,  44 },  L2(2),  775000, 106},
+	{ 0, {  499200, HFPLL, 2,  52 },  L2(2),  775000, 125},
+	{ 0, {  576000, HFPLL, 1,  30 },  L2(3),  775000, 145},
+	{ 1, {  652800, HFPLL, 1,  34 },  L2(3),  775000, 164},
+	{ 1, {  729600, HFPLL, 1,  38 },  L2(4),  775000, 183},
+	{ 0, {  806400, HFPLL, 1,  42 },  L2(4),  775000, 202},
+	{ 1, {  883200, HFPLL, 1,  46 },  L2(4),  775000, 222},
+	{ 1, {  960000, HFPLL, 1,  50 },  L2(9),  775000, 241},
+	{ 1, { 1036800, HFPLL, 1,  54 }, L2(10),  775000, 261},
+	{ 0, { 1113600, HFPLL, 1,  58 }, L2(10),  780000, 282},
+	{ 1, { 1190400, HFPLL, 1,  62 }, L2(10),  790000, 305},
+	{ 1, { 1267200, HFPLL, 1,  66 }, L2(13),  800000, 327},
+	{ 0, { 1344000, HFPLL, 1,  70 }, L2(14),  810000, 350},
+	{ 0, { 1420800, HFPLL, 1,  74 }, L2(15),  820000, 373},
+	{ 1, { 1497600, HFPLL, 1,  78 }, L2(16),  830000, 398},
+	{ 1, { 1574400, HFPLL, 1,  82 }, L2(17),  840000, 424},
+	{ 0, { 1651200, HFPLL, 1,  86 }, L2(17),  850000, 449},
+	{ 1, { 1728000, HFPLL, 1,  90 }, L2(18),  865000, 476},
+	{ 0, { 1804800, HFPLL, 1,  94 }, L2(18),  880000, 503},
+	{ 0, { 1881600, HFPLL, 1,  98 }, L2(18),  895000, 530},
+	{ 1, { 1958400, HFPLL, 1, 102 }, L2(19),  910000, 559},
+	{ 0, { 2035200, HFPLL, 1, 106 }, L2(19),  925000, 590},
+	{ 0, { 2112000, HFPLL, 1, 110 }, L2(19),  940000, 621},
+	{ 0, { 2188800, HFPLL, 1, 114 }, L2(19),  955000, 654},
+	{ 1, { 2265600, HFPLL, 1, 118 }, L2(19),  970000, 686},
+	{ 0, { 2342400, HFPLL, 1, 122 }, L2(19),  985000, 723},
+	{ 0, { 2419200, HFPLL, 1, 126 }, L2(19), 1005000, 761},
+	{ 1, { 2496000, HFPLL, 1, 130 }, L2(19), 1025000, 800},
+	{ 0, { 0 } }
+};
+
+static struct acpu_level acpu_ftbl_pro_2p5g_pvs4[] __initdata = {
+	{ 1, {  300000, PLL_0, 0,   0 },  L2(0),  750000,  76},
+	{ 0, {  345600, HFPLL, 2,  36 },  L2(1),  750000,  87},
+	{ 1, {  422400, HFPLL, 2,  44 },  L2(2),  750000, 106},
+	{ 0, {  499200, HFPLL, 2,  52 },  L2(2),  750000, 125},
+	{ 0, {  576000, HFPLL, 1,  30 },  L2(3),  750000, 145},
+	{ 1, {  652800, HFPLL, 1,  34 },  L2(3),  750000, 164},
+	{ 1, {  729600, HFPLL, 1,  38 },  L2(4),  750000, 183},
+	{ 0, {  806400, HFPLL, 1,  42 },  L2(4),  750000, 202},
+	{ 1, {  883200, HFPLL, 1,  46 },  L2(4),  750000, 222},
+	{ 1, {  960000, HFPLL, 1,  50 },  L2(9),  750000, 241},
+	{ 1, { 1036800, HFPLL, 1,  54 }, L2(10),  760000, 261},
+	{ 0, { 1113600, HFPLL, 1,  58 }, L2(10),  770000, 282},
+	{ 1, { 1190400, HFPLL, 1,  62 }, L2(10),  780000, 305},
+	{ 1, { 1267200, HFPLL, 1,  66 }, L2(13),  790000, 327},
+	{ 0, { 1344000, HFPLL, 1,  70 }, L2(14),  800000, 350},
+	{ 0, { 1420800, HFPLL, 1,  74 }, L2(15),  810000, 373},
+	{ 1, { 1497600, HFPLL, 1,  78 }, L2(16),  820000, 398},
+	{ 1, { 1574400, HFPLL, 1,  82 }, L2(17),  830000, 424},
+	{ 0, { 1651200, HFPLL, 1,  86 }, L2(17),  840000, 449},
+	{ 1, { 1728000, HFPLL, 1,  90 }, L2(18),  850000, 476},
+	{ 0, { 1804800, HFPLL, 1,  94 }, L2(18),  865000, 503},
+	{ 0, { 1881600, HFPLL, 1,  98 }, L2(18),  880000, 530},
+	{ 1, { 1958400, HFPLL, 1, 102 }, L2(19),  895000, 559},
+	{ 0, { 2035200, HFPLL, 1, 106 }, L2(19),  910000, 590},
+	{ 0, { 2112000, HFPLL, 1, 110 }, L2(19),  925000, 621},
+	{ 0, { 2188800, HFPLL, 1, 114 }, L2(19),  940000, 654},
+	{ 1, { 2265600, HFPLL, 1, 118 }, L2(19),  955000, 686},
+	{ 0, { 2342400, HFPLL, 1, 122 }, L2(19),  970000, 723},
+	{ 0, { 2419200, HFPLL, 1, 126 }, L2(19),  985000, 761},
+	{ 1, { 2496000, HFPLL, 1, 130 }, L2(19), 1000000, 800},
+	{ 0, { 0 } }
+};
+
+static struct acpu_level acpu_ftbl_pro_2p5g_pvs5[] __initdata = {
+	{ 1, {  300000, PLL_0, 0,   0 },  L2(0),  750000,  76},
+	{ 0, {  345600, HFPLL, 2,  36 },  L2(1),  750000,  87},
+	{ 1, {  422400, HFPLL, 2,  44 },  L2(2),  750000, 106},
+	{ 0, {  499200, HFPLL, 2,  52 },  L2(2),  750000, 125},
+	{ 0, {  576000, HFPLL, 1,  30 },  L2(3),  750000, 145},
+	{ 1, {  652800, HFPLL, 1,  34 },  L2(3),  750000, 164},
+	{ 1, {  729600, HFPLL, 1,  38 },  L2(4),  750000, 183},
+	{ 0, {  806400, HFPLL, 1,  42 },  L2(4),  750000, 202},
+	{ 1, {  883200, HFPLL, 1,  46 },  L2(4),  750000, 222},
+	{ 1, {  960000, HFPLL, 1,  50 },  L2(9),  750000, 241},
+	{ 1, { 1036800, HFPLL, 1,  54 }, L2(10),  750000, 261},
+	{ 0, { 1113600, HFPLL, 1,  58 }, L2(10),  760000, 282},
+	{ 1, { 1190400, HFPLL, 1,  62 }, L2(10),  770000, 305},
+	{ 1, { 1267200, HFPLL, 1,  66 }, L2(13),  780000, 327},
+	{ 0, { 1344000, HFPLL, 1,  70 }, L2(14),  790000, 350},
+	{ 0, { 1420800, HFPLL, 1,  74 }, L2(15),  800000, 373},
+	{ 1, { 1497600, HFPLL, 1,  78 }, L2(16),  810000, 398},
+	{ 1, { 1574400, HFPLL, 1,  82 }, L2(17),  820000, 424},
+	{ 0, { 1651200, HFPLL, 1,  86 }, L2(17),  830000, 449},
+	{ 1, { 1728000, HFPLL, 1,  90 }, L2(18),  840000, 476},
+	{ 0, { 1804800, HFPLL, 1,  94 }, L2(18),  850000, 503},
+	{ 0, { 1881600, HFPLL, 1,  98 }, L2(18),  860000, 530},
+	{ 1, { 1958400, HFPLL, 1, 102 }, L2(19),  870000, 559},
+	{ 0, { 2035200, HFPLL, 1, 106 }, L2(19),  885000, 590},
+	{ 0, { 2112000, HFPLL, 1, 110 }, L2(19),  900000, 621},
+	{ 0, { 2188800, HFPLL, 1, 114 }, L2(19),  915000, 654},
+	{ 1, { 2265600, HFPLL, 1, 118 }, L2(19),  930000, 686},
+	{ 0, { 2342400, HFPLL, 1, 122 }, L2(19),  945000, 723},
+	{ 0, { 2419200, HFPLL, 1, 126 }, L2(19),  960000, 761},
+	{ 1, { 2496000, HFPLL, 1, 130 }, L2(19),  975000, 800},
+	{ 0, { 0 } }
+};
+
+static struct acpu_level acpu_ftbl_pro_2p5g_pvs6[] __initdata = {
+	{ 1, {  300000, PLL_0, 0,   0 },  L2(0),  725000,  76},
+	{ 0, {  345600, HFPLL, 2,  36 },  L2(1),  725000,  87},
+	{ 1, {  422400, HFPLL, 2,  44 },  L2(2),  725000, 106},
+	{ 0, {  499200, HFPLL, 2,  52 },  L2(2),  725000, 125},
+	{ 0, {  576000, HFPLL, 1,  30 },  L2(3),  725000, 145},
+	{ 1, {  652800, HFPLL, 1,  34 },  L2(3),  725000, 164},
+	{ 1, {  729600, HFPLL, 1,  38 },  L2(4),  725000, 183},
+	{ 0, {  806400, HFPLL, 1,  42 },  L2(4),  725000, 202},
+	{ 1, {  883200, HFPLL, 1,  46 },  L2(4),  725000, 222},
+	{ 1, {  960000, HFPLL, 1,  50 },  L2(9),  725000, 241},
+	{ 1, { 1036800, HFPLL, 1,  54 }, L2(10),  735000, 261},
+	{ 0, { 1113600, HFPLL, 1,  58 }, L2(10),  745000, 282},
+	{ 1, { 1190400, HFPLL, 1,  62 }, L2(10),  755000, 305},
+	{ 1, { 1267200, HFPLL, 1,  66 }, L2(13),  765000, 327},
+	{ 0, { 1344000, HFPLL, 1,  70 }, L2(14),  775000, 350},
+	{ 0, { 1420800, HFPLL, 1,  74 }, L2(15),  785000, 373},
+	{ 1, { 1497600, HFPLL, 1,  78 }, L2(16),  795000, 398},
+	{ 1, { 1574400, HFPLL, 1,  82 }, L2(17),  805000, 424},
+	{ 0, { 1651200, HFPLL, 1,  86 }, L2(17),  815000, 449},
+	{ 1, { 1728000, HFPLL, 1,  90 }, L2(18),  825000, 476},
+	{ 0, { 1804800, HFPLL, 1,  94 }, L2(18),  835000, 503},
+	{ 0, { 1881600, HFPLL, 1,  98 }, L2(18),  845000, 530},
+	{ 1, { 1958400, HFPLL, 1, 102 }, L2(19),  855000, 559},
+	{ 0, { 2035200, HFPLL, 1, 106 }, L2(19),  865000, 590},
+	{ 0, { 2112000, HFPLL, 1, 110 }, L2(19),  875000, 621},
+	{ 0, { 2188800, HFPLL, 1, 114 }, L2(19),  890000, 654},
+	{ 1, { 2265600, HFPLL, 1, 118 }, L2(19),  905000, 686},
+	{ 0, { 2342400, HFPLL, 1, 122 }, L2(19),  920000, 723},
+	{ 0, { 2419200, HFPLL, 1, 126 }, L2(19),  935000, 761},
+	{ 1, { 2496000, HFPLL, 1, 130 }, L2(19),  950000, 800},
+	{ 0, { 0 } }
+};
 
 static struct pvs_table pvs_v1[NUM_SPEED_BINS][NUM_PVS] __initdata = {
 	/* 8974v1 1.7GHz Parts */
@@ -974,45 +1396,45 @@
 };
 
 static struct pvs_table pvs_pro[NUM_SPEED_BINS][NUM_PVS] __initdata = {
-	/* Not used by 8974Pro */
-	[0][0] = { acpu_freq_tbl_pro_pvs0, sizeof(acpu_freq_tbl_pro_pvs0) },
-	[0][1] = { acpu_freq_tbl_pro_pvs0, sizeof(acpu_freq_tbl_pro_pvs0) },
-	[0][2] = { acpu_freq_tbl_pro_pvs0, sizeof(acpu_freq_tbl_pro_pvs0) },
-	[0][3] = { acpu_freq_tbl_pro_pvs0, sizeof(acpu_freq_tbl_pro_pvs0) },
-	[0][4] = { acpu_freq_tbl_pro_pvs0, sizeof(acpu_freq_tbl_pro_pvs0) },
-	[0][5] = { acpu_freq_tbl_pro_pvs0, sizeof(acpu_freq_tbl_pro_pvs0) },
-	[0][6] = { acpu_freq_tbl_pro_pvs0, sizeof(acpu_freq_tbl_pro_pvs0) },
-	[0][7] = { acpu_freq_tbl_pro_pvs0, sizeof(acpu_freq_tbl_pro_pvs0) },
+	/* 2.0 GHz is not used on 8974Pro */
+	[0][0] = { acpu_freq_tbl_2g_pvs0, sizeof(acpu_freq_tbl_2g_pvs0) },
+	[0][1] = { acpu_freq_tbl_2g_pvs1, sizeof(acpu_freq_tbl_2g_pvs1) },
+	[0][2] = { acpu_freq_tbl_2g_pvs2, sizeof(acpu_freq_tbl_2g_pvs2) },
+	[0][3] = { acpu_freq_tbl_2g_pvs3, sizeof(acpu_freq_tbl_2g_pvs3) },
+	[0][4] = { acpu_freq_tbl_2g_pvs4, sizeof(acpu_freq_tbl_2g_pvs4) },
+	[0][5] = { acpu_freq_tbl_2g_pvs5, sizeof(acpu_freq_tbl_2g_pvs5) },
+	[0][6] = { acpu_freq_tbl_2g_pvs6, sizeof(acpu_freq_tbl_2g_pvs6) },
+	[0][7] = { acpu_freq_tbl_2g_pvs6, sizeof(acpu_freq_tbl_2g_pvs6) },
 
-	/* 8974Pro AB Bringup */
-	[1][0] = { acpu_freq_tbl_pro_pvs0, sizeof(acpu_freq_tbl_pro_pvs0) },
-	[1][1] = { acpu_freq_tbl_pro_pvs0, sizeof(acpu_freq_tbl_pro_pvs0) },
-	[1][2] = { acpu_freq_tbl_pro_pvs0, sizeof(acpu_freq_tbl_pro_pvs0) },
-	[1][3] = { acpu_freq_tbl_pro_pvs0, sizeof(acpu_freq_tbl_pro_pvs0) },
-	[1][4] = { acpu_freq_tbl_pro_pvs0, sizeof(acpu_freq_tbl_pro_pvs0) },
-	[1][5] = { acpu_freq_tbl_pro_pvs0, sizeof(acpu_freq_tbl_pro_pvs0) },
-	[1][6] = { acpu_freq_tbl_pro_pvs0, sizeof(acpu_freq_tbl_pro_pvs0) },
-	[1][7] = { acpu_freq_tbl_pro_pvs0, sizeof(acpu_freq_tbl_pro_pvs0) },
+	/* 8974Pro AB 2.3GHz */
+	[1][0] = { acpu_ftbl_pro_2p3g_pvs0, sizeof(acpu_ftbl_pro_2p3g_pvs0) },
+	[1][1] = { acpu_ftbl_pro_2p3g_pvs1, sizeof(acpu_ftbl_pro_2p3g_pvs1) },
+	[1][2] = { acpu_ftbl_pro_2p3g_pvs2, sizeof(acpu_ftbl_pro_2p3g_pvs2) },
+	[1][3] = { acpu_ftbl_pro_2p3g_pvs3, sizeof(acpu_ftbl_pro_2p3g_pvs3) },
+	[1][4] = { acpu_ftbl_pro_2p3g_pvs4, sizeof(acpu_ftbl_pro_2p3g_pvs4) },
+	[1][5] = { acpu_ftbl_pro_2p3g_pvs5, sizeof(acpu_ftbl_pro_2p3g_pvs5) },
+	[1][6] = { acpu_ftbl_pro_2p3g_pvs6, sizeof(acpu_ftbl_pro_2p3g_pvs6) },
+	[1][7] = { acpu_ftbl_pro_2p3g_pvs6, sizeof(acpu_ftbl_pro_2p3g_pvs6) },
 
-	/* Not used by 8974Pro */
-	[2][0] = { acpu_freq_tbl_pro_pvs0, sizeof(acpu_freq_tbl_pro_pvs0) },
-	[2][1] = { acpu_freq_tbl_pro_pvs0, sizeof(acpu_freq_tbl_pro_pvs0) },
-	[2][2] = { acpu_freq_tbl_pro_pvs0, sizeof(acpu_freq_tbl_pro_pvs0) },
-	[2][3] = { acpu_freq_tbl_pro_pvs0, sizeof(acpu_freq_tbl_pro_pvs0) },
-	[2][4] = { acpu_freq_tbl_pro_pvs0, sizeof(acpu_freq_tbl_pro_pvs0) },
-	[2][5] = { acpu_freq_tbl_pro_pvs0, sizeof(acpu_freq_tbl_pro_pvs0) },
-	[2][6] = { acpu_freq_tbl_pro_pvs0, sizeof(acpu_freq_tbl_pro_pvs0) },
-	[2][7] = { acpu_freq_tbl_pro_pvs0, sizeof(acpu_freq_tbl_pro_pvs0) },
+	/* 2.2GHz is not used on 8974Pro */
+	[2][0] = { acpu_freq_tbl_2p2g_pvs0, sizeof(acpu_freq_tbl_2p2g_pvs0) },
+	[2][1] = { acpu_freq_tbl_2p2g_pvs1, sizeof(acpu_freq_tbl_2p2g_pvs1) },
+	[2][2] = { acpu_freq_tbl_2p2g_pvs2, sizeof(acpu_freq_tbl_2p2g_pvs2) },
+	[2][3] = { acpu_freq_tbl_2p2g_pvs3, sizeof(acpu_freq_tbl_2p2g_pvs3) },
+	[2][4] = { acpu_freq_tbl_2p2g_pvs4, sizeof(acpu_freq_tbl_2p2g_pvs4) },
+	[2][5] = { acpu_freq_tbl_2p2g_pvs5, sizeof(acpu_freq_tbl_2p2g_pvs5) },
+	[2][6] = { acpu_freq_tbl_2p2g_pvs6, sizeof(acpu_freq_tbl_2p2g_pvs6) },
+	[2][7] = { acpu_freq_tbl_2p2g_pvs6, sizeof(acpu_freq_tbl_2p2g_pvs6) },
 
-	/* 8974Pro Bringup */
-	[3][0] = { acpu_freq_tbl_pro_pvs0, sizeof(acpu_freq_tbl_pro_pvs0) },
-	[3][1] = { acpu_freq_tbl_pro_pvs0, sizeof(acpu_freq_tbl_pro_pvs0) },
-	[3][2] = { acpu_freq_tbl_pro_pvs0, sizeof(acpu_freq_tbl_pro_pvs0) },
-	[3][3] = { acpu_freq_tbl_pro_pvs0, sizeof(acpu_freq_tbl_pro_pvs0) },
-	[3][4] = { acpu_freq_tbl_pro_pvs0, sizeof(acpu_freq_tbl_pro_pvs0) },
-	[3][5] = { acpu_freq_tbl_pro_pvs0, sizeof(acpu_freq_tbl_pro_pvs0) },
-	[3][6] = { acpu_freq_tbl_pro_pvs0, sizeof(acpu_freq_tbl_pro_pvs0) },
-	[3][7] = { acpu_freq_tbl_pro_pvs0, sizeof(acpu_freq_tbl_pro_pvs0) },
+	/* 8974Pro AC 2.5GHz */
+	[3][0] = { acpu_ftbl_pro_2p5g_pvs0, sizeof(acpu_ftbl_pro_2p5g_pvs0) },
+	[3][1] = { acpu_ftbl_pro_2p5g_pvs1, sizeof(acpu_ftbl_pro_2p5g_pvs1) },
+	[3][2] = { acpu_ftbl_pro_2p5g_pvs2, sizeof(acpu_ftbl_pro_2p5g_pvs2) },
+	[3][3] = { acpu_ftbl_pro_2p5g_pvs3, sizeof(acpu_ftbl_pro_2p5g_pvs3) },
+	[3][4] = { acpu_ftbl_pro_2p5g_pvs4, sizeof(acpu_ftbl_pro_2p5g_pvs4) },
+	[3][5] = { acpu_ftbl_pro_2p5g_pvs5, sizeof(acpu_ftbl_pro_2p5g_pvs5) },
+	[3][6] = { acpu_ftbl_pro_2p5g_pvs6, sizeof(acpu_ftbl_pro_2p5g_pvs6) },
+	[3][7] = { acpu_ftbl_pro_2p5g_pvs6, sizeof(acpu_ftbl_pro_2p5g_pvs6) },
 };
 
 static struct msm_bus_scale_pdata bus_scale_data __initdata = {
diff --git a/arch/arm/mach-msm/acpuclock-krait.c b/arch/arm/mach-msm/acpuclock-krait.c
index e3a3f54..0479844 100644
--- a/arch/arm/mach-msm/acpuclock-krait.c
+++ b/arch/arm/mach-msm/acpuclock-krait.c
@@ -55,20 +55,49 @@
 	return drv.scalable[cpu].cur_speed->khz;
 }
 
-/* Select a source on the primary MUX. */
-static void set_pri_clk_src(struct scalable *sc, u32 pri_src_sel)
+struct set_clk_src_args {
+	struct scalable *sc;
+	u32 src_sel;
+};
+
+static void __set_pri_clk_src(struct scalable *sc, u32 pri_src_sel)
 {
 	u32 regval;
 
 	regval = get_l2_indirect_reg(sc->l2cpmr_iaddr);
 	regval &= ~0x3;
-	regval |= (pri_src_sel & 0x3);
+	regval |= pri_src_sel;
+	if (sc != &drv.scalable[L2]) {
+		regval &= ~(0x3 << 8);
+		regval |= pri_src_sel << 8;
+	}
 	set_l2_indirect_reg(sc->l2cpmr_iaddr, regval);
 	/* Wait for switch to complete. */
 	mb();
 	udelay(1);
 }
 
+static void __set_cpu_pri_clk_src(void *data)
+{
+	struct set_clk_src_args *args = data;
+	__set_pri_clk_src(args->sc, args->src_sel);
+}
+
+/* Select a source on the primary MUX. */
+static void set_pri_clk_src(struct scalable *sc, u32 pri_src_sel)
+{
+	int cpu = sc - drv.scalable;
+	if (sc != &drv.scalable[L2] && cpu_online(cpu)) {
+		struct set_clk_src_args args = {
+			.sc = sc,
+			.src_sel = pri_src_sel,
+		};
+		smp_call_function_single(cpu, __set_cpu_pri_clk_src, &args, 1);
+	} else {
+		__set_pri_clk_src(sc, pri_src_sel);
+	}
+}
+
 /* Select a source on the secondary MUX. */
 static void __cpuinit set_sec_clk_src(struct scalable *sc, u32 sec_src_sel)
 {
@@ -76,7 +105,11 @@
 
 	regval = get_l2_indirect_reg(sc->l2cpmr_iaddr);
 	regval &= ~(0x3 << 2);
-	regval |= ((sec_src_sel & 0x3) << 2);
+	regval |= sec_src_sel << 2;
+	if (sc != &drv.scalable[L2]) {
+		regval &= ~(0x3 << 10);
+		regval |= sec_src_sel << 10;
+	}
 	set_l2_indirect_reg(sc->l2cpmr_iaddr, regval);
 	/* Wait for switch to complete. */
 	mb();
@@ -785,6 +818,8 @@
 	/* Set PRI_SRC_SEL_HFPLL_DIV2 divider to div-2. */
 	regval = get_l2_indirect_reg(sc->l2cpmr_iaddr);
 	regval &= ~(0x3 << 6);
+	if (sc != &drv.scalable[L2])
+		regval &= ~(0x3 << 14);
 	set_l2_indirect_reg(sc->l2cpmr_iaddr, regval);
 
 	/* Enable and switch to the target clock source. */
diff --git a/arch/arm/mach-msm/acpuclock.c b/arch/arm/mach-msm/acpuclock.c
index 2c120da..42242d5 100644
--- a/arch/arm/mach-msm/acpuclock.c
+++ b/arch/arm/mach-msm/acpuclock.c
@@ -27,19 +27,10 @@
 
 int acpuclk_set_rate(int cpu, unsigned long rate, enum setrate_reason reason)
 {
-	int ret;
-
 	if (!acpuclk_data || !acpuclk_data->set_rate)
 		return 0;
 
-	trace_cpu_frequency_switch_start(acpuclk_get_rate(cpu), rate, cpu);
-	ret = acpuclk_data->set_rate(cpu, rate, reason);
-	if (!ret) {
-		trace_cpu_frequency_switch_end(cpu);
-		trace_cpu_frequency(rate, cpu);
-	}
-
-	return ret;
+	return acpuclk_data->set_rate(cpu, rate, reason);
 }
 
 uint32_t acpuclk_get_switch_time(void)
diff --git a/arch/arm/mach-msm/bam_dmux.c b/arch/arm/mach-msm/bam_dmux.c
index 1460f94..6281395 100644
--- a/arch/arm/mach-msm/bam_dmux.c
+++ b/arch/arm/mach-msm/bam_dmux.c
@@ -195,6 +195,7 @@
 static struct sps_register_event rx_register_event;
 static bool satellite_mode;
 static uint32_t num_buffers;
+static unsigned long long last_rx_pkt_timestamp;
 
 static struct bam_ch_info bam_ch[BAM_DMUX_NUM_CHANNELS];
 static int bam_mux_initialized;
@@ -1117,6 +1118,29 @@
 	queue_work_on(0, bam_mux_rx_workqueue, &rx_timer_work);
 }
 
+/**
+ * store_rx_timestamp() - store the current raw time as as a timestamp for when
+ *			the last rx packet was processed
+ */
+static void store_rx_timestamp(void)
+{
+	last_rx_pkt_timestamp = sched_clock();
+}
+
+/**
+ * log_rx_timestamp() - Log the stored rx pkt timestamp in a human readable
+ *			format
+ */
+static void log_rx_timestamp(void)
+{
+	unsigned long long t = last_rx_pkt_timestamp;
+	unsigned long nanosec_rem;
+
+	nanosec_rem = do_div(t, 1000000000U);
+	BAM_DMUX_LOG("Last rx pkt processed at [%6u.%09lu]\n", (unsigned)t,
+								nanosec_rem);
+}
+
 static void rx_timer_work_func(struct work_struct *work)
 {
 	struct sps_iovec iov;
@@ -1125,20 +1149,26 @@
 	int ret;
 	u32 buffs_unused, buffs_used;
 
+	BAM_DMUX_LOG("%s: polling start\n", __func__);
 	while (bam_connection_is_active) { /* timer loop */
 		++inactive_cycles;
 		while (bam_connection_is_active) { /* deplete queue loop */
-			if (in_global_reset)
+			if (in_global_reset) {
+				BAM_DMUX_LOG(
+						"%s: polling exit, global reset detected\n",
+						__func__);
 				return;
+			}
 
 			ret = sps_get_iovec(bam_rx_pipe, &iov);
 			if (ret) {
-				pr_err("%s: sps_get_iovec failed %d\n",
+				DMUX_LOG_KERR("%s: sps_get_iovec failed %d\n",
 						__func__, ret);
 				break;
 			}
 			if (iov.addr == 0)
 				break;
+			store_rx_timestamp();
 			inactive_cycles = 0;
 			mutex_lock(&bam_rx_pool_mutexlock);
 			if (unlikely(list_empty(&bam_rx_pool))) {
@@ -1171,6 +1201,7 @@
 		}
 
 		if (inactive_cycles >= POLLING_INACTIVITY) {
+			BAM_DMUX_LOG("%s: polling exit, no data\n", __func__);
 			rx_switch_to_interrupt_mode();
 			break;
 		}
@@ -1182,7 +1213,8 @@
 						&buffs_unused);
 
 			if (ret) {
-				pr_err("%s: error getting num buffers unused after sleep\n",
+				DMUX_LOG_KERR(
+					"%s: error getting num buffers unused after sleep\n",
 					__func__);
 
 				break;
@@ -1583,6 +1615,12 @@
 {
 	int ret = 0;
 
+	if (in_global_reset) {
+		DMUX_LOG_KERR("%s: modem timeout: already in SSR\n",
+			__func__);
+		return 1;
+	}
+
 	DMUX_LOG_KERR("%s: modem timeout: BAM DMUX disabled for SSR\n",
 								__func__);
 	in_global_reset = 1;
@@ -1755,11 +1793,16 @@
 	unsigned long flags;
 	unsigned long time_remaining;
 
-	time_remaining = wait_for_completion_timeout(&shutdown_completion,
-			msecs_to_jiffies(SHUTDOWN_TIMEOUT_MS));
-	if (time_remaining == 0) {
-		pr_err("%s: shutdown completion timed out\n", __func__);
-		ssrestart_check();
+	if (!in_global_reset) {
+		time_remaining = wait_for_completion_timeout(
+				&shutdown_completion,
+				msecs_to_jiffies(SHUTDOWN_TIMEOUT_MS));
+		if (time_remaining == 0) {
+			DMUX_LOG_KERR("%s: shutdown completion timed out\n",
+					__func__);
+			log_rx_timestamp();
+			ssrestart_check();
+		}
 	}
 
 	bam_connection_is_active = 0;
@@ -2226,6 +2269,11 @@
 {
 	static unsigned int clear_bit; /* 0 = set the bit, else clear bit */
 
+	if (in_global_reset) {
+		BAM_DMUX_LOG("%s: skipped due to SSR\n", __func__);
+		return;
+	}
+
 	BAM_DMUX_LOG("%s: apps ack %d->%d\n", __func__,
 			clear_bit & 0x1, ~clear_bit & 0x1);
 	smsm_change_state(SMSM_APPS_STATE,
diff --git a/arch/arm/mach-msm/board-8226-gpiomux.c b/arch/arm/mach-msm/board-8226-gpiomux.c
index 78a73c4..5dd9bab 100644
--- a/arch/arm/mach-msm/board-8226-gpiomux.c
+++ b/arch/arm/mach-msm/board-8226-gpiomux.c
@@ -57,7 +57,7 @@
 
 static struct gpiomux_setting synaptics_reset_sus_cfg = {
 	.func = GPIOMUX_FUNC_GPIO,
-	.drv = GPIOMUX_DRV_6MA,
+	.drv = GPIOMUX_DRV_2MA,
 	.pull = GPIOMUX_PULL_DOWN,
 };
 
@@ -73,17 +73,28 @@
 	.pull = GPIOMUX_PULL_NONE,
 };
 
-static struct gpiomux_setting gpio_spi_config = {
+static struct gpiomux_setting gpio_spi_act_config = {
 	.func = GPIOMUX_FUNC_1,
 	.drv = GPIOMUX_DRV_8MA,
 	.pull = GPIOMUX_PULL_NONE,
 };
 
-static struct gpiomux_setting gpio_spi_cs_config = {
+static struct gpiomux_setting gpio_spi_cs_act_config = {
 	.func = GPIOMUX_FUNC_1,
 	.drv = GPIOMUX_DRV_6MA,
 	.pull = GPIOMUX_PULL_DOWN,
 };
+static struct gpiomux_setting gpio_spi_susp_config = {
+	.func = GPIOMUX_FUNC_GPIO,
+	.drv = GPIOMUX_DRV_2MA,
+	.pull = GPIOMUX_PULL_DOWN,
+};
+
+static struct gpiomux_setting gpio_spi_cs_eth_config = {
+	.func = GPIOMUX_FUNC_4,
+	.drv = GPIOMUX_DRV_6MA,
+	.pull = GPIOMUX_PULL_DOWN,
+};
 
 static struct gpiomux_setting wcnss_5wire_suspend_cfg = {
 	.func = GPIOMUX_FUNC_GPIO,
@@ -154,60 +165,76 @@
 	{
 		.gpio      = 0,		/* BLSP1 QUP1 SPI_DATA_MOSI */
 		.settings = {
-			[GPIOMUX_SUSPENDED] = &gpio_spi_config,
+			[GPIOMUX_ACTIVE] = &gpio_spi_act_config,
+			[GPIOMUX_SUSPENDED] = &gpio_spi_susp_config,
 		},
 	},
 	{
 		.gpio      = 1,		/* BLSP1 QUP1 SPI_DATA_MISO */
 		.settings = {
-			[GPIOMUX_SUSPENDED] = &gpio_spi_config,
+			[GPIOMUX_ACTIVE] = &gpio_spi_act_config,
+			[GPIOMUX_SUSPENDED] = &gpio_spi_susp_config,
 		},
 	},
 	{
 		.gpio      = 2,		/* BLSP1 QUP1 SPI_CS1 */
 		.settings = {
-			[GPIOMUX_SUSPENDED] = &gpio_spi_cs_config,
+			[GPIOMUX_ACTIVE] = &gpio_spi_cs_act_config,
+			[GPIOMUX_SUSPENDED] = &gpio_spi_susp_config,
 		},
 	},
 	{
 		.gpio      = 3,		/* BLSP1 QUP1 SPI_CLK */
 		.settings = {
-			[GPIOMUX_SUSPENDED] = &gpio_spi_config,
+			[GPIOMUX_ACTIVE] = &gpio_spi_act_config,
+			[GPIOMUX_SUSPENDED] = &gpio_spi_susp_config,
 		},
 	},
 	{
 		.gpio      = 14,	/* BLSP1 QUP4 I2C_SDA */
 		.settings = {
+			[GPIOMUX_ACTIVE] = &gpio_i2c_config,
 			[GPIOMUX_SUSPENDED] = &gpio_i2c_config,
 		},
 	},
 	{
 		.gpio      = 15,	/* BLSP1 QUP4 I2C_SCL */
 		.settings = {
+			[GPIOMUX_ACTIVE] = &gpio_i2c_config,
 			[GPIOMUX_SUSPENDED] = &gpio_i2c_config,
 		},
 	},
 	{
 		.gpio      = 18,		/* BLSP1 QUP5 I2C_SDA */
 		.settings = {
+			[GPIOMUX_ACTIVE] = &gpio_i2c_config,
 			[GPIOMUX_SUSPENDED] = &gpio_i2c_config,
 		},
 	},
 	{
 		.gpio      = 19,		/* BLSP1 QUP5 I2C_SCL */
 		.settings = {
+			[GPIOMUX_ACTIVE] = &gpio_i2c_config,
 			[GPIOMUX_SUSPENDED] = &gpio_i2c_config,
 		},
 	},
+	{
+		.gpio      = 22,		/* BLSP1 QUP1 SPI_CS_ETH */
+		.settings = {
+			[GPIOMUX_SUSPENDED] = &gpio_spi_cs_eth_config,
+		},
+	},
 	{					/*  NFC   */
 		.gpio      = 10,		/* BLSP1 QUP3 I2C_DAT */
 		.settings = {
+			[GPIOMUX_ACTIVE] = &gpio_i2c_config,
 			[GPIOMUX_SUSPENDED] = &gpio_i2c_config,
 		},
 	},
 	{					/*  NFC   */
 		.gpio      = 11,		/* BLSP1 QUP3 I2C_CLK */
 		.settings = {
+			[GPIOMUX_ACTIVE] = &gpio_i2c_config,
 			[GPIOMUX_SUSPENDED] = &gpio_i2c_config,
 		},
 	},
@@ -230,6 +257,189 @@
 	},
 };
 
+static struct gpiomux_setting gpio_nc_cfg = {
+	.func = GPIOMUX_FUNC_GPIO,
+	.drv = GPIOMUX_DRV_2MA,
+	.pull = GPIOMUX_PULL_NONE,
+};
+
+static struct gpiomux_setting goodix_ldo_en_act_cfg = {
+	.func = GPIOMUX_FUNC_GPIO,
+	.drv = GPIOMUX_DRV_6MA,
+	.pull = GPIOMUX_PULL_UP,
+};
+
+static struct gpiomux_setting goodix_ldo_en_sus_cfg = {
+	.func = GPIOMUX_FUNC_GPIO,
+	.drv = GPIOMUX_DRV_6MA,
+	.pull = GPIOMUX_PULL_UP,
+};
+
+static struct gpiomux_setting goodix_int_act_cfg = {
+	.func = GPIOMUX_FUNC_GPIO,
+	.drv = GPIOMUX_DRV_8MA,
+	.pull = GPIOMUX_PULL_UP,
+};
+
+static struct gpiomux_setting goodix_int_sus_cfg = {
+	.func = GPIOMUX_FUNC_GPIO,
+	.drv = GPIOMUX_DRV_2MA,
+	.pull = GPIOMUX_PULL_DOWN,
+};
+
+static struct gpiomux_setting goodix_reset_act_cfg = {
+	.func = GPIOMUX_FUNC_GPIO,
+	.drv = GPIOMUX_DRV_8MA,
+	.pull = GPIOMUX_PULL_UP,
+};
+
+static struct gpiomux_setting goodix_reset_sus_cfg = {
+	.func = GPIOMUX_FUNC_GPIO,
+	.drv = GPIOMUX_DRV_8MA,
+	.pull = GPIOMUX_PULL_UP,
+};
+
+static struct msm_gpiomux_config msm_skuf_blsp_configs[] __initdata = {
+	{
+		.gpio      = 2,		/* NC */
+		.settings = {
+			[GPIOMUX_SUSPENDED] = &gpio_nc_cfg,
+		},
+	},
+	{
+		.gpio      = 3,		/* NC */
+		.settings = {
+			[GPIOMUX_SUSPENDED] = &gpio_nc_cfg,
+		},
+	},
+	{
+		.gpio      = 4,		/* NC */
+		.settings = {
+			[GPIOMUX_SUSPENDED] = &gpio_nc_cfg,
+		},
+	},
+	{
+		.gpio      = 14,	/* NC */
+		.settings = {
+			[GPIOMUX_SUSPENDED] = &gpio_nc_cfg,
+		},
+	},
+};
+
+static struct msm_gpiomux_config msm_skuf_goodix_configs[] __initdata = {
+	{
+		.gpio = 15,		/* LDO EN */
+		.settings = {
+			[GPIOMUX_ACTIVE] = &goodix_ldo_en_act_cfg,
+			[GPIOMUX_SUSPENDED] = &goodix_ldo_en_sus_cfg,
+		},
+	},
+	{
+		.gpio = 16,		/* RESET */
+		.settings = {
+			[GPIOMUX_ACTIVE] = &goodix_reset_act_cfg,
+			[GPIOMUX_SUSPENDED] = &goodix_reset_sus_cfg,
+		},
+	},
+	{
+		.gpio = 17,		/* INT */
+		.settings = {
+			[GPIOMUX_ACTIVE] = &goodix_int_act_cfg,
+			[GPIOMUX_SUSPENDED] = &goodix_int_sus_cfg,
+		},
+	},
+	{
+		.gpio      = 18,		/* BLSP1 QUP5 I2C_SDA */
+		.settings = {
+			[GPIOMUX_ACTIVE] = &gpio_i2c_config,
+			[GPIOMUX_SUSPENDED] = &gpio_i2c_config,
+		},
+	},
+	{
+		.gpio      = 19,		/* BLSP1 QUP5 I2C_SCL */
+		.settings = {
+			[GPIOMUX_ACTIVE] = &gpio_i2c_config,
+			[GPIOMUX_SUSPENDED] = &gpio_i2c_config,
+		},
+	},
+};
+
+static struct gpiomux_setting nfc_ldo_act_cfg = {
+	.func = GPIOMUX_FUNC_GPIO,
+	.drv = GPIOMUX_DRV_6MA,
+	.pull = GPIOMUX_PULL_UP,
+};
+
+static struct gpiomux_setting nfc_ldo_sus_cfg = {
+	.func = GPIOMUX_FUNC_GPIO,
+	.drv = GPIOMUX_DRV_6MA,
+	.pull = GPIOMUX_PULL_UP,
+};
+
+static struct gpiomux_setting nfc_regc_act_cfg = {
+	.func = GPIOMUX_FUNC_GPIO,
+	.drv = GPIOMUX_DRV_6MA,
+	.pull = GPIOMUX_PULL_UP,
+};
+
+static struct gpiomux_setting nfc_regc_sus_cfg = {
+	.func = GPIOMUX_FUNC_GPIO,
+	.drv = GPIOMUX_DRV_2MA,
+	.pull = GPIOMUX_PULL_NONE,
+	.dir = GPIOMUX_OUT_LOW,
+};
+
+static struct gpiomux_setting nfc_wake_act_cfg = {
+	.func = GPIOMUX_FUNC_GPIO,
+	.drv = GPIOMUX_DRV_6MA,
+	.pull = GPIOMUX_PULL_UP,
+};
+
+static struct gpiomux_setting nfc_wake_sus_cfg = {
+	.func = GPIOMUX_FUNC_GPIO,
+	.drv = GPIOMUX_DRV_2MA,
+	.pull = GPIOMUX_PULL_NONE,
+	.dir = GPIOMUX_OUT_LOW,
+};
+
+static struct msm_gpiomux_config msm_skuf_nfc_configs[] __initdata = {
+	{					/*  NFC  LDO EN */
+		.gpio      = 0,
+		.settings = {
+			[GPIOMUX_ACTIVE] = &nfc_ldo_act_cfg,
+			[GPIOMUX_SUSPENDED] = &nfc_ldo_sus_cfg,
+		},
+	},
+	{					/*  NFC  REGC*/
+		.gpio      = 1,
+		.settings = {
+			[GPIOMUX_ACTIVE] = &nfc_regc_act_cfg,
+			[GPIOMUX_SUSPENDED] = &nfc_regc_sus_cfg,
+		},
+	},
+	{					/*  NFC   WAKE */
+		.gpio      = 5,
+		.settings = {
+			[GPIOMUX_ACTIVE] = &nfc_wake_act_cfg,
+			[GPIOMUX_SUSPENDED] = &nfc_wake_sus_cfg,
+		},
+	},
+	{					/*  NFC   */
+		.gpio      = 10,		/* BLSP1 QUP3 I2C_DAT */
+		.settings = {
+			[GPIOMUX_ACTIVE] = &gpio_i2c_config,
+			[GPIOMUX_SUSPENDED] = &gpio_i2c_config,
+		},
+	},
+	{					/*  NFC   */
+		.gpio      = 11,		/* BLSP1 QUP3 I2C_CLK */
+		.settings = {
+			[GPIOMUX_ACTIVE] = &gpio_i2c_config,
+			[GPIOMUX_SUSPENDED] = &gpio_i2c_config,
+		},
+	},
+};
+
 static struct gpiomux_setting sd_card_det_active_config = {
 	.func = GPIOMUX_FUNC_GPIO,
 	.drv = GPIOMUX_DRV_2MA,
@@ -382,20 +592,6 @@
 		},
 	},
 	{
-		.gpio = 22, /* CAM1_VDD */
-		.settings = {
-			[GPIOMUX_ACTIVE]    = &cam_settings[3],
-			[GPIOMUX_SUSPENDED] = &cam_settings[4],
-		},
-	},
-	{
-		.gpio = 34, /* CAM1 VCM_PWDN */
-		.settings = {
-			[GPIOMUX_ACTIVE]    = &cam_settings[3],
-			[GPIOMUX_SUSPENDED] = &cam_settings[4],
-		},
-	},
-	{
 		.gpio = 35, /* CAM2_STANDBY_N */
 		.settings = {
 			[GPIOMUX_ACTIVE]    = &cam_settings[3],
@@ -412,6 +608,24 @@
 
 };
 
+static struct msm_gpiomux_config msm_sensor_configs_skuf_plus[] __initdata = {
+	{
+		.gpio = 22, /* CAM1_VDD */
+		.settings = {
+			[GPIOMUX_ACTIVE]    = &cam_settings[3],
+			[GPIOMUX_SUSPENDED] = &cam_settings[4],
+		},
+	},
+	{
+		.gpio = 34, /* CAM1 VCM_PWDN */
+		.settings = {
+			[GPIOMUX_ACTIVE]    = &cam_settings[3],
+			[GPIOMUX_SUSPENDED] = &cam_settings[4],
+		},
+	},
+};
+
+
 static struct gpiomux_setting auxpcm_act_cfg = {
 	.func = GPIOMUX_FUNC_1,
 	.drv = GPIOMUX_DRV_8MA,
@@ -571,16 +785,37 @@
 	msm_gpiomux_install(msm_keypad_configs,
 			ARRAY_SIZE(msm_keypad_configs));
 
-	msm_gpiomux_install(msm_blsp_configs, ARRAY_SIZE(msm_blsp_configs));
+	if (of_board_is_skuf())
+		msm_gpiomux_install(msm_skuf_blsp_configs,
+			ARRAY_SIZE(msm_skuf_blsp_configs));
+	else
+		msm_gpiomux_install(msm_blsp_configs,
+			ARRAY_SIZE(msm_blsp_configs));
+
 	msm_gpiomux_install(wcnss_5wire_interface,
 				ARRAY_SIZE(wcnss_5wire_interface));
 
 	msm_gpiomux_install(&sd_card_det, 1);
-	msm_gpiomux_install(msm_synaptics_configs,
-			ARRAY_SIZE(msm_synaptics_configs));
+	if (of_board_is_skuf())
+		msm_gpiomux_install(msm_skuf_goodix_configs,
+				ARRAY_SIZE(msm_skuf_goodix_configs));
+	else
+		msm_gpiomux_install(msm_synaptics_configs,
+				ARRAY_SIZE(msm_synaptics_configs));
+
+	if (of_board_is_skuf())
+		msm_gpiomux_install(msm_skuf_nfc_configs,
+				ARRAY_SIZE(msm_skuf_nfc_configs));
+
 	msm_gpiomux_install_nowrite(msm_lcd_configs,
 			ARRAY_SIZE(msm_lcd_configs));
+
 	msm_gpiomux_install(msm_sensor_configs, ARRAY_SIZE(msm_sensor_configs));
+
+	if (of_board_is_skuf())
+		msm_gpiomux_install(msm_sensor_configs_skuf_plus,
+			ARRAY_SIZE(msm_sensor_configs_skuf_plus));
+
 	msm_gpiomux_install(msm_auxpcm_configs,
 			ARRAY_SIZE(msm_auxpcm_configs));
 
diff --git a/arch/arm/mach-msm/board-8610-gpiomux.c b/arch/arm/mach-msm/board-8610-gpiomux.c
index 01f1468..87794c4 100644
--- a/arch/arm/mach-msm/board-8610-gpiomux.c
+++ b/arch/arm/mach-msm/board-8610-gpiomux.c
@@ -23,6 +23,11 @@
 	.drv = GPIOMUX_DRV_6MA,
 	.pull = GPIOMUX_PULL_NONE,
 };
+static struct gpiomux_setting gpio_spi_susp_config = {
+	.func = GPIOMUX_FUNC_GPIO,
+	.drv = GPIOMUX_DRV_2MA,
+	.pull = GPIOMUX_PULL_DOWN,
+};
 
 static struct gpiomux_setting gpio_i2c_config = {
 	.func = GPIOMUX_FUNC_3,
@@ -188,36 +193,42 @@
 	{
 		.gpio      = 2,		/* BLSP1 QUP1 I2C_SDA */
 		.settings = {
+			[GPIOMUX_ACTIVE] = &gpio_i2c_config,
 			[GPIOMUX_SUSPENDED] = &gpio_i2c_config,
 		},
 	},
 	{
 		.gpio      = 3,		/* BLSP1 QUP1 I2C_SCL */
 		.settings = {
+			[GPIOMUX_ACTIVE] = &gpio_i2c_config,
 			[GPIOMUX_SUSPENDED] = &gpio_i2c_config,
 		},
 	},
 	{
 		.gpio      = 10,	/* BLSP1 QUP3 I2C_SDA */
 		.settings = {
+			[GPIOMUX_ACTIVE] = &gpio_i2c_config,
 			[GPIOMUX_SUSPENDED] = &gpio_i2c_config,
 		},
 	},
 	{
 		.gpio      = 11,	/* BLSP1 QUP3 I2C_SCL */
 		.settings = {
+			[GPIOMUX_ACTIVE] = &gpio_i2c_config,
 			[GPIOMUX_SUSPENDED] = &gpio_i2c_config,
 		},
 	},
 	{
 		.gpio      = 16,	/* BLSP1 QUP6 I2C_SDA */
 		.settings = {
+			[GPIOMUX_ACTIVE] = &gpio_cam_i2c_config,
 			[GPIOMUX_SUSPENDED] = &gpio_cam_i2c_config,
 		},
 	},
 	{
 		.gpio      = 17,	/* BLSP1 QUP6 I2C_SCL */
 		.settings = {
+			[GPIOMUX_ACTIVE] = &gpio_cam_i2c_config,
 			[GPIOMUX_SUSPENDED] = &gpio_cam_i2c_config,
 		},
 	},
@@ -241,25 +252,29 @@
 	{
 		.gpio      = 86,		/* BLSP1 QUP4 SPI_DATA_MOSI */
 		.settings = {
-			[GPIOMUX_SUSPENDED] = &gpio_spi_config,
+			[GPIOMUX_ACTIVE] = &gpio_spi_config,
+			[GPIOMUX_SUSPENDED] = &gpio_spi_susp_config,
 		},
 	},
 	{
 		.gpio      = 87,		/* BLSP1 QUP4 SPI_DATA_MISO */
 		.settings = {
-			[GPIOMUX_SUSPENDED] = &gpio_spi_config,
+			[GPIOMUX_ACTIVE] = &gpio_spi_config,
+			[GPIOMUX_SUSPENDED] = &gpio_spi_susp_config,
 		},
 	},
 	{
 		.gpio      = 89,		/* BLSP1 QUP4 SPI_CLK */
 		.settings = {
-			[GPIOMUX_SUSPENDED] = &gpio_spi_config,
+			[GPIOMUX_ACTIVE] = &gpio_spi_config,
+			[GPIOMUX_SUSPENDED] = &gpio_spi_susp_config,
 		},
 	},
 	{
 		.gpio      = 88,		/* BLSP1 QUP4 SPI_CS */
 		.settings = {
-			[GPIOMUX_SUSPENDED] = &gpio_spi_config,
+			[GPIOMUX_ACTIVE] = &gpio_spi_config,
+			[GPIOMUX_SUSPENDED] = &gpio_spi_susp_config,
 		},
 	},
 };
@@ -282,25 +297,29 @@
 	{
 		.gpio      = 86,		/* BLSP1 QUP4 SPI_DATA_MOSI */
 		.settings = {
-			[GPIOMUX_SUSPENDED] = &gpio_spi_config,
+			[GPIOMUX_ACTIVE] = &gpio_spi_config,
+			[GPIOMUX_SUSPENDED] = &gpio_spi_susp_config,
 		},
 	},
 	{
 		.gpio      = 87,		/* BLSP1 QUP4 SPI_DATA_MISO */
 		.settings = {
-			[GPIOMUX_SUSPENDED] = &gpio_spi_config,
+			[GPIOMUX_ACTIVE] = &gpio_spi_config,
+			[GPIOMUX_SUSPENDED] = &gpio_spi_susp_config,
 		},
 	},
 	{
 		.gpio      = 89,		/* BLSP1 QUP4 SPI_CLK */
 		.settings = {
-			[GPIOMUX_SUSPENDED] = &gpio_spi_config,
+			[GPIOMUX_ACTIVE] = &gpio_spi_config,
+			[GPIOMUX_SUSPENDED] = &gpio_spi_susp_config,
 		},
 	},
 	{
 		.gpio      = 88,		/* BLSP1 QUP4 SPI_CS */
 		.settings = {
-			[GPIOMUX_SUSPENDED] = &gpio_spi_config,
+			[GPIOMUX_ACTIVE] = &gpio_spi_config,
+			[GPIOMUX_SUSPENDED] = &gpio_spi_susp_config,
 		},
 	},
 };
@@ -422,14 +441,14 @@
 	{
 		.gpio = 18, /* FLASH_LED_EN */
 		.settings = {
-			[GPIOMUX_ACTIVE]    = &cam_settings[0],
+			[GPIOMUX_ACTIVE]    = &cam_settings[3],
 			[GPIOMUX_SUSPENDED] = &gpio_suspend_config[1],
 		},
 	},
 	{
 		.gpio = 19, /* FLASH_LED_NOW */
 		.settings = {
-			[GPIOMUX_ACTIVE]    = &cam_settings[0],
+			[GPIOMUX_ACTIVE]    = &cam_settings[3],
 			[GPIOMUX_SUSPENDED] = &gpio_suspend_config[1],
 		},
 	},
@@ -511,6 +530,62 @@
 	},
 };
 
+static struct gpiomux_setting interrupt_gpio_active = {
+	.func = GPIOMUX_FUNC_GPIO,
+	.drv = GPIOMUX_DRV_6MA,
+	.pull = GPIOMUX_PULL_UP,
+};
+
+static struct gpiomux_setting interrupt_gpio_suspend_pullup = {
+	.func = GPIOMUX_FUNC_GPIO,
+	.drv = GPIOMUX_DRV_6MA,
+	.pull = GPIOMUX_PULL_UP,
+};
+
+static struct gpiomux_setting interrupt_gpio_suspend_pulldown = {
+	.func = GPIOMUX_FUNC_GPIO,
+	.drv = GPIOMUX_DRV_6MA,
+	.pull = GPIOMUX_PULL_UP,
+};
+
+static struct msm_gpiomux_config msm_interrupt_configs[] __initdata = {
+	{
+		.gpio = 77,	/* NFC_IRQ */
+		.settings = {
+			[GPIOMUX_ACTIVE]    = &interrupt_gpio_active,
+			[GPIOMUX_SUSPENDED] = &interrupt_gpio_suspend_pullup,
+		},
+	},
+	{
+		.gpio = 78,	/*ETH_INT */
+		.settings = {
+			[GPIOMUX_ACTIVE]    = &interrupt_gpio_active,
+			[GPIOMUX_SUSPENDED] = &interrupt_gpio_suspend_pullup,
+		},
+	},
+	{
+		.gpio = 80,	/*ALSP_INT */
+		.settings = {
+			[GPIOMUX_ACTIVE]    = &interrupt_gpio_active,
+			[GPIOMUX_SUSPENDED] = &interrupt_gpio_suspend_pullup,
+		},
+	},
+	{
+		.gpio = 81,	/*ACCEL_INT1 */
+		.settings = {
+			[GPIOMUX_ACTIVE]    = &interrupt_gpio_active,
+			[GPIOMUX_SUSPENDED] = &interrupt_gpio_suspend_pulldown,
+		},
+	},
+	{
+		.gpio = 82,	/*ACCEL_INT2 */
+		.settings = {
+			[GPIOMUX_ACTIVE]    = &interrupt_gpio_active,
+			[GPIOMUX_SUSPENDED] = &interrupt_gpio_suspend_pulldown,
+		},
+	},
+};
+
 void __init msm8610_init_gpiomux(void)
 {
 	int rc;
@@ -539,4 +614,7 @@
 	msm_gpiomux_install(msm_sensor_configs, ARRAY_SIZE(msm_sensor_configs));
 	msm_gpiomux_install(msm_gpio_int_configs,
 			ARRAY_SIZE(msm_gpio_int_configs));
+	if (of_board_is_qrd())
+		msm_gpiomux_install(msm_interrupt_configs,
+			ARRAY_SIZE(msm_interrupt_configs));
 }
diff --git a/arch/arm/mach-msm/board-8960-regulator.c b/arch/arm/mach-msm/board-8960-regulator.c
index a93cfe5..a29bb88 100644
--- a/arch/arm/mach-msm/board-8960-regulator.c
+++ b/arch/arm/mach-msm/board-8960-regulator.c
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2011-2012, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2011-2013, The Linux Foundation. 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 and
@@ -630,16 +630,27 @@
 	static struct rpm_regulator_init_data *rpm_data;
 	int i;
 
-	if (machine_is_msm8960_cdp()) {
+	if (machine_is_msm8960_cdp() || cpu_is_msm8960ab()) {
 		/* Only modify LVS6 consumers for CDP targets. */
 		for (i = 0; i < ARRAY_SIZE(msm_rpm_regulator_init_data); i++) {
 			rpm_data = &msm_rpm_regulator_init_data[i];
-			if (rpm_data->id == RPM_VREG_ID_PM8921_LVS6) {
+			if (machine_is_msm8960_cdp() &&
+				rpm_data->id == RPM_VREG_ID_PM8921_LVS6) {
 				rpm_data->init_data.consumer_supplies
 					= vreg_consumers_CDP_LVS6;
 				rpm_data->init_data.num_consumer_supplies
 					= ARRAY_SIZE(vreg_consumers_CDP_LVS6);
 			}
+			if (cpu_is_msm8960ab() &&
+				rpm_data->id == RPM_VREG_ID_PM8921_S7) {
+				rpm_data->init_data.constraints.min_uV =
+								1275000;
+				rpm_data->init_data.constraints.max_uV =
+								1275000;
+				rpm_data->init_data.constraints.input_uV =
+								1275000;
+				rpm_data->default_uV = 1275000;
+			}
 		}
 	}
 }
diff --git a/arch/arm/mach-msm/board-8960.c b/arch/arm/mach-msm/board-8960.c
index 37567ed..f234712 100644
--- a/arch/arm/mach-msm/board-8960.c
+++ b/arch/arm/mach-msm/board-8960.c
@@ -75,7 +75,7 @@
 #include <linux/mfd/wcd9xxx/pdata.h>
 #endif
 
-#include <linux/smsc3503.h>
+#include <linux/smsc_hub.h>
 #include <linux/msm_ion.h>
 #include <mach/ion.h>
 #include <mach/mdm2.h>
diff --git a/arch/arm/mach-msm/board-8974-gpiomux.c b/arch/arm/mach-msm/board-8974-gpiomux.c
index 6165c32..c35a607 100644
--- a/arch/arm/mach-msm/board-8974-gpiomux.c
+++ b/arch/arm/mach-msm/board-8974-gpiomux.c
@@ -143,6 +143,11 @@
 	.drv = GPIOMUX_DRV_12MA,
 	.pull = GPIOMUX_PULL_NONE,
 };
+static struct gpiomux_setting gpio_spi_susp_config = {
+	.func = GPIOMUX_FUNC_GPIO,
+	.drv = GPIOMUX_DRV_2MA,
+	.pull = GPIOMUX_PULL_DOWN,
+};
 
 static struct gpiomux_setting gpio_spi_cs1_config = {
 	.func = GPIOMUX_FUNC_GPIO,
@@ -223,6 +228,17 @@
 	.pull = GPIOMUX_PULL_NONE,
 };
 
+static struct gpiomux_setting gpio_i2c_act_config = {
+	.func = GPIOMUX_FUNC_3,
+	/*
+	 * Please keep I2C GPIOs drive-strength at minimum (2ma). It is a
+	 * workaround for HW issue of glitches caused by rapid GPIO current-
+	 * change.
+	 */
+	.drv = GPIOMUX_DRV_2MA,
+	.pull = GPIOMUX_PULL_UP,
+};
+
 static struct gpiomux_setting lcd_en_act_cfg = {
 	.func = GPIOMUX_FUNC_GPIO,
 	.drv = GPIOMUX_DRV_8MA,
@@ -553,31 +569,36 @@
 	{
 		.gpio      = 0,		/* BLSP1 QUP SPI_DATA_MOSI */
 		.settings = {
-			[GPIOMUX_SUSPENDED] = &gpio_spi_config,
+			[GPIOMUX_ACTIVE] = &gpio_spi_config,
+			[GPIOMUX_SUSPENDED] = &gpio_spi_susp_config,
 		},
 	},
 	{
 		.gpio      = 1,		/* BLSP1 QUP SPI_DATA_MISO */
 		.settings = {
-			[GPIOMUX_SUSPENDED] = &gpio_spi_config,
+			[GPIOMUX_ACTIVE] = &gpio_spi_config,
+			[GPIOMUX_SUSPENDED] = &gpio_spi_susp_config,
 		},
 	},
 	{
 		.gpio      = 3,		/* BLSP1 QUP SPI_CLK */
 		.settings = {
-			[GPIOMUX_SUSPENDED] = &gpio_spi_config,
+			[GPIOMUX_ACTIVE] = &gpio_spi_config,
+			[GPIOMUX_SUSPENDED] = &gpio_spi_susp_config,
 		},
 	},
 	{
 		.gpio      = 9,		/* BLSP1 QUP SPI_CS2A_N */
 		.settings = {
-			[GPIOMUX_SUSPENDED] = &gpio_spi_cs2_config,
+			[GPIOMUX_ACTIVE] = &gpio_spi_cs2_config,
+			[GPIOMUX_SUSPENDED] = &gpio_spi_susp_config,
 		},
 	},
 	{
 		.gpio      = 8,		/* BLSP1 QUP SPI_CS1_N */
 		.settings = {
-			[GPIOMUX_SUSPENDED] = &gpio_spi_cs1_config,
+			[GPIOMUX_ACTIVE] = &gpio_spi_cs1_config,
+			[GPIOMUX_SUSPENDED] = &gpio_spi_susp_config,
 		},
 	},
 #endif
@@ -585,12 +606,14 @@
 		.gpio      = 6,		/* BLSP1 QUP2 I2C_DAT */
 		.settings = {
 			[GPIOMUX_SUSPENDED] = &gpio_i2c_config,
+			[GPIOMUX_ACTIVE] = &gpio_i2c_act_config,
 		},
 	},
 	{
 		.gpio      = 7,		/* BLSP1 QUP2 I2C_CLK */
 		.settings = {
 			[GPIOMUX_SUSPENDED] = &gpio_i2c_config,
+			[GPIOMUX_ACTIVE] = &gpio_i2c_act_config,
 		},
 	},
 	{
@@ -1346,6 +1369,11 @@
 		return;
 	}
 
+	pr_err("%s:%d socinfo_get_version %x\n", __func__, __LINE__,
+		socinfo_get_version());
+	if (socinfo_get_version() >= 0x20000)
+		msm_tlmm_misc_reg_write(TLMM_SPARE_REG, 0xf);
+
 #if defined(CONFIG_KS8851) || defined(CONFIG_KS8851_MODULE)
 	if (!(of_board_is_dragonboard() && machine_is_apq8074()))
 		msm_gpiomux_install(msm_eth_configs, \
diff --git a/arch/arm/mach-msm/board-samarium.c b/arch/arm/mach-msm/board-samarium.c
index 6133983..52a947b 100644
--- a/arch/arm/mach-msm/board-samarium.c
+++ b/arch/arm/mach-msm/board-samarium.c
@@ -16,6 +16,7 @@
 #include <linux/of_address.h>
 #include <linux/of_platform.h>
 #include <linux/memory.h>
+#include <linux/msm_tsens.h>
 #include <asm/hardware/gic.h>
 #include <asm/mach/map.h>
 #include <asm/mach/arch.h>
@@ -35,6 +36,10 @@
 #include "modem_notifier.h"
 
 static struct clk_lookup msm_clocks_dummy[] = {
+	CLK_DUMMY("xo",                CXO_CLK, "fc880000.qcom,mss", OFF),
+	CLK_DUMMY("bus_clk",   MSS_BIMC_Q6_CLK, "fc880000.qcom,mss", OFF),
+	CLK_DUMMY("iface_clk", MSS_CFG_AHB_CLK, "fc880000.qcom,mss", OFF),
+	CLK_DUMMY("mem_clk",  BOOT_ROM_AHB_CLK, "fc880000.qcom,mss", OFF),
 	CLK_DUMMY("core_clk",   BLSP1_UART_CLK, "f991f000.serial", OFF),
 	CLK_DUMMY("iface_clk",  BLSP1_UART_CLK, "f991f000.serial", OFF),
 	CLK_DUMMY("core_clk",	SDC1_CLK,	"msm_sdcc.1", OFF),
@@ -109,6 +114,7 @@
 	msm_init_modem_notifier_list();
 	msm_smd_init();
 	msm_clock_init(&msm_dummy_clock_init_data);
+	tsens_tm_init_driver();
 }
 
 static void __init msmsamarium_map_io(void)
diff --git a/arch/arm/mach-msm/clock-8084.c b/arch/arm/mach-msm/clock-8084.c
index ffd33a8..939a637 100644
--- a/arch/arm/mach-msm/clock-8084.c
+++ b/arch/arm/mach-msm/clock-8084.c
@@ -415,6 +415,7 @@
 	CLK_DUMMY("core_clk", qdss_clk.c, "fc342000.cti", OFF),
 	CLK_DUMMY("core_clk", qdss_clk.c, "fc343000.cti", OFF),
 	CLK_DUMMY("core_clk", qdss_clk.c, "fc344000.cti", OFF),
+	CLK_DUMMY("core_clk", qdss_clk.c, "fd828018.hwevent", OFF),
 
 	CLK_DUMMY("core_a_clk", qdss_a_clk.c, "fc326000.tmc", OFF),
 	CLK_DUMMY("core_a_clk", qdss_a_clk.c, "fc324000.replicator", OFF),
@@ -444,6 +445,13 @@
 	CLK_DUMMY("core_a_clk", qdss_a_clk.c, "fc342000.cti", OFF),
 	CLK_DUMMY("core_a_clk", qdss_a_clk.c, "fc343000.cti", OFF),
 	CLK_DUMMY("core_a_clk", qdss_a_clk.c, "fc344000.cti", OFF),
+	CLK_DUMMY("core_a_clk", qdss_a_clk.c, "fd828018.hwevent", OFF),
+
+	CLK_DUMMY("core_mmss_clk", mmss_misc_ahb_clk.c, "fd828018.hwevent",
+		  OFF),
+
+	CLK_DUMMY("iface_clk", gcc_prng_ahb_clk.c,
+					"f9bff000.qcom,msm-rng", OFF),
 };
 
 struct clock_init_data msm8084_clock_init_data __initdata = {
diff --git a/arch/arm/mach-msm/clock-8226.c b/arch/arm/mach-msm/clock-8226.c
index cf6c23f..1999379 100644
--- a/arch/arm/mach-msm/clock-8226.c
+++ b/arch/arm/mach-msm/clock-8226.c
@@ -353,7 +353,6 @@
 #define GPLL1_N_VAL                                        (0x004C)
 #define GPLL1_USER_CTL                                     (0x0050)
 #define GPLL1_STATUS                                       (0x005C)
-#define PERIPH_NOC_AHB_CBCR                                (0x0184)
 #define NOC_CONF_XPU_AHB_CBCR                              (0x01C0)
 #define MMSS_NOC_CFG_AHB_CBCR                              (0x024C)
 #define MSS_CFG_AHB_CBCR                                   (0x0280)
@@ -1394,17 +1393,6 @@
 	},
 };
 
-static struct branch_clk gcc_periph_noc_ahb_clk = {
-	.cbcr_reg = PERIPH_NOC_AHB_CBCR,
-	.has_sibling = 1,
-	.base = &virt_bases[GCC_BASE],
-	.c = {
-		.dbg_name = "gcc_periph_noc_ahb_clk",
-		.ops = &clk_ops_branch,
-		CLK_INIT(gcc_periph_noc_ahb_clk.c),
-	},
-};
-
 static struct local_vote_clk gcc_prng_ahb_clk = {
 	.cbcr_reg = PRNG_AHB_CBCR,
 	.vote_reg = APCS_CLOCK_BRANCH_ENA_VOTE,
@@ -1571,7 +1559,6 @@
 };
 
 static struct measure_mux_entry measure_mux_GCC[] = {
-	{ &gcc_periph_noc_ahb_clk.c,  GCC_BASE, 0x0010 },
 	{ &gcc_mss_cfg_ahb_clk.c,  GCC_BASE, 0x0030 },
 	{ &gcc_mss_q6_bimc_axi_clk.c,  GCC_BASE, 0x0031 },
 	{ &gcc_usb_hsic_ahb_clk.c,  GCC_BASE, 0x0058 },
@@ -1616,7 +1603,15 @@
 	{ &gcc_ce1_axi_clk.c,  GCC_BASE, 0x0139 },
 	{ &gcc_ce1_ahb_clk.c,  GCC_BASE, 0x013a },
 	{ &gcc_lpass_q6_axi_clk.c,  GCC_BASE, 0x0160 },
-	{&dummy_clk, N_BASES, 0x0000},
+	{ &pnoc_clk.c, GCC_BASE, 0x010},
+	{ &snoc_clk.c, GCC_BASE, 0x000},
+	{ &cnoc_clk.c, GCC_BASE, 0x008},
+	/*
+	 * measure the gcc_bimc_kpss_axi_clk instead to account for the DDR
+	 * rate being gcc_bimc_clk/2.
+	 */
+	{ &bimc_clk.c, GCC_BASE, 0x155},
+	{ &dummy_clk, N_BASES, 0x0000},
 };
 
 static struct pll_vote_clk mmpll0_pll = {
@@ -2738,6 +2733,7 @@
 	{ &camss_csi1rdi_clk.c,  MMSS_BASE, 0x0049 },
 	{ &camss_csi1pix_clk.c,  MMSS_BASE, 0x004a },
 	{ &camss_ispif_ahb_clk.c,  MMSS_BASE, 0x0055 },
+	{ &mmssnoc_ahb_clk.c,  MMSS_BASE, 0x0001 },
 	{&dummy_clk, N_BASES, 0x0000},
 };
 
@@ -2833,6 +2829,8 @@
 	F_APCS_PLL(1305600000, 68, 0x0, 0x1, 0x0, 0x0, 0x0),
 	F_APCS_PLL(1344000000, 70, 0x0, 0x1, 0x0, 0x0, 0x0),
 	F_APCS_PLL(1401600000, 73, 0x0, 0x1, 0x0, 0x0, 0x0),
+	F_APCS_PLL(1497600000, 78, 0x0, 0x1, 0x0, 0x0, 0x0),
+	F_APCS_PLL(1593600000, 83, 0x0, 0x1, 0x0, 0x0, 0x0),
 	PLL_F_END
 };
 
@@ -3251,6 +3249,7 @@
 	CLK_LOOKUP("xo",                 cxo_otg_clk.c, "f9a55000.usb"),
 	CLK_LOOKUP("iface_clk",   gcc_usb_hs_ahb_clk.c, "f9a55000.usb"),
 	CLK_LOOKUP("core_clk", gcc_usb_hs_system_clk.c, "f9a55000.usb"),
+	CLK_LOOKUP("sleep_clk", gcc_usb2a_phy_sleep_clk.c, "f9a55000.usb"),
 
 	/* SPS CLOCKS */
 	CLK_LOOKUP("dfab_clk",            pnoc_sps_clk.c, "f9984000.qcom,sps"),
@@ -3309,10 +3308,6 @@
 	CLK_LOOKUP("iface_clk", gcc_sdcc3_ahb_clk.c, "msm_sdcc.3"),
 	CLK_LOOKUP("core_clk", gcc_sdcc3_apps_clk.c, "msm_sdcc.3"),
 
-	CLK_LOOKUP("sleep_a_clk", gcc_usb2a_phy_sleep_clk.c, "msm_dwc3"),
-	CLK_LOOKUP("ref_clk", diff_clk.c, "msm_dwc3"),
-
-
 	CLK_LOOKUP("bus_clk", pnoc_clk.c, ""),
 	CLK_LOOKUP("bus_clk", pnoc_a_clk.c, ""),
 	CLK_LOOKUP("bus_clk", snoc_clk.c, ""),
@@ -3392,15 +3387,21 @@
 	CLK_LOOKUP("cam_src_clk", mclk0_clk_src.c, "6d.qcom,camera"),
 	CLK_LOOKUP("cam_src_clk", mclk0_clk_src.c, "6a.qcom,camera"),
 	CLK_LOOKUP("cam_src_clk", mclk0_clk_src.c, "6c.qcom,camera"),
+	CLK_LOOKUP("cam_src_clk", mclk0_clk_src.c, "20.qcom,camera"),
 	CLK_LOOKUP("cam_clk", camss_mclk0_clk.c, "6f.qcom,camera"),
 	CLK_LOOKUP("cam_clk", camss_mclk0_clk.c, "90.qcom,camera"),
 	CLK_LOOKUP("cam_clk", camss_mclk0_clk.c, "6d.qcom,camera"),
 	CLK_LOOKUP("cam_clk", camss_mclk0_clk.c, "6a.qcom,camera"),
 	CLK_LOOKUP("cam_clk", camss_mclk0_clk.c, "6c.qcom,camera"),
+	CLK_LOOKUP("cam_clk", camss_mclk0_clk.c, "20.qcom,camera"),
 
 	/* eeprom clocks */
 	CLK_LOOKUP("cam_src_clk", mclk0_clk_src.c, "6c.qcom,eeprom"),
 	CLK_LOOKUP("cam_clk", camss_mclk0_clk.c, "6c.qcom,eeprom"),
+	CLK_LOOKUP("cam_src_clk", mclk0_clk_src.c, "18.qcom,eeprom"),
+	CLK_LOOKUP("cam_clk", camss_mclk0_clk.c, "18.qcom,eeprom"),
+	CLK_LOOKUP("cam_src_clk", mclk0_clk_src.c, "6b.qcom,eeprom"),
+	CLK_LOOKUP("cam_clk", camss_mclk0_clk.c, "6b.qcom,eeprom"),
 
 	/* CCI clocks */
 	CLK_LOOKUP("camss_top_ahb_clk", camss_top_ahb_clk.c,
diff --git a/arch/arm/mach-msm/clock-8610.c b/arch/arm/mach-msm/clock-8610.c
index b1b9397..33dcd9f 100644
--- a/arch/arm/mach-msm/clock-8610.c
+++ b/arch/arm/mach-msm/clock-8610.c
@@ -240,6 +240,7 @@
 #define                 GFX3D_CMD_RCGR	    0x4000
 #define               OXILI_GFX3D_CBCR	    0x4028
 #define                OXILI_GFX3D_BCR	    0x4030
+#define                 GMEM_GFX3D_BCR	    0x4040
 #define                  OXILI_AHB_BCR	    0x4044
 #define                 OXILI_AHB_CBCR	    0x403C
 #define                   AHB_CMD_RCGR	    0x5000
@@ -507,6 +508,7 @@
 static DEFINE_CLK_VOTER(bimc_msmbus_a_clk, &bimc_a_clk.c, LONG_MAX);
 static DEFINE_CLK_VOTER(bimc_acpu_a_clk, &bimc_a_clk.c, LONG_MAX);
 
+static DEFINE_CLK_VOTER(pnoc_keepalive_a_clk, &pnoc_a_clk.c, LONG_MAX);
 static DEFINE_CLK_VOTER(pnoc_sps_clk, &pnoc_clk.c, LONG_MAX);
 static DEFINE_CLK_VOTER(pnoc_iommu_clk, &pnoc_clk.c, LONG_MAX);
 
@@ -1549,7 +1551,6 @@
 	F_END,
 };
 
-static struct branch_clk mmss_mmssnoc_axi_clk;
 static struct rcg_clk axi_clk_src = {
 	.cmd_rcgr_reg = AXI_CMD_RCGR,
 	.set_rate = set_rate_hid,
@@ -1561,7 +1562,6 @@
 		.ops = &clk_ops_rcg,
 		VDD_DIG_FMAX_MAP2(LOW, 100000000, NOMINAL, 200000000),
 		CLK_INIT(axi_clk_src.c),
-		.depends = &mmss_mmssnoc_axi_clk.c
 	},
 };
 
@@ -2146,6 +2146,7 @@
 
 static struct branch_clk csi_vfe_clk = {
 	.cbcr_reg = CSI_VFE_CBCR,
+	.bcr_reg = CSI_VFE_BCR,
 	.has_sibling = 1,
 	.base = &virt_bases[MMSS_BASE],
 	.c = {
@@ -2216,6 +2217,7 @@
 
 static struct branch_clk gmem_gfx3d_clk = {
 	.cbcr_reg = GMEM_GFX3D_CBCR,
+	.bcr_reg = GMEM_GFX3D_BCR,
 	.has_sibling = 1,
 	.base = &virt_bases[MMSS_BASE],
 	.c = {
@@ -2261,6 +2263,7 @@
 	},
 };
 
+static struct branch_clk mmss_mmssnoc_axi_clk;
 static struct branch_clk mdp_axi_clk = {
 	.cbcr_reg = MDP_AXI_CBCR,
 	.base = &virt_bases[MMSS_BASE],
@@ -2271,6 +2274,7 @@
 		.dbg_name = "mdp_axi_clk",
 		.ops = &clk_ops_branch,
 		CLK_INIT(mdp_axi_clk.c),
+		.depends = &mmss_mmssnoc_axi_clk.c,
 	},
 };
 
@@ -2326,6 +2330,7 @@
 	.has_sibling = 1,
 	.base = &virt_bases[MMSS_BASE],
 	.c = {
+		.parent = &axi_clk_src.c,
 		.dbg_name = "mmss_mmssnoc_axi_clk",
 		.ops = &clk_ops_branch,
 		CLK_INIT(mmss_mmssnoc_axi_clk.c),
@@ -2341,6 +2346,7 @@
 		.dbg_name = "mmss_s0_axi_clk",
 		.ops = &clk_ops_branch,
 		CLK_INIT(mmss_s0_axi_clk.c),
+		.depends = &mmss_mmssnoc_axi_clk.c,
 	},
 };
 
@@ -2357,6 +2363,7 @@
 
 static struct branch_clk oxili_ahb_clk = {
 	.cbcr_reg = OXILI_AHB_CBCR,
+	.bcr_reg = OXILI_AHB_BCR,
 	.has_sibling = 1,
 	.base = &virt_bases[MMSS_BASE],
 	.c = {
@@ -2368,6 +2375,7 @@
 
 static struct branch_clk oxili_gfx3d_clk = {
 	.cbcr_reg = OXILI_GFX3D_CBCR,
+	.bcr_reg = OXILI_GFX3D_BCR,
 	.has_sibling = 0,
 	.base = &virt_bases[MMSS_BASE],
 	.c = {
@@ -2380,6 +2388,7 @@
 
 static struct branch_clk vfe_clk = {
 	.cbcr_reg = VFE_CBCR,
+	.bcr_reg = VFE_BCR,
 	.has_sibling = 1,
 	.base = &virt_bases[MMSS_BASE],
 	.c = {
@@ -2392,6 +2401,7 @@
 
 static struct branch_clk vfe_ahb_clk = {
 	.cbcr_reg = VFE_AHB_CBCR,
+	.bcr_reg = VFE_AHB_BCR,
 	.has_sibling = 1,
 	.base = &virt_bases[MMSS_BASE],
 	.c = {
@@ -2403,6 +2413,7 @@
 
 static struct branch_clk vfe_axi_clk = {
 	.cbcr_reg = VFE_AXI_CBCR,
+	.bcr_reg = VFE_AXI_BCR,
 	.has_sibling = 1,
 	.base = &virt_bases[MMSS_BASE],
 	 /* FIXME: Remove this once simulation is fixed. */
@@ -2412,6 +2423,7 @@
 		.dbg_name = "vfe_axi_clk",
 		.ops = &clk_ops_branch,
 		CLK_INIT(vfe_axi_clk.c),
+		.depends = &mmss_mmssnoc_axi_clk.c,
 	},
 };
 
@@ -2749,7 +2761,7 @@
 };
 
 static struct clk_lookup msm_clocks_8610[] = {
-	CLK_LOOKUP("xo",	cxo_otg_clk.c, "msm_otg"),
+	CLK_LOOKUP("xo",	cxo_otg_clk.c, "f9a55000.usb"),
 	CLK_LOOKUP("xo",	cxo_lpass_pil_clk.c, "fe200000.qcom,lpass"),
 	CLK_LOOKUP("xo",        cxo_lpm_clk.c, "fc4281d0.qcom,mpm"),
 
@@ -2767,7 +2779,7 @@
 	CLK_LOOKUP("core_clk",  gcc_blsp1_uart3_apps_clk.c, "f991f000.serial"),
 	CLK_LOOKUP("iface_clk",  gcc_blsp1_ahb_clk.c, "f991e000.serial"),
 	CLK_LOOKUP("core_clk",  gcc_blsp1_uart2_apps_clk.c, "f991e000.serial"),
-
+	CLK_LOOKUP("bus_clk", pnoc_keepalive_a_clk.c, ""),
 	CLK_LOOKUP("dfab_clk", pnoc_sps_clk.c, "msm_sps"),
 
 	CLK_LOOKUP("bus_clk", snoc_clk.c, ""),
@@ -2924,7 +2936,7 @@
 	CLK_LOOKUP("core_clk",           gcc_sdcc1_apps_clk.c, "msm_sdcc.1"),
 	CLK_LOOKUP("iface_clk",            gcc_sdcc2_ahb_clk.c, "msm_sdcc.2"),
 	CLK_LOOKUP("core_clk",           gcc_sdcc2_apps_clk.c, "msm_sdcc.2"),
-	CLK_LOOKUP("core_clk",      gcc_usb2a_phy_sleep_clk.c, ""),
+	CLK_LOOKUP("sleep_clk",      gcc_usb2a_phy_sleep_clk.c, "f9a55000.usb"),
 	CLK_LOOKUP("iface_clk",           gcc_usb_hs_ahb_clk.c, "f9a55000.usb"),
 	CLK_LOOKUP("core_clk",        gcc_usb_hs_system_clk.c, "f9a55000.usb"),
 
@@ -3014,11 +3026,13 @@
 	CLK_LOOKUP("cam_src_clk", mclk0_clk_src.c, "6-006d"),
 	CLK_LOOKUP("cam_src_clk", mclk1_clk_src.c, "6-0078"),
 	CLK_LOOKUP("cam_src_clk", mclk0_clk_src.c, "6-0020"),
+	CLK_LOOKUP("cam_src_clk", mclk0_clk_src.c, "6-006a"),
 	CLK_LOOKUP("cam_clk", mclk0_clk.c, "6-006f"),
 	CLK_LOOKUP("cam_clk", mclk0_clk.c, "6-007d"),
 	CLK_LOOKUP("cam_clk", mclk0_clk.c, "6-006d"),
 	CLK_LOOKUP("cam_clk", mclk1_clk.c, "6-0078"),
 	CLK_LOOKUP("cam_clk", mclk0_clk.c, "6-0020"),
+	CLK_LOOKUP("cam_clk", mclk0_clk.c, "6-006a"),
 
 
 	/* CSIPHY clocks */
@@ -3132,6 +3146,14 @@
 	CLK_LOOKUP("iface_clk",    gcc_ce1_ahb_clk.c, "fd404000.qcom,qcrypto"),
 	CLK_LOOKUP("bus_clk",      gcc_ce1_axi_clk.c, "fd404000.qcom,qcrypto"),
 	CLK_LOOKUP("core_clk_src", ce1_clk_src.c,     "fd404000.qcom,qcrypto"),
+
+	/* GDSC clocks */
+	CLK_LOOKUP("core_clk", vfe_clk.c,	"fd8c36a4.qcom,gdsc"),
+	CLK_LOOKUP("iface_clk", vfe_ahb_clk.c,	"fd8c36a4.qcom,gdsc"),
+	CLK_LOOKUP("bus_clk",  vfe_axi_clk.c,	"fd8c36a4.qcom,gdsc"),
+	CLK_LOOKUP("core_clk", oxili_gfx3d_clk.c, "fd8c4034.qcom,gdsc"),
+	CLK_LOOKUP("iface_clk", oxili_ahb_clk.c, "fd8c4034.qcom,gdsc"),
+	CLK_LOOKUP("mem_clk", gmem_gfx3d_clk.c, "fd8c4034.qcom,gdsc"),
 };
 
 static struct clk_lookup msm_clocks_8610_rumi[] = {
@@ -3229,8 +3251,11 @@
 	 * to remain on whenever CPUs aren't power collapsed.
 	 */
 	clk_prepare_enable(&gcc_xo_a_clk_src.c);
-
-
+	/*
+	 * Hold an active set vote for the PNOC AHB source. Sleep set vote is 0.
+	 */
+	clk_set_rate(&pnoc_keepalive_a_clk.c, 19200000);
+	clk_prepare_enable(&pnoc_keepalive_a_clk.c);
 	/* Set rates for single-rate clocks. */
 	clk_set_rate(&usb_hs_system_clk_src.c,
 			usb_hs_system_clk_src.freq_tbl[0].freq_hz);
diff --git a/arch/arm/mach-msm/clock-8974.c b/arch/arm/mach-msm/clock-8974.c
index cd6d582..654dbd3 100644
--- a/arch/arm/mach-msm/clock-8974.c
+++ b/arch/arm/mach-msm/clock-8974.c
@@ -4897,10 +4897,29 @@
 	CLK_DUMMY("core_clk", NULL, "fdc84000.qcom,iommu", oFF),
 };
 
-static struct clk_lookup msm_clocks_8974ac_only[] __initdata = {
+static struct clk_lookup msm_clocks_8974pro_only[] __initdata = {
 	CLK_LOOKUP("gpll4", gpll4_clk_src.c, ""),
 	CLK_LOOKUP("sleep_clk", gcc_sdcc1_cdccal_sleep_clk.c, "msm_sdcc.1"),
 	CLK_LOOKUP("cal_clk", gcc_sdcc1_cdccal_ff_clk.c, "msm_sdcc.1"),
+	CLK_LOOKUP("cam_src_clk", mclk0_clk_src.c, "6e.qcom,camera"),
+	CLK_LOOKUP("cam_src_clk", mclk0_clk_src.c, "20.qcom,camera"),
+	CLK_LOOKUP("cam_src_clk", mclk2_clk_src.c, "6c.qcom,camera"),
+	CLK_LOOKUP("cam_src_clk", mclk1_clk_src.c, "90.qcom,camera"),
+	CLK_LOOKUP("cam_clk", camss_mclk0_clk.c, "6e.qcom,camera"),
+	CLK_LOOKUP("cam_clk", camss_mclk0_clk.c, "20.qcom,camera"),
+	CLK_LOOKUP("cam_clk", camss_mclk2_clk.c, "6c.qcom,camera"),
+	CLK_LOOKUP("cam_clk", camss_mclk1_clk.c, "90.qcom,camera"),
+};
+
+static struct clk_lookup msm_clocks_8974_only[] __initdata = {
+	CLK_LOOKUP("cam_src_clk", mmss_gp0_clk_src.c, "6e.qcom,camera"),
+	CLK_LOOKUP("cam_src_clk", mmss_gp0_clk_src.c, "20.qcom,camera"),
+	CLK_LOOKUP("cam_src_clk", gp1_clk_src.c, "6c.qcom,camera"),
+	CLK_LOOKUP("cam_src_clk", mmss_gp1_clk_src.c, "90.qcom,camera"),
+	CLK_LOOKUP("cam_clk", camss_gp0_clk.c, "6e.qcom,camera"),
+	CLK_LOOKUP("cam_clk", camss_gp0_clk.c, "20.qcom,camera"),
+	CLK_LOOKUP("cam_clk", gcc_gp1_clk.c, "6c.qcom,camera"),
+	CLK_LOOKUP("cam_clk", camss_gp1_clk.c, "90.qcom,camera"),
 };
 
 static struct clk_lookup msm_clocks_8974_common[] __initdata = {
@@ -5076,22 +5095,16 @@
 	CLK_LOOKUP("core_clk_src", mdp_clk_src.c, "mdp.0"),
 	CLK_LOOKUP("vsync_clk", mdss_vsync_clk.c, "mdp.0"),
 
-	/* MM sensor clocks */
-	CLK_LOOKUP("cam_src_clk", mclk0_clk_src.c, "6e.qcom,camera"),
-	CLK_LOOKUP("cam_src_clk", mclk0_clk_src.c, "20.qcom,camera"),
-	CLK_LOOKUP("cam_src_clk", mclk2_clk_src.c, "6c.qcom,camera"),
-	CLK_LOOKUP("cam_src_clk", mclk1_clk_src.c, "90.qcom,camera"),
-	CLK_LOOKUP("cam_clk", camss_mclk0_clk.c, "6e.qcom,camera"),
-	CLK_LOOKUP("cam_clk", camss_mclk0_clk.c, "20.qcom,camera"),
-	CLK_LOOKUP("cam_clk", camss_mclk2_clk.c, "6c.qcom,camera"),
-	CLK_LOOKUP("cam_clk", camss_mclk1_clk.c, "90.qcom,camera"),
-	CLK_LOOKUP("cam_clk", camss_mclk1_clk.c, ""),
-	CLK_LOOKUP("cam_clk", camss_mclk2_clk.c, ""),
-	CLK_LOOKUP("cam_clk", camss_mclk3_clk.c, ""),
-	CLK_LOOKUP("cam_gp0_src_clk", mmss_gp0_clk_src.c, ""),
-	CLK_LOOKUP("cam_gp1_src_clk", mmss_gp1_clk_src.c, ""),
-	CLK_LOOKUP("cam_gp0_clk", camss_gp0_clk.c, ""),
-	CLK_LOOKUP("cam_gp1_clk", camss_gp1_clk.c, ""),
+	/* MM sensor clocks placeholder */
+	CLK_LOOKUP("", camss_mclk0_clk.c, ""),
+	CLK_LOOKUP("", camss_mclk1_clk.c, ""),
+	CLK_LOOKUP("", camss_mclk2_clk.c, ""),
+	CLK_LOOKUP("", camss_mclk3_clk.c, ""),
+	CLK_LOOKUP("", mmss_gp0_clk_src.c, ""),
+	CLK_LOOKUP("", mmss_gp1_clk_src.c, ""),
+	CLK_LOOKUP("", camss_gp0_clk.c, ""),
+	CLK_LOOKUP("", camss_gp1_clk.c, ""),
+
 	/* CCI clocks */
 	CLK_LOOKUP("camss_top_ahb_clk", camss_top_ahb_clk.c,
 		"fda0c000.qcom,cci"),
@@ -5450,7 +5463,8 @@
 };
 
 static struct clk_lookup msm_clocks_8974[ARRAY_SIZE(msm_clocks_8974_common)
-	+ ARRAY_SIZE(msm_clocks_8974ac_only)];
+	+ ARRAY_SIZE(msm_clocks_8974_only)
+	+ ARRAY_SIZE(msm_clocks_8974pro_only)];
 
 static struct pll_config_regs mmpll0_regs __initdata = {
 	.l_reg = (void __iomem *)MMPLL0_L_REG,
@@ -5797,18 +5811,26 @@
 
 	memcpy(msm_clocks_8974, msm_clocks_8974_common,
 	       sizeof(msm_clocks_8974_common));
-	msm8974_clock_init_data.size -= ARRAY_SIZE(msm_clocks_8974ac_only);
 
-	/* version specific changes */
+	/* version specific clock changes */
 	if (SOCINFO_VERSION_MAJOR(socinfo_get_version()) >= 2
 	    || cpu_is_msm8974pro())
 		msm8974_v2_clock_override();
-	if (cpu_is_msm8974pro()) {
+	if (cpu_is_msm8974pro())
 		msm8974_pro_clock_override();
+
+	/* version specific lookup table changes */
+	if (cpu_is_msm8974()) {
 		memcpy(msm_clocks_8974 + ARRAY_SIZE(msm_clocks_8974_common),
-		       msm_clocks_8974ac_only, sizeof(msm_clocks_8974ac_only));
+		       msm_clocks_8974_only, sizeof(msm_clocks_8974_only));
 		msm8974_clock_init_data.size +=
-			ARRAY_SIZE(msm_clocks_8974ac_only);
+			ARRAY_SIZE(msm_clocks_8974_only);
+	} else if (cpu_is_msm8974pro()) {
+		memcpy(msm_clocks_8974 + ARRAY_SIZE(msm_clocks_8974_common),
+		       msm_clocks_8974pro_only,
+		       sizeof(msm_clocks_8974pro_only));
+		msm8974_clock_init_data.size +=
+			ARRAY_SIZE(msm_clocks_8974pro_only);
 	}
 
 	clk_ops_pixel_clock = clk_ops_pixel;
@@ -5841,7 +5863,7 @@
 
 struct clock_init_data msm8974_clock_init_data __initdata = {
 	.table = msm_clocks_8974,
-	.size = ARRAY_SIZE(msm_clocks_8974),
+	.size = ARRAY_SIZE(msm_clocks_8974_common),
 	.pre_init = msm8974_clock_pre_init,
 	.post_init = msm8974_clock_post_init,
 };
diff --git a/arch/arm/mach-msm/clock-krait.c b/arch/arm/mach-msm/clock-krait.c
new file mode 100644
index 0000000..b96ba62
--- /dev/null
+++ b/arch/arm/mach-msm/clock-krait.c
@@ -0,0 +1,521 @@
+/*
+ * Copyright (c) 2013, The Linux Foundation. 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 and
+ * only 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/kernel.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/io.h>
+#include <linux/delay.h>
+#include <linux/err.h>
+#include <linux/errno.h>
+
+#include <linux/clk.h>
+#include <mach/clk-provider.h>
+#include <mach/clk.h>
+#include <mach/clock-generic.h>
+#include <mach/msm-krait-l2-accessors.h>
+#include "clock-krait.h"
+#include "avs.h"
+
+static DEFINE_SPINLOCK(kpss_clock_reg_lock);
+
+static void __kpss_mux_set_sel(struct mux_clk *mux, int sel)
+{
+	unsigned long flags;
+	u32 regval;
+
+	spin_lock_irqsave(&kpss_clock_reg_lock, flags);
+	regval = get_l2_indirect_reg(mux->offset);
+	regval &= ~(mux->mask << mux->shift);
+	regval |= (sel & mux->mask) << mux->shift;
+	set_l2_indirect_reg(mux->offset, regval);
+	spin_unlock_irqrestore(&kpss_clock_reg_lock, flags);
+
+	/* Wait for switch to complete. */
+	mb();
+	udelay(1);
+}
+static int kpss_mux_set_sel(struct mux_clk *mux, int sel)
+{
+	mux->en_mask = sel;
+	if (mux->c.count)
+		__kpss_mux_set_sel(mux, sel);
+	return 0;
+}
+
+static int kpss_mux_get_sel(struct mux_clk *mux)
+{
+	u32 sel;
+
+	sel = get_l2_indirect_reg(mux->offset);
+	sel >>= mux->shift;
+	sel &= mux->mask;
+	mux->en_mask = sel;
+
+	return sel;
+}
+
+static int kpss_mux_enable(struct mux_clk *mux)
+{
+	__kpss_mux_set_sel(mux, mux->en_mask);
+	return 0;
+}
+
+static void kpss_mux_disable(struct mux_clk *mux)
+{
+	__kpss_mux_set_sel(mux, mux->safe_sel);
+}
+
+struct clk_mux_ops clk_mux_ops_kpss = {
+	.enable = kpss_mux_enable,
+	.disable = kpss_mux_disable,
+	.set_mux_sel = kpss_mux_set_sel,
+	.get_mux_sel = kpss_mux_get_sel,
+};
+
+/*
+ * The divider can divide by 2, 4, 6 and 8. But we only really need div-2. So
+ * force it to div-2 during handoff and treat it like a fixed div-2 clock.
+ */
+static int kpss_div2_get_div(struct div_clk *div)
+{
+	unsigned long flags;
+	u32 regval;
+	int val;
+
+	spin_lock_irqsave(&kpss_clock_reg_lock, flags);
+	regval = get_l2_indirect_reg(div->offset);
+	val = (regval >> div->shift) && div->mask;
+	regval &= ~(div->mask << div->shift);
+	set_l2_indirect_reg(div->offset, regval);
+	spin_unlock_irqrestore(&kpss_clock_reg_lock, flags);
+
+	val = (val + 1) * 2;
+	WARN(val != 2, "Divider %s was configured to div-%d instead of 2!\n",
+		div->c.dbg_name, val);
+
+	return 2;
+}
+
+struct clk_div_ops clk_div_ops_kpss_div2 = {
+	.get_div = kpss_div2_get_div,
+};
+
+#define LOCK_BIT	BIT(16)
+
+/* Initialize a HFPLL at a given rate and enable it. */
+static void __hfpll_clk_init_once(struct clk *c)
+{
+	struct hfpll_clk *h = to_hfpll_clk(c);
+	struct hfpll_data const *hd = h->d;
+
+	if (likely(h->init_done))
+		return;
+
+	/* Configure PLL parameters for integer mode. */
+	writel_relaxed(hd->config_val, h->base + hd->config_offset);
+	writel_relaxed(0, h->base + hd->m_offset);
+	writel_relaxed(1, h->base + hd->n_offset);
+
+	if (hd->user_offset) {
+		u32 regval = hd->user_val;
+		unsigned long rate;
+
+		rate = readl_relaxed(h->base + hd->l_offset) * h->src_rate;
+
+		/* Pick the right VCO. */
+		if (rate > hd->low_vco_max_rate)
+			regval |= hd->user_vco_mask;
+		writel_relaxed(regval, h->base + hd->user_offset);
+	}
+
+	if (hd->droop_offset)
+		writel_relaxed(hd->droop_val, h->base + hd->droop_offset);
+
+	h->init_done = true;
+}
+
+/* Enable an already-configured HFPLL. */
+static int hfpll_clk_enable(struct clk *c)
+{
+	struct hfpll_clk *h = to_hfpll_clk(c);
+	struct hfpll_data const *hd = h->d;
+
+	if (!h->base)
+		return -ENODEV;
+
+	__hfpll_clk_init_once(c);
+
+	/* Disable PLL bypass mode. */
+	writel_relaxed(0x2, h->base + hd->mode_offset);
+
+	/*
+	 * H/W requires a 5us delay between disabling the bypass and
+	 * de-asserting the reset. Delay 10us just to be safe.
+	 */
+	mb();
+	udelay(10);
+
+	/* De-assert active-low PLL reset. */
+	writel_relaxed(0x6, h->base + hd->mode_offset);
+
+	/* Wait for PLL to lock. */
+	if (hd->status_offset) {
+		while (!(readl_relaxed(h->base + hd->status_offset) & LOCK_BIT))
+			;
+	} else {
+		mb();
+		udelay(60);
+	}
+
+	/* Enable PLL output. */
+	writel_relaxed(0x7, h->base + hd->mode_offset);
+
+	/* Make sure the enable is done before returning. */
+	mb();
+
+	return 0;
+}
+
+static void hfpll_clk_disable(struct clk *c)
+{
+	struct hfpll_clk *h = to_hfpll_clk(c);
+	struct hfpll_data const *hd = h->d;
+
+	/*
+	 * Disable the PLL output, disable test mode, enable the bypass mode,
+	 * and assert the reset.
+	 */
+	writel_relaxed(0, h->base + hd->mode_offset);
+}
+
+static long hfpll_clk_round_rate(struct clk *c, unsigned long rate)
+{
+	struct hfpll_clk *h = to_hfpll_clk(c);
+	struct hfpll_data const *hd = h->d;
+	unsigned long rrate;
+
+	if (!h->src_rate)
+		return 0;
+
+	rate = max(rate, hd->min_rate);
+	rate = min(rate, hd->max_rate);
+
+	rrate = DIV_ROUND_UP(rate, h->src_rate) * h->src_rate;
+	if (rrate > hd->max_rate)
+		rrate -= h->src_rate;
+
+	return rrate;
+}
+
+/*
+ * For optimization reasons, assumes no downstream clocks are actively using
+ * it.
+ */
+static int hfpll_clk_set_rate(struct clk *c, unsigned long rate)
+{
+	struct hfpll_clk *h = to_hfpll_clk(c);
+	struct hfpll_data const *hd = h->d;
+	unsigned long flags;
+	u32 l_val;
+
+	if (!h->base)
+		return -ENODEV;
+
+	if (rate != hfpll_clk_round_rate(c, rate))
+		return -EINVAL;
+
+	l_val = rate / h->src_rate;
+
+	spin_lock_irqsave(&c->lock, flags);
+
+	if (c->count)
+		hfpll_clk_disable(c);
+
+	/* Pick the right VCO. */
+	if (hd->user_offset) {
+		u32 regval;
+		regval = readl_relaxed(h->base + hd->user_offset);
+		if (rate <= hd->low_vco_max_rate)
+			regval &= ~hd->user_vco_mask;
+		else
+			regval |= hd->user_vco_mask;
+		writel_relaxed(regval, h->base  + hd->user_offset);
+	}
+
+	writel_relaxed(l_val, h->base + hd->l_offset);
+
+	if (c->count)
+		hfpll_clk_enable(c);
+
+	spin_unlock_irqrestore(&c->lock, flags);
+
+	return 0;
+}
+
+static enum handoff hfpll_clk_handoff(struct clk *c)
+{
+	struct hfpll_clk *h = to_hfpll_clk(c);
+	struct hfpll_data const *hd = h->d;
+	u32 l_val, mode;
+
+	if (!hd)
+		return HANDOFF_DISABLED_CLK;
+
+	if (!h->base)
+		return HANDOFF_DISABLED_CLK;
+
+	/* Assume parent rate doesn't change and cache it. */
+	h->src_rate = clk_get_rate(c->parent);
+	l_val = readl_relaxed(h->base + hd->l_offset);
+	c->rate = l_val * h->src_rate;
+
+	mode = readl_relaxed(h->base + hd->mode_offset) & 0x7;
+	if (mode != 0x7) {
+		__hfpll_clk_init_once(c);
+		return HANDOFF_DISABLED_CLK;
+	}
+
+	if (hd->status_offset &&
+		!(readl_relaxed(h->base + hd->status_offset) & LOCK_BIT)) {
+		WARN(1, "HFPLL %s is ON, but not locked!\n", c->dbg_name);
+		hfpll_clk_disable(c);
+		__hfpll_clk_init_once(c);
+		return HANDOFF_DISABLED_CLK;
+	}
+
+	WARN(c->rate < hd->min_rate || c->rate > hd->max_rate,
+		"HFPLL %s rate %lu outside spec!\n", c->dbg_name, c->rate);
+
+	return HANDOFF_ENABLED_CLK;
+}
+
+struct clk_ops clk_ops_hfpll = {
+	.enable = hfpll_clk_enable,
+	.disable = hfpll_clk_disable,
+	.round_rate = hfpll_clk_round_rate,
+	.set_rate = hfpll_clk_set_rate,
+	.handoff = hfpll_clk_handoff,
+};
+
+struct cpu_hwcg_action {
+	bool read;
+	bool enable;
+};
+
+static void cpu_hwcg_rw(void *info)
+{
+	struct cpu_hwcg_action *action = info;
+
+	u32 val;
+	asm volatile ("mrc p15, 7, %[cpmr0], c15, c0, 5\n\t"
+			: [cpmr0]"=r" (val));
+
+	if (action->read) {
+		action->enable = !(val & BIT(0));
+		return;
+	}
+
+	if (action->enable)
+		val &= ~BIT(0);
+	else
+		val |= BIT(0);
+
+	asm volatile ("mcr p15, 7, %[cpmr0], c15, c0, 5\n\t"
+			: : [cpmr0]"r" (val));
+}
+
+static void kpss_cpu_enable_hwcg(struct clk *c)
+{
+	struct kpss_core_clk *cpu = to_kpss_core_clk(c);
+	struct cpu_hwcg_action action = { .enable = true };
+
+	smp_call_function_single(cpu->id, cpu_hwcg_rw, &action, 1);
+}
+
+static void kpss_cpu_disable_hwcg(struct clk *c)
+{
+	struct kpss_core_clk *cpu = to_kpss_core_clk(c);
+	struct cpu_hwcg_action action = { .enable = false };
+
+	smp_call_function_single(cpu->id, cpu_hwcg_rw, &action, 1);
+}
+
+static int kpss_cpu_in_hwcg_mode(struct clk *c)
+{
+	struct kpss_core_clk *cpu = to_kpss_core_clk(c);
+	struct cpu_hwcg_action action = { .read = true };
+
+	smp_call_function_single(cpu->id, cpu_hwcg_rw, &action, 1);
+	return action.enable;
+}
+
+static enum handoff kpss_cpu_handoff(struct clk *c)
+{
+	struct kpss_core_clk *cpu = to_kpss_core_clk(c);
+
+	c->rate = clk_get_rate(c->parent);
+
+	/*
+	 * Don't unnecessarily turn on the parents for an offline CPU and
+	 * then have them turned off at late init.
+	 */
+	return (cpu_online(cpu->id) ?
+		HANDOFF_ENABLED_CLK : HANDOFF_DISABLED_CLK);
+}
+
+u32 find_dscr(struct avs_data *t, unsigned long rate)
+{
+	int i;
+
+	if (!t)
+		return 0;
+
+	for (i = 0; i < t->num; i++) {
+		if (t->rate[i] == rate)
+			return t->dscr[i];
+	}
+
+	return 0;
+}
+
+static int kpss_cpu_pre_set_rate(struct clk *c, unsigned long new_rate)
+{
+	struct kpss_core_clk *cpu = to_kpss_core_clk(c);
+	u32 dscr = find_dscr(cpu->avs_tbl, c->rate);
+
+	if (!c->prepare_count)
+		return -ENODEV;
+
+	if (dscr)
+		AVS_DISABLE(cpu->id);
+	return 0;
+}
+
+static long kpss_core_round_rate(struct clk *c, unsigned long rate)
+{
+	if (c->fmax && c->num_fmax)
+		rate = min(rate, c->fmax[c->num_fmax-1]);
+
+	return clk_round_rate(c->parent, rate);
+}
+
+static int kpss_core_set_rate(struct clk *c, unsigned long rate)
+{
+	if (!c->prepare_count)
+		return -ENODEV;
+
+	return clk_set_rate(c->parent, rate);
+}
+
+static void kpss_cpu_post_set_rate(struct clk *c, unsigned long old_rate)
+{
+	struct kpss_core_clk *cpu = to_kpss_core_clk(c);
+	u32 dscr = find_dscr(cpu->avs_tbl, c->rate);
+
+	/*
+	 * FIXME: If AVS enable/disable needs to be done in the
+	 * enable/disable op to correctly handle power collapse, then might
+	 * need to grab the spinlock here.
+	 */
+	if (dscr)
+		AVS_ENABLE(cpu->id, dscr);
+}
+
+static unsigned long kpss_core_get_rate(struct clk *c)
+{
+	return clk_get_rate(c->parent);
+}
+
+static long kpss_core_list_rate(struct clk *c, unsigned n)
+{
+	if (!c->fmax || c->num_fmax <= n)
+		return -ENXIO;
+
+	return c->fmax[n];
+}
+
+struct clk_ops clk_ops_kpss_cpu = {
+	.enable_hwcg = kpss_cpu_enable_hwcg,
+	.disable_hwcg = kpss_cpu_disable_hwcg,
+	.in_hwcg_mode = kpss_cpu_in_hwcg_mode,
+	.pre_set_rate = kpss_cpu_pre_set_rate,
+	.round_rate = kpss_core_round_rate,
+	.set_rate = kpss_core_set_rate,
+	.post_set_rate = kpss_cpu_post_set_rate,
+	.get_rate = kpss_core_get_rate,
+	.list_rate = kpss_core_list_rate,
+	.handoff = kpss_cpu_handoff,
+};
+
+#define SLPDLY_SHIFT		10
+#define SLPDLY_MASK		0x3
+static void kpss_l2_enable_hwcg(struct clk *c)
+{
+	struct kpss_core_clk *l2 = to_kpss_core_clk(c);
+	u32 regval;
+	unsigned long flags;
+
+	spin_lock_irqsave(&kpss_clock_reg_lock, flags);
+	regval = get_l2_indirect_reg(l2->cp15_iaddr);
+	regval &= ~(SLPDLY_MASK << SLPDLY_SHIFT);
+	regval |= l2->l2_slp_delay;
+	set_l2_indirect_reg(l2->cp15_iaddr, regval);
+	spin_unlock_irqrestore(&kpss_clock_reg_lock, flags);
+}
+
+static void kpss_l2_disable_hwcg(struct clk *c)
+{
+	struct kpss_core_clk *l2 = to_kpss_core_clk(c);
+	u32 regval;
+	unsigned long flags;
+
+	/*
+	 * NOTE: Should not be called when HW clock gating is already
+	 * disabled.
+	 */
+	spin_lock_irqsave(&kpss_clock_reg_lock, flags);
+	regval = get_l2_indirect_reg(l2->cp15_iaddr);
+	l2->l2_slp_delay = regval & (SLPDLY_MASK << SLPDLY_SHIFT);
+	regval |= (SLPDLY_MASK << SLPDLY_SHIFT);
+	set_l2_indirect_reg(l2->cp15_iaddr, regval);
+	spin_unlock_irqrestore(&kpss_clock_reg_lock, flags);
+}
+
+static int kpss_l2_in_hwcg_mode(struct clk *c)
+{
+	struct kpss_core_clk *l2 = to_kpss_core_clk(c);
+	u32 regval;
+
+	regval = get_l2_indirect_reg(l2->cp15_iaddr);
+	regval >>= SLPDLY_SHIFT;
+	regval &= SLPDLY_MASK;
+	return (regval != SLPDLY_MASK);
+}
+
+static enum handoff kpss_l2_handoff(struct clk *c)
+{
+	c->rate = clk_get_rate(c->parent);
+	return HANDOFF_ENABLED_CLK;
+}
+
+struct clk_ops clk_ops_kpss_l2 = {
+	.enable_hwcg = kpss_l2_enable_hwcg,
+	.disable_hwcg = kpss_l2_disable_hwcg,
+	.in_hwcg_mode = kpss_l2_in_hwcg_mode,
+	.round_rate = kpss_core_round_rate,
+	.set_rate = kpss_core_set_rate,
+	.get_rate = kpss_core_get_rate,
+	.list_rate = kpss_core_list_rate,
+	.handoff = kpss_l2_handoff,
+};
diff --git a/arch/arm/mach-msm/clock-krait.h b/arch/arm/mach-msm/clock-krait.h
new file mode 100644
index 0000000..2691a8c
--- /dev/null
+++ b/arch/arm/mach-msm/clock-krait.h
@@ -0,0 +1,99 @@
+/*
+ * Copyright (c) 2013, The Linux Foundation. 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 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#ifndef __ARCH_ARM_MACH_MSM_CLOCK_KRAIT_H
+#define __ARCH_ARM_MACH_MSM_CLOCK_KRAIT_H
+
+#include <mach/clk-provider.h>
+#include <mach/clock-generic.h>
+
+extern struct clk_mux_ops clk_mux_ops_kpss;
+extern struct clk_div_ops clk_div_ops_kpss_div2;
+
+#define DEFINE_KPSS_DIV2_CLK(clk_name, _parent, _offset) \
+static struct div_clk clk_name = {		\
+	.div = 2,				\
+	.min_div = 2,				\
+	.max_div = 2,				\
+	.ops = &clk_div_ops_kpss_div2,		\
+	.offset = _offset,			\
+	.mask = 0x3,				\
+	.shift = 6,				\
+	.c = {					\
+		.parent = _parent,		\
+		.dbg_name = #clk_name,		\
+		.ops = &clk_ops_div,		\
+		.flags = CLKFLAG_NO_RATE_CACHE,	\
+		CLK_INIT(clk_name.c),		\
+	}					\
+}
+
+struct hfpll_data {
+	const u32 mode_offset;
+	const u32 l_offset;
+	const u32 m_offset;
+	const u32 n_offset;
+	const u32 user_offset;
+	const u32 droop_offset;
+	const u32 config_offset;
+	const u32 status_offset;
+
+	const u32 droop_val;
+	const u32 config_val;
+	const u32 user_val;
+	const u32 user_vco_mask;
+	unsigned long low_vco_max_rate;
+
+	unsigned long min_rate;
+	unsigned long max_rate;
+};
+
+struct hfpll_clk {
+	void  * __iomem base;
+	struct hfpll_data const *d;
+	unsigned long	src_rate;
+	int		init_done;
+
+	struct clk	c;
+};
+
+static inline struct hfpll_clk *to_hfpll_clk(struct clk *c)
+{
+	return container_of(c, struct hfpll_clk, c);
+}
+
+extern struct clk_ops clk_ops_hfpll;
+
+struct avs_data {
+	unsigned long	*rate;
+	u32		*dscr;
+	int		num;
+};
+
+struct kpss_core_clk {
+	int		id;
+	u32		cp15_iaddr;
+	u32		l2_slp_delay;
+	struct avs_data	*avs_tbl;
+	struct clk	c;
+};
+
+static inline struct kpss_core_clk *to_kpss_core_clk(struct clk *c)
+{
+	return container_of(c, struct kpss_core_clk, c);
+}
+
+extern struct clk_ops clk_ops_kpss_cpu;
+extern struct clk_ops clk_ops_kpss_l2;
+
+#endif
diff --git a/arch/arm/mach-msm/clock-krypton.c b/arch/arm/mach-msm/clock-krypton.c
index 0b615cc..176dc32 100644
--- a/arch/arm/mach-msm/clock-krypton.c
+++ b/arch/arm/mach-msm/clock-krypton.c
@@ -18,12 +18,12 @@
 #include <linux/spinlock.h>
 #include <linux/delay.h>
 #include <linux/clk.h>
-#include <linux/iopoll.h>
 #include <linux/regulator/consumer.h>
+#include <linux/iopoll.h>
 
+#include <mach/clk.h>
 #include <mach/rpm-regulator-smd.h>
 #include <mach/socinfo.h>
-#include <mach/rpm-smd.h>
 
 #include "clock-local2.h"
 #include "clock-pll.h"
@@ -31,97 +31,2051 @@
 #include "clock-voter.h"
 #include "clock.h"
 
-static struct clk_lookup msm_clocks_dummy[] = {
-	CLK_DUMMY("core_clk",   BLSP1_UART_CLK, "f991f000.serial", OFF),
-	CLK_DUMMY("iface_clk",  BLSP1_UART_CLK, "f991f000.serial", OFF),
-	CLK_DUMMY("core_clk",	SPI_CLK,	"f9928000.spi",  OFF),
-	CLK_DUMMY("iface_clk",	SPI_P_CLK,	"f9928000.spi",  OFF),
-
-	CLK_DUMMY("bus_clk", cnoc_msmbus_clk.c, "msm_config_noc", OFF),
-	CLK_DUMMY("bus_a_clk", cnoc_msmbus_a_clk.c, "msm_config_noc", OFF),
-	CLK_DUMMY("bus_clk", snoc_msmbus_clk.c, "msm_sys_noc", OFF),
-	CLK_DUMMY("bus_a_clk", snoc_msmbus_a_clk.c, "msm_sys_noc", OFF),
-	CLK_DUMMY("bus_clk", pnoc_msmbus_clk.c, "msm_periph_noc", OFF),
-	CLK_DUMMY("bus_a_clk", pnoc_msmbus_a_clk.c, "msm_periph_noc", OFF),
-	CLK_DUMMY("mem_clk", bimc_msmbus_clk.c, "msm_bimc", OFF),
-	CLK_DUMMY("mem_a_clk", bimc_msmbus_a_clk.c, "msm_bimc", OFF),
-	CLK_DUMMY("mem_clk", bimc_acpu_a_clk.c, "", OFF),
-	CLK_DUMMY("dfab_clk",	DFAB_CLK,	"msm_sps", OFF),
-	CLK_DUMMY("dma_bam_pclk",	DMA_BAM_P_CLK,	"msm_sps", OFF),
-
-	CLK_DUMMY("clktype", gcc_imem_axi_clk         , "drivername", OFF),
-	CLK_DUMMY("clktype", gcc_imem_cfg_ahb_clk     , "drivername", OFF),
-	CLK_DUMMY("clktype", gcc_mss_cfg_ahb_clk      , "drivername", OFF),
-	CLK_DUMMY("clktype", gcc_mss_q6_bimc_axi_clk  , "drivername", OFF),
-	CLK_DUMMY("mem_clk", gcc_usb30_master_clk     , "drivername", OFF),
-	CLK_DUMMY("sleep_clk", gcc_usb30_sleep_clk    , "drivername", OFF),
-	CLK_DUMMY("utmi_clk", gcc_usb30_mock_utmi_clk , "drivername", OFF),
-	CLK_DUMMY("iface_clk", gcc_usb_hsic_ahb_clk   , "drivername", OFF),
-	CLK_DUMMY("core_clk", gcc_usb_hsic_system_clk , "drivername", OFF),
-	CLK_DUMMY("phyclk", gcc_usb_hsic_clk         , "drivername", OFF),
-	CLK_DUMMY("cal_clk", gcc_usb_hsic_io_cal_clk  , "drivername", OFF),
-	CLK_DUMMY("core_clk", gcc_usb_hs_system_clk   , "drivername", OFF),
-	CLK_DUMMY("iface_clk", gcc_usb_hs_ahb_clk     , "drivername", OFF),
-	CLK_DUMMY("sleep_a_clk", gcc_usb2a_phy_sleep_clk  , "drivername", OFF),
-	CLK_DUMMY("sleep_b_clk", gcc_usb2b_phy_sleep_clk  , "drivername", OFF),
-	CLK_DUMMY("core_clk", gcc_sdcc2_apps_clk      , "drivername", OFF),
-	CLK_DUMMY("iface_clk", gcc_sdcc2_ahb_clk      , "drivername", OFF),
-	CLK_DUMMY("core_clk", gcc_sdcc3_apps_clk      , "drivername", OFF),
-	CLK_DUMMY("iface_clk", gcc_sdcc3_ahb_clk      , "drivername", OFF),
-	CLK_DUMMY("core_clk", sdcc3_apps_clk_src      , "drivername", OFF),
-	CLK_DUMMY("iface_clk", gcc_blsp1_ahb_clk      , "drivername", OFF),
-	CLK_DUMMY("core_clk", gcc_blsp1_qup1_spi_apps_clk, "drivername", OFF),
-	CLK_DUMMY("core_clk", gcc_blsp1_qup1_i2c_apps_clk, "drivername", OFF),
-	CLK_DUMMY("core_clk", gcc_blsp1_uart1_apps_clk , "drivername", OFF),
-	CLK_DUMMY("core_clk", gcc_blsp1_qup2_spi_apps_clk, "drivername", OFF),
-	CLK_DUMMY("core_clk", gcc_blsp1_qup2_i2c_apps_clk, "drivername", OFF),
-	CLK_DUMMY("core_clk", gcc_blsp1_uart2_apps_clk , "drivername", OFF),
-	CLK_DUMMY("core_clk", gcc_blsp1_qup3_spi_apps_clk, "drivername", OFF),
-	CLK_DUMMY("core_clk", gcc_blsp1_qup3_i2c_apps_clk, "drivername", OFF),
-	CLK_DUMMY("core_clk", gcc_blsp1_uart3_apps_clk , "drivername", OFF),
-	CLK_DUMMY("core_clk", gcc_blsp1_qup4_spi_apps_clk, "drivername", OFF),
-	CLK_DUMMY("core_clk", gcc_blsp1_qup4_i2c_apps_clk, "drivername", OFF),
-	CLK_DUMMY("core_clk", gcc_blsp1_uart4_apps_clk , "drivername", OFF),
-	CLK_DUMMY("core_clk", gcc_blsp1_qup5_spi_apps_clk, "drivername", OFF),
-	CLK_DUMMY("core_clk", gcc_blsp1_qup5_i2c_apps_clk, "drivername", OFF),
-	CLK_DUMMY("core_clk", gcc_blsp1_uart5_apps_clk , "drivername", OFF),
-	CLK_DUMMY("core_clk", gcc_blsp1_qup6_spi_apps_clk, "drivername", OFF),
-	CLK_DUMMY("core_clk", gcc_blsp1_qup6_i2c_apps_clk, "drivername", OFF),
-	CLK_DUMMY("core_clk", gcc_blsp1_uart6_apps_clk , "drivername", OFF),
-	CLK_DUMMY("core_clk", blsp1_uart6_apps_clk_src , "drivername", OFF),
-	CLK_DUMMY("iface_clk", gcc_pdm_ahb_clk        , "drivername", OFF),
-	CLK_DUMMY("core_clk", gcc_pdm2_clk            , "drivername", OFF),
-	CLK_DUMMY("core_clk", gcc_prng_ahb_clk        , "drivername", OFF),
-	CLK_DUMMY("dma_bam_pclk", gcc_bam_dma_ahb_clk , "drivername", OFF),
-	CLK_DUMMY("mem_clk", gcc_boot_rom_ahb_clk     , "drivername", OFF),
-	CLK_DUMMY("core_clk", gcc_ce1_clk             , "drivername", OFF),
-	CLK_DUMMY("core_clk", gcc_ce1_axi_clk         , "drivername", OFF),
-	CLK_DUMMY("core_clk", gcc_ce1_ahb_clk         , "drivername", OFF),
-	CLK_DUMMY("core_clk_src", ce1_clk_src         , "drivername", OFF),
-	CLK_DUMMY("bus_clk", gcc_lpass_q6_axi_clk     , "drivername", OFF),
-	CLK_DUMMY("clktype", pcie_pipe_clk            , "drivername", OFF),
-	CLK_DUMMY("clktype", gcc_gp1_clk              , "drivername", OFF),
-	CLK_DUMMY("clktype", gp1_clk_src              , "drivername", OFF),
-	CLK_DUMMY("clktype", gcc_gp2_clk              , "drivername", OFF),
-	CLK_DUMMY("clktype", gp2_clk_src              , "drivername", OFF),
-	CLK_DUMMY("clktype", gcc_gp3_clk              , "drivername", OFF),
-	CLK_DUMMY("clktype", gp3_clk_src              , "drivername", OFF),
-	CLK_DUMMY("core_clk", gcc_ipa_clk             , "drivername", OFF),
-	CLK_DUMMY("iface_clk", gcc_ipa_cnoc_clk       , "drivername", OFF),
-	CLK_DUMMY("inactivity_clk", gcc_ipa_sleep_clk , "drivername", OFF),
-	CLK_DUMMY("core_clk_src", ipa_clk_src         , "drivername", OFF),
-	CLK_DUMMY("clktype", gcc_dcs_clk              , "drivername", OFF),
-	CLK_DUMMY("clktype", dcs_clk_src              , "drivername", OFF),
-	CLK_DUMMY("clktype", gcc_pcie_cfg_ahb_clk     , "drivername", OFF),
-	CLK_DUMMY("clktype", gcc_pcie_pipe_clk        , "drivername", OFF),
-	CLK_DUMMY("clktype", gcc_pcie_axi_clk         , "drivername", OFF),
-	CLK_DUMMY("clktype", gcc_pcie_sleep_clk       , "drivername", OFF),
-	CLK_DUMMY("clktype", gcc_pcie_axi_mstr_clk    , "drivername", OFF),
-	CLK_DUMMY("clktype", pcie_pipe_clk_src        , "drivername", OFF),
-	CLK_DUMMY("clktype", pcie_aux_clk_src         , "drivername", OFF),
+enum {
+	GCC_BASE,
+	LPASS_BASE,
+	APCS_GLB_BASE,
+	APCS_GCC_BASE,
+	APCS_ACC_BASE,
+	N_BASES,
 };
 
+static void __iomem *virt_bases[N_BASES];
+
+#define GCC_REG_BASE(x) (void __iomem *)(virt_bases[GCC_BASE] + (x))
+#define APCS_GCC_BASE(x) (void __iomem *)(virt_bases[APCS_GCC_BASE] + (x))
+
+/* Mux source select values */
+#define xo_source_val	0
+#define gpll0_source_val 1
+#define gpll1_source_val 4
+#define gnd_source_val	5
+
+#define usb3_pipe_clk_source_val	2
+#define pcie_pipe_clk_source_val	2
+
+/* Prevent a divider of -1 */
+#define FIXDIV(div) (div ? (2 * (div) - 1) : (0))
+
+#define F(f, s, div, m, n) \
+	{ \
+		.freq_hz = (f), \
+		.src_clk = &s.c, \
+		.m_val = (m), \
+		.n_val = ~((n)-(m)) * !!(n), \
+		.d_val = ~(n),\
+		.div_src_val = BVAL(4, 0, (int)(FIXDIV(div))) \
+			| BVAL(10, 8, s##_source_val), \
+	}
+
+#define F_EXT_SRC(f, s, div, m, n) \
+	{ \
+		.freq_hz = (f), \
+		.m_val = (m), \
+		.n_val = ~((n)-(m)) * !!(n), \
+		.d_val = ~(n),\
+		.div_src_val = BVAL(4, 0, (int)(FIXDIV(div))) \
+			| BVAL(10, 8, s##_source_val), \
+	}
+
+#define VDD_DIG_FMAX_MAP1(l1, f1) \
+	.vdd_class = &vdd_dig,			\
+	.fmax = (unsigned long[VDD_DIG_NUM]) {	\
+		[VDD_DIG_##l1] = (f1),		\
+	},					\
+	.num_fmax = VDD_DIG_NUM
+#define VDD_DIG_FMAX_MAP2(l1, f1, l2, f2) \
+	.vdd_class = &vdd_dig,			\
+	.fmax = (unsigned long[VDD_DIG_NUM]) {	\
+		[VDD_DIG_##l1] = (f1),		\
+		[VDD_DIG_##l2] = (f2),		\
+	},					\
+	.num_fmax = VDD_DIG_NUM
+#define VDD_DIG_FMAX_MAP3(l1, f1, l2, f2, l3, f3) \
+	.vdd_class = &vdd_dig,			\
+	.fmax = (unsigned long[VDD_DIG_NUM]) {	\
+		[VDD_DIG_##l1] = (f1),		\
+		[VDD_DIG_##l2] = (f2),		\
+		[VDD_DIG_##l3] = (f3),		\
+	},					\
+	.num_fmax = VDD_DIG_NUM
+
+enum vdd_dig_levels {
+	VDD_DIG_NONE,
+	VDD_DIG_LOW,
+	VDD_DIG_NOMINAL,
+	VDD_DIG_HIGH,
+	VDD_DIG_NUM
+};
+
+static int vdd_corner[] = {
+	RPM_REGULATOR_CORNER_NONE,		/* VDD_DIG_NONE */
+	RPM_REGULATOR_CORNER_SVS_SOC,		/* VDD_DIG_LOW */
+	RPM_REGULATOR_CORNER_NORMAL,		/* VDD_DIG_NOMINAL */
+	RPM_REGULATOR_CORNER_SUPER_TURBO,	/* VDD_DIG_HIGH */
+};
+
+static DEFINE_VDD_REGULATORS(vdd_dig, VDD_DIG_NUM, 1, vdd_corner, NULL);
+
+#define RPM_MISC_CLK_TYPE	0x306b6c63
+#define RPM_BUS_CLK_TYPE	0x316b6c63
+#define RPM_MEM_CLK_TYPE	0x326b6c63
+#define RPM_QPIC_CLK_TYPE	0x63697071
+
+#define RPM_SMD_KEY_ENABLE	0x62616E45
+
+#define CXO_ID			0x0
+#define QDSS_ID			0x1
+
+#define PNOC_ID		0x0
+#define SNOC_ID		0x1
+#define CNOC_ID		0x2
+
+#define BIMC_ID		0x0
+#define QPIC_ID		0x0
+
+#define D0_ID		 1
+#define D1_ID		 2
+#define A0_ID		 3
+#define A1_ID		 4
+#define A2_ID		 5
+
+#define APCS_CLK_DIAG                                      (0x001C)
+#define GPLL0_MODE                                         (0x0000)
+#define GPLL1_MODE                                         (0x0040)
+#define SYS_NOC_USB3_AXI_CBCR                              (0x0108)
+#define MSS_CFG_AHB_CBCR                                   (0x0280)
+#define MSS_Q6_BIMC_AXI_CBCR                               (0x0284)
+#define USB_30_BCR                                         (0x03C0)
+#define USB30_MASTER_CBCR                                  (0x03C8)
+#define USB30_SLEEP_CBCR                                   (0x03CC)
+#define USB30_MOCK_UTMI_CBCR                               (0x03D0)
+#define USB30_MASTER_CMD_RCGR                              (0x03D4)
+#define USB30_MOCK_UTMI_CMD_RCGR                           (0x03E8)
+#define USB3_PIPE_CBCR                                     (0x1B90)
+#define USB3_AUX_CBCR                                      (0x1B94)
+#define USB3_PIPE_CMD_RCGR                                 (0x1B98)
+#define USB3_AUX_CMD_RCGR                                  (0x1BC0)
+#define USB_HS_HSIC_BCR                                    (0x0400)
+#define USB_HSIC_AHB_CBCR                                  (0x0408)
+#define USB_HSIC_SYSTEM_CMD_RCGR                           (0x041C)
+#define USB_HSIC_SYSTEM_CBCR                               (0x040C)
+#define USB_HSIC_CMD_RCGR                                  (0x0440)
+#define USB_HSIC_CBCR                                      (0x0410)
+#define USB_HSIC_IO_CAL_CMD_RCGR                           (0x0458)
+#define USB_HSIC_IO_CAL_CBCR                               (0x0414)
+#define USB_HSIC_IO_CAL_SLEEP_CBCR                         (0x0418)
+#define USB_HSIC_XCVR_FS_CMD_RCGR                          (0x0424)
+#define USB_HSIC_XCVR_FS_CBCR                              (0x042C)
+#define USB_HS_BCR                                         (0x0480)
+#define USB_HS_SYSTEM_CBCR                                 (0x0484)
+#define USB_HS_AHB_CBCR                                    (0x0488)
+#define USB_HS_SYSTEM_CMD_RCGR                             (0x0490)
+#define SDCC2_APPS_CMD_RCGR                                (0x0510)
+#define SDCC2_APPS_CBCR                                    (0x0504)
+#define SDCC2_AHB_CBCR                                     (0x0508)
+#define SDCC3_APPS_CMD_RCGR                                (0x0550)
+#define SDCC3_APPS_CBCR                                    (0x0544)
+#define SDCC3_AHB_CBCR                                     (0x0548)
+#define BLSP1_AHB_CBCR                                     (0x05C4)
+#define BLSP1_QUP1_SPI_APPS_CBCR                           (0x0644)
+#define BLSP1_QUP1_I2C_APPS_CBCR                           (0x0648)
+#define BLSP1_QUP1_I2C_APPS_CMD_RCGR                       (0x0660)
+#define BLSP1_QUP2_I2C_APPS_CMD_RCGR                       (0x06E0)
+#define BLSP1_QUP3_I2C_APPS_CMD_RCGR                       (0x0760)
+#define BLSP1_QUP4_I2C_APPS_CMD_RCGR                       (0x07E0)
+#define BLSP1_QUP5_I2C_APPS_CMD_RCGR                       (0x0860)
+#define BLSP1_QUP6_I2C_APPS_CMD_RCGR                       (0x08E0)
+#define BLSP1_QUP1_SPI_APPS_CMD_RCGR                       (0x064C)
+#define BLSP1_UART1_APPS_CBCR                              (0x0684)
+#define BLSP1_UART1_APPS_CMD_RCGR                          (0x068C)
+#define BLSP1_QUP2_SPI_APPS_CBCR                           (0x06C4)
+#define BLSP1_QUP2_I2C_APPS_CBCR                           (0x06C8)
+#define BLSP1_QUP2_SPI_APPS_CMD_RCGR                       (0x06CC)
+#define BLSP1_UART2_APPS_CBCR                              (0x0704)
+#define BLSP1_UART2_APPS_CMD_RCGR                          (0x070C)
+#define BLSP1_QUP3_SPI_APPS_CBCR                           (0x0744)
+#define BLSP1_QUP3_I2C_APPS_CBCR                           (0x0748)
+#define BLSP1_QUP3_SPI_APPS_CMD_RCGR                       (0x074C)
+#define BLSP1_UART3_APPS_CBCR                              (0x0784)
+#define BLSP1_UART3_APPS_CMD_RCGR                          (0x078C)
+#define BLSP1_QUP4_SPI_APPS_CBCR                           (0x07C4)
+#define BLSP1_QUP4_I2C_APPS_CBCR                           (0x07C8)
+#define BLSP1_QUP4_SPI_APPS_CMD_RCGR                       (0x07CC)
+#define BLSP1_UART4_APPS_CBCR                              (0x0804)
+#define BLSP1_UART4_APPS_CMD_RCGR                          (0x080C)
+#define BLSP1_QUP5_SPI_APPS_CBCR                           (0x0844)
+#define BLSP1_QUP5_I2C_APPS_CBCR                           (0x0848)
+#define BLSP1_QUP5_SPI_APPS_CMD_RCGR                       (0x084C)
+#define BLSP1_UART5_APPS_CBCR                              (0x0884)
+#define BLSP1_UART5_APPS_CMD_RCGR                          (0x088C)
+#define BLSP1_QUP6_SPI_APPS_CBCR                           (0x08C4)
+#define BLSP1_QUP6_I2C_APPS_CBCR                           (0x08C8)
+#define BLSP1_QUP6_SPI_APPS_CMD_RCGR                       (0x08CC)
+#define BLSP1_UART6_APPS_CBCR                              (0x0904)
+#define BLSP1_UART6_APPS_CMD_RCGR                          (0x090C)
+#define PDM_AHB_CBCR                                       (0x0CC4)
+#define PDM2_CBCR                                          (0x0CCC)
+#define PDM2_CMD_RCGR                                      (0x0CD0)
+#define PRNG_AHB_CBCR                                      (0x0D04)
+#define BAM_DMA_AHB_CBCR                                   (0x0D44)
+#define BAM_DMA_INACTIVITY_TIMERS_CBCR                     (0x0D48)
+#define BOOT_ROM_AHB_CBCR                                  (0x0E04)
+#define RPM_MISC                                           (0x0F24)
+#define CE1_CMD_RCGR                                       (0x1050)
+#define CE1_CBCR                                           (0x1044)
+#define CE1_AXI_CBCR                                       (0x1048)
+#define CE1_AHB_CBCR                                       (0x104C)
+#define GCC_XO_DIV4_CBCR                                   (0x10C8)
+#define LPASS_Q6_AXI_CBCR                                  (0x11C0)
+#define APCS_GPLL_ENA_VOTE                                 (0x1480)
+#define APCS_CLOCK_BRANCH_ENA_VOTE                         (0x1484)
+#define GCC_DEBUG_CLK_CTL                                  (0x1880)
+#define CLOCK_FRQ_MEASURE_CTL                              (0x1884)
+#define CLOCK_FRQ_MEASURE_STATUS                           (0x1888)
+#define PLLTEST_PAD_CFG                                    (0x188C)
+#define PCIE_CFG_AHB_CBCR                                  (0x1C04)
+#define PCIE_PIPE_CBCR                                     (0x1C08)
+#define PCIE_AXI_CBCR                                      (0x1C0C)
+#define PCIE_SLEEP_CBCR                                    (0x1C10)
+#define PCIE_AXI_MSTR_CBCR                                 (0x1C2C)
+#define PCIE_PIPE_CMD_RCGR                                 (0x1C14)
+#define PCIE_AUX_CMD_RCGR                                  (0x1E00)
+#define Q6SS_AHB_LFABIF_CBCR                               (0x22000)
+#define Q6SS_AHBM_CBCR                                     (0x22004)
+
+DEFINE_CLK_RPM_SMD_BRANCH(xo, xo_a_clk, RPM_MISC_CLK_TYPE, CXO_ID, 19200000);
+
+static unsigned int soft_vote_gpll0;
+
+static struct pll_vote_clk gpll0 = {
+	.en_reg = (void __iomem *)APCS_GPLL_ENA_VOTE,
+	.en_mask = BIT(0),
+	.status_reg = (void __iomem *)GPLL0_MODE,
+	.status_mask = BIT(31),
+	.soft_vote = &soft_vote_gpll0,
+	.soft_vote_mask = PLL_SOFT_VOTE_PRIMARY,
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.rate = 600000000,
+		.parent = &xo.c,
+		.dbg_name = "gpll0",
+		.ops = &clk_ops_pll_acpu_vote,
+		CLK_INIT(gpll0.c),
+	},
+};
+
+/* Don't vote for xo if using this clock to allow xo shutdown */
+static struct pll_vote_clk gpll0_ao = {
+	.en_reg = (void __iomem *)APCS_GPLL_ENA_VOTE,
+	.en_mask = BIT(0),
+	.status_reg = (void __iomem *)GPLL0_MODE,
+	.status_mask = BIT(31),
+	.soft_vote = &soft_vote_gpll0,
+	.soft_vote_mask = PLL_SOFT_VOTE_ACPU,
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.rate = 600000000,
+		.dbg_name = "gpll0_ao",
+		.ops = &clk_ops_pll_acpu_vote,
+		CLK_INIT(gpll0_ao.c),
+	},
+};
+
+static struct pll_vote_clk gpll1 = {
+	.en_reg = (void __iomem *)APCS_GPLL_ENA_VOTE,
+	.en_mask = BIT(1),
+	.status_reg = (void __iomem *)GPLL1_MODE,
+	.status_mask = BIT(31),
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.rate = 480000000,
+		.parent = &xo.c,
+		.dbg_name = "gpll1",
+		.ops = &clk_ops_pll_vote,
+		CLK_INIT(gpll1.c),
+	},
+};
+
+static struct clk_freq_tbl ftbl_gcc_usb30_master_clk[] = {
+	F( 125000000,      gpll0,    1,    5,    24),
+	F_END
+};
+
+static struct rcg_clk usb30_master_clk_src = {
+	.cmd_rcgr_reg = USB30_MASTER_CMD_RCGR,
+	.set_rate = set_rate_mnd,
+	.freq_tbl = ftbl_gcc_usb30_master_clk,
+	.current_freq = &rcg_dummy_freq,
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "usb30_master_clk_src",
+		.ops = &clk_ops_rcg_mnd,
+		VDD_DIG_FMAX_MAP1(LOW, 125000000),
+		CLK_INIT(usb30_master_clk_src.c),
+	},
+};
+
+static struct clk_freq_tbl ftbl_gcc_blsp1_qup1_6_i2c_apps_clk[] = {
+	F(  19200000,         xo,    1,    0,     0),
+	F_END
+};
+
+static struct rcg_clk blsp1_qup1_i2c_apps_clk_src = {
+	.cmd_rcgr_reg = BLSP1_QUP1_I2C_APPS_CMD_RCGR,
+	.set_rate = set_rate_hid,
+	.freq_tbl = ftbl_gcc_blsp1_qup1_6_i2c_apps_clk,
+	.current_freq = &rcg_dummy_freq,
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "blsp1_qup1_i2c_apps_clk_src",
+		.ops = &clk_ops_rcg,
+		VDD_DIG_FMAX_MAP1(LOW, 19200000),
+		CLK_INIT(blsp1_qup1_i2c_apps_clk_src.c),
+	},
+};
+
+static struct clk_freq_tbl ftbl_gcc_blsp1_qup1_6_spi_apps_clk[] = {
+	F(    960000,         xo,   10,    1,     2),
+	F(   4800000,         xo,    4,    0,     0),
+	F(   9600000,         xo,    2,    0,     0),
+	F(  15000000,      gpll0,   10,    1,     4),
+	F(  19200000,         xo,    1,    0,     0),
+	F(  25000000,      gpll0,   12,    1,     2),
+	F(  50000000,      gpll0,   12,    0,     0),
+	F_END
+};
+
+static struct rcg_clk blsp1_qup1_spi_apps_clk_src = {
+	.cmd_rcgr_reg = BLSP1_QUP1_SPI_APPS_CMD_RCGR,
+	.set_rate = set_rate_mnd,
+	.freq_tbl = ftbl_gcc_blsp1_qup1_6_spi_apps_clk,
+	.current_freq = &rcg_dummy_freq,
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "blsp1_qup1_spi_apps_clk_src",
+		.ops = &clk_ops_rcg_mnd,
+		VDD_DIG_FMAX_MAP2(LOW, 25000000, NOMINAL, 50000000),
+		CLK_INIT(blsp1_qup1_spi_apps_clk_src.c),
+	},
+};
+
+static struct rcg_clk blsp1_qup2_i2c_apps_clk_src = {
+	.cmd_rcgr_reg = BLSP1_QUP2_I2C_APPS_CMD_RCGR,
+	.set_rate = set_rate_hid,
+	.freq_tbl = ftbl_gcc_blsp1_qup1_6_i2c_apps_clk,
+	.current_freq = &rcg_dummy_freq,
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "blsp1_qup2_i2c_apps_clk_src",
+		.ops = &clk_ops_rcg,
+		VDD_DIG_FMAX_MAP1(LOW, 19200000),
+		CLK_INIT(blsp1_qup2_i2c_apps_clk_src.c),
+	},
+};
+
+static struct rcg_clk blsp1_qup2_spi_apps_clk_src = {
+	.cmd_rcgr_reg = BLSP1_QUP2_SPI_APPS_CMD_RCGR,
+	.set_rate = set_rate_mnd,
+	.freq_tbl = ftbl_gcc_blsp1_qup1_6_spi_apps_clk,
+	.current_freq = &rcg_dummy_freq,
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "blsp1_qup2_spi_apps_clk_src",
+		.ops = &clk_ops_rcg_mnd,
+		VDD_DIG_FMAX_MAP2(LOW, 25000000, NOMINAL, 50000000),
+		CLK_INIT(blsp1_qup2_spi_apps_clk_src.c),
+	},
+};
+
+static struct rcg_clk blsp1_qup3_i2c_apps_clk_src = {
+	.cmd_rcgr_reg = BLSP1_QUP3_I2C_APPS_CMD_RCGR,
+	.set_rate = set_rate_hid,
+	.freq_tbl = ftbl_gcc_blsp1_qup1_6_i2c_apps_clk,
+	.current_freq = &rcg_dummy_freq,
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "blsp1_qup3_i2c_apps_clk_src",
+		.ops = &clk_ops_rcg,
+		VDD_DIG_FMAX_MAP1(LOW, 19200000),
+		CLK_INIT(blsp1_qup3_i2c_apps_clk_src.c),
+	},
+};
+
+static struct rcg_clk blsp1_qup3_spi_apps_clk_src = {
+	.cmd_rcgr_reg = BLSP1_QUP3_SPI_APPS_CMD_RCGR,
+	.set_rate = set_rate_mnd,
+	.freq_tbl = ftbl_gcc_blsp1_qup1_6_spi_apps_clk,
+	.current_freq = &rcg_dummy_freq,
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "blsp1_qup3_spi_apps_clk_src",
+		.ops = &clk_ops_rcg_mnd,
+		VDD_DIG_FMAX_MAP2(LOW, 25000000, NOMINAL, 50000000),
+		CLK_INIT(blsp1_qup3_spi_apps_clk_src.c),
+	},
+};
+
+static struct rcg_clk blsp1_qup4_i2c_apps_clk_src = {
+	.cmd_rcgr_reg = BLSP1_QUP4_I2C_APPS_CMD_RCGR,
+	.set_rate = set_rate_hid,
+	.freq_tbl = ftbl_gcc_blsp1_qup1_6_i2c_apps_clk,
+	.current_freq = &rcg_dummy_freq,
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "blsp1_qup4_i2c_apps_clk_src",
+		.ops = &clk_ops_rcg,
+		VDD_DIG_FMAX_MAP1(LOW, 19200000),
+		CLK_INIT(blsp1_qup4_i2c_apps_clk_src.c),
+	},
+};
+
+static struct rcg_clk blsp1_qup4_spi_apps_clk_src = {
+	.cmd_rcgr_reg = BLSP1_QUP4_SPI_APPS_CMD_RCGR,
+	.set_rate = set_rate_mnd,
+	.freq_tbl = ftbl_gcc_blsp1_qup1_6_spi_apps_clk,
+	.current_freq = &rcg_dummy_freq,
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "blsp1_qup4_spi_apps_clk_src",
+		.ops = &clk_ops_rcg_mnd,
+		VDD_DIG_FMAX_MAP2(LOW, 25000000, NOMINAL, 50000000),
+		CLK_INIT(blsp1_qup4_spi_apps_clk_src.c),
+	},
+};
+
+static struct rcg_clk blsp1_qup5_i2c_apps_clk_src = {
+	.cmd_rcgr_reg = BLSP1_QUP5_I2C_APPS_CMD_RCGR,
+	.set_rate = set_rate_hid,
+	.freq_tbl = ftbl_gcc_blsp1_qup1_6_i2c_apps_clk,
+	.current_freq = &rcg_dummy_freq,
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "blsp1_qup5_i2c_apps_clk_src",
+		.ops = &clk_ops_rcg,
+		VDD_DIG_FMAX_MAP1(LOW, 19200000),
+		CLK_INIT(blsp1_qup5_i2c_apps_clk_src.c),
+	},
+};
+
+static struct rcg_clk blsp1_qup5_spi_apps_clk_src = {
+	.cmd_rcgr_reg = BLSP1_QUP5_SPI_APPS_CMD_RCGR,
+	.set_rate = set_rate_mnd,
+	.freq_tbl = ftbl_gcc_blsp1_qup1_6_spi_apps_clk,
+	.current_freq = &rcg_dummy_freq,
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "blsp1_qup5_spi_apps_clk_src",
+		.ops = &clk_ops_rcg_mnd,
+		VDD_DIG_FMAX_MAP2(LOW, 25000000, NOMINAL, 50000000),
+		CLK_INIT(blsp1_qup5_spi_apps_clk_src.c),
+	},
+};
+
+static struct rcg_clk blsp1_qup6_i2c_apps_clk_src = {
+	.cmd_rcgr_reg = BLSP1_QUP6_I2C_APPS_CMD_RCGR,
+	.set_rate = set_rate_hid,
+	.freq_tbl = ftbl_gcc_blsp1_qup1_6_i2c_apps_clk,
+	.current_freq = &rcg_dummy_freq,
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "blsp1_qup6_i2c_apps_clk_src",
+		.ops = &clk_ops_rcg,
+		VDD_DIG_FMAX_MAP1(LOW, 19200000),
+		CLK_INIT(blsp1_qup6_i2c_apps_clk_src.c),
+	},
+};
+
+static struct rcg_clk blsp1_qup6_spi_apps_clk_src = {
+	.cmd_rcgr_reg = BLSP1_QUP6_SPI_APPS_CMD_RCGR,
+	.set_rate = set_rate_mnd,
+	.freq_tbl = ftbl_gcc_blsp1_qup1_6_spi_apps_clk,
+	.current_freq = &rcg_dummy_freq,
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "blsp1_qup6_spi_apps_clk_src",
+		.ops = &clk_ops_rcg_mnd,
+		VDD_DIG_FMAX_MAP2(LOW, 25000000, NOMINAL, 50000000),
+		CLK_INIT(blsp1_qup6_spi_apps_clk_src.c),
+	},
+};
+
+static struct clk_freq_tbl ftbl_gcc_blsp1_uart1_6_apps_clk[] = {
+	F(   3686400,      gpll0,    1,   96, 15625),
+	F(   7372800,      gpll0,    1,  192, 15625),
+	F(  14745600,      gpll0,    1,  384, 15625),
+	F(  16000000,      gpll0,    5,    2,    15),
+	F(  19200000,         xo,    1,    0,     0),
+	F(  24000000,      gpll0,    5,    1,     5),
+	F(  32000000,      gpll0,    1,    4,    75),
+	F(  40000000,      gpll0,   15,    0,     0),
+	F(  46400000,      gpll0,    1,   29,   375),
+	F(  48000000,      gpll0, 12.5,    0,     0),
+	F(  51200000,      gpll0,    1,   32,   375),
+	F(  56000000,      gpll0,    1,    7,    75),
+	F(  58982400,      gpll0,    1, 1536, 15625),
+	F(  60000000,      gpll0,   10,    0,     0),
+	F_END
+};
+
+static struct rcg_clk blsp1_uart1_apps_clk_src = {
+	.cmd_rcgr_reg = BLSP1_UART1_APPS_CMD_RCGR,
+	.set_rate = set_rate_mnd,
+	.freq_tbl = ftbl_gcc_blsp1_uart1_6_apps_clk,
+	.current_freq = &rcg_dummy_freq,
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "blsp1_uart1_apps_clk_src",
+		.ops = &clk_ops_rcg_mnd,
+		VDD_DIG_FMAX_MAP2(LOW, 31580000, NOMINAL, 63160000),
+		CLK_INIT(blsp1_uart1_apps_clk_src.c),
+	},
+};
+
+static struct rcg_clk blsp1_uart2_apps_clk_src = {
+	.cmd_rcgr_reg = BLSP1_UART2_APPS_CMD_RCGR,
+	.set_rate = set_rate_mnd,
+	.freq_tbl = ftbl_gcc_blsp1_uart1_6_apps_clk,
+	.current_freq = &rcg_dummy_freq,
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "blsp1_uart2_apps_clk_src",
+		.ops = &clk_ops_rcg_mnd,
+		VDD_DIG_FMAX_MAP2(LOW, 31580000, NOMINAL, 63160000),
+		CLK_INIT(blsp1_uart2_apps_clk_src.c),
+	},
+};
+
+static struct rcg_clk blsp1_uart3_apps_clk_src = {
+	.cmd_rcgr_reg = BLSP1_UART3_APPS_CMD_RCGR,
+	.set_rate = set_rate_mnd,
+	.freq_tbl = ftbl_gcc_blsp1_uart1_6_apps_clk,
+	.current_freq = &rcg_dummy_freq,
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "blsp1_uart3_apps_clk_src",
+		.ops = &clk_ops_rcg_mnd,
+		VDD_DIG_FMAX_MAP2(LOW, 31580000, NOMINAL, 63160000),
+		CLK_INIT(blsp1_uart3_apps_clk_src.c),
+	},
+};
+
+static struct rcg_clk blsp1_uart4_apps_clk_src = {
+	.cmd_rcgr_reg = BLSP1_UART4_APPS_CMD_RCGR,
+	.set_rate = set_rate_mnd,
+	.freq_tbl = ftbl_gcc_blsp1_uart1_6_apps_clk,
+	.current_freq = &rcg_dummy_freq,
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "blsp1_uart4_apps_clk_src",
+		.ops = &clk_ops_rcg_mnd,
+		VDD_DIG_FMAX_MAP2(LOW, 31580000, NOMINAL, 63160000),
+		CLK_INIT(blsp1_uart4_apps_clk_src.c),
+	},
+};
+
+static struct rcg_clk blsp1_uart5_apps_clk_src = {
+	.cmd_rcgr_reg = BLSP1_UART5_APPS_CMD_RCGR,
+	.set_rate = set_rate_mnd,
+	.freq_tbl = ftbl_gcc_blsp1_uart1_6_apps_clk,
+	.current_freq = &rcg_dummy_freq,
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "blsp1_uart5_apps_clk_src",
+		.ops = &clk_ops_rcg_mnd,
+		VDD_DIG_FMAX_MAP2(LOW, 31580000, NOMINAL, 63160000),
+		CLK_INIT(blsp1_uart5_apps_clk_src.c),
+	},
+};
+
+static struct rcg_clk blsp1_uart6_apps_clk_src = {
+	.cmd_rcgr_reg = BLSP1_UART6_APPS_CMD_RCGR,
+	.set_rate = set_rate_mnd,
+	.freq_tbl = ftbl_gcc_blsp1_uart1_6_apps_clk,
+	.current_freq = &rcg_dummy_freq,
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "blsp1_uart6_apps_clk_src",
+		.ops = &clk_ops_rcg_mnd,
+		VDD_DIG_FMAX_MAP2(LOW, 31580000, NOMINAL, 63160000),
+		CLK_INIT(blsp1_uart6_apps_clk_src.c),
+	},
+};
+
+static struct clk_freq_tbl ftbl_gcc_ce1_clk[] = {
+	F(  50000000,      gpll0,   12,    0,     0),
+	F(  85710000,      gpll0,    7,    0,     0),
+	F( 100000000,      gpll0,    6,    0,     0),
+	F( 171430000,      gpll0,  3.5,    0,     0),
+	F( 200000000,      gpll0,    3,    0,     0),
+	F_END
+};
+
+static struct rcg_clk ce1_clk_src = {
+	.cmd_rcgr_reg = CE1_CMD_RCGR,
+	.set_rate = set_rate_hid,
+	.freq_tbl = ftbl_gcc_ce1_clk,
+	.current_freq = &rcg_dummy_freq,
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "ce1_clk_src",
+		.ops = &clk_ops_rcg,
+		VDD_DIG_FMAX_MAP3(LOW, 85710000, NOMINAL, 171430000, HIGH,
+			200000000),
+		CLK_INIT(ce1_clk_src.c),
+	},
+};
+
+static struct clk_freq_tbl ftbl_gcc_pcie_sleep_clk[] = {
+	F(   1000000,         xo,    1,    5,    96),
+	F_END
+};
+
+static struct rcg_clk pcie_aux_clk_src = {
+	.cmd_rcgr_reg = PCIE_AUX_CMD_RCGR,
+	.set_rate = set_rate_mnd,
+	.freq_tbl = ftbl_gcc_pcie_sleep_clk,
+	.current_freq = &rcg_dummy_freq,
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "pcie_aux_clk_src",
+		.ops = &clk_ops_rcg_mnd,
+		VDD_DIG_FMAX_MAP1(LOW, 1000000),
+		CLK_INIT(pcie_aux_clk_src.c),
+	},
+};
+
+static struct clk_freq_tbl ftbl_gcc_pcie_pipe_clk[] = {
+	F_EXT_SRC(  62500000, pcie_pipe_clk,    2,    0,     0),
+	F_EXT_SRC( 125000000, pcie_pipe_clk,    1,    0,     0),
+	F_END
+};
+
+static struct rcg_clk pcie_pipe_clk_src = {
+	.cmd_rcgr_reg = PCIE_PIPE_CMD_RCGR,
+	.set_rate = set_rate_hid,
+	.freq_tbl = ftbl_gcc_pcie_pipe_clk,
+	.current_freq = &rcg_dummy_freq,
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "pcie_pipe_clk_src",
+		.ops = &clk_ops_rcg,
+		VDD_DIG_FMAX_MAP2(LOW, 62500000, NOMINAL, 125000000),
+		CLK_INIT(pcie_pipe_clk_src.c),
+	},
+};
+
+static struct clk_freq_tbl ftbl_gcc_pdm2_clk[] = {
+	F(  60000000,      gpll0,   10,    0,     0),
+	F_END
+};
+
+static struct rcg_clk pdm2_clk_src = {
+	.cmd_rcgr_reg = PDM2_CMD_RCGR,
+	.set_rate = set_rate_hid,
+	.freq_tbl = ftbl_gcc_pdm2_clk,
+	.current_freq = &rcg_dummy_freq,
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "pdm2_clk_src",
+		.ops = &clk_ops_rcg,
+		VDD_DIG_FMAX_MAP1(LOW, 60000000),
+		CLK_INIT(pdm2_clk_src.c),
+	},
+};
+
+static struct clk_freq_tbl ftbl_gcc_sdcc2_3_apps_clk[] = {
+	F(    144000,         xo,   16,    3,    25),
+	F(    400000,         xo,   12,    1,     4),
+	F(  20000000,      gpll0,   15,    1,     2),
+	F(  25000000,      gpll0,   12,    1,     2),
+	F(  50000000,      gpll0,   12,    0,     0),
+	F( 100000000,      gpll0,    6,    0,     0),
+	F( 200000000,      gpll0,    3,    0,     0),
+	F_END
+};
+
+static struct rcg_clk sdcc2_apps_clk_src = {
+	.cmd_rcgr_reg = SDCC2_APPS_CMD_RCGR,
+	.set_rate = set_rate_mnd,
+	.freq_tbl = ftbl_gcc_sdcc2_3_apps_clk,
+	.current_freq = &rcg_dummy_freq,
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "sdcc2_apps_clk_src",
+		.ops = &clk_ops_rcg_mnd,
+		VDD_DIG_FMAX_MAP2(LOW, 100000000, NOMINAL, 200000000),
+		CLK_INIT(sdcc2_apps_clk_src.c),
+	},
+};
+
+static struct rcg_clk sdcc3_apps_clk_src = {
+	.cmd_rcgr_reg = SDCC3_APPS_CMD_RCGR,
+	.set_rate = set_rate_mnd,
+	.freq_tbl = ftbl_gcc_sdcc2_3_apps_clk,
+	.current_freq = &rcg_dummy_freq,
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "sdcc3_apps_clk_src",
+		.ops = &clk_ops_rcg_mnd,
+		VDD_DIG_FMAX_MAP2(LOW, 50000000, NOMINAL, 100000000),
+		CLK_INIT(sdcc3_apps_clk_src.c),
+	},
+};
+
+static struct clk_freq_tbl ftbl_gcc_usb3_aux_clk[] = {
+	F(   1000000,         xo,    1,    5,    96),
+	F_END
+};
+
+static struct rcg_clk usb3_aux_clk_src = {
+	.cmd_rcgr_reg = USB3_AUX_CMD_RCGR,
+	.set_rate = set_rate_mnd,
+	.freq_tbl = ftbl_gcc_usb3_aux_clk,
+	.current_freq = &rcg_dummy_freq,
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "usb3_aux_clk_src",
+		.ops = &clk_ops_rcg_mnd,
+		VDD_DIG_FMAX_MAP1(LOW, 1000000),
+		CLK_INIT(usb3_aux_clk_src.c),
+	},
+};
+
+static struct clk_freq_tbl ftbl_gcc_usb3_pipe_clk[] = {
+	F_EXT_SRC( 125000000, usb3_pipe_clk,    1,    0,     0),
+	F_END
+};
+
+static struct rcg_clk usb3_pipe_clk_src = {
+	.cmd_rcgr_reg = USB3_PIPE_CMD_RCGR,
+	.set_rate = set_rate_hid,
+	.freq_tbl = ftbl_gcc_usb3_pipe_clk,
+	.current_freq = &rcg_dummy_freq,
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "usb3_pipe_clk_src",
+		.ops = &clk_ops_rcg,
+		VDD_DIG_FMAX_MAP1(LOW, 125000000),
+		CLK_INIT(usb3_pipe_clk_src.c),
+	},
+};
+
+static struct clk_freq_tbl ftbl_gcc_usb30_mock_utmi_clk[] = {
+	F(  60000000,      gpll0,   10,    0,     0),
+	F_END
+};
+
+static struct rcg_clk usb30_mock_utmi_clk_src = {
+	.cmd_rcgr_reg = USB30_MOCK_UTMI_CMD_RCGR,
+	.set_rate = set_rate_hid,
+	.freq_tbl = ftbl_gcc_usb30_mock_utmi_clk,
+	.current_freq = &rcg_dummy_freq,
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "usb30_mock_utmi_clk_src",
+		.ops = &clk_ops_rcg,
+		VDD_DIG_FMAX_MAP1(LOW, 60000000),
+		CLK_INIT(usb30_mock_utmi_clk_src.c),
+	},
+};
+
+static struct clk_freq_tbl ftbl_gcc_usb_hs_system_clk[] = {
+	F(  60000000,      gpll0,   10,    0,     0),
+	F(  75000000,      gpll0,    8,    0,     0),
+	F_END
+};
+
+static struct rcg_clk usb_hs_system_clk_src = {
+	.cmd_rcgr_reg = USB_HS_SYSTEM_CMD_RCGR,
+	.set_rate = set_rate_hid,
+	.freq_tbl = ftbl_gcc_usb_hs_system_clk,
+	.current_freq = &rcg_dummy_freq,
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "usb_hs_system_clk_src",
+		.ops = &clk_ops_rcg,
+		VDD_DIG_FMAX_MAP2(LOW, 60000000, NOMINAL, 75000000),
+		CLK_INIT(usb_hs_system_clk_src.c),
+	},
+};
+
+static struct clk_freq_tbl ftbl_gcc_usb_hsic_clk[] = {
+	F( 480000000,      gpll1,    1,    0,     0),
+	F_END
+};
+
+static struct rcg_clk usb_hsic_clk_src = {
+	.cmd_rcgr_reg = USB_HSIC_CMD_RCGR,
+	.set_rate = set_rate_hid,
+	.freq_tbl = ftbl_gcc_usb_hsic_clk,
+	.current_freq = &rcg_dummy_freq,
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "usb_hsic_clk_src",
+		.ops = &clk_ops_rcg,
+		VDD_DIG_FMAX_MAP1(LOW, 480000000),
+		CLK_INIT(usb_hsic_clk_src.c),
+	},
+};
+
+static struct clk_freq_tbl ftbl_gcc_usb_hsic_io_cal_clk[] = {
+	F(   9600000,         xo,    2,    0,     0),
+	F_END
+};
+
+static struct rcg_clk usb_hsic_io_cal_clk_src = {
+	.cmd_rcgr_reg = USB_HSIC_IO_CAL_CMD_RCGR,
+	.set_rate = set_rate_hid,
+	.freq_tbl = ftbl_gcc_usb_hsic_io_cal_clk,
+	.current_freq = &rcg_dummy_freq,
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "usb_hsic_io_cal_clk_src",
+		.ops = &clk_ops_rcg,
+		VDD_DIG_FMAX_MAP1(LOW, 9600000),
+		CLK_INIT(usb_hsic_io_cal_clk_src.c),
+	},
+};
+
+static struct clk_freq_tbl ftbl_gcc_usb_hsic_system_clk[] = {
+	F(  60000000,      gpll0,   10,    0,     0),
+	F(  75000000,      gpll0,    8,    0,     0),
+	F_END
+};
+
+static struct rcg_clk usb_hsic_system_clk_src = {
+	.cmd_rcgr_reg = USB_HSIC_SYSTEM_CMD_RCGR,
+	.set_rate = set_rate_hid,
+	.freq_tbl = ftbl_gcc_usb_hsic_system_clk,
+	.current_freq = &rcg_dummy_freq,
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "usb_hsic_system_clk_src",
+		.ops = &clk_ops_rcg,
+		VDD_DIG_FMAX_MAP2(LOW, 60000000, NOMINAL, 75000000),
+		CLK_INIT(usb_hsic_system_clk_src.c),
+	},
+};
+
+static struct clk_freq_tbl ftbl_gcc_usb_hsic_xcvr_fs_clk[] = {
+	F(  60000000,      gpll0,   10,    0,     0),
+	F_END
+};
+
+static struct rcg_clk usb_hsic_xcvr_fs_clk_src = {
+	.cmd_rcgr_reg = USB_HSIC_XCVR_FS_CMD_RCGR,
+	.set_rate = set_rate_hid,
+	.freq_tbl = ftbl_gcc_usb_hsic_xcvr_fs_clk,
+	.current_freq = &rcg_dummy_freq,
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "usb_hsic_xcvr_fs_clk_src",
+		.ops = &clk_ops_rcg,
+		VDD_DIG_FMAX_MAP1(LOW, 60000000),
+		CLK_INIT(usb_hsic_xcvr_fs_clk_src.c),
+	},
+};
+
+DEFINE_CLK_RPM_SMD(bimc_clk, bimc_a_clk, RPM_MEM_CLK_TYPE, BIMC_ID, NULL);
+
+DEFINE_CLK_RPM_SMD(cnoc_clk, cnoc_a_clk, RPM_BUS_CLK_TYPE, CNOC_ID, NULL);
+
+DEFINE_CLK_RPM_SMD(pnoc_clk, pnoc_a_clk, RPM_BUS_CLK_TYPE, PNOC_ID, NULL);
+
+DEFINE_CLK_RPM_SMD_QDSS(qdss_clk, qdss_a_clk, RPM_MISC_CLK_TYPE, QDSS_ID);
+
+DEFINE_CLK_RPM_SMD(qpic_clk, qpic_a_clk, RPM_QPIC_CLK_TYPE, QPIC_ID, NULL);
+
+DEFINE_CLK_RPM_SMD(snoc_clk, snoc_a_clk, RPM_BUS_CLK_TYPE, SNOC_ID, NULL);
+
+static struct local_vote_clk gcc_bam_dma_ahb_clk = {
+	.cbcr_reg = BAM_DMA_AHB_CBCR,
+	.vote_reg = APCS_CLOCK_BRANCH_ENA_VOTE,
+	.en_mask = BIT(12),
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "gcc_bam_dma_ahb_clk",
+		.ops = &clk_ops_vote,
+		CLK_INIT(gcc_bam_dma_ahb_clk.c),
+	},
+};
+
+static struct branch_clk gcc_bam_dma_inactivity_timers_clk = {
+	.cbcr_reg = BAM_DMA_INACTIVITY_TIMERS_CBCR,
+	.has_sibling = 1,
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "gcc_bam_dma_inactivity_timers_clk",
+		.ops = &clk_ops_branch,
+		CLK_INIT(gcc_bam_dma_inactivity_timers_clk.c),
+	},
+};
+
+static struct local_vote_clk gcc_blsp1_ahb_clk = {
+	.cbcr_reg = BLSP1_AHB_CBCR,
+	.vote_reg = APCS_CLOCK_BRANCH_ENA_VOTE,
+	.en_mask = BIT(17),
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "gcc_blsp1_ahb_clk",
+		.ops = &clk_ops_vote,
+		CLK_INIT(gcc_blsp1_ahb_clk.c),
+	},
+};
+
+static struct branch_clk gcc_blsp1_qup1_i2c_apps_clk = {
+	.cbcr_reg = BLSP1_QUP1_I2C_APPS_CBCR,
+	.has_sibling = 0,
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "gcc_blsp1_qup1_i2c_apps_clk",
+		.parent = &blsp1_qup1_i2c_apps_clk_src.c,
+		.ops = &clk_ops_branch,
+		CLK_INIT(gcc_blsp1_qup1_i2c_apps_clk.c),
+	},
+};
+
+static struct branch_clk gcc_blsp1_qup1_spi_apps_clk = {
+	.cbcr_reg = BLSP1_QUP1_SPI_APPS_CBCR,
+	.has_sibling = 0,
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "gcc_blsp1_qup1_spi_apps_clk",
+		.parent = &blsp1_qup1_spi_apps_clk_src.c,
+		.ops = &clk_ops_branch,
+		CLK_INIT(gcc_blsp1_qup1_spi_apps_clk.c),
+	},
+};
+
+static struct branch_clk gcc_blsp1_qup2_i2c_apps_clk = {
+	.cbcr_reg = BLSP1_QUP2_I2C_APPS_CBCR,
+	.has_sibling = 0,
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "gcc_blsp1_qup2_i2c_apps_clk",
+		.parent = &blsp1_qup2_i2c_apps_clk_src.c,
+		.ops = &clk_ops_branch,
+		CLK_INIT(gcc_blsp1_qup2_i2c_apps_clk.c),
+	},
+};
+
+static struct branch_clk gcc_blsp1_qup2_spi_apps_clk = {
+	.cbcr_reg = BLSP1_QUP2_SPI_APPS_CBCR,
+	.has_sibling = 0,
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "gcc_blsp1_qup2_spi_apps_clk",
+		.parent = &blsp1_qup2_spi_apps_clk_src.c,
+		.ops = &clk_ops_branch,
+		CLK_INIT(gcc_blsp1_qup2_spi_apps_clk.c),
+	},
+};
+
+static struct branch_clk gcc_blsp1_qup3_i2c_apps_clk = {
+	.cbcr_reg = BLSP1_QUP3_I2C_APPS_CBCR,
+	.has_sibling = 0,
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "gcc_blsp1_qup3_i2c_apps_clk",
+		.parent = &blsp1_qup3_i2c_apps_clk_src.c,
+		.ops = &clk_ops_branch,
+		CLK_INIT(gcc_blsp1_qup3_i2c_apps_clk.c),
+	},
+};
+
+static struct branch_clk gcc_blsp1_qup3_spi_apps_clk = {
+	.cbcr_reg = BLSP1_QUP3_SPI_APPS_CBCR,
+	.has_sibling = 0,
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "gcc_blsp1_qup3_spi_apps_clk",
+		.parent = &blsp1_qup3_spi_apps_clk_src.c,
+		.ops = &clk_ops_branch,
+		CLK_INIT(gcc_blsp1_qup3_spi_apps_clk.c),
+	},
+};
+
+static struct branch_clk gcc_blsp1_qup4_i2c_apps_clk = {
+	.cbcr_reg = BLSP1_QUP4_I2C_APPS_CBCR,
+	.has_sibling = 0,
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "gcc_blsp1_qup4_i2c_apps_clk",
+		.parent = &blsp1_qup4_i2c_apps_clk_src.c,
+		.ops = &clk_ops_branch,
+		CLK_INIT(gcc_blsp1_qup4_i2c_apps_clk.c),
+	},
+};
+
+static struct branch_clk gcc_blsp1_qup4_spi_apps_clk = {
+	.cbcr_reg = BLSP1_QUP4_SPI_APPS_CBCR,
+	.has_sibling = 0,
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "gcc_blsp1_qup4_spi_apps_clk",
+		.parent = &blsp1_qup4_spi_apps_clk_src.c,
+		.ops = &clk_ops_branch,
+		CLK_INIT(gcc_blsp1_qup4_spi_apps_clk.c),
+	},
+};
+
+static struct branch_clk gcc_blsp1_qup5_i2c_apps_clk = {
+	.cbcr_reg = BLSP1_QUP5_I2C_APPS_CBCR,
+	.has_sibling = 0,
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "gcc_blsp1_qup5_i2c_apps_clk",
+		.parent = &blsp1_qup5_i2c_apps_clk_src.c,
+		.ops = &clk_ops_branch,
+		CLK_INIT(gcc_blsp1_qup5_i2c_apps_clk.c),
+	},
+};
+
+static struct branch_clk gcc_blsp1_qup5_spi_apps_clk = {
+	.cbcr_reg = BLSP1_QUP5_SPI_APPS_CBCR,
+	.has_sibling = 0,
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "gcc_blsp1_qup5_spi_apps_clk",
+		.parent = &blsp1_qup5_spi_apps_clk_src.c,
+		.ops = &clk_ops_branch,
+		CLK_INIT(gcc_blsp1_qup5_spi_apps_clk.c),
+	},
+};
+
+static struct branch_clk gcc_blsp1_qup6_i2c_apps_clk = {
+	.cbcr_reg = BLSP1_QUP6_I2C_APPS_CBCR,
+	.has_sibling = 0,
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "gcc_blsp1_qup6_i2c_apps_clk",
+		.parent = &blsp1_qup6_i2c_apps_clk_src.c,
+		.ops = &clk_ops_branch,
+		CLK_INIT(gcc_blsp1_qup6_i2c_apps_clk.c),
+	},
+};
+
+static struct branch_clk gcc_blsp1_qup6_spi_apps_clk = {
+	.cbcr_reg = BLSP1_QUP6_SPI_APPS_CBCR,
+	.has_sibling = 0,
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "gcc_blsp1_qup6_spi_apps_clk",
+		.parent = &blsp1_qup6_spi_apps_clk_src.c,
+		.ops = &clk_ops_branch,
+		CLK_INIT(gcc_blsp1_qup6_spi_apps_clk.c),
+	},
+};
+
+static struct branch_clk gcc_blsp1_uart1_apps_clk = {
+	.cbcr_reg = BLSP1_UART1_APPS_CBCR,
+	.has_sibling = 0,
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "gcc_blsp1_uart1_apps_clk",
+		.parent = &blsp1_uart1_apps_clk_src.c,
+		.ops = &clk_ops_branch,
+		CLK_INIT(gcc_blsp1_uart1_apps_clk.c),
+	},
+};
+
+static struct branch_clk gcc_blsp1_uart2_apps_clk = {
+	.cbcr_reg = BLSP1_UART2_APPS_CBCR,
+	.has_sibling = 0,
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "gcc_blsp1_uart2_apps_clk",
+		.parent = &blsp1_uart2_apps_clk_src.c,
+		.ops = &clk_ops_branch,
+		CLK_INIT(gcc_blsp1_uart2_apps_clk.c),
+	},
+};
+
+static struct branch_clk gcc_blsp1_uart3_apps_clk = {
+	.cbcr_reg = BLSP1_UART3_APPS_CBCR,
+	.has_sibling = 0,
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "gcc_blsp1_uart3_apps_clk",
+		.parent = &blsp1_uart3_apps_clk_src.c,
+		.ops = &clk_ops_branch,
+		CLK_INIT(gcc_blsp1_uart3_apps_clk.c),
+	},
+};
+
+static struct branch_clk gcc_blsp1_uart4_apps_clk = {
+	.cbcr_reg = BLSP1_UART4_APPS_CBCR,
+	.has_sibling = 0,
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "gcc_blsp1_uart4_apps_clk",
+		.parent = &blsp1_uart4_apps_clk_src.c,
+		.ops = &clk_ops_branch,
+		CLK_INIT(gcc_blsp1_uart4_apps_clk.c),
+	},
+};
+
+static struct branch_clk gcc_blsp1_uart5_apps_clk = {
+	.cbcr_reg = BLSP1_UART5_APPS_CBCR,
+	.has_sibling = 0,
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "gcc_blsp1_uart5_apps_clk",
+		.parent = &blsp1_uart5_apps_clk_src.c,
+		.ops = &clk_ops_branch,
+		CLK_INIT(gcc_blsp1_uart5_apps_clk.c),
+	},
+};
+
+static struct branch_clk gcc_blsp1_uart6_apps_clk = {
+	.cbcr_reg = BLSP1_UART6_APPS_CBCR,
+	.has_sibling = 0,
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "gcc_blsp1_uart6_apps_clk",
+		.parent = &blsp1_uart6_apps_clk_src.c,
+		.ops = &clk_ops_branch,
+		CLK_INIT(gcc_blsp1_uart6_apps_clk.c),
+	},
+};
+
+static struct local_vote_clk gcc_boot_rom_ahb_clk = {
+	.cbcr_reg = BOOT_ROM_AHB_CBCR,
+	.vote_reg = APCS_CLOCK_BRANCH_ENA_VOTE,
+	.en_mask = BIT(10),
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "gcc_boot_rom_ahb_clk",
+		.ops = &clk_ops_vote,
+		CLK_INIT(gcc_boot_rom_ahb_clk.c),
+	},
+};
+
+static struct local_vote_clk gcc_ce1_ahb_clk = {
+	.cbcr_reg = CE1_AHB_CBCR,
+	.vote_reg = APCS_CLOCK_BRANCH_ENA_VOTE,
+	.en_mask = BIT(3),
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "gcc_ce1_ahb_clk",
+		.ops = &clk_ops_vote,
+		CLK_INIT(gcc_ce1_ahb_clk.c),
+	},
+};
+
+static struct local_vote_clk gcc_ce1_axi_clk = {
+	.cbcr_reg = CE1_AXI_CBCR,
+	.vote_reg = APCS_CLOCK_BRANCH_ENA_VOTE,
+	.en_mask = BIT(4),
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "gcc_ce1_axi_clk",
+		.ops = &clk_ops_vote,
+		CLK_INIT(gcc_ce1_axi_clk.c),
+	},
+};
+
+static struct local_vote_clk gcc_ce1_clk = {
+	.cbcr_reg = CE1_CBCR,
+	.vote_reg = APCS_CLOCK_BRANCH_ENA_VOTE,
+	.en_mask = BIT(5),
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "gcc_ce1_clk",
+		.ops = &clk_ops_vote,
+		CLK_INIT(gcc_ce1_clk.c),
+	},
+};
+
+static struct branch_clk gcc_lpass_q6_axi_clk = {
+	.cbcr_reg = LPASS_Q6_AXI_CBCR,
+	.has_sibling = 1,
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "gcc_lpass_q6_axi_clk",
+		.ops = &clk_ops_branch,
+		CLK_INIT(gcc_lpass_q6_axi_clk.c),
+	},
+};
+
+static struct branch_clk gcc_mss_cfg_ahb_clk = {
+	.cbcr_reg = MSS_CFG_AHB_CBCR,
+	.has_sibling = 1,
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "gcc_mss_cfg_ahb_clk",
+		.ops = &clk_ops_branch,
+		CLK_INIT(gcc_mss_cfg_ahb_clk.c),
+	},
+};
+
+static struct branch_clk gcc_mss_q6_bimc_axi_clk = {
+	.cbcr_reg = MSS_Q6_BIMC_AXI_CBCR,
+	.has_sibling = 1,
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "gcc_mss_q6_bimc_axi_clk",
+		.ops = &clk_ops_branch,
+		CLK_INIT(gcc_mss_q6_bimc_axi_clk.c),
+	},
+};
+
+static struct branch_clk gcc_pcie_axi_clk = {
+	.cbcr_reg = PCIE_AXI_CBCR,
+	.has_sibling = 1,
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "gcc_pcie_axi_clk",
+		.ops = &clk_ops_branch,
+		CLK_INIT(gcc_pcie_axi_clk.c),
+	},
+};
+
+static struct branch_clk gcc_pcie_axi_mstr_clk = {
+	.cbcr_reg = PCIE_AXI_MSTR_CBCR,
+	.has_sibling = 1,
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "gcc_pcie_axi_mstr_clk",
+		.ops = &clk_ops_branch,
+		CLK_INIT(gcc_pcie_axi_mstr_clk.c),
+	},
+};
+
+static struct branch_clk gcc_pcie_cfg_ahb_clk = {
+	.cbcr_reg = PCIE_CFG_AHB_CBCR,
+	.has_sibling = 1,
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "gcc_pcie_cfg_ahb_clk",
+		.ops = &clk_ops_branch,
+		CLK_INIT(gcc_pcie_cfg_ahb_clk.c),
+	},
+};
+
+static struct branch_clk gcc_pcie_pipe_clk = {
+	.cbcr_reg = PCIE_PIPE_CBCR,
+	.has_sibling = 0,
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "gcc_pcie_pipe_clk",
+		.parent = &pcie_pipe_clk_src.c,
+		.ops = &clk_ops_branch,
+		CLK_INIT(gcc_pcie_pipe_clk.c),
+	},
+};
+
+static struct branch_clk gcc_pcie_sleep_clk = {
+	.cbcr_reg = PCIE_SLEEP_CBCR,
+	.has_sibling = 0,
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "gcc_pcie_sleep_clk",
+		.parent = &pcie_aux_clk_src.c,
+		.ops = &clk_ops_branch,
+		CLK_INIT(gcc_pcie_sleep_clk.c),
+	},
+};
+
+static struct branch_clk gcc_pdm2_clk = {
+	.cbcr_reg = PDM2_CBCR,
+	.has_sibling = 0,
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "gcc_pdm2_clk",
+		.parent = &pdm2_clk_src.c,
+		.ops = &clk_ops_branch,
+		CLK_INIT(gcc_pdm2_clk.c),
+	},
+};
+
+static struct branch_clk gcc_pdm_ahb_clk = {
+	.cbcr_reg = PDM_AHB_CBCR,
+	.has_sibling = 1,
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "gcc_pdm_ahb_clk",
+		.ops = &clk_ops_branch,
+		CLK_INIT(gcc_pdm_ahb_clk.c),
+	},
+};
+
+static struct local_vote_clk gcc_prng_ahb_clk = {
+	.cbcr_reg = PRNG_AHB_CBCR,
+	.vote_reg = APCS_CLOCK_BRANCH_ENA_VOTE,
+	.en_mask = BIT(13),
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "gcc_prng_ahb_clk",
+		.ops = &clk_ops_vote,
+		CLK_INIT(gcc_prng_ahb_clk.c),
+	},
+};
+
+static struct branch_clk gcc_sdcc2_ahb_clk = {
+	.cbcr_reg = SDCC2_AHB_CBCR,
+	.has_sibling = 1,
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "gcc_sdcc2_ahb_clk",
+		.ops = &clk_ops_branch,
+		CLK_INIT(gcc_sdcc2_ahb_clk.c),
+	},
+};
+
+static struct branch_clk gcc_sdcc2_apps_clk = {
+	.cbcr_reg = SDCC2_APPS_CBCR,
+	.has_sibling = 0,
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "gcc_sdcc2_apps_clk",
+		.parent = &sdcc2_apps_clk_src.c,
+		.ops = &clk_ops_branch,
+		CLK_INIT(gcc_sdcc2_apps_clk.c),
+	},
+};
+
+static struct branch_clk gcc_sdcc3_ahb_clk = {
+	.cbcr_reg = SDCC3_AHB_CBCR,
+	.has_sibling = 1,
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "gcc_sdcc3_ahb_clk",
+		.ops = &clk_ops_branch,
+		CLK_INIT(gcc_sdcc3_ahb_clk.c),
+	},
+};
+
+static struct branch_clk gcc_sdcc3_apps_clk = {
+	.cbcr_reg = SDCC3_APPS_CBCR,
+	.has_sibling = 0,
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "gcc_sdcc3_apps_clk",
+		.parent = &sdcc3_apps_clk_src.c,
+		.ops = &clk_ops_branch,
+		CLK_INIT(gcc_sdcc3_apps_clk.c),
+	},
+};
+
+static struct branch_clk gcc_sys_noc_usb3_axi_clk = {
+	.cbcr_reg = SYS_NOC_USB3_AXI_CBCR,
+	.has_sibling = 1,
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "gcc_sys_noc_usb3_axi_clk",
+		.parent = &usb30_master_clk_src.c,
+		.ops = &clk_ops_branch,
+		CLK_INIT(gcc_sys_noc_usb3_axi_clk.c),
+	},
+};
+
+static struct branch_clk gcc_usb3_aux_clk = {
+	.cbcr_reg = USB3_AUX_CBCR,
+	.has_sibling = 0,
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "gcc_usb3_aux_clk",
+		.parent = &usb3_aux_clk_src.c,
+		.ops = &clk_ops_branch,
+		CLK_INIT(gcc_usb3_aux_clk.c),
+	},
+};
+
+static struct branch_clk gcc_usb3_pipe_clk = {
+	.cbcr_reg = USB3_PIPE_CBCR,
+	.has_sibling = 0,
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "gcc_usb3_pipe_clk",
+		.parent = &usb3_pipe_clk_src.c,
+		.ops = &clk_ops_branch,
+		CLK_INIT(gcc_usb3_pipe_clk.c),
+	},
+};
+
+static struct branch_clk gcc_usb30_master_clk = {
+	.cbcr_reg = USB30_MASTER_CBCR,
+	.bcr_reg = USB_30_BCR,
+	.has_sibling = 1,
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "gcc_usb30_master_clk",
+		.parent = &usb30_master_clk_src.c,
+		.ops = &clk_ops_branch,
+		CLK_INIT(gcc_usb30_master_clk.c),
+		.depends = &gcc_sys_noc_usb3_axi_clk.c,
+	},
+};
+
+static struct branch_clk gcc_usb30_mock_utmi_clk = {
+	.cbcr_reg = USB30_MOCK_UTMI_CBCR,
+	.has_sibling = 0,
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "gcc_usb30_mock_utmi_clk",
+		.parent = &usb30_mock_utmi_clk_src.c,
+		.ops = &clk_ops_branch,
+		CLK_INIT(gcc_usb30_mock_utmi_clk.c),
+	},
+};
+
+static struct branch_clk gcc_usb30_sleep_clk = {
+	.cbcr_reg = USB30_SLEEP_CBCR,
+	.has_sibling = 1,
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "gcc_usb30_sleep_clk",
+		.ops = &clk_ops_branch,
+		CLK_INIT(gcc_usb30_sleep_clk.c),
+	},
+};
+
+static struct branch_clk gcc_usb_hs_ahb_clk = {
+	.cbcr_reg = USB_HS_AHB_CBCR,
+	.has_sibling = 1,
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "gcc_usb_hs_ahb_clk",
+		.ops = &clk_ops_branch,
+		CLK_INIT(gcc_usb_hs_ahb_clk.c),
+	},
+};
+
+static struct branch_clk gcc_usb_hs_system_clk = {
+	.cbcr_reg = USB_HS_SYSTEM_CBCR,
+	.has_sibling = 0,
+	.bcr_reg = USB_HS_BCR,
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "gcc_usb_hs_system_clk",
+		.parent = &usb_hs_system_clk_src.c,
+		.ops = &clk_ops_branch,
+		CLK_INIT(gcc_usb_hs_system_clk.c),
+	},
+};
+
+static struct branch_clk gcc_usb_hsic_ahb_clk = {
+	.cbcr_reg = USB_HSIC_AHB_CBCR,
+	.has_sibling = 1,
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "gcc_usb_hsic_ahb_clk",
+		.ops = &clk_ops_branch,
+		CLK_INIT(gcc_usb_hsic_ahb_clk.c),
+	},
+};
+
+static struct branch_clk gcc_usb_hsic_clk = {
+	.cbcr_reg = USB_HSIC_CBCR,
+	.has_sibling = 0,
+	.bcr_reg = USB_HS_HSIC_BCR,
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "gcc_usb_hsic_clk",
+		.parent = &usb_hsic_clk_src.c,
+		.ops = &clk_ops_branch,
+		CLK_INIT(gcc_usb_hsic_clk.c),
+	},
+};
+
+static struct branch_clk gcc_usb_hsic_io_cal_clk = {
+	.cbcr_reg = USB_HSIC_IO_CAL_CBCR,
+	.has_sibling = 0,
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "gcc_usb_hsic_io_cal_clk",
+		.parent = &usb_hsic_io_cal_clk_src.c,
+		.ops = &clk_ops_branch,
+		CLK_INIT(gcc_usb_hsic_io_cal_clk.c),
+	},
+};
+
+static struct branch_clk gcc_usb_hsic_io_cal_sleep_clk = {
+	.cbcr_reg = USB_HSIC_IO_CAL_SLEEP_CBCR,
+	.has_sibling = 1,
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "gcc_usb_hsic_io_cal_sleep_clk",
+		.ops = &clk_ops_branch,
+		CLK_INIT(gcc_usb_hsic_io_cal_sleep_clk.c),
+	},
+};
+
+static struct branch_clk gcc_usb_hsic_system_clk = {
+	.cbcr_reg = USB_HSIC_SYSTEM_CBCR,
+	.has_sibling = 0,
+	.bcr_reg = USB_HS_HSIC_BCR,
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "gcc_usb_hsic_system_clk",
+		.parent = &usb_hsic_system_clk_src.c,
+		.ops = &clk_ops_branch,
+		CLK_INIT(gcc_usb_hsic_system_clk.c),
+	},
+};
+
+static struct branch_clk gcc_usb_hsic_xcvr_fs_clk = {
+	.cbcr_reg = USB_HSIC_XCVR_FS_CBCR,
+	.has_sibling = 0,
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "gcc_usb_hsic_xcvr_fs_clk",
+		.parent = &usb_hsic_xcvr_fs_clk_src.c,
+		.ops = &clk_ops_branch,
+		CLK_INIT(gcc_usb_hsic_xcvr_fs_clk.c),
+	},
+};
+
+static struct branch_clk q6ss_ahb_lfabif_clk = {
+	.cbcr_reg = Q6SS_AHB_LFABIF_CBCR,
+	.has_sibling = 1,
+	.base = &virt_bases[LPASS_BASE],
+	.c = {
+		.dbg_name = "q6ss_ahb_lfabif_clk",
+		.ops = &clk_ops_branch,
+		CLK_INIT(q6ss_ahb_lfabif_clk.c),
+	},
+};
+
+static struct branch_clk q6ss_ahbm_clk = {
+	.cbcr_reg = Q6SS_AHBM_CBCR,
+	.has_sibling = 1,
+	.base = &virt_bases[LPASS_BASE],
+	.c = {
+		.dbg_name = "q6ss_ahbm_clk",
+		.ops = &clk_ops_branch,
+		CLK_INIT(q6ss_ahbm_clk.c),
+	},
+};
+
+static DEFINE_CLK_VOTER(pnoc_msmbus_clk, &pnoc_clk.c, LONG_MAX);
+static DEFINE_CLK_VOTER(snoc_msmbus_clk, &snoc_clk.c, LONG_MAX);
+static DEFINE_CLK_VOTER(cnoc_msmbus_clk, &cnoc_clk.c, LONG_MAX);
+static DEFINE_CLK_VOTER(pnoc_msmbus_a_clk, &pnoc_a_clk.c, LONG_MAX);
+static DEFINE_CLK_VOTER(snoc_msmbus_a_clk, &snoc_a_clk.c, LONG_MAX);
+static DEFINE_CLK_VOTER(cnoc_msmbus_a_clk, &cnoc_a_clk.c, LONG_MAX);
+
+static DEFINE_CLK_VOTER(bimc_msmbus_clk, &bimc_clk.c, LONG_MAX);
+static DEFINE_CLK_VOTER(bimc_msmbus_a_clk, &bimc_a_clk.c, LONG_MAX);
+
+static DEFINE_CLK_VOTER(pnoc_sdcc2_clk, &pnoc_clk.c, LONG_MAX);
+static DEFINE_CLK_VOTER(pnoc_sdcc3_clk, &pnoc_clk.c, LONG_MAX);
+
+static DEFINE_CLK_VOTER(pnoc_sps_clk, &pnoc_clk.c, LONG_MAX);
+
+static DEFINE_CLK_BRANCH_VOTER(cxo_pil_lpass_clk, &xo.c);
+static DEFINE_CLK_BRANCH_VOTER(cxo_pil_mss_clk, &xo.c);
+
+static DEFINE_CLK_MEASURE(a7_m_clk);
+
+#ifdef CONFIG_DEBUG_FS
+
+struct measure_mux_entry {
+	struct clk *c;
+	int base;
+	u32 debug_mux;
+};
+
+struct measure_mux_entry measure_mux[] = {
+	{&gcc_mss_cfg_ahb_clk.c,               GCC_BASE, 0x0030},
+	{&gcc_mss_q6_bimc_axi_clk.c,           GCC_BASE, 0x0031},
+	{&gcc_usb30_master_clk.c,              GCC_BASE, 0x0050},
+	{&gcc_usb30_sleep_clk.c,               GCC_BASE, 0x0051},
+	{&gcc_usb30_mock_utmi_clk.c,           GCC_BASE, 0x0052},
+	{&gcc_usb3_pipe_clk.c,                 GCC_BASE, 0x0054},
+	{&gcc_usb3_aux_clk.c,                  GCC_BASE, 0x0055},
+	{&gcc_usb_hsic_ahb_clk.c,              GCC_BASE, 0x0058},
+	{&gcc_usb_hsic_system_clk.c,           GCC_BASE, 0x0059},
+	{&gcc_usb_hsic_clk.c,                  GCC_BASE, 0x005a},
+	{&gcc_usb_hsic_io_cal_clk.c,           GCC_BASE, 0x005b},
+	{&gcc_usb_hsic_io_cal_sleep_clk.c,     GCC_BASE, 0x005c},
+	{&gcc_usb_hsic_xcvr_fs_clk.c,          GCC_BASE, 0x005d},
+	{&gcc_usb_hs_system_clk.c,             GCC_BASE, 0x0060},
+	{&gcc_usb_hs_ahb_clk.c,                GCC_BASE, 0x0061},
+	{&gcc_sdcc2_apps_clk.c,                GCC_BASE, 0x0070},
+	{&gcc_sdcc2_ahb_clk.c,                 GCC_BASE, 0x0071},
+	{&gcc_sdcc3_apps_clk.c,                GCC_BASE, 0x0078},
+	{&gcc_sdcc3_ahb_clk.c,                 GCC_BASE, 0x0079},
+	{&gcc_blsp1_ahb_clk.c,                 GCC_BASE, 0x0088},
+	{&gcc_blsp1_qup1_spi_apps_clk.c,       GCC_BASE, 0x008a},
+	{&gcc_blsp1_qup1_i2c_apps_clk.c,       GCC_BASE, 0x008b},
+	{&gcc_blsp1_uart1_apps_clk.c,          GCC_BASE, 0x008c},
+	{&gcc_blsp1_qup2_spi_apps_clk.c,       GCC_BASE, 0x008e},
+	{&gcc_blsp1_qup2_i2c_apps_clk.c,       GCC_BASE, 0x0090},
+	{&gcc_blsp1_uart2_apps_clk.c,          GCC_BASE, 0x0091},
+	{&gcc_blsp1_qup3_spi_apps_clk.c,       GCC_BASE, 0x0093},
+	{&gcc_blsp1_qup3_i2c_apps_clk.c,       GCC_BASE, 0x0094},
+	{&gcc_blsp1_uart3_apps_clk.c,          GCC_BASE, 0x0095},
+	{&gcc_blsp1_qup4_spi_apps_clk.c,       GCC_BASE, 0x0098},
+	{&gcc_blsp1_qup4_i2c_apps_clk.c,       GCC_BASE, 0x0099},
+	{&gcc_blsp1_uart4_apps_clk.c,          GCC_BASE, 0x009a},
+	{&gcc_blsp1_qup5_spi_apps_clk.c,       GCC_BASE, 0x009c},
+	{&gcc_blsp1_qup5_i2c_apps_clk.c,       GCC_BASE, 0x009d},
+	{&gcc_blsp1_uart5_apps_clk.c,          GCC_BASE, 0x009e},
+	{&gcc_blsp1_qup6_spi_apps_clk.c,       GCC_BASE, 0x00a1},
+	{&gcc_blsp1_qup6_i2c_apps_clk.c,       GCC_BASE, 0x00a2},
+	{&gcc_blsp1_uart6_apps_clk.c,          GCC_BASE, 0x00a3},
+	{&gcc_pdm_ahb_clk.c,                   GCC_BASE, 0x00d0},
+	{&gcc_pdm2_clk.c,                      GCC_BASE, 0x00d2},
+	{&gcc_prng_ahb_clk.c,                  GCC_BASE, 0x00d8},
+	{&gcc_bam_dma_ahb_clk.c,               GCC_BASE, 0x00e0},
+	{&gcc_bam_dma_inactivity_timers_clk.c, GCC_BASE, 0x00e1},
+	{&gcc_boot_rom_ahb_clk.c,              GCC_BASE, 0x00f8},
+	{&gcc_ce1_clk.c,                       GCC_BASE, 0x0138},
+	{&gcc_ce1_axi_clk.c,                   GCC_BASE, 0x0139},
+	{&gcc_ce1_ahb_clk.c,                   GCC_BASE, 0x013a},
+	{&gcc_lpass_q6_axi_clk.c,              GCC_BASE, 0x0160},
+	{&gcc_pcie_cfg_ahb_clk.c,              GCC_BASE, 0x01f0},
+	{&gcc_pcie_pipe_clk.c,                 GCC_BASE, 0x01f1},
+	{&gcc_pcie_axi_clk.c,                  GCC_BASE, 0x01f2},
+	{&gcc_pcie_sleep_clk.c,                GCC_BASE, 0x01f3},
+	{&gcc_pcie_axi_mstr_clk.c,             GCC_BASE, 0x01f4},
+
+	{&bimc_clk.c,                          GCC_BASE, 0x0155},
+	{&cnoc_clk.c,                          GCC_BASE, 0x0008},
+	{&pnoc_clk.c,                          GCC_BASE, 0x0010},
+	{&snoc_clk.c,                          GCC_BASE, 0x0000},
+
+	{&q6ss_ahbm_clk.c,                   LPASS_BASE, 0x001d},
+	{&q6ss_ahb_lfabif_clk.c,             LPASS_BASE, 0x001e},
+
+	{&a7_m_clk,			  APCS_GCC_BASE,    0x3},
+	{&dummy_clk,				N_BASES, 0x0000},
+};
+
+static int measure_clk_set_parent(struct clk *c, struct clk *parent)
+{
+	struct measure_clk *clk = to_measure_clk(c);
+	unsigned long flags;
+	u32 regval, clk_sel, i;
+
+	if (!parent)
+		return -EINVAL;
+
+	for (i = 0; i < (ARRAY_SIZE(measure_mux) - 1); i++)
+		if (measure_mux[i].c == parent)
+			break;
+
+	if (measure_mux[i].c == &dummy_clk)
+		return -EINVAL;
+
+	spin_lock_irqsave(&local_clock_reg_lock, flags);
+	/*
+	 * Program the test vector, measurement period (sample_ticks)
+	 * and scaling multiplier.
+	 */
+	clk->sample_ticks = 0x10000;
+	clk->multiplier = 1;
+
+	writel_relaxed(0, GCC_REG_BASE(GCC_DEBUG_CLK_CTL));
+
+	switch (measure_mux[i].base) {
+
+	case GCC_BASE:
+		clk_sel = measure_mux[i].debug_mux;
+		break;
+
+	case APCS_GCC_BASE:
+		clk_sel = 0x16A;
+		regval = BVAL(5, 3, measure_mux[i].debug_mux);
+		writel_relaxed(regval, APCS_GCC_BASE(APCS_CLK_DIAG));
+		break;
+
+	default:
+		return -EINVAL;
+	}
+
+	/* Set debug mux clock index */
+	regval = BVAL(9, 0, clk_sel);
+	writel_relaxed(regval, GCC_REG_BASE(GCC_DEBUG_CLK_CTL));
+
+	/* Activate debug clock output */
+	regval |= BIT(16);
+	writel_relaxed(regval, GCC_REG_BASE(GCC_DEBUG_CLK_CTL));
+
+	/* Make sure test vector is set before starting measurements. */
+	mb();
+	spin_unlock_irqrestore(&local_clock_reg_lock, flags);
+
+	return 0;
+}
+
+/* Sample clock for 'ticks' reference clock ticks. */
+static u32 run_measurement(unsigned ticks)
+{
+	/* Stop counters and set the XO4 counter start value. */
+	writel_relaxed(ticks, GCC_REG_BASE(CLOCK_FRQ_MEASURE_CTL));
+
+	/* Wait for timer to become ready. */
+	while ((readl_relaxed(GCC_REG_BASE(CLOCK_FRQ_MEASURE_STATUS)) &
+			BIT(25)) != 0)
+		cpu_relax();
+
+	/* Run measurement and wait for completion. */
+	writel_relaxed(BIT(20)|ticks, GCC_REG_BASE(CLOCK_FRQ_MEASURE_CTL));
+	while ((readl_relaxed(GCC_REG_BASE(CLOCK_FRQ_MEASURE_STATUS)) &
+			BIT(25)) == 0)
+		cpu_relax();
+
+	/* Return measured ticks. */
+	return readl_relaxed(GCC_REG_BASE(CLOCK_FRQ_MEASURE_STATUS)) &
+				BM(24, 0);
+}
+
+/*
+ * Perform a hardware rate measurement for a given clock.
+ * FOR DEBUG USE ONLY: Measurements take ~15 ms!
+ */
+static unsigned long measure_clk_get_rate(struct clk *c)
+{
+	unsigned long flags;
+	u32 gcc_xo4_reg_backup;
+	u64 raw_count_short, raw_count_full;
+	struct measure_clk *clk = to_measure_clk(c);
+	unsigned ret;
+
+	ret = clk_prepare_enable(&xo.c);
+	if (ret) {
+		pr_warning("CXO clock failed to enable. Can't measure\n");
+		return 0;
+	}
+
+	spin_lock_irqsave(&local_clock_reg_lock, flags);
+
+	/* Enable CXO/4 and RINGOSC branch. */
+	gcc_xo4_reg_backup = readl_relaxed(GCC_REG_BASE(GCC_XO_DIV4_CBCR));
+	writel_relaxed(0x1, GCC_REG_BASE(GCC_XO_DIV4_CBCR));
+
+	/*
+	 * The ring oscillator counter will not reset if the measured clock
+	 * is not running.  To detect this, run a short measurement before
+	 * the full measurement.  If the raw results of the two are the same
+	 * then the clock must be off.
+	 */
+
+	/* Run a short measurement. (~1 ms) */
+	raw_count_short = run_measurement(0x1000);
+	/* Run a full measurement. (~14 ms) */
+	raw_count_full = run_measurement(clk->sample_ticks);
+
+	writel_relaxed(gcc_xo4_reg_backup, GCC_REG_BASE(GCC_XO_DIV4_CBCR));
+
+	/* Return 0 if the clock is off. */
+	if (raw_count_full == raw_count_short) {
+		ret = 0;
+	} else {
+		/* Compute rate in Hz. */
+		raw_count_full = ((raw_count_full * 10) + 15) * 4800000;
+		do_div(raw_count_full, ((clk->sample_ticks * 10) + 35));
+		ret = (raw_count_full * clk->multiplier);
+	}
+
+	writel_relaxed(0x51A00, GCC_REG_BASE(PLLTEST_PAD_CFG));
+	spin_unlock_irqrestore(&local_clock_reg_lock, flags);
+
+	clk_disable_unprepare(&xo.c);
+
+	return ret;
+}
+#else /* !CONFIG_DEBUG_FS */
+static int measure_clk_set_parent(struct clk *clk, struct clk *parent)
+{
+	return -EINVAL;
+}
+
+static unsigned long measure_clk_get_rate(struct clk *clk)
+{
+	return 0;
+}
+#endif /* CONFIG_DEBUG_FS */
+
+static struct clk_ops clk_ops_measure = {
+	.set_parent = measure_clk_set_parent,
+	.get_rate = measure_clk_get_rate,
+};
+
+static struct measure_clk measure_clk = {
+	.c = {
+		.dbg_name = "measure_clk",
+		.ops = &clk_ops_measure,
+		CLK_INIT(measure_clk.c),
+	},
+	.multiplier = 1,
+};
+
+static struct clk_lookup msm_clocks_krypton[] = {
+	CLK_LOOKUP("xo",	xo.c,	""),
+	CLK_LOOKUP("measure",	measure_clk.c,	"debug"),
+
+	/* PLLS */
+	CLK_LOOKUP("",	gpll0.c,	""),
+	CLK_LOOKUP("",	gpll1.c,	""),
+	CLK_LOOKUP("",  gpll0_ao.c,     ""),
+
+	/* PIL-LPASS */
+	CLK_LOOKUP("xo",          cxo_pil_lpass_clk.c, "fe200000.qcom,lpass"),
+	CLK_LOOKUP("bus_clk",  gcc_lpass_q6_axi_clk.c, "fe200000.qcom,lpass"),
+	CLK_LOOKUP("core_clk",    cxo_pil_lpass_clk.c, "fe200000.qcom,lpass"),
+	CLK_LOOKUP("iface_clk", q6ss_ahb_lfabif_clk.c, "fe200000.qcom,lpass"),
+	CLK_LOOKUP("reg_clk",         q6ss_ahbm_clk.c, "fe200000.qcom,lpass"),
+
+	/* PIL-MODEM */
+	CLK_LOOKUP("xo",              cxo_pil_mss_clk.c, "fc880000.qcom,mss"),
+	CLK_LOOKUP("bus_clk", gcc_mss_q6_bimc_axi_clk.c, "fc880000.qcom,mss"),
+	CLK_LOOKUP("iface_clk",   gcc_mss_cfg_ahb_clk.c, "fc880000.qcom,mss"),
+	CLK_LOOKUP("mem_clk",    gcc_boot_rom_ahb_clk.c, "fc880000.qcom,mss"),
+
+	/* SPS */
+	CLK_LOOKUP("dma_bam_pclk", gcc_bam_dma_ahb_clk.c, "msm_sps"),
+	CLK_LOOKUP("inactivity_clk", gcc_bam_dma_inactivity_timers_clk.c,
+								"msm_sps"),
+	CLK_LOOKUP("dfab_clk", pnoc_sps_clk.c, "msm_sps"),
+
+
+	CLK_LOOKUP("iface_clk", gcc_blsp1_ahb_clk.c, "f991f000.serial"),
+	CLK_LOOKUP("core_clk", gcc_blsp1_uart3_apps_clk.c, "f991f000.serial"),
+
+	CLK_LOOKUP("iface_clk", gcc_blsp1_ahb_clk.c, "f9928000.spi"),
+	CLK_LOOKUP("core_clk", gcc_blsp1_qup6_spi_apps_clk.c, "f9928000.spi"),
+
+	CLK_LOOKUP("iface_clk", gcc_blsp1_ahb_clk.c, "f9925000.i2c"),
+	CLK_LOOKUP("core_clk", gcc_blsp1_qup3_i2c_apps_clk.c, "f9925000.i2c"),
+
+	CLK_LOOKUP("iface_clk", gcc_blsp1_ahb_clk.c, "f991d000.uart"),
+	CLK_LOOKUP("core_clk", gcc_blsp1_uart1_apps_clk.c, "f991d000.uart"),
+
+	CLK_LOOKUP("core_clk", gcc_blsp1_qup1_i2c_apps_clk.c, ""),
+	CLK_LOOKUP("core_clk", gcc_blsp1_qup1_spi_apps_clk.c, ""),
+	CLK_LOOKUP("core_clk", gcc_blsp1_qup2_i2c_apps_clk.c, ""),
+	CLK_LOOKUP("core_clk", gcc_blsp1_qup2_spi_apps_clk.c, ""),
+	CLK_LOOKUP("core_clk", gcc_blsp1_qup3_spi_apps_clk.c, ""),
+	CLK_LOOKUP("core_clk", gcc_blsp1_qup4_i2c_apps_clk.c, ""),
+	CLK_LOOKUP("core_clk", gcc_blsp1_qup4_spi_apps_clk.c, ""),
+	CLK_LOOKUP("core_clk", gcc_blsp1_qup5_i2c_apps_clk.c, ""),
+	CLK_LOOKUP("core_clk", gcc_blsp1_qup5_spi_apps_clk.c, ""),
+	CLK_LOOKUP("core_clk", gcc_blsp1_qup6_i2c_apps_clk.c, ""),
+	CLK_LOOKUP("core_clk", gcc_blsp1_qup6_spi_apps_clk.c, ""),
+
+	CLK_LOOKUP("core_clk", gcc_blsp1_uart2_apps_clk.c, ""),
+	CLK_LOOKUP("core_clk", gcc_blsp1_uart4_apps_clk.c, ""),
+	CLK_LOOKUP("core_clk", gcc_blsp1_uart5_apps_clk.c, ""),
+	CLK_LOOKUP("core_clk", gcc_blsp1_uart6_apps_clk.c, ""),
+
+	CLK_LOOKUP("iface_clk", gcc_prng_ahb_clk.c, "f9bff000.qcom,msm-rng"),
+
+	CLK_LOOKUP("core_clk", gcc_pdm2_clk.c, ""),
+	CLK_LOOKUP("iface_clk", gcc_pdm_ahb_clk.c, ""),
+
+	CLK_LOOKUP("iface_clk", gcc_sdcc2_ahb_clk.c, "msm_sdcc.2"),
+	CLK_LOOKUP("core_clk", gcc_sdcc2_apps_clk.c, "msm_sdcc.2"),
+	CLK_LOOKUP("bus_clk",  pnoc_sdcc2_clk.c, "msm_sdcc.2"),
+	CLK_LOOKUP("iface_clk", gcc_sdcc3_ahb_clk.c, "msm_sdcc.3"),
+	CLK_LOOKUP("core_clk", gcc_sdcc3_apps_clk.c, "msm_sdcc.3"),
+	CLK_LOOKUP("bus_clk", pnoc_sdcc3_clk.c, "msm_sdcc.3"),
+
+	CLK_LOOKUP("iface_clk", gcc_usb_hs_ahb_clk.c,     "f9a55000.usb"),
+	CLK_LOOKUP("core_clk", gcc_usb_hs_system_clk.c,   "f9a55000.usb"),
+	CLK_LOOKUP("iface_clk", gcc_usb_hsic_ahb_clk.c,	  "msm_hsic_host"),
+	CLK_LOOKUP("phy_clk", gcc_usb_hsic_clk.c,	  "msm_hsic_host"),
+	CLK_LOOKUP("cal_clk", gcc_usb_hsic_io_cal_clk.c,  "msm_hsic_host"),
+	CLK_LOOKUP("core_clk", gcc_usb_hsic_system_clk.c, "msm_hsic_host"),
+	CLK_LOOKUP("alt_core_clk", gcc_usb_hsic_xcvr_fs_clk.c, ""),
+	CLK_LOOKUP("inactivity_clk", gcc_usb_hsic_io_cal_sleep_clk.c,
+							"msm_hsic_host"),
+
+	CLK_LOOKUP("core_clk", gcc_ce1_clk.c, "fd400000.qcom,qcedev"),
+	CLK_LOOKUP("iface_clk", gcc_ce1_ahb_clk.c, "fd400000.qcom,qcedev"),
+	CLK_LOOKUP("bus_clk", gcc_ce1_axi_clk.c, "fd400000.qcom,qcedev"),
+	CLK_LOOKUP("core_clk_src", ce1_clk_src.c, "fd400000.qcom,qcedev"),
+
+	CLK_LOOKUP("core_clk", gcc_ce1_clk.c, "fd400000.qcom,qcrypto"),
+	CLK_LOOKUP("iface_clk", gcc_ce1_ahb_clk.c, "fd400000.qcom,qcrypto"),
+	CLK_LOOKUP("bus_clk", gcc_ce1_axi_clk.c, "fd400000.qcom,qcrypto"),
+	CLK_LOOKUP("core_clk_src", ce1_clk_src.c, "fd400000.qcom,qcrypto"),
+
+	/* RPM and voter clocks */
+	CLK_LOOKUP("bus_clk", snoc_clk.c, ""),
+	CLK_LOOKUP("bus_clk", pnoc_clk.c, ""),
+	CLK_LOOKUP("bus_clk", cnoc_clk.c, ""),
+	CLK_LOOKUP("mem_clk", bimc_clk.c, ""),
+	CLK_LOOKUP("bus_clk", snoc_a_clk.c, ""),
+	CLK_LOOKUP("bus_clk", pnoc_a_clk.c, ""),
+	CLK_LOOKUP("bus_clk", cnoc_a_clk.c, ""),
+	CLK_LOOKUP("mem_clk", bimc_a_clk.c, ""),
+
+	CLK_LOOKUP("bus_clk",	cnoc_msmbus_clk.c,	"msm_config_noc"),
+	CLK_LOOKUP("bus_a_clk",	cnoc_msmbus_a_clk.c,	"msm_config_noc"),
+	CLK_LOOKUP("bus_clk",	snoc_msmbus_clk.c,	"msm_sys_noc"),
+	CLK_LOOKUP("bus_a_clk",	snoc_msmbus_a_clk.c,	"msm_sys_noc"),
+	CLK_LOOKUP("bus_clk",	pnoc_msmbus_clk.c,	"msm_periph_noc"),
+	CLK_LOOKUP("bus_a_clk",	pnoc_msmbus_a_clk.c,	"msm_periph_noc"),
+	CLK_LOOKUP("mem_clk",	bimc_msmbus_clk.c,	"msm_bimc"),
+	CLK_LOOKUP("mem_a_clk",	bimc_msmbus_a_clk.c,	"msm_bimc"),
+
+	CLK_LOOKUP("a7_m_clk", a7_m_clk, ""),
+
+	/* CoreSight clocks */
+	CLK_LOOKUP("core_clk", qdss_clk.c, "fc322000.tmc"),
+	CLK_LOOKUP("core_clk", qdss_clk.c, "fc318000.tpiu"),
+	CLK_LOOKUP("core_clk", qdss_clk.c, "fc31c000.replicator"),
+	CLK_LOOKUP("core_clk", qdss_clk.c, "fc307000.tmc"),
+	CLK_LOOKUP("core_clk", qdss_clk.c, "fc31b000.funnel"),
+	CLK_LOOKUP("core_clk", qdss_clk.c, "fc319000.funnel"),
+	CLK_LOOKUP("core_clk", qdss_clk.c, "fc31a000.funnel"),
+	CLK_LOOKUP("core_clk", qdss_clk.c, "fc321000.stm"),
+	CLK_LOOKUP("core_clk", qdss_clk.c, "fc332000.etm"),
+	CLK_LOOKUP("core_clk", qdss_clk.c, "fc332000.jtagmm"),
+	CLK_LOOKUP("core_clk", qdss_clk.c, "fc308000.cti"),
+	CLK_LOOKUP("core_clk", qdss_clk.c, "fc309000.cti"),
+	CLK_LOOKUP("core_clk", qdss_clk.c, "fc30a000.cti"),
+	CLK_LOOKUP("core_clk", qdss_clk.c, "fc30b000.cti"),
+	CLK_LOOKUP("core_clk", qdss_clk.c, "fc30c000.cti"),
+	CLK_LOOKUP("core_clk", qdss_clk.c, "fc30d000.cti"),
+	CLK_LOOKUP("core_clk", qdss_clk.c, "fc30e000.cti"),
+	CLK_LOOKUP("core_clk", qdss_clk.c, "fc30f000.cti"),
+	CLK_LOOKUP("core_clk", qdss_clk.c, "fc310000.cti"),
+	CLK_LOOKUP("core_clk", qdss_clk.c, "fc333000.cti"),
+	CLK_LOOKUP("core_clk", qdss_clk.c, "f9011038.hwevent"),
+
+	CLK_LOOKUP("core_a_clk", qdss_a_clk.c, "fc322000.tmc"),
+	CLK_LOOKUP("core_a_clk", qdss_a_clk.c, "fc318000.tpiu"),
+	CLK_LOOKUP("core_a_clk", qdss_a_clk.c, "fc31c000.replicator"),
+	CLK_LOOKUP("core_a_clk", qdss_a_clk.c, "fc307000.tmc"),
+	CLK_LOOKUP("core_a_clk", qdss_a_clk.c, "fc31b000.funnel"),
+	CLK_LOOKUP("core_a_clk", qdss_a_clk.c, "fc319000.funnel"),
+	CLK_LOOKUP("core_a_clk", qdss_a_clk.c, "fc31a000.funnel"),
+	CLK_LOOKUP("core_a_clk", qdss_a_clk.c, "fc321000.stm"),
+	CLK_LOOKUP("core_a_clk", qdss_a_clk.c, "fc332000.etm"),
+	CLK_LOOKUP("core_a_clk", qdss_a_clk.c, "fc332000.jtagmm"),
+	CLK_LOOKUP("core_a_clk", qdss_a_clk.c, "fc308000.cti"),
+	CLK_LOOKUP("core_a_clk", qdss_a_clk.c, "fc309000.cti"),
+	CLK_LOOKUP("core_a_clk", qdss_a_clk.c, "fc30a000.cti"),
+	CLK_LOOKUP("core_a_clk", qdss_a_clk.c, "fc30b000.cti"),
+	CLK_LOOKUP("core_a_clk", qdss_a_clk.c, "fc30c000.cti"),
+	CLK_LOOKUP("core_a_clk", qdss_a_clk.c, "fc30d000.cti"),
+	CLK_LOOKUP("core_a_clk", qdss_a_clk.c, "fc30e000.cti"),
+	CLK_LOOKUP("core_a_clk", qdss_a_clk.c, "fc30f000.cti"),
+	CLK_LOOKUP("core_a_clk", qdss_a_clk.c, "fc310000.cti"),
+	CLK_LOOKUP("core_a_clk", qdss_a_clk.c, "fc333000.cti"),
+	CLK_LOOKUP("core_a_clk", qdss_a_clk.c, "f9011038.hwevent"),
+
+	/* Misc rcgs without clients */
+	CLK_LOOKUP("",	usb30_master_clk_src.c,	""),
+	CLK_LOOKUP("",	blsp1_qup1_i2c_apps_clk_src.c,	""),
+	CLK_LOOKUP("",	blsp1_qup1_spi_apps_clk_src.c,	""),
+	CLK_LOOKUP("",	blsp1_qup2_i2c_apps_clk_src.c,	""),
+	CLK_LOOKUP("",	blsp1_qup2_spi_apps_clk_src.c,	""),
+	CLK_LOOKUP("",	blsp1_qup3_i2c_apps_clk_src.c,	""),
+	CLK_LOOKUP("",	blsp1_qup3_spi_apps_clk_src.c,	""),
+	CLK_LOOKUP("",	blsp1_qup4_i2c_apps_clk_src.c,	""),
+	CLK_LOOKUP("",	blsp1_qup4_spi_apps_clk_src.c,	""),
+	CLK_LOOKUP("",	blsp1_qup5_i2c_apps_clk_src.c,	""),
+	CLK_LOOKUP("",	blsp1_qup5_spi_apps_clk_src.c,	""),
+	CLK_LOOKUP("",	blsp1_qup6_i2c_apps_clk_src.c,	""),
+	CLK_LOOKUP("",	blsp1_qup6_spi_apps_clk_src.c,	""),
+	CLK_LOOKUP("",	blsp1_uart1_apps_clk_src.c,	""),
+	CLK_LOOKUP("",	blsp1_uart2_apps_clk_src.c,	""),
+	CLK_LOOKUP("",	blsp1_uart3_apps_clk_src.c,	""),
+	CLK_LOOKUP("",	blsp1_uart4_apps_clk_src.c,	""),
+	CLK_LOOKUP("",	blsp1_uart5_apps_clk_src.c,	""),
+	CLK_LOOKUP("",	blsp1_uart6_apps_clk_src.c,	""),
+	CLK_LOOKUP("",	pcie_aux_clk_src.c,	""),
+	CLK_LOOKUP("",	pcie_pipe_clk_src.c,	""),
+	CLK_LOOKUP("",	pdm2_clk_src.c,	""),
+	CLK_LOOKUP("",	sdcc2_apps_clk_src.c,	""),
+	CLK_LOOKUP("",	sdcc3_apps_clk_src.c,	""),
+	CLK_LOOKUP("",	usb3_aux_clk_src.c,	""),
+	CLK_LOOKUP("",	usb3_pipe_clk_src.c,	""),
+	CLK_LOOKUP("",	usb30_mock_utmi_clk_src.c,	""),
+	CLK_LOOKUP("",	usb_hs_system_clk_src.c,	""),
+	CLK_LOOKUP("",	usb_hsic_clk_src.c,	""),
+	CLK_LOOKUP("",	usb_hsic_io_cal_clk_src.c,	""),
+	CLK_LOOKUP("",	usb_hsic_system_clk_src.c,	""),
+	CLK_LOOKUP("",	usb_hsic_xcvr_fs_clk_src.c,	""),
+
+	CLK_LOOKUP("",	gcc_pcie_axi_clk.c,	""),
+	CLK_LOOKUP("",	gcc_pcie_axi_mstr_clk.c,	""),
+	CLK_LOOKUP("",	gcc_pcie_cfg_ahb_clk.c,	""),
+	CLK_LOOKUP("",	gcc_pcie_pipe_clk.c,	""),
+	CLK_LOOKUP("",	gcc_pcie_sleep_clk.c,	""),
+	CLK_LOOKUP("",	gcc_sys_noc_usb3_axi_clk.c,	""),
+	CLK_LOOKUP("",	gcc_usb3_aux_clk.c,	""),
+	CLK_LOOKUP("",	gcc_usb3_pipe_clk.c,	""),
+	CLK_LOOKUP("",	gcc_usb30_master_clk.c,	""),
+	CLK_LOOKUP("",	gcc_usb30_mock_utmi_clk.c,	""),
+	CLK_LOOKUP("",	gcc_usb30_sleep_clk.c,	""),
+};
+
+static void __init reg_init(void)
+{
+	u32 regval;
+
+	/* Vote for GPLL0 to turn on. Needed by acpuclock. */
+	regval = readl_relaxed(GCC_REG_BASE(APCS_GPLL_ENA_VOTE));
+	regval |= BIT(0);
+	writel_relaxed(regval, GCC_REG_BASE(APCS_GPLL_ENA_VOTE));
+}
+
+static void __init msmkrypton_clock_post_init(void)
+{
+	/*
+	 * Hold an active set vote for CXO; this is because CXO is expected
+	 * to remain on whenever CPUs aren't power collapsed.
+	 */
+	clk_prepare_enable(&xo_a_clk.c);
+}
+
+#define GCC_CC_PHYS		0xFC400000
+#define GCC_CC_SIZE		SZ_8K
+
+#define LPASS_CC_PHYS		0xFE000000
+#define LPASS_CC_SIZE		SZ_256K
+
+#define APCS_GLB_PHYS		0xF9010000
+#define APCS_GLB_SIZE		0x38
+
+#define APCS_GCC_PHYS		0xF9011000
+#define APCS_GCC_SIZE		0x1C
+
+#define APCS_ACC_PHYS		0xF9008000
+#define APCS_ACC_SIZE		0x40
+
+static void __init msmkrypton_clock_pre_init(void)
+{
+	virt_bases[GCC_BASE] = ioremap(GCC_CC_PHYS, GCC_CC_SIZE);
+	if (!virt_bases[GCC_BASE])
+		panic("clock-krypton: Unable to ioremap GCC memory!");
+
+	virt_bases[LPASS_BASE] = ioremap(LPASS_CC_PHYS, LPASS_CC_SIZE);
+	if (!virt_bases[LPASS_BASE])
+		panic("clock-8226: Unable to ioremap LPASS_CC memory!");
+
+	virt_bases[APCS_GLB_BASE] = ioremap(APCS_GLB_PHYS, APCS_GLB_SIZE);
+	if (!virt_bases[APCS_GLB_BASE])
+		panic("clock-krypton: Unable to ioremap APCS_GLB memory!");
+
+	virt_bases[APCS_GCC_BASE] = ioremap(APCS_GCC_PHYS, APCS_GCC_SIZE);
+	if (!virt_bases[APCS_GCC_BASE])
+		panic("clock-krypton: Unable to ioremap APCS_GCC memory!");
+
+	virt_bases[APCS_ACC_BASE] = ioremap(APCS_ACC_PHYS, APCS_ACC_SIZE);
+	if (!virt_bases[APCS_ACC_BASE])
+		panic("clock-krypton: Unable to ioremap APCS_PLL memory!");
+
+	vdd_dig.regulator[0] = regulator_get(NULL, "vdd_dig");
+	if (IS_ERR(vdd_dig.regulator[0]))
+		panic("clock-krypton: Unable to get the vdd_dig regulator!");
+
+	enable_rpm_scaling();
+
+	reg_init();
+}
+
 struct clock_init_data msmkrypton_clock_init_data __initdata = {
-	.table = msm_clocks_dummy,
-	.size = ARRAY_SIZE(msm_clocks_dummy),
+	.table = msm_clocks_krypton,
+	.size = ARRAY_SIZE(msm_clocks_krypton),
+	.pre_init = msmkrypton_clock_pre_init,
+	.post_init = msmkrypton_clock_post_init,
 };
diff --git a/arch/arm/mach-msm/clock-local2.c b/arch/arm/mach-msm/clock-local2.c
index b7852fe..4488869 100644
--- a/arch/arm/mach-msm/clock-local2.c
+++ b/arch/arm/mach-msm/clock-local2.c
@@ -549,19 +549,21 @@
 	u32 cbcr_val;
 	unsigned long irq_flags;
 	struct branch_clk *branch = to_branch_clk(c);
-	int ret = 0;
+	int delay_us = 0, ret = 0;
 
 	spin_lock_irqsave(&local_clock_reg_lock, irq_flags);
 	cbcr_val = readl_relaxed(CBCR_REG(branch));
 	switch (flags) {
 	case CLKFLAG_RETAIN_PERIPH:
 		cbcr_val |= BIT(13);
+		delay_us = 1;
 		break;
 	case CLKFLAG_NORETAIN_PERIPH:
 		cbcr_val &= ~BIT(13);
 		break;
 	case CLKFLAG_RETAIN_MEM:
 		cbcr_val |= BIT(14);
+		delay_us = 1;
 		break;
 	case CLKFLAG_NORETAIN_MEM:
 		cbcr_val &= ~BIT(14);
@@ -570,17 +572,11 @@
 		ret = -EINVAL;
 	}
 	writel_relaxed(cbcr_val, CBCR_REG(branch));
-	/*
-	 * 8974v2.2 has a requirement that writes to set bits 13 and 14 are
-	 * separated by at least 2 bus cycles. Cover one of these cycles by
-	 * performing an extra write here. The other cycle is covered by the
-	 * read-modify-write design of this function.
-	 */
-	writel_relaxed(cbcr_val, CBCR_REG(branch));
-	spin_unlock_irqrestore(&local_clock_reg_lock, irq_flags);
-
-	/* Make sure write is issued before returning. */
+	/* Make sure power is enabled before returning. */
 	mb();
+	udelay(delay_us);
+
+	spin_unlock_irqrestore(&local_clock_reg_lock, irq_flags);
 
 	return ret;
 }
diff --git a/arch/arm/mach-msm/clock-mdss-8974.c b/arch/arm/mach-msm/clock-mdss-8974.c
index 47332a4..3bb4c57 100644
--- a/arch/arm/mach-msm/clock-mdss-8974.c
+++ b/arch/arm/mach-msm/clock-mdss-8974.c
@@ -31,8 +31,8 @@
 #define DSS_REG_W(base, offset, data)	REG_W((data), (base) + (offset))
 #define DSS_REG_R(base, offset)		REG_R((base) + (offset))
 
-#define GDSC_PHYS		0xFD8C2304
-#define GDSC_SIZE		0x4
+#define GDSC_PHYS		0xFD8C2300
+#define GDSC_SIZE		0x8
 
 #define DSI_PHY_PHYS		0xFD922A00
 #define DSI_PHY_SIZE		0x000000D4
@@ -163,7 +163,8 @@
 	if (!gdsc_base)
 		return 0;
 
-	return !!(readl_relaxed(gdsc_base) & BIT(31));
+	return (readl_relaxed(gdsc_base + 0x4) & BIT(31)) &&
+		(!(readl_relaxed(gdsc_base) & BIT(0)));
 }
 
 void hdmi_pll_disable(void)
@@ -1140,6 +1141,11 @@
 	int i, rc = 0;
 	struct dsi_pll_vco_clk *vco = to_vco_clk(c);
 
+	if (!mdss_gdsc_enabled()) {
+		pr_err("%s: mdss GDSC is not enabled\n", __func__);
+		return -EPERM;
+	}
+
 	rc = clk_enable(mdss_ahb_clk);
 	if (rc) {
 		pr_err("%s: failed to enable mdss ahb clock. rc=%d\n",
@@ -1167,6 +1173,12 @@
 {
 	int rc = 0;
 
+	if (!mdss_gdsc_enabled()) {
+		pr_warn("%s: mdss GDSC disabled before disabling DSI PLL\n",
+			__func__);
+		return;
+	}
+
 	rc = clk_enable(mdss_ahb_clk);
 	if (rc) {
 		pr_err("%s: failed to enable mdss ahb clock. rc=%d\n",
diff --git a/arch/arm/mach-msm/cpr-regulator.c b/arch/arm/mach-msm/cpr-regulator.c
index 60a62ec..59e0e2a 100644
--- a/arch/arm/mach-msm/cpr-regulator.c
+++ b/arch/arm/mach-msm/cpr-regulator.c
@@ -28,6 +28,7 @@
 #include <linux/regulator/driver.h>
 #include <linux/regulator/of_regulator.h>
 #include <linux/regulator/cpr-regulator.h>
+#include <mach/scm.h>
 
 /* Register Offsets for RB-CPR and Bit Definitions */
 
@@ -147,12 +148,15 @@
 	void __iomem	*efuse_base;
 
 	/* Process voltage parameters */
-	u32		pvs_bin_process[CPR_PVS_EFUSE_BINS_MAX];
+	u32		pvs_init_v[CPR_PVS_EFUSE_BINS_MAX];
 	u32		pvs_corner_v[NUM_APC_PVS][CPR_CORNER_MAX];
 	/* Process voltage variables */
 	u32		pvs_bin;
 	u32		process;
 
+	/* Control parameter to read efuse parameters by trustzone API */
+	bool		use_tz_api;
+
 	/* APC voltage regulator */
 	struct regulator	*vdd_apc;
 
@@ -223,6 +227,45 @@
 			pr_debug(message, ##__VA_ARGS__); \
 	} while (0)
 
+
+static u64 cpr_read_efuse_row(struct cpr_regulator *cpr_vreg, u32 row_num)
+{
+	int rc;
+	u64 efuse_bits;
+	struct cpr_read_req {
+		u32 row_address;
+		int addr_type;
+	} req;
+
+	struct cpr_read_rsp {
+		u32 row_data[2];
+		u32 status;
+	} rsp;
+
+	if (cpr_vreg->use_tz_api != true) {
+		efuse_bits = readll_relaxed(cpr_vreg->efuse_base
+			+ row_num * BYTES_PER_FUSE_ROW);
+		return efuse_bits;
+	}
+
+	req.row_address = cpr_vreg->efuse_addr + row_num * BYTES_PER_FUSE_ROW;
+	req.addr_type = 0;
+	efuse_bits = 0;
+
+	rc = scm_call(SCM_SVC_FUSE, SCM_FUSE_READ,
+			&req, sizeof(req), &rsp, sizeof(rsp));
+
+	if (rc) {
+		pr_err("read row %d failed, err code = %d", row_num, rc);
+	} else {
+		efuse_bits = ((u64)(rsp.row_data[1]) << 32) +
+				(u64)rsp.row_data[0];
+	}
+
+	return efuse_bits;
+}
+
+
 static bool cpr_is_allowed(struct cpr_regulator *cpr_vreg)
 {
 	if (cpr_vreg->cpr_fuse_disable || !cpr_enable)
@@ -933,18 +976,17 @@
 static int __devinit cpr_is_fuse_redundant(struct cpr_regulator *cpr_vreg,
 					 u32 redun_sel[4])
 {
-	u32 fuse_bits;
+	u64 fuse_bits;
 	int redundant;
 
-	fuse_bits = readl_relaxed(cpr_vreg->efuse_base
-				  + redun_sel[0] * BYTES_PER_FUSE_ROW);
+	fuse_bits = cpr_read_efuse_row(cpr_vreg, redun_sel[0]);
 	fuse_bits = (fuse_bits >> redun_sel[1]) & ((1 << redun_sel[2]) - 1);
 	if (fuse_bits == redun_sel[3])
 		redundant = 1;
 	else
 		redundant = 0;
 
-	pr_info("[row:%d] = 0x%x @%d:%d = %d?: redundant=%d\n",
+	pr_info("[row:%d] = 0x%llx @%d:%d = %d?: redundant=%d\n",
 		redun_sel[0], fuse_bits,
 		redun_sel[1], redun_sel[2], redun_sel[3], redundant);
 	return redundant;
@@ -954,9 +996,10 @@
 			       struct cpr_regulator *cpr_vreg)
 {
 	struct device_node *of_node = pdev->dev.of_node;
-	u32 efuse_bits;
+	u64 efuse_bits;
 	int rc, process;
 	u32 pvs_fuse[3], pvs_fuse_redun_sel[4];
+	u32 init_v;
 	bool redundant;
 	size_t pvs_bins;
 
@@ -986,31 +1029,41 @@
 	}
 
 	/* Construct PVS process # from the efuse bits */
-	efuse_bits = readl_relaxed(cpr_vreg->efuse_base +
-				   pvs_fuse[0] * BYTES_PER_FUSE_ROW);
+
+	efuse_bits = cpr_read_efuse_row(cpr_vreg, pvs_fuse[0]);
 	cpr_vreg->pvs_bin = (efuse_bits >> pvs_fuse[1]) &
 				   ((1 << pvs_fuse[2]) - 1);
 
 	pvs_bins = 1 << pvs_fuse[2];
-	rc = of_property_read_u32_array(of_node, "qcom,pvs-bin-process",
-					cpr_vreg->pvs_bin_process,
-					pvs_bins);
+
+	rc = of_property_read_u32_array(of_node, "qcom,pvs-init-voltage",
+					cpr_vreg->pvs_init_v, pvs_bins);
 	if (rc < 0) {
-		pr_err("pvs-bin-process missing: rc=%d\n", rc);
+		pr_err("pvs-init-voltage missing: rc=%d\n", rc);
 		return rc;
 	}
 
-	process = cpr_vreg->pvs_bin_process[cpr_vreg->pvs_bin];
-	pr_info("[row:%d] = 0x%08X, n_bits=%d, bin=%d (%d)\n",
-		pvs_fuse[0], efuse_bits, pvs_fuse[2],
-		cpr_vreg->pvs_bin, process);
+	init_v = cpr_vreg->pvs_init_v[cpr_vreg->pvs_bin];
+	for (process = NUM_APC_PVS - 1; process > APC_PVS_NO; process--) {
+		if (init_v <= cpr_vreg->pvs_corner_v[process][CPR_CORNER_TURBO])
+			break;
+	}
 
-	if (process == APC_PVS_NO || process >= NUM_APC_PVS) {
-		pr_err("Bin=%d (%d) is out of spec. Assume SLOW.\n",
-		       cpr_vreg->pvs_bin, process);
+	if (process == APC_PVS_NO) {
+		process = APC_PVS_SLOW;
+		cpr_vreg->pvs_corner_v[process][CPR_CORNER_TURBO] = init_v;
+		cpr_vreg->ceiling_max = init_v;
+	} else if (process == APC_PVS_FAST &&
+		init_v < cpr_vreg->pvs_corner_v[APC_PVS_FAST][CPR_CORNER_SVS]) {
 		process = APC_PVS_SLOW;
 	}
 
+	pr_info("[row:%d] = 0x%llX, n_bits=%d, bin=%d (%d)",
+		pvs_fuse[0], efuse_bits, pvs_fuse[2],
+		cpr_vreg->pvs_bin, process);
+	pr_info("pvs initial turbo voltage_= from %u to %u\n",
+		init_v, cpr_vreg->pvs_corner_v[process][CPR_CORNER_TURBO]);
+
 	cpr_vreg->process = process;
 
 	return 0;
@@ -1147,8 +1200,7 @@
 	}
 
 	/* Read the control bits of eFuse */
-	fuse_bits = readll_relaxed(cpr_vreg->efuse_base
-				   + cpr_fuse_row * BYTES_PER_FUSE_ROW);
+	fuse_bits = cpr_read_efuse_row(cpr_vreg, cpr_fuse_row);
 	pr_info("[row:%d] = 0x%llx\n", cpr_fuse_row, fuse_bits);
 
 	if (redundant) {
@@ -1175,8 +1227,8 @@
 					  &temp_row, rc);
 			if (rc)
 				return rc;
-			fuse_bits_2 = readll_relaxed(cpr_vreg->efuse_base
-					+ temp_row * BYTES_PER_FUSE_ROW);
+
+			fuse_bits_2 = cpr_read_efuse_row(cpr_vreg, temp_row);
 			pr_info("[original row:%d] = 0x%llx\n",
 				temp_row, fuse_bits_2);
 		}
@@ -1391,6 +1443,7 @@
 		pr_err("efuse_addr missing: res=%p\n", res);
 		return -EINVAL;
 	}
+
 	cpr_vreg->efuse_addr = res->start;
 	len = res->end - res->start + 1;
 
@@ -1402,6 +1455,12 @@
 				cpr_vreg->efuse_addr);
 		return -EINVAL;
 	}
+
+	if (of_property_read_bool(pdev->dev.of_node, "qcom,use-tz-api"))
+		cpr_vreg->use_tz_api = true;
+	else
+		cpr_vreg->use_tz_api = false;
+
 	return 0;
 }
 
diff --git a/arch/arm/mach-msm/cpufreq.c b/arch/arm/mach-msm/cpufreq.c
index e02df3e..a6c86af 100644
--- a/arch/arm/mach-msm/cpufreq.c
+++ b/arch/arm/mach-msm/cpufreq.c
@@ -27,6 +27,7 @@
 #include <linux/cpumask.h>
 #include <linux/sched.h>
 #include <linux/suspend.h>
+#include <trace/events/power.h>
 #include <mach/socinfo.h>
 #include <mach/cpufreq.h>
 
@@ -98,9 +99,12 @@
 
 	cpufreq_notify_transition(&freqs, CPUFREQ_PRECHANGE);
 
+	trace_cpu_frequency_switch_start(freqs.old, freqs.new, policy->cpu);
 	ret = acpuclk_set_rate(policy->cpu, new_freq, SETRATE_CPUFREQ);
-	if (!ret)
+	if (!ret) {
+		trace_cpu_frequency_switch_end(policy->cpu);
 		cpufreq_notify_transition(&freqs, CPUFREQ_POSTCHANGE);
+	}
 
 	/* Restore priority after clock ramp-up */
 	if (freqs.new > freqs.old && saved_sched_policy >= 0) {
diff --git a/arch/arm/mach-msm/devices-8064.c b/arch/arm/mach-msm/devices-8064.c
index 4daccb1..2fd1bf3 100644
--- a/arch/arm/mach-msm/devices-8064.c
+++ b/arch/arm/mach-msm/devices-8064.c
@@ -2634,11 +2634,12 @@
 
 static struct msm_rpm_master_stats_platform_data msm_rpm_master_stat_pdata = {
 	.masters = master_names,
-	.nomasters = ARRAY_SIZE(master_names),
+	.num_masters = ARRAY_SIZE(master_names),
+	.master_offset = 32,
 };
 
 struct platform_device apq8064_rpm_master_stat_device = {
-	.name = "msm_rpm_master_stat",
+	.name = "msm_rpm_master_stats",
 	.id = -1,
 	.num_resources	= ARRAY_SIZE(resources_rpm_master_stats),
 	.resource	= resources_rpm_master_stats,
diff --git a/arch/arm/mach-msm/devices-8930.c b/arch/arm/mach-msm/devices-8930.c
index e2a57f9..c4fe0df 100644
--- a/arch/arm/mach-msm/devices-8930.c
+++ b/arch/arm/mach-msm/devices-8930.c
@@ -610,11 +610,12 @@
 
 static struct msm_rpm_master_stats_platform_data msm_rpm_master_stat_pdata = {
 	.masters = master_names,
-	.nomasters = ARRAY_SIZE(master_names),
+	.num_masters = ARRAY_SIZE(master_names),
+	.master_offset = 32,
 };
 
 struct platform_device msm8930_rpm_master_stat_device = {
-	.name = "msm_rpm_master_stat",
+	.name = "msm_rpm_master_stats",
 	.id = -1,
 	.num_resources	= ARRAY_SIZE(resources_rpm_master_stats),
 	.resource	= resources_rpm_master_stats,
diff --git a/arch/arm/mach-msm/devices-8960.c b/arch/arm/mach-msm/devices-8960.c
index 71f58a6..6664e17 100644
--- a/arch/arm/mach-msm/devices-8960.c
+++ b/arch/arm/mach-msm/devices-8960.c
@@ -4018,11 +4018,12 @@
 
 static struct msm_rpm_master_stats_platform_data msm_rpm_master_stat_pdata = {
 	.masters = master_names,
-	.nomasters = ARRAY_SIZE(master_names),
+	.num_masters = ARRAY_SIZE(master_names),
+	.master_offset = 32,
 };
 
 struct platform_device msm8960_rpm_master_stat_device = {
-	.name = "msm_rpm_master_stat",
+	.name = "msm_rpm_master_stats",
 	.id = -1,
 	.num_resources	= ARRAY_SIZE(resources_rpm_master_stats),
 	.resource	= resources_rpm_master_stats,
diff --git a/arch/arm/mach-msm/devices-9615.c b/arch/arm/mach-msm/devices-9615.c
index 483d8b3..6a48646 100644
--- a/arch/arm/mach-msm/devices-9615.c
+++ b/arch/arm/mach-msm/devices-9615.c
@@ -1431,11 +1431,12 @@
 
 static struct msm_rpm_master_stats_platform_data msm_rpm_master_stat_pdata = {
 	.masters = master_names,
-	.nomasters = ARRAY_SIZE(master_names),
+	.num_masters = ARRAY_SIZE(master_names),
+	.master_offset = 32,
 };
 
 struct platform_device msm9615_rpm_master_stat_device = {
-	.name = "msm_rpm_master_stat",
+	.name = "msm_rpm_master_stats",
 	.id = -1,
 	.num_resources	= ARRAY_SIZE(resources_rpm_master_stats),
 	.resource	= resources_rpm_master_stats,
diff --git a/arch/arm/mach-msm/early_random.c b/arch/arm/mach-msm/early_random.c
new file mode 100644
index 0000000..e315b86
--- /dev/null
+++ b/arch/arm/mach-msm/early_random.c
@@ -0,0 +1,83 @@
+/* Copyright (c) 2013, The Linux Foundation. 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 and
+ * only 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/kernel.h>
+
+#include <mach/scm.h>
+
+#include <asm/io.h>
+#include <asm/cacheflush.h>
+
+#define TZ_SVC_CRYPTO	10
+#define PRNG_CMD_ID	0x01
+
+static int use_arch_random = 1;
+struct tz_prng_data {
+	uint8_t		*out_buf;
+	uint32_t	out_buf_sz;
+} __packed;
+
+DEFINE_SCM_BUFFER(common_scm_buf)
+DEFINE_MUTEX(arch_random_lock);
+#define RANDOM_BUFFER_SIZE	PAGE_SIZE
+char random_buffer[RANDOM_BUFFER_SIZE] __aligned(PAGE_SIZE);
+
+int arch_get_random_common(void *v, size_t size)
+{
+	struct tz_prng_data data;
+	int ret;
+	u32 resp;
+
+	if (!use_arch_random)
+		return 0;
+
+	if (size > sizeof(random_buffer))
+		return 0;
+
+	mutex_lock(&arch_random_lock);
+	data.out_buf = (uint8_t *) virt_to_phys(random_buffer);
+	data.out_buf_sz = size;
+
+	ret = scm_call_noalloc(TZ_SVC_CRYPTO, PRNG_CMD_ID, &data,
+			sizeof(data), &resp, sizeof(resp),
+			common_scm_buf, SCM_BUFFER_SIZE(common_scm_buf));
+	if (!ret) {
+		dmac_inv_range(random_buffer, random_buffer +
+						RANDOM_BUFFER_SIZE);
+		outer_inv_range(
+			(unsigned long) virt_to_phys(random_buffer),
+			(unsigned long) virt_to_phys(random_buffer) +
+						RANDOM_BUFFER_SIZE);
+		memcpy(v, random_buffer, size);
+	}
+	mutex_unlock(&arch_random_lock);
+	return !ret;
+}
+
+int arch_get_random_long(unsigned long *v)
+{
+	return arch_get_random_common(v, sizeof(unsigned long));
+}
+
+int arch_get_random_int(unsigned int *v)
+{
+	return arch_get_random_common(v, sizeof(unsigned int));
+}
+
+int arch_random_init(void)
+{
+	use_arch_random = 0;
+
+	return 0;
+}
+module_init(arch_random_init);
diff --git a/arch/arm/mach-msm/gdsc.c b/arch/arm/mach-msm/gdsc.c
index 774548c..ea4865d 100644
--- a/arch/arm/mach-msm/gdsc.c
+++ b/arch/arm/mach-msm/gdsc.c
@@ -111,6 +111,13 @@
 	uint32_t regval;
 	int i, ret = 0;
 
+	for (i = sc->clock_count-1; i >= 0; i--) {
+		if (sc->toggle_mem)
+			clk_set_flags(sc->clocks[i], CLKFLAG_NORETAIN_MEM);
+		if (sc->toggle_periph)
+			clk_set_flags(sc->clocks[i], CLKFLAG_NORETAIN_PERIPH);
+	}
+
 	if (sc->toggle_logic) {
 		regval = readl_relaxed(sc->gdscr);
 		regval |= SW_COLLAPSE_MASK;
@@ -123,18 +130,11 @@
 			dev_err(&rdev->dev, "%s disable timed out\n",
 				sc->rdesc.name);
 	} else {
-		for (i = 0; i < sc->clock_count; i++)
+		for (i = sc->clock_count-1; i >= 0; i--)
 			clk_reset(sc->clocks[i], CLK_RESET_ASSERT);
 		sc->resets_asserted = true;
 	}
 
-	for (i = 0; i < sc->clock_count; i++) {
-		if (sc->toggle_mem)
-			clk_set_flags(sc->clocks[i], CLKFLAG_NORETAIN_MEM);
-		if (sc->toggle_periph)
-			clk_set_flags(sc->clocks[i], CLKFLAG_NORETAIN_PERIPH);
-	}
-
 	return ret;
 }
 
@@ -225,20 +225,9 @@
 
 	retain_mem = of_property_read_bool(pdev->dev.of_node,
 					    "qcom,retain-mem");
+	sc->toggle_mem = !retain_mem;
 	retain_periph = of_property_read_bool(pdev->dev.of_node,
 					    "qcom,retain-periph");
-	for (i = 0; i < sc->clock_count; i++) {
-		if (retain_mem || (regval & PWR_ON_MASK))
-			clk_set_flags(sc->clocks[i], CLKFLAG_RETAIN_MEM);
-		else
-			clk_set_flags(sc->clocks[i], CLKFLAG_NORETAIN_MEM);
-
-		if (retain_periph || (regval & PWR_ON_MASK))
-			clk_set_flags(sc->clocks[i], CLKFLAG_RETAIN_PERIPH);
-		else
-			clk_set_flags(sc->clocks[i], CLKFLAG_NORETAIN_PERIPH);
-	}
-	sc->toggle_mem = !retain_mem;
 	sc->toggle_periph = !retain_periph;
 	sc->toggle_logic = !of_property_read_bool(pdev->dev.of_node,
 						"qcom,skip-logic-collapse");
@@ -255,6 +244,18 @@
 		}
 	}
 
+	for (i = 0; i < sc->clock_count; i++) {
+		if (retain_mem || (regval & PWR_ON_MASK))
+			clk_set_flags(sc->clocks[i], CLKFLAG_RETAIN_MEM);
+		else
+			clk_set_flags(sc->clocks[i], CLKFLAG_NORETAIN_MEM);
+
+		if (retain_periph || (regval & PWR_ON_MASK))
+			clk_set_flags(sc->clocks[i], CLKFLAG_RETAIN_PERIPH);
+		else
+			clk_set_flags(sc->clocks[i], CLKFLAG_NORETAIN_PERIPH);
+	}
+
 	sc->rdev = regulator_register(&sc->rdesc, &pdev->dev, init_data, sc,
 				      pdev->dev.of_node);
 	if (IS_ERR(sc->rdev)) {
diff --git a/arch/arm/mach-msm/include/mach/camera2.h b/arch/arm/mach-msm/include/mach/camera2.h
index 887c594..a9da79e 100644
--- a/arch/arm/mach-msm/include/mach/camera2.h
+++ b/arch/arm/mach-msm/include/mach/camera2.h
@@ -114,6 +114,7 @@
 
 struct eeprom_memory_map_t {
 	struct eeprom_map_t page;
+	struct eeprom_map_t pageen;
 	struct eeprom_map_t poll;
 	struct eeprom_map_t mem;
 };
diff --git a/arch/arm/mach-msm/include/mach/gpio.h b/arch/arm/mach-msm/include/mach/gpio.h
index bfcce73..45be31f 100644
--- a/arch/arm/mach-msm/include/mach/gpio.h
+++ b/arch/arm/mach-msm/include/mach/gpio.h
@@ -1,6 +1,6 @@
 /*
  * Copyright (C) 2007 Google, Inc.
- * Copyright (c) 2009-2012, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2009-2013, The Linux Foundation. All rights reserved.
  * Author: Mike Lockwood <lockwood@android.com>
  *
  * This software is licensed under the terms of the GNU General Public
@@ -188,6 +188,7 @@
 	TLMM_PULL_SDC1_CLK,
 	TLMM_PULL_SDC1_CMD,
 	TLMM_PULL_SDC1_DATA,
+	TLMM_PULL_SDC1_RCLK,
 };
 
 #if defined(CONFIG_GPIO_MSM_V2) || defined(CONFIG_GPIO_MSM_V3)
diff --git a/arch/arm/mach-msm/include/mach/gpiomux.h b/arch/arm/mach-msm/include/mach/gpiomux.h
index 9aae3fb..bd1a4a2 100644
--- a/arch/arm/mach-msm/include/mach/gpiomux.h
+++ b/arch/arm/mach-msm/include/mach/gpiomux.h
@@ -113,6 +113,7 @@
 enum msm_tlmm_misc_reg {
 	TLMM_ETM_MODE_REG = 0x2014,
 	TLMM_SDC2_HDRV_PULL_CTL = 0x2048,
+	TLMM_SPARE_REG = 0x2024,
 };
 
 void msm_tlmm_misc_reg_write(enum msm_tlmm_misc_reg misc_reg, int val);
diff --git a/arch/arm/mach-msm/include/mach/msm_smd.h b/arch/arm/mach-msm/include/mach/msm_smd.h
index 2653ae4..cd07662 100644
--- a/arch/arm/mach-msm/include/mach/msm_smd.h
+++ b/arch/arm/mach-msm/include/mach/msm_smd.h
@@ -316,6 +316,15 @@
  */
 int __init msm_smd_init(void);
 
+/**
+ * smd_remote_ss_to_edge() - return edge type from remote ss type
+ * @name:	remote subsystem name
+ *
+ * Returns the edge type connected between the local subsystem(APPS)
+ * and remote subsystem @name.
+ */
+int smd_remote_ss_to_edge(const char *name);
+
 #else
 
 static inline int smd_open(const char *name, smd_channel_t **ch, void *priv,
@@ -447,6 +456,11 @@
 {
 	return 0;
 }
+
+static inline int smd_remote_ss_to_edge(const char *name)
+{
+	return -EINVAL;
+}
 #endif
 
 #endif
diff --git a/arch/arm/mach-msm/include/mach/msm_smem.h b/arch/arm/mach-msm/include/mach/msm_smem.h
index a121791..5556db9 100644
--- a/arch/arm/mach-msm/include/mach/msm_smem.h
+++ b/arch/arm/mach-msm/include/mach/msm_smem.h
@@ -27,7 +27,6 @@
 };
 
 #define SMEM_NUM_SMD_STREAM_CHANNELS        64
-#define SMEM_NUM_SMD_BLOCK_CHANNELS         64
 
 enum {
 	/* fixed items */
@@ -87,13 +86,13 @@
 	SMEM_ID_VENDOR1,
 	SMEM_ID_VENDOR2,
 	SMEM_HW_SW_BUILD_ID,
-	SMEM_SMD_BLOCK_PORT_BASE_ID,
-	SMEM_SMD_BLOCK_PORT_PROC0_HEAP = SMEM_SMD_BLOCK_PORT_BASE_ID +
-						SMEM_NUM_SMD_BLOCK_CHANNELS,
-	SMEM_SMD_BLOCK_PORT_PROC1_HEAP = SMEM_SMD_BLOCK_PORT_PROC0_HEAP +
-						SMEM_NUM_SMD_BLOCK_CHANNELS,
-	SMEM_I2C_MUTEX = SMEM_SMD_BLOCK_PORT_PROC1_HEAP +
-						SMEM_NUM_SMD_BLOCK_CHANNELS,
+	SMEM_SMD_BASE_ID_2,
+	SMEM_SMD_FIFO_BASE_ID_2 = SMEM_SMD_BASE_ID_2 +
+						SMEM_NUM_SMD_STREAM_CHANNELS,
+	SMEM_CHANNEL_ALLOC_TBL_2 = SMEM_SMD_FIFO_BASE_ID_2 +
+						SMEM_NUM_SMD_STREAM_CHANNELS,
+	SMEM_I2C_MUTEX = SMEM_CHANNEL_ALLOC_TBL_2 +
+						SMEM_NUM_SMD_STREAM_CHANNELS,
 	SMEM_SCLK_CONVERSION,
 	SMEM_SMD_SMSM_INTR_MUX,
 	SMEM_SMSM_CPU_INTR_MASK,
diff --git a/arch/arm/mach-msm/include/mach/qdsp6v2/rtac.h b/arch/arm/mach-msm/include/mach/qdsp6v2/rtac.h
index 07be428..0a1cdd4 100644
--- a/arch/arm/mach-msm/include/mach/qdsp6v2/rtac.h
+++ b/arch/arm/mach-msm/include/mach/qdsp6v2/rtac.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2011, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2011, 2013, The Linux Foundation. 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 and
@@ -19,6 +19,31 @@
 #define RTAC_CVS		1
 #define RTAC_VOICE_MODES	2
 
+enum {
+	ADM_RTAC_CAL,
+	ASM_RTAC_CAL,
+	VOICE_RTAC_CAL,
+	MAX_RTAC_BLOCKS
+};
+
+struct rtac_cal_mem_map_data {
+	uint32_t		map_size;
+	uint32_t		map_handle;
+	struct ion_client	*ion_client;
+	struct ion_handle	*ion_handle;
+};
+
+struct rtac_cal_data {
+	uint32_t		size;
+	uint32_t		kvaddr;
+	uint32_t		paddr;
+};
+
+struct rtac_cal_block_data {
+	struct rtac_cal_mem_map_data	map_data;
+	struct rtac_cal_data		cal_data;
+};
+
 void rtac_add_adm_device(u32 port_id, u32 copp_id, u32 path_id, u32 popp_id);
 void rtac_remove_adm_device(u32 port_id);
 void rtac_remove_popp_from_adm_devices(u32 popp_id);
@@ -35,5 +60,6 @@
 void rtac_set_voice_handle(u32 mode, void *handle);
 bool rtac_make_voice_callback(u32 mode, uint32_t *payload, u32 payload_size);
 void rtac_copy_voice_payload_to_user(void *payload, u32 payload_size);
+int rtac_clear_mapping(uint32_t cal_type);
 
 #endif
diff --git a/arch/arm/mach-msm/include/mach/qpnp-int.h b/arch/arm/mach-msm/include/mach/qpnp-int.h
index 2b86216..1f31ea5 100644
--- a/arch/arm/mach-msm/include/mach/qpnp-int.h
+++ b/arch/arm/mach-msm/include/mach/qpnp-int.h
@@ -71,6 +71,28 @@
  */
 int qpnpint_handle_irq(struct spmi_controller *spmi_ctrl,
 		       struct qpnp_irq_spec *spec);
+
+/**
+ * qpnpint_show_irq - Prints the Linux interrupt number
+ *
+ * Pass a PMIC Arbiter interrupt to Linux.
+ */
+int qpnpint_show_irq(struct spmi_controller *spmi_ctrl,
+		       struct qpnp_irq_spec *spec);
+
+#ifdef CONFIG_MSM_SHOW_RESUME_IRQ
+extern int msm_show_resume_irq_mask;
+static inline bool qpnpint_show_resume_irq(void)
+{
+	return msm_show_resume_irq_mask;
+}
+#else
+static inline bool qpnpint_show_resume_irq(void)
+{
+	return false;
+}
+#endif
+
 #else
 static inline int __init qpnpint_of_init(struct device_node *node,
 				  struct device_node *parent)
@@ -97,5 +119,15 @@
 {
 	return -ENXIO;
 }
+int qpnpint_show_irq(struct spmi_controller *spmi_ctrl,
+		       struct qpnp_irq_spec *spec)
+{
+	return -ENXIO;
+}
+
+static inline bool qpnpint_show_resume_irq(void)
+{
+	return false;
+}
 #endif /* CONFIG_MSM_QPNP_INT */
 #endif /* QPNPINT_H */
diff --git a/arch/arm/mach-msm/include/mach/qseecomi.h b/arch/arm/mach-msm/include/mach/qseecomi.h
index a4021d4..688dea0 100644
--- a/arch/arm/mach-msm/include/mach/qseecomi.h
+++ b/arch/arm/mach-msm/include/mach/qseecomi.h
@@ -46,8 +46,12 @@
 	QSEOS_UNLOAD_SERV_IMAGE_COMMAND,
 	QSEOS_APP_REGION_NOTIFICATION,
 	QSEOS_REGISTER_LOG_BUF_COMMAND,
-	QSEE_RPMB_PROVISION_KEY_COMMAND,
-	QSEE_RPMB_ERASE_COMMAND,
+	QSEOS_RPMB_PROVISION_KEY_COMMAND,
+	QSEOS_RPMB_ERASE_COMMAND,
+	QSEOS_GENERATE_KEY  = 0x11,
+	QSEOS_DELETE_KEY,
+	QSEOS_MAX_KEY_COUNT,
+	QSEOS_SET_KEY,
 	QSEOS_CMD_MAX     = 0xEFFFFFFF
 };
 
@@ -57,15 +61,6 @@
 	QSEOS_RESULT_FAILURE  = 0xFFFFFFFF
 };
 
-/* Key Management requests */
-enum qseecom_qceos_key_gen_cmd_id {
-	QSEOS_GENERATE_KEY  = 0x11,
-	QSEOS_DELETE_KEY,
-	QSEOS_MAX_KEY_COUNT,
-	QSEOS_SET_KEY,
-	QSEOS_KEY_CMD_MAX   = 0xEFFFFFFF
-};
-
 enum qseecom_pipe_type {
 	QSEOS_PIPE_ENC = 0x1,
 	QSEOS_PIPE_ENC_XTS = 0x2,
diff --git a/arch/arm/mach-msm/include/mach/scm.h b/arch/arm/mach-msm/include/mach/scm.h
index 4186603..9d186ce 100644
--- a/arch/arm/mach-msm/include/mach/scm.h
+++ b/arch/arm/mach-msm/include/mach/scm.h
@@ -26,10 +26,24 @@
 #define SCM_SVC_ES			0x10
 #define SCM_SVC_TZSCHEDULER		0xFC
 
+#define SCM_FUSE_READ			0x7
+
+#define DEFINE_SCM_BUFFER(__n) \
+static char __n[PAGE_SIZE] __aligned(PAGE_SIZE);
+
+#define SCM_BUFFER_SIZE(__buf)	sizeof(__buf)
+
+#define SCM_BUFFER_PHYS(__buf)	virt_to_phys(__buf)
+
 #ifdef CONFIG_MSM_SCM
 extern int scm_call(u32 svc_id, u32 cmd_id, const void *cmd_buf, size_t cmd_len,
 		void *resp_buf, size_t resp_len);
 
+extern int scm_call_noalloc(u32 svc_id, u32 cmd_id, const void *cmd_buf,
+		size_t cmd_len, void *resp_buf, size_t resp_len,
+		void *scm_buf, size_t scm_buf_size);
+
+
 extern s32 scm_call_atomic1(u32 svc, u32 cmd, u32 arg1);
 extern s32 scm_call_atomic2(u32 svc, u32 cmd, u32 arg1, u32 arg2);
 extern s32 scm_call_atomic3(u32 svc, u32 cmd, u32 arg1, u32 arg2, u32 arg3);
@@ -50,6 +64,13 @@
 	return 0;
 }
 
+static inline int scm_call_noalloc(u32 svc_id, u32 cmd_id,
+		const void *cmd_buf, size_t cmd_len, void *resp_buf,
+		size_t resp_len, void *scm_buf, size_t scm_buf_size)
+{
+	return 0;
+}
+
 static inline s32 scm_call_atomic1(u32 svc, u32 cmd, u32 arg1)
 {
 	return 0;
diff --git a/arch/arm/mach-msm/include/mach/socinfo.h b/arch/arm/mach-msm/include/mach/socinfo.h
index 830992c..b06189f 100644
--- a/arch/arm/mach-msm/include/mach/socinfo.h
+++ b/arch/arm/mach-msm/include/mach/socinfo.h
@@ -43,6 +43,7 @@
 #define of_board_is_mtp()	of_machine_is_compatible("qcom,mtp")
 #define of_board_is_qrd()	of_machine_is_compatible("qcom,qrd")
 #define of_board_is_xpm()	of_machine_is_compatible("qcom,xpm")
+#define of_board_is_skuf()	of_machine_is_compatible("qcom,skuf")
 
 #define machine_is_msm8974()	of_machine_is_compatible("qcom,msm8974")
 #define machine_is_msm9625()	of_machine_is_compatible("qcom,msm9625")
@@ -72,6 +73,7 @@
 #define of_board_is_mtp()		0
 #define of_board_is_qrd()		0
 #define of_board_is_xpm()		0
+#define of_board_is_skuf()		0
 
 #define machine_is_msm8974()		0
 #define machine_is_msm9625()		0
diff --git a/arch/arm/mach-msm/ipc_router.c b/arch/arm/mach-msm/ipc_router.c
index 64986d0..ce66531 100644
--- a/arch/arm/mach-msm/ipc_router.c
+++ b/arch/arm/mach-msm/ipc_router.c
@@ -98,6 +98,7 @@
 #define IPC_ROUTER_LOG_EVENT_ERROR      0x00
 #define IPC_ROUTER_LOG_EVENT_TX         0x01
 #define IPC_ROUTER_LOG_EVENT_RX         0x02
+#define IPC_ROUTER_DUMMY_DEST_NODE	0xFFFFFFFF
 
 static LIST_HEAD(control_ports);
 static DECLARE_RWSEM(control_ports_lock_lha5);
@@ -297,6 +298,8 @@
 		pr_err("%s: failure\n", __func__);
 		return NULL;
 	}
+	memcpy(&(cloned_pkt->hdr), &(pkt->hdr), sizeof(struct rr_header_v1));
+	/* TODO: Copy optional headers, if available */
 
 	pkt_fragment_q = kmalloc(sizeof(struct sk_buff_head), GFP_KERNEL);
 	if (!pkt_fragment_q) {
@@ -322,6 +325,7 @@
 		kfree_skb(temp_skb);
 	}
 	kfree(pkt_fragment_q);
+	/* TODO: Free optional headers, if present */
 	kfree(cloned_pkt);
 	return NULL;
 }
@@ -360,6 +364,7 @@
 		kfree_skb(temp_skb);
 	}
 	kfree(pkt->pkt_fragment_q);
+	/* TODO: Free Optional headers, if present */
 	kfree(pkt);
 	return;
 }
@@ -372,6 +377,8 @@
 	int first = 1, offset = 0;
 	int skb_size, data_size;
 	void *data;
+	int last = 1;
+	int align_size;
 
 	skb_head = kmalloc(sizeof(struct sk_buff_head), GFP_KERNEL);
 	if (!skb_head) {
@@ -381,10 +388,13 @@
 	skb_queue_head_init(skb_head);
 
 	data_size = buf_len;
+	align_size = ALIGN_SIZE(data_size);
 	while (offset != buf_len) {
 		skb_size = data_size;
 		if (first)
 			skb_size += IPC_ROUTER_HDR_SIZE;
+		if (last)
+			skb_size += align_size;
 
 		skb = alloc_skb(skb_size, GFP_KERNEL);
 		if (!skb) {
@@ -393,6 +403,7 @@
 				goto buf_to_skb_error;
 			}
 			data_size = data_size / 2;
+			last = 0;
 			continue;
 		}
 
@@ -406,6 +417,7 @@
 		skb_queue_tail(skb_head, skb);
 		offset += data_size;
 		data_size = buf_len - offset;
+		last = 1;
 	}
 	return skb_head;
 
@@ -446,7 +458,7 @@
 	return buf;
 }
 
-static void msm_ipc_router_free_skb(struct sk_buff_head *skb_head)
+void msm_ipc_router_free_skb(struct sk_buff_head *skb_head)
 {
 	struct sk_buff *temp_skb;
 
@@ -460,6 +472,328 @@
 	kfree(skb_head);
 }
 
+/**
+ * extract_header_v1() - Extract IPC Router header of version 1
+ * @pkt: Packet structure into which the header has to be extraced.
+ * @skb: SKB from which the header has to be extracted.
+ *
+ * @return: 0 on success, standard Linux error codes on failure.
+ */
+static int extract_header_v1(struct rr_packet *pkt, struct sk_buff *skb)
+{
+	if (!pkt || !skb) {
+		pr_err("%s: Invalid pkt or skb\n", __func__);
+		return -EINVAL;
+	}
+
+	memcpy(&pkt->hdr, skb->data, sizeof(struct rr_header_v1));
+	skb_pull(skb, sizeof(struct rr_header_v1));
+	pkt->length -= sizeof(struct rr_header_v1);
+	return 0;
+}
+
+/**
+ * extract_header_v2() - Extract IPC Router header of version 2
+ * @pkt: Packet structure into which the header has to be extraced.
+ * @skb: SKB from which the header has to be extracted.
+ *
+ * @return: 0 on success, standard Linux error codes on failure.
+ */
+static int extract_header_v2(struct rr_packet *pkt, struct sk_buff *skb)
+{
+	struct rr_header_v2 *hdr;
+
+	if (!pkt || !skb) {
+		pr_err("%s: Invalid pkt or skb\n", __func__);
+		return -EINVAL;
+	}
+
+	hdr = (struct rr_header_v2 *)skb->data;
+	pkt->hdr.version = (uint32_t)hdr->version;
+	pkt->hdr.type = (uint32_t)hdr->type;
+	pkt->hdr.src_node_id = (uint32_t)hdr->src_node_id;
+	pkt->hdr.src_port_id = (uint32_t)hdr->src_port_id;
+	pkt->hdr.size = (uint32_t)hdr->size;
+	pkt->hdr.control_flag = (uint32_t)hdr->control_flag;
+	pkt->hdr.dst_node_id = (uint32_t)hdr->dst_node_id;
+	pkt->hdr.dst_port_id = (uint32_t)hdr->dst_port_id;
+	skb_pull(skb, sizeof(struct rr_header_v2));
+	pkt->length -= sizeof(struct rr_header_v2);
+	return 0;
+}
+
+/**
+ * extract_header() - Extract IPC Router header
+ * @pkt: Packet from which the header has to be extraced.
+ *
+ * @return: 0 on success, standard Linux error codes on failure.
+ *
+ * This function will check if the header version is v1 or v2 and invoke
+ * the corresponding helper function to extract the IPC Router header.
+ */
+static int extract_header(struct rr_packet *pkt)
+{
+	struct sk_buff *temp_skb;
+	int ret;
+
+	if (!pkt) {
+		pr_err("%s: NULL PKT\n", __func__);
+		return -EINVAL;
+	}
+
+	temp_skb = skb_peek(pkt->pkt_fragment_q);
+	if (!temp_skb || !temp_skb->data) {
+		pr_err("%s: No SKBs in skb_queue\n", __func__);
+		return -EINVAL;
+	}
+
+	if (temp_skb->data[0] == IPC_ROUTER_V1) {
+		ret = extract_header_v1(pkt, temp_skb);
+	} else if (temp_skb->data[0] == IPC_ROUTER_V2) {
+		ret = extract_header_v2(pkt, temp_skb);
+		/* TODO: Extract optional headers if present */
+	} else {
+		pr_err("%s: Invalid Header version %02x\n",
+			__func__, temp_skb->data[0]);
+		print_hex_dump(KERN_ERR, "Header: ", DUMP_PREFIX_ADDRESS,
+			       16, 1, temp_skb->data, pkt->length, true);
+		return -EINVAL;
+	}
+	return ret;
+}
+
+/**
+ * calc_tx_header_size() - Calculate header size to be reserved in SKB
+ * @pkt: Packet in which the space for header has to be reserved.
+ * @dst_xprt_info: XPRT through which the destination is reachable.
+ *
+ * @return: required header size on success,
+ *          starndard Linux error codes on failure.
+ *
+ * This function is used to calculate the header size that has to be reserved
+ * in a transmit SKB. The header size is calculated based on the XPRT through
+ * which the destination node is reachable.
+ */
+static int calc_tx_header_size(struct rr_packet *pkt,
+			       struct msm_ipc_router_xprt_info *dst_xprt_info)
+{
+	int hdr_size = 0;
+	int xprt_version = 0;
+	struct msm_ipc_routing_table_entry *rt_entry;
+	struct msm_ipc_router_xprt_info *xprt_info = dst_xprt_info;
+
+	if (!pkt) {
+		pr_err("%s: NULL PKT\n", __func__);
+		return -EINVAL;
+	}
+
+	if (!xprt_info) {
+		rt_entry = lookup_routing_table(pkt->hdr.dst_node_id);
+		if (!rt_entry || !(rt_entry->xprt_info)) {
+			pr_err("%s: Node %d is not up\n",
+				__func__, pkt->hdr.dst_node_id);
+			return -ENODEV;
+		}
+
+		xprt_info = rt_entry->xprt_info;
+	}
+	if (xprt_info)
+		xprt_version = xprt_info->xprt->get_version(xprt_info->xprt);
+
+	if (xprt_version == IPC_ROUTER_V1) {
+		pkt->hdr.version = IPC_ROUTER_V1;
+		hdr_size = sizeof(struct rr_header_v1);
+	} else if (xprt_version == IPC_ROUTER_V2) {
+		pkt->hdr.version = IPC_ROUTER_V2;
+		hdr_size = sizeof(struct rr_header_v2);
+		/* TODO: Calculate optional header length, if present */
+	} else {
+		pr_err("%s: Invalid xprt_version %d\n",
+			__func__, xprt_version);
+		hdr_size = -EINVAL;
+	}
+
+	return hdr_size;
+}
+
+/**
+ * prepend_header_v1() - Prepend IPC Router header of version 1
+ * @pkt: Packet structure which contains the header info to be prepended.
+ * @hdr_size: Size of the header
+ *
+ * @return: 0 on success, standard Linux error codes on failure.
+ */
+static int prepend_header_v1(struct rr_packet *pkt, int hdr_size)
+{
+	struct sk_buff *temp_skb;
+	struct rr_header_v1 *hdr;
+
+	if (!pkt || hdr_size <= 0) {
+		pr_err("%s: Invalid input parameters\n", __func__);
+		return -EINVAL;
+	}
+
+	temp_skb = skb_peek(pkt->pkt_fragment_q);
+	if (!temp_skb || !temp_skb->data) {
+		pr_err("%s: No SKBs in skb_queue\n", __func__);
+		return -EINVAL;
+	}
+
+	if (skb_headroom(temp_skb) < hdr_size) {
+		temp_skb = alloc_skb(hdr_size, GFP_KERNEL);
+		if (!temp_skb) {
+			pr_err("%s: Could not allocate SKB of size %d\n",
+				__func__, hdr_size);
+			return -ENOMEM;
+		}
+	}
+
+	hdr = (struct rr_header_v1 *)skb_push(temp_skb, hdr_size);
+	memcpy(hdr, &pkt->hdr, hdr_size);
+	if (temp_skb != skb_peek(pkt->pkt_fragment_q))
+		skb_queue_head(pkt->pkt_fragment_q, temp_skb);
+	pkt->length += hdr_size;
+	return 0;
+}
+
+/**
+ * prepend_header_v2() - Prepend IPC Router header of version 2
+ * @pkt: Packet structure which contains the header info to be prepended.
+ * @hdr_size: Size of the header
+ *
+ * @return: 0 on success, standard Linux error codes on failure.
+ */
+static int prepend_header_v2(struct rr_packet *pkt, int hdr_size)
+{
+	struct sk_buff *temp_skb;
+	struct rr_header_v2 *hdr;
+
+	if (!pkt || hdr_size <= 0) {
+		pr_err("%s: Invalid input parameters\n", __func__);
+		return -EINVAL;
+	}
+
+	temp_skb = skb_peek(pkt->pkt_fragment_q);
+	if (!temp_skb || !temp_skb->data) {
+		pr_err("%s: No SKBs in skb_queue\n", __func__);
+		return -EINVAL;
+	}
+
+	if (skb_headroom(temp_skb) < hdr_size) {
+		temp_skb = alloc_skb(hdr_size, GFP_KERNEL);
+		if (!temp_skb) {
+			pr_err("%s: Could not allocate SKB of size %d\n",
+				__func__, hdr_size);
+			return -ENOMEM;
+		}
+	}
+
+	hdr = (struct rr_header_v2 *)skb_push(temp_skb, hdr_size);
+	hdr->version = (uint8_t)pkt->hdr.version;
+	hdr->type = (uint8_t)pkt->hdr.type;
+	hdr->control_flag = (uint16_t)pkt->hdr.control_flag;
+	hdr->size = (uint32_t)pkt->hdr.size;
+	hdr->src_node_id = (uint16_t)pkt->hdr.src_node_id;
+	hdr->src_port_id = (uint16_t)pkt->hdr.src_port_id;
+	hdr->dst_node_id = (uint16_t)pkt->hdr.dst_node_id;
+	hdr->dst_port_id = (uint16_t)pkt->hdr.dst_port_id;
+	/* TODO: Add optional headers, if present */
+	if (temp_skb != skb_peek(pkt->pkt_fragment_q))
+		skb_queue_head(pkt->pkt_fragment_q, temp_skb);
+	pkt->length += hdr_size;
+	return 0;
+}
+
+/**
+ * prepend_header() - Prepend IPC Router header
+ * @pkt: Packet structure which contains the header info to be prepended.
+ * @xprt_info: XPRT through which the packet is transmitted.
+ *
+ * @return: 0 on success, standard Linux error codes on failure.
+ *
+ * This function prepends the header to the packet to be transmitted. The
+ * IPC Router header version to be prepended depends on the XPRT through
+ * which the destination is reachable.
+ */
+static int prepend_header(struct rr_packet *pkt,
+			  struct msm_ipc_router_xprt_info *xprt_info)
+{
+	int hdr_size;
+	struct sk_buff *temp_skb;
+
+	if (!pkt) {
+		pr_err("%s: NULL PKT\n", __func__);
+		return -EINVAL;
+	}
+
+	temp_skb = skb_peek(pkt->pkt_fragment_q);
+	if (!temp_skb || !temp_skb->data) {
+		pr_err("%s: No SKBs in skb_queue\n", __func__);
+		return -EINVAL;
+	}
+
+	hdr_size = calc_tx_header_size(pkt, xprt_info);
+	if (hdr_size <= 0)
+		return hdr_size;
+
+	if (pkt->hdr.version == IPC_ROUTER_V1)
+		return prepend_header_v1(pkt, hdr_size);
+	else if (pkt->hdr.version == IPC_ROUTER_V2)
+		return prepend_header_v2(pkt, hdr_size);
+	else
+		return -EINVAL;
+}
+
+/**
+ * defragment_pkt() - Defragment and linearize the packet
+ * @pkt: Packet to be linearized.
+ *
+ * @return: 0 on success, standard Linux error codes on failure.
+ *
+ * Some packets contain fragments of data over multiple SKBs. If an XPRT
+ * does not supported fragmented writes, linearize multiple SKBs into one
+ * single SKB.
+ */
+static int defragment_pkt(struct rr_packet *pkt)
+{
+	struct sk_buff *dst_skb, *src_skb, *temp_skb;
+	int offset = 0, buf_len = 0, copy_len;
+	void *buf;
+	int align_size;
+
+	if (!pkt || pkt->length <= 0) {
+		pr_err("%s: Invalid PKT\n", __func__);
+		return -EINVAL;
+	}
+
+	if (skb_queue_len(pkt->pkt_fragment_q) == 1)
+		return 0;
+
+	align_size = ALIGN_SIZE(pkt->length);
+	dst_skb = alloc_skb(pkt->length + align_size, GFP_KERNEL);
+	if (!dst_skb) {
+		pr_err("%s: could not allocate one skb of size %d\n",
+			__func__, pkt->length);
+		return -ENOMEM;
+	}
+	buf = skb_put(dst_skb, pkt->length);
+	buf_len = pkt->length;
+
+	skb_queue_walk(pkt->pkt_fragment_q, src_skb) {
+		copy_len =  buf_len < src_skb->len ? buf_len : src_skb->len;
+		memcpy(buf + offset, src_skb->data, copy_len);
+		offset += copy_len;
+		buf_len -= copy_len;
+	}
+
+	while (!skb_queue_empty(pkt->pkt_fragment_q)) {
+		temp_skb = skb_dequeue(pkt->pkt_fragment_q);
+		kfree_skb(temp_skb);
+	}
+	skb_queue_tail(pkt->pkt_fragment_q, dst_skb);
+	return 0;
+}
+
 static int post_pkt_to_port(struct msm_ipc_port *port_ptr,
 			    struct rr_packet *pkt, int clone)
 {
@@ -514,7 +848,7 @@
 	down_read(&local_ports_lock_lha2);
 	do {
 		next_port_id++;
-		if ((next_port_id & 0xFFFFFFFE) == 0xFFFFFFFE)
+		if ((next_port_id & IPC_ROUTER_ADDRESS) == IPC_ROUTER_ADDRESS)
 			next_port_id = 1;
 
 		key = (next_port_id & (LP_HASH_SIZE - 1));
@@ -926,11 +1260,12 @@
 
 static int msm_ipc_router_send_control_msg(
 		struct msm_ipc_router_xprt_info *xprt_info,
-		union rr_control_msg *msg)
+		union rr_control_msg *msg,
+		uint32_t dst_node_id)
 {
 	struct rr_packet *pkt;
 	struct sk_buff *ipc_rtr_pkt;
-	struct rr_header *hdr;
+	struct rr_header_v1 *hdr;
 	int pkt_size;
 	void *data;
 	struct sk_buff_head *pkt_fragment_q;
@@ -971,29 +1306,33 @@
 	skb_reserve(ipc_rtr_pkt, IPC_ROUTER_HDR_SIZE);
 	data = skb_put(ipc_rtr_pkt, sizeof(*msg));
 	memcpy(data, msg, sizeof(*msg));
-	hdr = (struct rr_header *)skb_push(ipc_rtr_pkt, IPC_ROUTER_HDR_SIZE);
-	if (!hdr) {
-		pr_err("%s: skb_push failed\n", __func__);
-		kfree_skb(ipc_rtr_pkt);
-		kfree(pkt_fragment_q);
-		kfree(pkt);
-		return -ENOMEM;
-	}
+	skb_queue_tail(pkt_fragment_q, ipc_rtr_pkt);
+	pkt->pkt_fragment_q = pkt_fragment_q;
+	pkt->length = sizeof(*msg);
 
-	hdr->version = IPC_ROUTER_VERSION;
+	hdr = &(pkt->hdr);
+	hdr->version = IPC_ROUTER_V1;
 	hdr->type = msg->cmd;
 	hdr->src_node_id = IPC_ROUTER_NID_LOCAL;
 	hdr->src_port_id = IPC_ROUTER_ADDRESS;
-	hdr->confirm_rx = 0;
+	hdr->control_flag = 0;
 	hdr->size = sizeof(*msg);
-	hdr->dst_node_id = xprt_info->remote_node_id;
+	if (hdr->type == IPC_ROUTER_CTRL_CMD_RESUME_TX)
+		hdr->dst_node_id = dst_node_id;
+	else
+		hdr->dst_node_id = xprt_info->remote_node_id;
 	hdr->dst_port_id = IPC_ROUTER_ADDRESS;
-	skb_queue_tail(pkt_fragment_q, ipc_rtr_pkt);
-	pkt->pkt_fragment_q = pkt_fragment_q;
-	pkt->length = pkt_size;
 
 	mutex_lock(&xprt_info->tx_lock_lhb2);
-	ret = xprt_info->xprt->write(pkt, pkt_size, xprt_info->xprt);
+	ret = prepend_header(pkt, xprt_info);
+	if (ret < 0) {
+		mutex_unlock(&xprt_info->tx_lock_lhb2);
+		pr_err("%s: Prepend Header failed\n", __func__);
+		release_pkt(pkt);
+		return ret;
+	}
+
+	ret = xprt_info->xprt->write(pkt, pkt->length, xprt_info->xprt);
 	mutex_unlock(&xprt_info->tx_lock_lhb2);
 
 	release_pkt(pkt);
@@ -1031,7 +1370,7 @@
 				ctl.srv.port_id =
 					server_port->server_addr.port_id;
 				msm_ipc_router_send_control_msg(xprt_info,
-								&ctl);
+					&ctl, IPC_ROUTER_DUMMY_DEST_NODE);
 			}
 		}
 	}
@@ -1069,7 +1408,7 @@
 {
 	struct rr_packet *pkt;
 	struct sk_buff *ipc_rtr_pkt;
-	struct rr_header *hdr;
+	struct rr_header_v1 *hdr;
 	int pkt_size;
 	void *data;
 	struct sk_buff_head *pkt_fragment_q;
@@ -1089,7 +1428,7 @@
 	}
 	skb_queue_head_init(pkt_fragment_q);
 
-	pkt_size = IPC_ROUTER_HDR_SIZE + sizeof(*msg);
+	pkt_size = sizeof(*msg);
 	ipc_rtr_pkt = alloc_skb(pkt_size, GFP_KERNEL);
 	if (!ipc_rtr_pkt) {
 		pr_err("%s: ipc_rtr_pkt alloc failed\n", __func__);
@@ -1098,22 +1437,14 @@
 		return -ENOMEM;
 	}
 
-	skb_reserve(ipc_rtr_pkt, IPC_ROUTER_HDR_SIZE);
 	data = skb_put(ipc_rtr_pkt, sizeof(*msg));
 	memcpy(data, msg, sizeof(*msg));
-	hdr = (struct rr_header *)skb_push(ipc_rtr_pkt, IPC_ROUTER_HDR_SIZE);
-	if (!hdr) {
-		pr_err("%s: skb_push failed\n", __func__);
-		kfree_skb(ipc_rtr_pkt);
-		kfree(pkt_fragment_q);
-		kfree(pkt);
-		return -ENOMEM;
-	}
-	hdr->version = IPC_ROUTER_VERSION;
+	hdr = &(pkt->hdr);
+	hdr->version = IPC_ROUTER_V1;
 	hdr->type = msg->cmd;
 	hdr->src_node_id = IPC_ROUTER_NID_LOCAL;
 	hdr->src_port_id = IPC_ROUTER_ADDRESS;
-	hdr->confirm_rx = 0;
+	hdr->control_flag = 0;
 	hdr->size = sizeof(*msg);
 	hdr->dst_node_id = IPC_ROUTER_NID_LOCAL;
 	hdr->dst_port_id = IPC_ROUTER_ADDRESS;
@@ -1132,7 +1463,8 @@
 
 	down_read(&xprt_info_list_lock_lha5);
 	list_for_each_entry(xprt_info, &xprt_info_list, list) {
-		msm_ipc_router_send_control_msg(xprt_info, ctl);
+		msm_ipc_router_send_control_msg(xprt_info, ctl,
+					IPC_ROUTER_DUMMY_DEST_NODE);
 	}
 	up_read(&xprt_info_list_lock_lha5);
 
@@ -1150,77 +1482,68 @@
 	down_read(&xprt_info_list_lock_lha5);
 	list_for_each_entry(fwd_xprt_info, &xprt_info_list, list) {
 		if (xprt_info->xprt->link_id != fwd_xprt_info->xprt->link_id)
-			msm_ipc_router_send_control_msg(fwd_xprt_info, ctl);
+			msm_ipc_router_send_control_msg(fwd_xprt_info, ctl,
+						IPC_ROUTER_DUMMY_DEST_NODE);
 	}
 	up_read(&xprt_info_list_lock_lha5);
 
 	return 0;
 }
 
-static int relay_msg(struct msm_ipc_router_xprt_info *xprt_info,
-		     struct rr_packet *pkt)
-{
-	struct msm_ipc_router_xprt_info *fwd_xprt_info;
-
-	if (!xprt_info || !pkt)
-		return -EINVAL;
-
-	down_read(&xprt_info_list_lock_lha5);
-	list_for_each_entry(fwd_xprt_info, &xprt_info_list, list) {
-		mutex_lock(&fwd_xprt_info->tx_lock_lhb2);
-		if (xprt_info->xprt->link_id != fwd_xprt_info->xprt->link_id)
-			fwd_xprt_info->xprt->write(pkt, pkt->length,
-						   fwd_xprt_info->xprt);
-		mutex_unlock(&fwd_xprt_info->tx_lock_lhb2);
-	}
-	up_read(&xprt_info_list_lock_lha5);
-	return 0;
-}
-
 static int forward_msg(struct msm_ipc_router_xprt_info *xprt_info,
 		       struct rr_packet *pkt)
 {
-	uint32_t dst_node_id;
-	struct sk_buff *head_pkt;
-	struct rr_header *hdr;
+	struct rr_header_v1 *hdr;
 	struct msm_ipc_router_xprt_info *fwd_xprt_info;
 	struct msm_ipc_routing_table_entry *rt_entry;
 	int ret = 0;
+	int fwd_xprt_option;
 
 	if (!xprt_info || !pkt)
 		return -EINVAL;
 
-	head_pkt = skb_peek(pkt->pkt_fragment_q);
-	if (!head_pkt)
-		return -EINVAL;
-
-	hdr = (struct rr_header *)head_pkt->data;
-	dst_node_id = hdr->dst_node_id;
+	hdr = &(pkt->hdr);
 	down_read(&routing_table_lock_lha3);
-	rt_entry = lookup_routing_table(dst_node_id);
+	rt_entry = lookup_routing_table(hdr->dst_node_id);
 	if (!(rt_entry) || !(rt_entry->xprt_info)) {
-		up_read(&routing_table_lock_lha3);
 		pr_err("%s: Routing table not initialized\n", __func__);
-		return -ENODEV;
+		ret = -ENODEV;
+		goto fm_error1;
 	}
 
 	down_read(&rt_entry->lock_lha4);
 	fwd_xprt_info = rt_entry->xprt_info;
+	ret = prepend_header(pkt, fwd_xprt_info);
+	if (ret < 0) {
+		pr_err("%s: Prepend Header failed\n", __func__);
+		goto fm_error2;
+	}
+	fwd_xprt_option = fwd_xprt_info->xprt->get_option(fwd_xprt_info->xprt);
+	if (!(fwd_xprt_option & FRAG_PKT_WRITE_ENABLE)) {
+		ret = defragment_pkt(pkt);
+		if (ret < 0)
+			goto fm_error2;
+	}
+
+	mutex_lock(&fwd_xprt_info->tx_lock_lhb2);
 	if (xprt_info->remote_node_id == fwd_xprt_info->remote_node_id) {
 		pr_err("%s: Discarding Command to route back\n", __func__);
 		ret = -EINVAL;
-		goto fwd_msg_out;
+		goto fm_error3;
 	}
 
 	if (xprt_info->xprt->link_id == fwd_xprt_info->xprt->link_id) {
 		pr_err("%s: DST in the same cluster\n", __func__);
-		goto fwd_msg_out;
+		ret = 0;
+		goto fm_error3;
 	}
-	mutex_lock(&fwd_xprt_info->tx_lock_lhb2);
 	fwd_xprt_info->xprt->write(pkt, pkt->length, fwd_xprt_info->xprt);
+
+fm_error3:
 	mutex_unlock(&fwd_xprt_info->tx_lock_lhb2);
-fwd_msg_out:
+fm_error2:
 	up_read(&rt_entry->lock_lha4);
+fm_error1:
 	up_read(&routing_table_lock_lha3);
 
 	return ret;
@@ -1252,7 +1575,8 @@
 		list_for_each_entry(tmp_xprt_info, &xprt_info_list, list) {
 			if (tmp_xprt_info != xprt_info)
 				continue;
-			msm_ipc_router_send_control_msg(tmp_xprt_info, &msg);
+			msm_ipc_router_send_control_msg(tmp_xprt_info, &msg,
+						IPC_ROUTER_DUMMY_DEST_NODE);
 			break;
 		}
 		up_read(&xprt_info_list_lock_lha5);
@@ -1342,7 +1666,7 @@
 	struct msm_ipc_router_xprt_info *xprt_info)
 {
 	int i;
-	struct msm_ipc_routing_table_entry *rt_entry;
+	struct msm_ipc_routing_table_entry *rt_entry, *tmp_rt_entry;
 
 	if (!xprt_info) {
 		pr_err("%s: Invalid xprt_info\n", __func__);
@@ -1352,7 +1676,8 @@
 	down_write(&server_list_lock_lha2);
 	down_write(&routing_table_lock_lha3);
 	for (i = 0; i < RT_HASH_SIZE; i++) {
-		list_for_each_entry(rt_entry, &routing_table[i], list) {
+		list_for_each_entry_safe(rt_entry, tmp_rt_entry,
+					 &routing_table[i], list) {
 			down_write(&rt_entry->lock_lha4);
 			if (rt_entry->xprt_info != xprt_info) {
 				up_write(&rt_entry->lock_lha4);
@@ -1361,6 +1686,8 @@
 			cleanup_rmt_ports(xprt_info, rt_entry);
 			rt_entry->xprt_info = NULL;
 			up_write(&rt_entry->lock_lha4);
+			list_del(&rt_entry->list);
+			kfree(rt_entry);
 		}
 	}
 	up_write(&routing_table_lock_lha3);
@@ -1459,7 +1786,7 @@
 }
 
 static int process_hello_msg(struct msm_ipc_router_xprt_info *xprt_info,
-			     struct rr_header *hdr)
+			     struct rr_header_v1 *hdr)
 {
 	int i, rc = 0;
 	union rr_control_msg ctl;
@@ -1497,8 +1824,9 @@
 
 	/* Send a reply HELLO message */
 	memset(&ctl, 0, sizeof(ctl));
-	ctl.cmd = IPC_ROUTER_CTRL_CMD_HELLO;
-	rc = msm_ipc_router_send_control_msg(xprt_info, &ctl);
+	ctl.hello.cmd = IPC_ROUTER_CTRL_CMD_HELLO;
+	rc = msm_ipc_router_send_control_msg(xprt_info, &ctl,
+						IPC_ROUTER_DUMMY_DEST_NODE);
 	if (rc < 0) {
 		pr_err("%s: Error sending reply HELLO message\n", __func__);
 		return rc;
@@ -1642,7 +1970,7 @@
 	 * to the cluster from which this message is received. Notify the
 	 * local clients waiting for this service.
 	 */
-	relay_msg(xprt_info, pkt);
+	relay_ctl_msg(xprt_info, msg);
 	post_control_ports(pkt);
 	return 0;
 }
@@ -1665,7 +1993,7 @@
 		 * belong to the cluster from which this message is received.
 		 * Notify the local clients communicating with the service.
 		 */
-		relay_msg(xprt_info, pkt);
+		relay_ctl_msg(xprt_info, msg);
 		post_control_ports(pkt);
 	}
 	up_write(&server_list_lock_lha2);
@@ -1685,7 +2013,7 @@
 		msm_ipc_router_destroy_remote_port(rport_ptr);
 	up_write(&routing_table_lock_lha3);
 
-	relay_msg(xprt_info, pkt);
+	relay_ctl_msg(xprt_info, msg);
 	post_control_ports(pkt);
 	return 0;
 }
@@ -1695,26 +2023,20 @@
 {
 	union rr_control_msg *msg;
 	int rc = 0;
-	struct sk_buff *temp_ptr;
-	struct rr_header *hdr;
+	struct rr_header_v1 *hdr;
 
-	if (pkt->length != (IPC_ROUTER_HDR_SIZE + sizeof(*msg))) {
+	if (pkt->length != sizeof(*msg)) {
 		pr_err("%s: r2r msg size %d != %d\n", __func__, pkt->length,
-			(IPC_ROUTER_HDR_SIZE + sizeof(*msg)));
+			sizeof(*msg));
 		return -EINVAL;
 	}
 
-	temp_ptr = skb_peek(pkt->pkt_fragment_q);
-	if (!temp_ptr) {
-		pr_err("%s: pkt_fragment_q is empty\n", __func__);
-		return -EINVAL;
+	hdr = &(pkt->hdr);
+	msg = msm_ipc_router_skb_to_buf(pkt->pkt_fragment_q, sizeof(*msg));
+	if (!msg) {
+		pr_err("%s: Error extracting control msg\n", __func__);
+		return -ENOMEM;
 	}
-	hdr = (struct rr_header *)temp_ptr->data;
-	if (!hdr) {
-		pr_err("%s: No data inside the skb\n", __func__);
-		return -EINVAL;
-	}
-	msg = (union rr_control_msg *)((char *)hdr + IPC_ROUTER_HDR_SIZE);
 
 	switch (msg->cmd) {
 	case IPC_ROUTER_CTRL_CMD_HELLO:
@@ -1740,18 +2062,17 @@
 		RR("o UNKNOWN(%08x)\n", msg->cmd);
 		rc = -ENOSYS;
 	}
-
+	kfree(msg);
 	return rc;
 }
 
 static void do_read_data(struct work_struct *work)
 {
-	struct rr_header *hdr;
+	struct rr_header_v1 *hdr;
 	struct rr_packet *pkt = NULL;
 	struct msm_ipc_port *port_ptr;
-	struct sk_buff *head_skb;
 	struct msm_ipc_router_remote_port *rport_ptr;
-	uint32_t resume_tx, resume_tx_node_id, resume_tx_port_id;
+	int ret;
 
 	struct msm_ipc_router_xprt_info *xprt_info =
 		container_of(work,
@@ -1766,24 +2087,15 @@
 			goto fail_data;
 		}
 
-		head_skb = skb_peek(pkt->pkt_fragment_q);
-		if (!head_skb) {
-			pr_err("%s: head_skb is invalid\n", __func__);
+		ret = extract_header(pkt);
+		if (ret < 0)
 			goto fail_data;
-		}
-
-		hdr = (struct rr_header *)(head_skb->data);
+		hdr = &(pkt->hdr);
 		RAW("ver=%d type=%d src=%d:%08x crx=%d siz=%d dst=%d:%08x\n",
 		     hdr->version, hdr->type, hdr->src_node_id,
-		     hdr->src_port_id, hdr->confirm_rx, hdr->size,
+		     hdr->src_port_id, hdr->control_flag, hdr->size,
 		     hdr->dst_node_id, hdr->dst_port_id);
 
-		if (hdr->version != IPC_ROUTER_VERSION) {
-			pr_err("version %d != %d\n",
-				hdr->version, IPC_ROUTER_VERSION);
-			goto fail_data;
-		}
-
 		if ((hdr->dst_node_id != IPC_ROUTER_NID_LOCAL) &&
 		    ((hdr->type == IPC_ROUTER_CTRL_CMD_RESUME_TX) ||
 		     (hdr->type == IPC_ROUTER_CTRL_CMD_DATA))) {
@@ -1792,8 +2104,7 @@
 			continue;
 		}
 
-		if ((hdr->dst_port_id == IPC_ROUTER_ADDRESS) ||
-		    (hdr->type == IPC_ROUTER_CTRL_CMD_HELLO)) {
+		if (hdr->type != IPC_ROUTER_CTRL_CMD_DATA) {
 			process_control_msg(xprt_info, pkt);
 			release_pkt(pkt);
 			continue;
@@ -1808,16 +2119,12 @@
 				(hdr->src_port_id & 0xffffff),
 				(hdr->dst_node_id << 24) |
 				(hdr->dst_port_id & 0xffffff),
-				(hdr->type << 24) | (hdr->confirm_rx << 16) |
+				(hdr->type << 24) | (hdr->control_flag << 16) |
 				(hdr->size & 0xffff));
 		}
 #endif
 #endif
 
-		resume_tx = hdr->confirm_rx;
-		resume_tx_node_id = hdr->dst_node_id;
-		resume_tx_port_id = hdr->dst_port_id;
-
 		down_read(&local_ports_lock_lha2);
 		port_ptr = msm_ipc_router_lookup_local_port(hdr->dst_port_id);
 		if (!port_ptr) {
@@ -1825,7 +2132,7 @@
 				hdr->dst_port_id);
 			up_read(&local_ports_lock_lha2);
 			release_pkt(pkt);
-			goto process_done;
+			return;
 		}
 
 		down_read(&routing_table_lock_lha3);
@@ -1841,26 +2148,13 @@
 					hdr->src_port_id);
 				up_read(&routing_table_lock_lha3);
 				up_read(&local_ports_lock_lha2);
-				goto process_done;
+				release_pkt(pkt);
+				return;
 			}
 		}
 		up_read(&routing_table_lock_lha3);
 		post_pkt_to_port(port_ptr, pkt, 0);
 		up_read(&local_ports_lock_lha2);
-
-process_done:
-		if (resume_tx) {
-			union rr_control_msg msg;
-			memset(&msg, 0, sizeof(msg));
-			msg.cmd = IPC_ROUTER_CTRL_CMD_RESUME_TX;
-			msg.cli.node_id = resume_tx_node_id;
-			msg.cli.port_id = resume_tx_port_id;
-
-			RR("x RESUME_TX id=%d:%08x\n",
-			   msg.cli.node_id, msg.cli.port_id);
-			msm_ipc_router_send_control_msg(xprt_info, &msg);
-		}
-
 	}
 	return;
 
@@ -1912,6 +2206,7 @@
 	ctl.srv.port_id = port_ptr->this_port.port_id;
 	up_write(&server_list_lock_lha2);
 	broadcast_ctl_msg(&ctl);
+	broadcast_ctl_msg_locally(&ctl);
 	spin_lock_irqsave(&port_ptr->port_lock, flags);
 	port_ptr->type = SERVER_PORT;
 	port_ptr->mode_info.mode = MULTI_LINK_MODE;
@@ -1963,6 +2258,7 @@
 				      port_ptr->this_port.port_id);
 	up_write(&server_list_lock_lha2);
 	broadcast_ctl_msg(&ctl);
+	broadcast_ctl_msg_locally(&ctl);
 	spin_lock_irqsave(&port_ptr->port_lock, flags);
 	port_ptr->type = CLIENT_PORT;
 	spin_unlock_irqrestore(&port_ptr->port_lock, flags);
@@ -1973,8 +2269,7 @@
 			uint32_t port_id,
 			struct sk_buff_head *data)
 {
-	struct sk_buff *head_skb;
-	struct rr_header *hdr;
+	struct rr_header_v1 *hdr;
 	struct msm_ipc_port *port_ptr;
 	struct rr_packet *pkt;
 	int ret_len;
@@ -1989,34 +2284,22 @@
 		pr_err("%s: New pkt create failed\n", __func__);
 		return -ENOMEM;
 	}
-
-	head_skb = skb_peek(pkt->pkt_fragment_q);
-	if (!head_skb) {
-		pr_err("%s: pkt_fragment_q is empty\n", __func__);
-		release_pkt(pkt);
-		return -EINVAL;
-	}
-	hdr = (struct rr_header *)skb_push(head_skb, IPC_ROUTER_HDR_SIZE);
-	if (!hdr) {
-		pr_err("%s: Prepend Header failed\n", __func__);
-		release_pkt(pkt);
-		return -ENOMEM;
-	}
-	hdr->version = IPC_ROUTER_VERSION;
+	hdr = &(pkt->hdr);
+	hdr->version = IPC_ROUTER_V1;
 	hdr->type = IPC_ROUTER_CTRL_CMD_DATA;
 	hdr->src_node_id = src->this_port.node_id;
 	hdr->src_port_id = src->this_port.port_id;
 	hdr->size = pkt->length;
-	hdr->confirm_rx = 0;
+	hdr->control_flag = 0;
 	hdr->dst_node_id = IPC_ROUTER_NID_LOCAL;
 	hdr->dst_port_id = port_id;
-	pkt->length += IPC_ROUTER_HDR_SIZE;
 
 	down_read(&local_ports_lock_lha2);
 	port_ptr = msm_ipc_router_lookup_local_port(port_id);
 	if (!port_ptr) {
 		pr_err("%s: Local port %d not present\n", __func__, port_id);
 		up_read(&local_ports_lock_lha2);
+		pkt->pkt_fragment_q = NULL;
 		release_pkt(pkt);
 		return -ENODEV;
 	}
@@ -2033,35 +2316,26 @@
 				struct msm_ipc_router_remote_port *rport_ptr,
 				struct rr_packet *pkt)
 {
-	struct sk_buff *head_skb;
-	struct rr_header *hdr;
+	struct rr_header_v1 *hdr;
 	struct msm_ipc_router_xprt_info *xprt_info;
 	struct msm_ipc_routing_table_entry *rt_entry;
 	struct msm_ipc_resume_tx_port  *resume_tx_port;
+	struct sk_buff *temp_skb;
+	int xprt_option;
 	int ret;
+	int align_size;
 
 	if (!rport_ptr || !src || !pkt)
 		return -EINVAL;
 
-	head_skb = skb_peek(pkt->pkt_fragment_q);
-	if (!head_skb) {
-		pr_err("%s: pkt_fragment_q is empty\n", __func__);
-		return -EINVAL;
-	}
-	hdr = (struct rr_header *)skb_push(head_skb, IPC_ROUTER_HDR_SIZE);
-	if (!hdr) {
-		pr_err("%s: Prepend Header failed\n", __func__);
-		return -ENOMEM;
-	}
-	hdr->version = IPC_ROUTER_VERSION;
+	hdr = &(pkt->hdr);
 	hdr->type = IPC_ROUTER_CTRL_CMD_DATA;
 	hdr->src_node_id = src->this_port.node_id;
 	hdr->src_port_id = src->this_port.port_id;
 	hdr->size = pkt->length;
-	hdr->confirm_rx = 0;
+	hdr->control_flag = 0;
 	hdr->dst_node_id = rport_ptr->node_id;
 	hdr->dst_port_id = rport_ptr->port_id;
-	pkt->length += IPC_ROUTER_HDR_SIZE;
 
 	mutex_lock(&rport_ptr->quota_lock_lhb2);
 	if (rport_ptr->tx_quota_cnt == IPC_ROUTER_DEFAULT_RX_QUOTA) {
@@ -2089,7 +2363,7 @@
 	}
 	rport_ptr->tx_quota_cnt++;
 	if (rport_ptr->tx_quota_cnt == IPC_ROUTER_DEFAULT_RX_QUOTA)
-		hdr->confirm_rx = 1;
+		hdr->control_flag |= CONTROL_FLAG_CONFIRM_RX;
 	mutex_unlock(&rport_ptr->quota_lock_lhb2);
 
 	rt_entry = lookup_routing_table(hdr->dst_node_id);
@@ -2100,6 +2374,25 @@
 	}
 	down_read(&rt_entry->lock_lha4);
 	xprt_info = rt_entry->xprt_info;
+	ret = prepend_header(pkt, xprt_info);
+	if (ret < 0) {
+		up_read(&rt_entry->lock_lha4);
+		pr_err("%s: Prepend Header failed\n", __func__);
+		return ret;
+	}
+	xprt_option = xprt_info->xprt->get_option(xprt_info->xprt);
+	if (!(xprt_option & FRAG_PKT_WRITE_ENABLE)) {
+		ret = defragment_pkt(pkt);
+		if (ret < 0) {
+			up_read(&rt_entry->lock_lha4);
+			return ret;
+		}
+	}
+
+	temp_skb = skb_peek_tail(pkt->pkt_fragment_q);
+	align_size = ALIGN_SIZE(pkt->length);
+	skb_put(temp_skb, align_size);
+	pkt->length += align_size;
 	mutex_lock(&xprt_info->tx_lock_lhb2);
 	ret = xprt_info->xprt->write(pkt, pkt->length, xprt_info->xprt);
 	mutex_unlock(&xprt_info->tx_lock_lhb2);
@@ -2113,10 +2406,10 @@
 
 	RAW_HDR("[w rr_h] "
 		"ver=%i,type=%s,src_nid=%08x,src_port_id=%08x,"
-		"confirm_rx=%i,size=%3i,dst_pid=%08x,dst_cid=%08x\n",
+		"control_flag=%i,size=%3i,dst_pid=%08x,dst_cid=%08x\n",
 		hdr->version, type_to_str(hdr->type),
 		hdr->src_node_id, hdr->src_port_id,
-		hdr->confirm_rx, hdr->size,
+		hdr->control_flag, hdr->size,
 		hdr->dst_node_id, hdr->dst_port_id);
 
 #if defined(CONFIG_MSM_SMD_LOGGING)
@@ -2129,13 +2422,13 @@
 			(hdr->src_port_id & 0xffffff),
 			(hdr->dst_node_id << 24) |
 			(hdr->dst_port_id & 0xffffff),
-			(hdr->type << 24) | (hdr->confirm_rx << 16) |
+			(hdr->type << 24) | (hdr->control_flag << 16) |
 			(hdr->size & 0xffff));
 	}
 #endif
 #endif
 
-	return pkt->length;
+	return hdr->size;
 }
 
 int msm_ipc_router_send_to(struct msm_ipc_port *src,
@@ -2209,6 +2502,8 @@
 
 	ret = msm_ipc_router_write_pkt(src, rport_ptr, pkt);
 	up_read(&routing_table_lock_lha3);
+	if (ret < 0)
+		pkt->pkt_fragment_q = NULL;
 	release_pkt(pkt);
 
 	return ret;
@@ -2228,25 +2523,67 @@
 	}
 
 	ret = msm_ipc_router_send_to(src, out_skb_head, dest);
-	if (ret == -EAGAIN)
-		return ret;
 	if (ret < 0) {
-		pr_err("%s: msm_ipc_router_send_to failed - ret: %d\n",
-			__func__, ret);
+		if (ret != -EAGAIN)
+			pr_err("%s: msm_ipc_router_send_to failed - ret: %d\n",
+				__func__, ret);
 		msm_ipc_router_free_skb(out_skb_head);
 		return ret;
 	}
 	return 0;
 }
 
+/**
+ * msm_ipc_router_send_resume_tx() - Send Resume_Tx message
+ * @data: Pointer to received data packet that has confirm_rx bit set
+ *
+ * @return: On success, number of bytes transferred is returned, else
+ *	    standard linux error code is returned.
+ *
+ * This function sends the Resume_Tx event to the remote node that
+ * sent the data with confirm_rx field set. In case of a multi-hop
+ * scenario also, this function makes sure that the destination node_id
+ * to which the resume_tx event should reach is right.
+ */
+static int msm_ipc_router_send_resume_tx(void *data)
+{
+	union rr_control_msg msg;
+	struct rr_header_v1 *hdr = (struct rr_header_v1 *)data;
+	struct msm_ipc_routing_table_entry *rt_entry;
+	int ret;
+
+	memset(&msg, 0, sizeof(msg));
+	msg.cmd = IPC_ROUTER_CTRL_CMD_RESUME_TX;
+	msg.cli.node_id = hdr->dst_node_id;
+	msg.cli.port_id = hdr->dst_port_id;
+	down_read(&routing_table_lock_lha3);
+	rt_entry = lookup_routing_table(hdr->src_node_id);
+	if (!rt_entry) {
+		pr_err("%s: %d Node is not present",
+				__func__, hdr->src_node_id);
+		up_read(&routing_table_lock_lha3);
+		return -ENODEV;
+	}
+	RR("x RESUME_TX id=%d:%08x\n",
+			msg.cli.node_id, msg.cli.port_id);
+	ret = msm_ipc_router_send_control_msg(rt_entry->xprt_info, &msg,
+						hdr->src_node_id);
+	up_read(&routing_table_lock_lha3);
+	if (ret < 0)
+		pr_err("%s: Send Resume_Tx Failed SRC_NODE: %d SRC_PORT: %d DEST_NODE: %d",
+			__func__, hdr->dst_node_id, hdr->dst_port_id,
+			hdr->src_node_id);
+
+	return ret;
+}
+
 int msm_ipc_router_read(struct msm_ipc_port *port_ptr,
-			struct sk_buff_head **data,
+			struct rr_packet **read_pkt,
 			size_t buf_len)
 {
 	struct rr_packet *pkt;
-	int ret;
 
-	if (!port_ptr || !data)
+	if (!port_ptr || !read_pkt)
 		return -EINVAL;
 
 	mutex_lock(&port_ptr->port_rx_q_lock_lhb3);
@@ -2256,19 +2593,19 @@
 	}
 
 	pkt = list_first_entry(&port_ptr->port_rx_q, struct rr_packet, list);
-	if ((buf_len) && ((pkt->length - IPC_ROUTER_HDR_SIZE) > buf_len)) {
+	if ((buf_len) && (pkt->hdr.size > buf_len)) {
 		mutex_unlock(&port_ptr->port_rx_q_lock_lhb3);
 		return -ETOOSMALL;
 	}
 	list_del(&pkt->list);
 	if (list_empty(&port_ptr->port_rx_q))
 		wake_unlock(&port_ptr->port_rx_wake_lock);
-	*data = pkt->pkt_fragment_q;
-	ret = pkt->length;
-	kfree(pkt);
+	*read_pkt = pkt;
 	mutex_unlock(&port_ptr->port_rx_q_lock_lhb3);
+	if (pkt->hdr.control_flag & CONTROL_FLAG_CONFIRM_RX)
+		msm_ipc_router_send_resume_tx(&pkt->hdr);
 
-	return ret;
+	return pkt->length;
 }
 
 /**
@@ -2316,7 +2653,7 @@
 /**
  * msm_ipc_router_recv_from() - Recieve messages destined to a local port.
  * @port_ptr: Pointer to the local port
- * @data : Pointer to the socket buffer head
+ * @pkt : Pointer to the router-to-router packet
  * @src: Pointer to local port address
  * @timeout: < 0 timeout indicates infinite wait till a message arrives.
  *	     > 0 timeout indicates the wait time.
@@ -2337,31 +2674,30 @@
  * of bytes that are read.
  */
 int msm_ipc_router_recv_from(struct msm_ipc_port *port_ptr,
-			     struct sk_buff_head **data,
+			     struct rr_packet **pkt,
 			     struct msm_ipc_addr *src,
 			     long timeout)
 {
 	int ret, data_len, align_size;
 	struct sk_buff *temp_skb;
-	struct rr_header *hdr = NULL;
+	struct rr_header_v1 *hdr = NULL;
 
-	if (!port_ptr || !data) {
+	if (!port_ptr || !pkt) {
 		pr_err("%s: Invalid pointers being passed\n", __func__);
 		return -EINVAL;
 	}
 
-	*data = NULL;
+	*pkt = NULL;
 
 	ret = msm_ipc_router_rx_data_wait(port_ptr, timeout);
 	if (ret)
 		return ret;
 
-	ret = msm_ipc_router_read(port_ptr, data, 0);
-	if (ret <= 0 || !(*data))
+	ret = msm_ipc_router_read(port_ptr, pkt, 0);
+	if (ret <= 0 || !(*pkt))
 		return ret;
 
-	temp_skb = skb_peek(*data);
-	hdr = (struct rr_header *)(temp_skb->data);
+	hdr = &((*pkt)->hdr);
 	if (src) {
 		src->addrtype = MSM_IPC_ADDR_ID;
 		src->addr.port_addr.node_id = hdr->src_node_id;
@@ -2369,10 +2705,9 @@
 	}
 
 	data_len = hdr->size;
-	skb_pull(temp_skb, IPC_ROUTER_HDR_SIZE);
 	align_size = ALIGN_SIZE(data_len);
 	if (align_size) {
-		temp_skb = skb_peek_tail(*data);
+		temp_skb = skb_peek_tail((*pkt)->pkt_fragment_q);
 		skb_trim(temp_skb, (temp_skb->len - align_size));
 	}
 	return data_len;
@@ -2383,11 +2718,10 @@
 			    unsigned char **data,
 			    unsigned int *len)
 {
-	struct sk_buff_head *in_skb_head;
+	struct rr_packet *pkt;
 	int ret;
 
-	ret = msm_ipc_router_recv_from(port_ptr, &in_skb_head, src, 0);
-
+	ret = msm_ipc_router_recv_from(port_ptr, &pkt, src, 0);
 	if (ret < 0) {
 		if (ret != -ENOMSG)
 			pr_err("%s: msm_ipc_router_recv_from failed - ret: %d\n",
@@ -2395,12 +2729,12 @@
 		return ret;
 	}
 
-	*data = msm_ipc_router_skb_to_buf(in_skb_head, ret);
+	*data = msm_ipc_router_skb_to_buf(pkt->pkt_fragment_q, ret);
 	if (!(*data))
 		pr_err("%s: Buf conversion failed\n", __func__);
 
 	*len = ret;
-	msm_ipc_router_free_skb(in_skb_head);
+	release_pkt(pkt);
 	return 0;
 }
 
diff --git a/arch/arm/mach-msm/ipc_router.h b/arch/arm/mach-msm/ipc_router.h
index 7bfc52b..8ffd661 100644
--- a/arch/arm/mach-msm/ipc_router.h
+++ b/arch/arm/mach-msm/ipc_router.h
@@ -24,12 +24,17 @@
 #include <net/sock.h>
 
 /* definitions for the R2R wire protcol */
-#define IPC_ROUTER_VERSION			1
+#define IPC_ROUTER_V1		1
+/*
+ * Ambiguous definition but will enable multiplexing IPC_ROUTER_V2 packets
+ * with an existing alternate transport in user-space, if needed.
+ */
+#define IPC_ROUTER_V2		3
 
-#define IPC_ROUTER_CLIENT_BCAST_ID		0xffffffff
-#define IPC_ROUTER_ADDRESS			0xfffffffe
+#define IPC_ROUTER_ADDRESS			0x0000FFFF
 
 #define IPC_ROUTER_NID_LOCAL			1
+#define MAX_IPC_PKT_SIZE 66000
 
 #define IPC_ROUTER_CTRL_CMD_DATA		1
 #define IPC_ROUTER_CTRL_CMD_HELLO		2
@@ -55,6 +60,11 @@
 #define ALL_SERVICE 0xFFFFFFFF
 #define ALL_INSTANCE 0xFFFFFFFF
 
+#define CONTROL_FLAG_CONFIRM_RX 0x1
+#define CONTROL_FLAG_OPT_HDR 0x2
+
+#define FRAG_PKT_WRITE_ENABLE 0x1
+
 enum {
 	CLIENT_PORT,
 	SERVER_PORT,
@@ -68,10 +78,22 @@
 	MULTI_LINK_MODE,
 };
 
+/**
+ * rr_control_msg - Control message structure
+ * @cmd: Command identifier for HELLO message in Version 1.
+ * @hello: Message structure for HELLO message in Version 2.
+ * @srv: Message structure for NEW_SERVER/REMOVE_SERVER events.
+ * @cli: Message structure for REMOVE_CLIENT event.
+ */
 union rr_control_msg {
 	uint32_t cmd;
 	struct {
 		uint32_t cmd;
+		uint32_t magic;
+		uint32_t capability;
+	} hello;
+	struct {
+		uint32_t cmd;
 		uint32_t service;
 		uint32_t instance;
 		uint32_t node_id;
@@ -84,22 +106,67 @@
 	} cli;
 };
 
-struct rr_header {
+/**
+ * rr_header_v1 - IPC Router header version 1
+ * @version: Version information.
+ * @type: IPC Router Message Type.
+ * @src_node_id: Source Node ID of the message.
+ * @src_port_id: Source Port ID of the message.
+ * @control_flag: Flag to indicate flow control.
+ * @size: Size of the IPC Router payload.
+ * @dst_node_id: Destination Node ID of the message.
+ * @dst_port_id: Destination Port ID of the message.
+ */
+struct rr_header_v1 {
 	uint32_t version;
 	uint32_t type;
 	uint32_t src_node_id;
 	uint32_t src_port_id;
-	uint32_t confirm_rx;
+	uint32_t control_flag;
 	uint32_t size;
 	uint32_t dst_node_id;
 	uint32_t dst_port_id;
 };
 
-#define IPC_ROUTER_HDR_SIZE sizeof(struct rr_header)
-#define MAX_IPC_PKT_SIZE 66000
+/**
+ * rr_header_v2 - IPC Router header version 2
+ * @version: Version information.
+ * @type: IPC Router Message Type.
+ * @control_flag: Flags to indicate flow control, optional header etc.
+ * @size: Size of the IPC Router payload.
+ * @src_node_id: Source Node ID of the message.
+ * @src_port_id: Source Port ID of the message.
+ * @dst_node_id: Destination Node ID of the message.
+ * @dst_port_id: Destination Port ID of the message.
+ */
+struct rr_header_v2 {
+	uint8_t version;
+	uint8_t type;
+	uint16_t control_flag;
+	uint32_t size;
+	uint16_t src_node_id;
+	uint16_t src_port_id;
+	uint16_t dst_node_id;
+	uint16_t dst_port_id;
+} __attribute__((__packed__));
 
+union rr_header {
+	struct rr_header_v1 hdr_v1;
+	struct rr_header_v2 hdr_v2;
+};
+
+#define IPC_ROUTER_HDR_SIZE sizeof(union rr_header)
+
+/**
+ * rr_packet - Router to Router packet structure
+ * @list: Pointer to prev & next packets in a port's rx list.
+ * @hdr: Header information extracted from or prepended to a packet.
+ * @pkt_fragment_q: Queue of SKBs containing payload.
+ * @length: Length of data in the chain of SKBs
+ */
 struct rr_packet {
 	struct list_head list;
+	struct rr_header_v1 hdr;
 	struct sk_buff_head *pkt_fragment_q;
 	uint32_t length;
 };
@@ -110,11 +177,28 @@
 	void *default_pil;
 };
 
+/**
+ * msm_ipc_router_xprt - Structure to hold XPRT specific information
+ * @name: Name of the XPRT.
+ * @link_id: Network cluster ID to which the XPRT belongs to.
+ * @priv: XPRT's private data.
+ * @get_version: Method to get header version supported by the XPRT.
+ * @get_option: Method to get XPRT specific options.
+ * @read_avail: Method to get data size available to be read from the XPRT.
+ * @read: Method to read data from the XPRT.
+ * @write_avail: Method to get write space available in the XPRT.
+ * @write: Method to write data to the XPRT.
+ * @close: Method to close the XPRT.
+ * @sft_close_done: Method to indicate to the XPRT that handling of reset
+ *                  event is complete.
+ */
 struct msm_ipc_router_xprt {
 	char *name;
 	uint32_t link_id;
 	void *priv;
 
+	int (*get_version)(struct msm_ipc_router_xprt *xprt);
+	int (*get_option)(struct msm_ipc_router_xprt *xprt);
 	int (*read_avail)(struct msm_ipc_router_xprt *xprt);
 	int (*read)(void *data, uint32_t len,
 		    struct msm_ipc_router_xprt *xprt);
@@ -141,12 +225,12 @@
 			   struct sk_buff_head *data,
 			   struct msm_ipc_addr *dest);
 int msm_ipc_router_read(struct msm_ipc_port *port_ptr,
-			struct sk_buff_head **data,
+			struct rr_packet **pkt,
 			size_t buf_len);
 int msm_ipc_router_bind_control_port(struct msm_ipc_port *port_ptr);
 
 int msm_ipc_router_recv_from(struct msm_ipc_port *port_ptr,
-		      struct sk_buff_head **data,
+		      struct rr_packet **pkt,
 		      struct msm_ipc_addr *src_addr,
 		      long timeout);
 int msm_ipc_router_register_server(struct msm_ipc_port *server_port,
@@ -173,4 +257,5 @@
 static inline void msm_ipc_unload_default_node(void *pil) { }
 #endif
 
+void msm_ipc_router_free_skb(struct sk_buff_head *skb_head);
 #endif
diff --git a/arch/arm/mach-msm/ipc_router_hsic_xprt.c b/arch/arm/mach-msm/ipc_router_hsic_xprt.c
new file mode 100644
index 0000000..0427c1c
--- /dev/null
+++ b/arch/arm/mach-msm/ipc_router_hsic_xprt.c
@@ -0,0 +1,503 @@
+/* Copyright (c) 2013, The Linux Foundation. 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 and
+ * only 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.
+ */
+
+/*
+ * IPC ROUTER HSIC XPRT module.
+ */
+#define DEBUG
+
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/types.h>
+
+#include <mach/ipc_bridge.h>
+#include <mach/subsystem_restart.h>
+
+#include "ipc_router.h"
+
+static int msm_ipc_router_hsic_xprt_debug_mask;
+module_param_named(debug_mask, msm_ipc_router_hsic_xprt_debug_mask,
+		   int, S_IRUGO | S_IWUSR | S_IWGRP);
+
+#if defined(DEBUG)
+#define D(x...) do { \
+if (msm_ipc_router_hsic_xprt_debug_mask) \
+	pr_info(x); \
+} while (0)
+#else
+#define D(x...) do { } while (0)
+#endif
+
+#define NUM_HSIC_XPRTS 1
+#define XPRT_NAME_LEN 32
+
+/**
+ * msm_ipc_router_hsic_xprt - IPC Router's HSIC XPRT strucutre
+ * @xprt: IPC Router XPRT structure to contain HSIC XPRT specific info.
+ * @pdev: Platform device registered by IPC Bridge function driver.
+ * @hsic_xprt_wq: Workqueue to queue read & other XPRT related works.
+ * @read_work: Read Work to perform read operation from HSIC's ipc_bridge.
+ * @in_pkt: Pointer to any partially read packet.
+ * @ss_reset_lock: Lock to protect access to the ss_reset flag.
+ * @sft_close_complete: Variable to indicate completion of SSR handling
+ *                      by IPC Router.
+ * @xprt_version: IPC Router header version supported by this XPRT.
+ * @xprt_option: XPRT specific options to be handled by IPC Router.
+ */
+struct msm_ipc_router_hsic_xprt {
+	struct msm_ipc_router_xprt xprt;
+	struct platform_device *pdev;
+	struct workqueue_struct *hsic_xprt_wq;
+	struct delayed_work read_work;
+	struct rr_packet *in_pkt;
+	struct mutex ss_reset_lock;
+	int ss_reset;
+	struct completion sft_close_complete;
+	unsigned xprt_version;
+	unsigned xprt_option;
+};
+
+struct msm_ipc_router_hsic_xprt_work {
+	struct msm_ipc_router_xprt *xprt;
+	struct work_struct work;
+};
+
+static void hsic_xprt_read_data(struct work_struct *work);
+
+/**
+ * msm_ipc_router_hsic_xprt_config - Config. Info. of each HSIC XPRT
+ * @ch_name: Name of the HSIC endpoint exported by ipc_bridge driver.
+ * @xprt_name: Name of the XPRT to be registered with IPC Router.
+ * @hsic_pdev_id: ID to differentiate among multiple ipc_bridge endpoints.
+ * @link_id: Network Cluster ID to which this XPRT belongs to.
+ * @xprt_version: IPC Router header version supported by this XPRT.
+ */
+struct msm_ipc_router_hsic_xprt_config {
+	char ch_name[XPRT_NAME_LEN];
+	char xprt_name[XPRT_NAME_LEN];
+	int hsic_pdev_id;
+	uint32_t link_id;
+	unsigned xprt_version;
+};
+
+struct msm_ipc_router_hsic_xprt_config hsic_xprt_cfg[] = {
+	{"ipc_bridge", "ipc_rtr_ipc_bridge1", 1, 1, 3},
+};
+
+static struct msm_ipc_router_hsic_xprt hsic_remote_xprt[NUM_HSIC_XPRTS];
+
+/**
+ * find_hsic_xprt_cfg() - Find the config info specific to an HSIC endpoint
+ * @pdev: Platform device registered by HSIC's ipc_bridge driver
+ *
+ * @return: Index to the entry in the hsic_remote_xprt table if matching
+ *          endpoint is found, < 0 on error.
+ *
+ * This function is used to find the configuration information specific to
+ * an HSIC endpoint from the hsic_remote_xprt table.
+ */
+static int find_hsic_xprt_cfg(struct platform_device *pdev)
+{
+	int i;
+
+	for (i = 0; i < NUM_HSIC_XPRTS; i++) {
+		/* TODO: Update the condition for multiple hsic links */
+		if (!strncmp(pdev->name, hsic_xprt_cfg[i].ch_name, 32))
+			return i;
+	}
+
+	return -ENODEV;
+}
+
+/**
+ * msm_ipc_router_hsic_get_xprt_version() - Get IPC Router header version
+ *                                          supported by the XPRT
+ * @xprt: XPRT for which the version information is required.
+ *
+ * @return: IPC Router header version supported by the XPRT.
+ */
+static int msm_ipc_router_hsic_get_xprt_version(
+	struct msm_ipc_router_xprt *xprt)
+{
+	struct msm_ipc_router_hsic_xprt *hsic_xprtp;
+	if (!xprt)
+		return -EINVAL;
+	hsic_xprtp = container_of(xprt, struct msm_ipc_router_hsic_xprt, xprt);
+
+	return (int)hsic_xprtp->xprt_version;
+}
+
+/**
+ * msm_ipc_router_hsic_get_xprt_option() - Get XPRT options
+ * @xprt: XPRT for which the option information is required.
+ *
+ * @return: Options supported by the XPRT.
+ */
+static int msm_ipc_router_hsic_get_xprt_option(
+	struct msm_ipc_router_xprt *xprt)
+{
+	struct msm_ipc_router_hsic_xprt *hsic_xprtp;
+	if (!xprt)
+		return -EINVAL;
+	hsic_xprtp = container_of(xprt, struct msm_ipc_router_hsic_xprt, xprt);
+
+	return (int)hsic_xprtp->xprt_option;
+}
+
+/**
+ * msm_ipc_router_hsic_remote_write_avail() - Get available write space
+ * @xprt: XPRT for which the available write space info. is required.
+ *
+ * @return: Write space in bytes on success, 0 on SSR.
+ */
+static int msm_ipc_router_hsic_remote_write_avail(
+	struct msm_ipc_router_xprt *xprt)
+{
+	struct ipc_bridge_platform_data *pdata;
+	int write_avail;
+	struct msm_ipc_router_hsic_xprt *hsic_xprtp =
+		container_of(xprt, struct msm_ipc_router_hsic_xprt, xprt);
+
+	mutex_lock(&hsic_xprtp->ss_reset_lock);
+	if (hsic_xprtp->ss_reset || !hsic_xprtp->pdev) {
+		write_avail = 0;
+	} else {
+		pdata = hsic_xprtp->pdev->dev.platform_data;
+		write_avail = pdata->max_write_size;
+	}
+	mutex_unlock(&hsic_xprtp->ss_reset_lock);
+	return write_avail;
+}
+
+/**
+ * msm_ipc_router_hsic_remote_write() - Write to XPRT
+ * @data: Data to be written to the XPRT.
+ * @len: Length of the data to be written.
+ * @xprt: XPRT to which the data has to be written.
+ *
+ * @return: Data Length on success, standard Linux error codes on failure.
+ */
+static int msm_ipc_router_hsic_remote_write(void *data,
+		uint32_t len, struct msm_ipc_router_xprt *xprt)
+{
+	struct rr_packet *pkt = (struct rr_packet *)data;
+	struct sk_buff *skb;
+	struct ipc_bridge_platform_data *pdata;
+	struct msm_ipc_router_hsic_xprt *hsic_xprtp;
+	int ret;
+
+	if (!pkt || pkt->length != len || !xprt) {
+		pr_err("%s: Invalid input parameters\n", __func__);
+		return -EINVAL;
+	}
+
+	hsic_xprtp = container_of(xprt, struct msm_ipc_router_hsic_xprt, xprt);
+	mutex_lock(&hsic_xprtp->ss_reset_lock);
+	if (hsic_xprtp->ss_reset) {
+		pr_err("%s: Trying to write on a reset link\n", __func__);
+		mutex_unlock(&hsic_xprtp->ss_reset_lock);
+		return -ENETRESET;
+	}
+
+	if (!hsic_xprtp->pdev) {
+		pr_err("%s: Trying to write on a closed link\n", __func__);
+		mutex_unlock(&hsic_xprtp->ss_reset_lock);
+		return -ENODEV;
+	}
+
+	pdata = hsic_xprtp->pdev->dev.platform_data;
+	if (!pdata || !pdata->write) {
+		pr_err("%s on a uninitialized link\n", __func__);
+		mutex_unlock(&hsic_xprtp->ss_reset_lock);
+		return -EFAULT;
+	}
+
+	skb = skb_peek(pkt->pkt_fragment_q);
+	if (!skb) {
+		pr_err("%s SKB is NULL\n", __func__);
+		mutex_unlock(&hsic_xprtp->ss_reset_lock);
+		return -EINVAL;
+	}
+	D("%s: About to write %d bytes\n", __func__, len);
+	ret = pdata->write(hsic_xprtp->pdev, skb->data, skb->len);
+	if (ret == skb->len)
+		ret = len;
+	D("%s: Finished writing %d bytes\n", __func__, len);
+	mutex_unlock(&hsic_xprtp->ss_reset_lock);
+	return ret;
+}
+
+/**
+ * msm_ipc_router_hsic_remote_close() - Close the XPRT
+ * @xprt: XPRT which needs to be closed.
+ *
+ * @return: 0 on success, standard Linux error codes on failure.
+ */
+static int msm_ipc_router_hsic_remote_close(
+	struct msm_ipc_router_xprt *xprt)
+{
+	struct msm_ipc_router_hsic_xprt *hsic_xprtp;
+	struct ipc_bridge_platform_data *pdata;
+
+	if (!xprt)
+		return -EINVAL;
+	hsic_xprtp = container_of(xprt, struct msm_ipc_router_hsic_xprt, xprt);
+
+	mutex_lock(&hsic_xprtp->ss_reset_lock);
+	hsic_xprtp->ss_reset = 1;
+	mutex_unlock(&hsic_xprtp->ss_reset_lock);
+	flush_workqueue(hsic_xprtp->hsic_xprt_wq);
+	destroy_workqueue(hsic_xprtp->hsic_xprt_wq);
+	pdata = hsic_xprtp->pdev->dev.platform_data;
+	if (pdata && pdata->close)
+		pdata->close(hsic_xprtp->pdev);
+	hsic_xprtp->pdev = NULL;
+	return 0;
+}
+
+/**
+ * hsic_xprt_read_data() - Read work to read from the XPRT
+ * @work: Read work to be executed.
+ *
+ * This function is a read work item queued on a XPRT specific workqueue.
+ * The work parameter contains information regarding the XPRT on which this
+ * read work has to be performed. The work item keeps reading from the HSIC
+ * endpoint, until the endpoint returns an error.
+ */
+static void hsic_xprt_read_data(struct work_struct *work)
+{
+	int pkt_size;
+	struct sk_buff *skb = NULL;
+	void *data;
+	struct ipc_bridge_platform_data *pdata;
+	struct delayed_work *rwork = to_delayed_work(work);
+	struct msm_ipc_router_hsic_xprt *hsic_xprtp =
+		container_of(rwork, struct msm_ipc_router_hsic_xprt, read_work);
+
+	while (1) {
+		mutex_lock(&hsic_xprtp->ss_reset_lock);
+		if (hsic_xprtp->ss_reset) {
+			mutex_unlock(&hsic_xprtp->ss_reset_lock);
+			break;
+		}
+		pdata = hsic_xprtp->pdev->dev.platform_data;
+		mutex_unlock(&hsic_xprtp->ss_reset_lock);
+		while (!hsic_xprtp->in_pkt) {
+			hsic_xprtp->in_pkt = kzalloc(sizeof(struct rr_packet),
+						     GFP_KERNEL);
+			if (hsic_xprtp->in_pkt)
+				break;
+			pr_err("%s: packet allocation failure\n", __func__);
+			msleep(100);
+		}
+		while (!hsic_xprtp->in_pkt->pkt_fragment_q) {
+			hsic_xprtp->in_pkt->pkt_fragment_q =
+				kmalloc(sizeof(struct sk_buff_head),
+					GFP_KERNEL);
+			if (hsic_xprtp->in_pkt->pkt_fragment_q)
+				break;
+			pr_err("%s: Couldn't alloc pkt_fragment_q\n",
+				__func__);
+			msleep(100);
+		}
+		skb_queue_head_init(hsic_xprtp->in_pkt->pkt_fragment_q);
+		D("%s: Allocated rr_packet\n", __func__);
+
+		while (!skb) {
+			skb = alloc_skb(pdata->max_read_size, GFP_KERNEL);
+			if (skb)
+				break;
+			pr_err("%s: Couldn't alloc SKB\n", __func__);
+			msleep(100);
+		}
+		data = skb_put(skb, pdata->max_read_size);
+		pkt_size = pdata->read(hsic_xprtp->pdev, data,
+					pdata->max_read_size);
+		if (pkt_size < 0) {
+			pr_err("%s: Error %d @ read operation\n",
+				__func__, pkt_size);
+			kfree_skb(skb);
+			kfree(hsic_xprtp->in_pkt->pkt_fragment_q);
+			kfree(hsic_xprtp->in_pkt);
+			break;
+		}
+		skb_queue_tail(hsic_xprtp->in_pkt->pkt_fragment_q, skb);
+		hsic_xprtp->in_pkt->length = pkt_size;
+		D("%s: Packet size read %d\n", __func__, pkt_size);
+		msm_ipc_router_xprt_notify(&hsic_xprtp->xprt,
+			IPC_ROUTER_XPRT_EVENT_DATA, (void *)hsic_xprtp->in_pkt);
+		release_pkt(hsic_xprtp->in_pkt);
+		hsic_xprtp->in_pkt = NULL;
+		skb = NULL;
+	}
+}
+
+/**
+ * hsic_xprt_sft_close_done() - Completion of XPRT reset
+ * @xprt: XPRT on which the reset operation is complete.
+ *
+ * This function is used by IPC Router to signal this HSIC XPRT Abstraction
+ * Layer(XAL) that the reset of XPRT is completely handled by IPC Router.
+ */
+static void hsic_xprt_sft_close_done(struct msm_ipc_router_xprt *xprt)
+{
+	struct msm_ipc_router_hsic_xprt *hsic_xprtp =
+		container_of(xprt, struct msm_ipc_router_hsic_xprt, xprt);
+
+	complete_all(&hsic_xprtp->sft_close_complete);
+}
+
+/**
+ * msm_ipc_router_hsic_remote_remove() - Remove an HSIC endpoint
+ * @pdev: Platform device corresponding to HSIC endpoint.
+ *
+ * @return: 0 on success, standard Linux error codes on error.
+ *
+ * This function is called when the underlying ipc_bridge driver unregisters
+ * a platform device, mapped to an HSIC endpoint, during SSR.
+ */
+static int msm_ipc_router_hsic_remote_remove(struct platform_device *pdev)
+{
+	int id;
+	struct ipc_bridge_platform_data *pdata;
+
+	id = find_hsic_xprt_cfg(pdev);
+	if (id < 0) {
+		pr_err("%s: called for unknown ch %s\n",
+			__func__, pdev->name);
+		return id;
+	}
+
+	mutex_lock(&hsic_remote_xprt[id].ss_reset_lock);
+	hsic_remote_xprt[id].ss_reset = 1;
+	mutex_unlock(&hsic_remote_xprt[id].ss_reset_lock);
+	flush_workqueue(hsic_remote_xprt[id].hsic_xprt_wq);
+	destroy_workqueue(hsic_remote_xprt[id].hsic_xprt_wq);
+	init_completion(&hsic_remote_xprt[id].sft_close_complete);
+	msm_ipc_router_xprt_notify(&hsic_remote_xprt[id].xprt,
+				   IPC_ROUTER_XPRT_EVENT_CLOSE, NULL);
+	D("%s: Notified IPC Router of %s CLOSE\n",
+	  __func__, hsic_remote_xprt[id].xprt.name);
+	wait_for_completion(&hsic_remote_xprt[id].sft_close_complete);
+	hsic_remote_xprt[id].pdev = NULL;
+	pdata = pdev->dev.platform_data;
+	if (pdata && pdata->close)
+		pdata->close(pdev);
+	return 0;
+}
+
+/**
+ * msm_ipc_router_hsic_remote_probe() - Probe an HSIC endpoint
+ * @pdev: Platform device corresponding to HSIC endpoint.
+ *
+ * @return: 0 on success, standard Linux error codes on error.
+ *
+ * This function is called when the underlying ipc_bridge driver registers
+ * a platform device, mapped to an HSIC endpoint.
+ */
+static int msm_ipc_router_hsic_remote_probe(struct platform_device *pdev)
+{
+	int rc;
+	int id;		/*Index into the hsic_xprt_cfg table*/
+	struct ipc_bridge_platform_data *pdata;
+
+	pdata = pdev->dev.platform_data;
+	if (!pdata || !pdata->open || !pdata->read ||
+	    !pdata->write || !pdata->close) {
+		pr_err("%s: pdata or pdata->operations is NULL\n", __func__);
+		return -EINVAL;
+	}
+
+	id = find_hsic_xprt_cfg(pdev);
+	if (id < 0) {
+		pr_err("%s: called for unknown ch %s\n",
+			__func__, pdev->name);
+		return id;
+	}
+
+	hsic_remote_xprt[id].hsic_xprt_wq =
+		create_singlethread_workqueue(pdev->name);
+	if (!hsic_remote_xprt[id].hsic_xprt_wq) {
+		pr_err("%s: WQ creation failed for %s\n",
+			__func__, pdev->name);
+		return -EFAULT;
+	}
+
+	hsic_remote_xprt[id].xprt.name = hsic_xprt_cfg[id].xprt_name;
+	hsic_remote_xprt[id].xprt.link_id = hsic_xprt_cfg[id].link_id;
+	hsic_remote_xprt[id].xprt.get_version =
+		msm_ipc_router_hsic_get_xprt_version;
+	hsic_remote_xprt[id].xprt.get_option =
+		 msm_ipc_router_hsic_get_xprt_option;
+	hsic_remote_xprt[id].xprt.read_avail = NULL;
+	hsic_remote_xprt[id].xprt.read = NULL;
+	hsic_remote_xprt[id].xprt.write_avail =
+		msm_ipc_router_hsic_remote_write_avail;
+	hsic_remote_xprt[id].xprt.write = msm_ipc_router_hsic_remote_write;
+	hsic_remote_xprt[id].xprt.close = msm_ipc_router_hsic_remote_close;
+	hsic_remote_xprt[id].xprt.sft_close_done = hsic_xprt_sft_close_done;
+	hsic_remote_xprt[id].xprt.priv = NULL;
+
+	hsic_remote_xprt[id].in_pkt = NULL;
+	INIT_DELAYED_WORK(&hsic_remote_xprt[id].read_work, hsic_xprt_read_data);
+	mutex_init(&hsic_remote_xprt[id].ss_reset_lock);
+	hsic_remote_xprt[id].ss_reset = 0;
+	hsic_remote_xprt[id].xprt_version = hsic_xprt_cfg[id].xprt_version;
+	hsic_remote_xprt[id].xprt_option = 0;
+
+	rc = pdata->open(pdev);
+	if (rc < 0) {
+		pr_err("%s: Channel open failed for %s.%d\n",
+			__func__, pdev->name, pdev->id);
+		destroy_workqueue(hsic_remote_xprt[id].hsic_xprt_wq);
+		return rc;
+	}
+	hsic_remote_xprt[id].pdev = pdev;
+	msm_ipc_router_xprt_notify(&hsic_remote_xprt[id].xprt,
+				   IPC_ROUTER_XPRT_EVENT_OPEN, NULL);
+	D("%s: Notified IPC Router of %s OPEN\n",
+	  __func__, hsic_remote_xprt[id].xprt.name);
+	queue_delayed_work(hsic_remote_xprt[id].hsic_xprt_wq,
+			   &hsic_remote_xprt[id].read_work, 0);
+	return 0;
+}
+
+static struct platform_driver msm_ipc_router_hsic_remote_driver[] = {
+	{
+		.probe		= msm_ipc_router_hsic_remote_probe,
+		.remove		= msm_ipc_router_hsic_remote_remove,
+		.driver		= {
+				.name	= "ipc_bridge",
+				.owner	= THIS_MODULE,
+		},
+	},
+};
+
+static int __init msm_ipc_router_hsic_init(void)
+{
+	int i, ret, rc = 0;
+	BUG_ON(ARRAY_SIZE(hsic_xprt_cfg) != NUM_HSIC_XPRTS);
+	for (i = 0; i < ARRAY_SIZE(msm_ipc_router_hsic_remote_driver); i++) {
+		ret = platform_driver_register(
+				&msm_ipc_router_hsic_remote_driver[i]);
+		if (ret) {
+			pr_err("%s: Failed to register platform driver for xprt%d. Continuing...\n",
+				__func__, i);
+			rc = ret;
+		}
+	}
+	return rc;
+}
+
+module_init(msm_ipc_router_hsic_init);
+MODULE_DESCRIPTION("IPC Router HSIC XPRT");
+MODULE_LICENSE("GPL v2");
diff --git a/arch/arm/mach-msm/ipc_router_smd_xprt.c b/arch/arm/mach-msm/ipc_router_smd_xprt.c
index d6a3e03..87880c2 100644
--- a/arch/arm/mach-msm/ipc_router_smd_xprt.c
+++ b/arch/arm/mach-msm/ipc_router_smd_xprt.c
@@ -55,6 +55,8 @@
 	int ss_reset;
 	void *pil;
 	struct completion sft_close_complete;
+	unsigned xprt_version;
+	unsigned xprt_option;
 };
 
 struct msm_ipc_router_smd_xprt_work {
@@ -71,13 +73,14 @@
 	char xprt_name[XPRT_NAME_LEN];
 	uint32_t edge;
 	uint32_t link_id;
+	unsigned xprt_version;
 };
 
 struct msm_ipc_router_smd_xprt_config smd_xprt_cfg[] = {
-	{"RPCRPY_CNTL", "ipc_rtr_smd_rpcrpy_cntl", SMD_APPS_MODEM, 1},
-	{"IPCRTR", "ipc_rtr_smd_ipcrtr", SMD_APPS_MODEM, 1},
-	{"IPCRTR", "ipc_rtr_q6_ipcrtr", SMD_APPS_QDSP, 1},
-	{"IPCRTR", "ipc_rtr_wcnss_ipcrtr", SMD_APPS_WCNSS, 1},
+	{"RPCRPY_CNTL", "ipc_rtr_smd_rpcrpy_cntl", SMD_APPS_MODEM, 1, 1},
+	{"IPCRTR", "ipc_rtr_smd_ipcrtr", SMD_APPS_MODEM, 1, 1},
+	{"IPCRTR", "ipc_rtr_q6_ipcrtr", SMD_APPS_QDSP, 1, 1},
+	{"IPCRTR", "ipc_rtr_wcnss_ipcrtr", SMD_APPS_WCNSS, 1, 1},
 };
 
 static struct msm_ipc_router_smd_xprt smd_remote_xprt[NUM_SMD_XPRTS];
@@ -95,6 +98,28 @@
 	return -ENODEV;
 }
 
+static int msm_ipc_router_smd_get_xprt_version(
+	struct msm_ipc_router_xprt *xprt)
+{
+	struct msm_ipc_router_smd_xprt *smd_xprtp;
+	if (!xprt)
+		return -EINVAL;
+	smd_xprtp = container_of(xprt, struct msm_ipc_router_smd_xprt, xprt);
+
+	return (int)smd_xprtp->xprt_version;
+}
+
+static int msm_ipc_router_smd_get_xprt_option(
+	struct msm_ipc_router_xprt *xprt)
+{
+	struct msm_ipc_router_smd_xprt *smd_xprtp;
+	if (!xprt)
+		return -EINVAL;
+	smd_xprtp = container_of(xprt, struct msm_ipc_router_smd_xprt, xprt);
+
+	return (int)smd_xprtp->xprt_option;
+}
+
 static int msm_ipc_router_smd_remote_write_avail(
 	struct msm_ipc_router_xprt *xprt)
 {
@@ -110,7 +135,6 @@
 {
 	struct rr_packet *pkt = (struct rr_packet *)data;
 	struct sk_buff *ipc_rtr_pkt;
-	int align_sz, align_data = 0;
 	int offset, sz_written = 0;
 	int ret, num_retries = 0;
 	unsigned long flags;
@@ -123,9 +147,7 @@
 	if (!len || pkt->length != len)
 		return -EINVAL;
 
-	align_sz = ALIGN_SIZE(pkt->length);
-	while ((ret = smd_write_start(smd_xprtp->channel,
-				      (len + align_sz))) < 0) {
+	while ((ret = smd_write_start(smd_xprtp->channel, len)) < 0) {
 		spin_lock_irqsave(&smd_xprtp->ss_reset_lock, flags);
 		if (smd_xprtp->ss_reset) {
 			spin_unlock_irqrestore(&smd_xprtp->ss_reset_lock,
@@ -143,7 +165,7 @@
 		num_retries++;
 	}
 
-	D("%s: Ready to write\n", __func__);
+	D("%s: Ready to write %d bytes\n", __func__, len);
 	skb_queue_walk(pkt->pkt_fragment_q, ipc_rtr_pkt) {
 		offset = 0;
 		while (offset < ipc_rtr_pkt->len) {
@@ -175,30 +197,6 @@
 		  __func__, offset, xprt->name);
 	}
 
-	if (align_sz) {
-		if (smd_write_segment_avail(smd_xprtp->channel) < align_sz)
-			smd_enable_read_intr(smd_xprtp->channel);
-
-		wait_event(smd_xprtp->write_avail_wait_q,
-			((smd_write_segment_avail(smd_xprtp->channel) >=
-			 align_sz) || smd_xprtp->ss_reset));
-		smd_disable_read_intr(smd_xprtp->channel);
-		spin_lock_irqsave(&smd_xprtp->ss_reset_lock, flags);
-		if (smd_xprtp->ss_reset) {
-			spin_unlock_irqrestore(
-				&smd_xprtp->ss_reset_lock, flags);
-			pr_err("%s: %s chnl reset\n",
-				__func__, xprt->name);
-			return -ENETRESET;
-		}
-		spin_unlock_irqrestore(&smd_xprtp->ss_reset_lock,
-					flags);
-
-		smd_write_segment(smd_xprtp->channel,
-				  &align_data, align_sz, 0);
-		D("%s: Wrote %d align bytes over %s\n",
-		  __func__, align_sz, xprt->name);
-	}
 	if (!smd_write_end(smd_xprtp->channel))
 		D("%s: Finished writing\n", __func__);
 	return len;
@@ -453,6 +451,10 @@
 
 	smd_remote_xprt[id].xprt.name = smd_xprt_cfg[id].xprt_name;
 	smd_remote_xprt[id].xprt.link_id = smd_xprt_cfg[id].link_id;
+	smd_remote_xprt[id].xprt.get_version =
+		msm_ipc_router_smd_get_xprt_version;
+	smd_remote_xprt[id].xprt.get_option =
+		msm_ipc_router_smd_get_xprt_option;
 	smd_remote_xprt[id].xprt.read_avail = NULL;
 	smd_remote_xprt[id].xprt.read = NULL;
 	smd_remote_xprt[id].xprt.write_avail =
@@ -468,6 +470,8 @@
 	INIT_DELAYED_WORK(&smd_remote_xprt[id].read_work, smd_xprt_read_data);
 	spin_lock_init(&smd_remote_xprt[id].ss_reset_lock);
 	smd_remote_xprt[id].ss_reset = 0;
+	smd_remote_xprt[id].xprt_version = smd_xprt_cfg[id].xprt_version;
+	smd_remote_xprt[id].xprt_option = FRAG_PKT_WRITE_ENABLE;
 
 	smd_remote_xprt[id].pil = msm_ipc_load_subsystem(
 					smd_xprt_cfg[id].edge);
diff --git a/arch/arm/mach-msm/ipc_socket.c b/arch/arm/mach-msm/ipc_socket.c
index ea27c71..bdda546 100644
--- a/arch/arm/mach-msm/ipc_socket.c
+++ b/arch/arm/mach-msm/ipc_socket.c
@@ -131,12 +131,15 @@
 	int i, copied, first = 1;
 	int data_size = 0, request_size, offset;
 	void *data;
+	int last = 0;
+	int align_size;
 
 	for (i = 0; i < num_sect; i++)
 		data_size += msg_sect[i].iov_len;
 
 	if (!data_size)
 		return NULL;
+	align_size = ALIGN_SIZE(data_size);
 
 	msg_head = kmalloc(sizeof(struct sk_buff_head), GFP_KERNEL);
 	if (!msg_head) {
@@ -148,10 +151,14 @@
 	for (copied = 1, i = 0; copied && (i < num_sect); i++) {
 		data_size = msg_sect[i].iov_len;
 		offset = 0;
+		if (i == (num_sect - 1))
+			last = 1;
 		while (offset != msg_sect[i].iov_len) {
 			request_size = data_size;
 			if (first)
 				request_size += IPC_ROUTER_HDR_SIZE;
+			if (last)
+				request_size += align_size;
 
 			msg = alloc_skb(request_size, GFP_KERNEL);
 			if (!msg) {
@@ -161,6 +168,7 @@
 					goto msg_build_failure;
 				}
 				data_size = data_size / 2;
+				last = 0;
 				continue;
 			}
 
@@ -182,6 +190,8 @@
 			skb_queue_tail(msg_head, msg);
 			offset += data_size;
 			data_size = msg_sect[i].iov_len - offset;
+			if (i == (num_sect - 1))
+				last = 1;
 		}
 	}
 	return msg_head;
@@ -196,24 +206,23 @@
 }
 
 static int msm_ipc_router_extract_msg(struct msghdr *m,
-				      struct sk_buff_head *msg_head)
+				      struct rr_packet *pkt)
 {
 	struct sockaddr_msm_ipc *addr;
-	struct rr_header *hdr;
+	struct rr_header_v1 *hdr;
 	struct sk_buff *temp;
 	union rr_control_msg *ctl_msg;
 	int offset = 0, data_len = 0, copy_len;
 
-	if (!m || !msg_head) {
+	if (!m || !pkt) {
 		pr_err("%s: Invalid pointers passed\n", __func__);
 		return -EINVAL;
 	}
 	addr = (struct sockaddr_msm_ipc *)m->msg_name;
 
-	temp = skb_peek(msg_head);
-	hdr = (struct rr_header *)(temp->data);
+	hdr = &(pkt->hdr);
 	if (addr && (hdr->type == IPC_ROUTER_CTRL_CMD_RESUME_TX)) {
-		skb_pull(temp, IPC_ROUTER_HDR_SIZE);
+		temp = skb_peek(pkt->pkt_fragment_q);
 		ctl_msg = (union rr_control_msg *)(temp->data);
 		addr->family = AF_MSM_IPC;
 		addr->address.addrtype = MSM_IPC_ADDR_ID;
@@ -222,7 +231,7 @@
 		m->msg_namelen = sizeof(struct sockaddr_msm_ipc);
 		return offset;
 	}
-	if (addr && (hdr->src_port_id != IPC_ROUTER_ADDRESS)) {
+	if (addr && (hdr->type == IPC_ROUTER_CTRL_CMD_DATA)) {
 		addr->family = AF_MSM_IPC;
 		addr->address.addrtype = MSM_IPC_ADDR_ID;
 		addr->address.addr.port_addr.node_id = hdr->src_node_id;
@@ -231,8 +240,7 @@
 	}
 
 	data_len = hdr->size;
-	skb_pull(temp, IPC_ROUTER_HDR_SIZE);
-	skb_queue_walk(msg_head, temp) {
+	skb_queue_walk(pkt->pkt_fragment_q, temp) {
 		copy_len = data_len < temp->len ? data_len : temp->len;
 		if (copy_to_user(m->msg_iov->iov_base + offset, temp->data,
 				 copy_len)) {
@@ -245,22 +253,6 @@
 	return offset;
 }
 
-static void msm_ipc_router_release_msg(struct sk_buff_head *msg_head)
-{
-	struct sk_buff *temp;
-
-	if (!msg_head) {
-		pr_err("%s: Invalid msg pointer\n", __func__);
-		return;
-	}
-
-	while (!skb_queue_empty(msg_head)) {
-		temp = skb_dequeue(msg_head);
-		kfree_skb(temp);
-	}
-	kfree(msg_head);
-}
-
 static int msm_ipc_router_create(struct net *net,
 				 struct socket *sock,
 				 int protocol,
@@ -385,8 +377,16 @@
 	if (ipc_buf)
 		msm_ipc_router_ipc_log(IPC_SEND, ipc_buf, port_ptr);
 	ret = msm_ipc_router_send_to(port_ptr, msg, &dest->address);
-	if (ret == (IPC_ROUTER_HDR_SIZE + total_len))
-		ret = total_len;
+	if (ret != total_len) {
+		if (ret < 0) {
+			if (ret != -EAGAIN)
+				pr_err("%s: Send_to failure %d\n",
+							__func__, ret);
+			msm_ipc_router_free_skb(msg);
+		} else if (ret >= 0) {
+			ret = -EFAULT;
+		}
+	}
 
 out_sendmsg:
 	release_sock(sk);
@@ -398,7 +398,7 @@
 {
 	struct sock *sk = sock->sk;
 	struct msm_ipc_port *port_ptr = msm_ipc_sk_port(sk);
-	struct sk_buff_head *msg;
+	struct rr_packet *pkt;
 	struct sk_buff *ipc_buf;
 	long timeout;
 	int ret;
@@ -420,18 +420,17 @@
 		return ret;
 	}
 
-	ret = msm_ipc_router_read(port_ptr, &msg, buf_len);
-	if (ret <= 0 || !msg) {
+	ret = msm_ipc_router_read(port_ptr, &pkt, buf_len);
+	if (ret <= 0 || !pkt) {
 		release_sock(sk);
 		return ret;
 	}
 
-	ret = msm_ipc_router_extract_msg(m, msg);
-	ipc_buf = skb_peek(msg);
+	ret = msm_ipc_router_extract_msg(m, pkt);
+	ipc_buf = skb_peek(pkt->pkt_fragment_q);
 	if (ipc_buf)
 		msm_ipc_router_ipc_log(IPC_RECV, ipc_buf, port_ptr);
-	msm_ipc_router_release_msg(msg);
-	msg = NULL;
+	release_pkt(pkt);
 	release_sock(sk);
 	return ret;
 }
@@ -460,7 +459,7 @@
 
 	switch (cmd) {
 	case IPC_ROUTER_IOCTL_GET_VERSION:
-		n = IPC_ROUTER_VERSION;
+		n = IPC_ROUTER_V1;
 		ret = put_user(n, (unsigned int *)arg);
 		break;
 
diff --git a/arch/arm/mach-msm/krait-regulator-pmic.c b/arch/arm/mach-msm/krait-regulator-pmic.c
new file mode 100644
index 0000000..5081e7b
--- /dev/null
+++ b/arch/arm/mach-msm/krait-regulator-pmic.c
@@ -0,0 +1,403 @@
+/* Copyright (c) 2013, The Linux Foundation. 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 and
+ * only 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.
+ */
+
+#define pr_fmt(fmt)	"PMIC PDN %s: " fmt, __func__
+
+#include <linux/module.h>
+#include <linux/slab.h>
+#include <linux/of.h>
+#include <linux/spmi.h>
+#include <linux/delay.h>
+
+#define KRAIT_REG_PMIC_DEV_NAME "qcom,krait-regulator-pmic"
+
+#define REG_DIG_MAJOR		0x01
+#define REG_DIG_MINOR		0x00
+
+#define REG_PERPH_TYPE		0x04
+#define CTRL_TYPE_VAL		0x1C
+#define PS_TYPE_VAL		0x1C
+#define FREQ_TYPE_VAL		0x1D
+
+#define REG_PERPH_SUBTYPE	0x05
+#define CTRL_SUBTYPE_VAL	0x08
+#define PS_SUBTYPE_VAL		0x01
+#define FREQ_SUBTYPE_VAL	0x19
+
+#define REG_V_CTL1		0x40
+#define V_CTL1_VAL		0x00
+
+#define REG_MODE_CTL		0x45
+#define NPM_MODE_BIT		BIT(7)
+#define AUTO_MODE_BIT		BIT(6)
+
+#define REG_EN_CTL		0x46
+#define EN_BIT			BIT(7)
+
+#define REG_PD_CTL		0x48
+#define PD_CTL_VAL		0x08
+
+#define REG_MULTIPHASE_CTL	0x51
+#define MULTIPHASE_EN_BIT	BIT(7)
+
+#define REG_PHASE_CTL		0x52
+#define BALANCE_EN_BIT		BIT(7)
+
+#define REG_VS_CTL		0x61
+#define VS_CTL_VAL		0x85
+
+#define REG_GANG_CTL2		0xC1
+#define GANG_EN_BIT		BIT(7)
+
+#define REG_PWM_CL			0x60
+
+struct krait_vreg_pmic_chip {
+	struct spmi_device	*spmi;
+	u16			ctrl_base;
+	u16			ps_base;
+	u16			freq_base;
+	u8			ctrl_dig_major;
+	u8			ctrl_dig_minor;
+};
+
+static struct krait_vreg_pmic_chip *the_chip;
+
+static struct of_device_id krait_vreg_pmic_match_table[] = {
+	{ .compatible = KRAIT_REG_PMIC_DEV_NAME },
+	{}
+};
+
+static int read_byte(struct spmi_device *spmi, u16 addr, u8 *val)
+{
+	int rc;
+
+	rc = spmi_ext_register_readl(spmi->ctrl, spmi->sid, addr, val, 1);
+	if (rc) {
+		pr_err("SPMI read failed [%d,0x%04x] rc=%d\n",
+							spmi->sid, addr, rc);
+		return rc;
+	}
+	return 0;
+}
+
+static int write_byte(struct spmi_device *spmi, u16 addr, u8 *val)
+{
+	int rc;
+
+	rc = spmi_ext_register_writel(spmi->ctrl, spmi->sid, addr, val, 1);
+	if (rc) {
+		pr_err("SPMI write failed [%d,0x%04x] val = 0x%02x rc=%d\n",
+						spmi->sid, addr, *val, rc);
+		return rc;
+	}
+	return 0;
+}
+
+#define ISTEP_MA			500
+#define IOFFSET_MA			1000
+#define OVERSHOOT_DIG_MAJOR		1
+#define OVERSHOOT_DIG_MINOR		1
+static bool v_overshoot_fixed(void)
+{
+	if (the_chip->ctrl_dig_major > OVERSHOOT_DIG_MAJOR
+		|| (the_chip->ctrl_dig_major == OVERSHOOT_DIG_MAJOR
+		&& the_chip->ctrl_dig_minor > OVERSHOOT_DIG_MINOR)) {
+		pr_debug("fixed in h/w\n");
+		return true;
+	}
+	return false;
+}
+
+/**
+ * krait_pmic_is_ready - function to check if the driver is initialized
+ *
+ * CONTEXT: Can be called in atomic context
+ *
+ * RETURNS: true if this driver has initialized, false otherwise
+ */
+bool krait_pmic_is_ready(void)
+{
+	if (the_chip == NULL) {
+		pr_debug("kait_regulator_pmic not ready yet\n");
+		return false;
+	}
+	return true;
+}
+EXPORT_SYMBOL(krait_pmic_is_ready);
+
+#define I_PFM_MA		2000
+
+/**
+ * krait_pmic_post_pfm_entry - workarounds after entering pfm mode
+ *
+ * CONTEXT: Can be called in atomic context
+ *
+ * RETURNS: 0 on success, error code on failure
+ */
+int krait_pmic_post_pfm_entry(void)
+{
+	u8 setpoint;
+	int rc;
+
+	if (the_chip == NULL) {
+		pr_debug("kait_regulator_pmic not ready yet\n");
+		return -ENXIO;
+	}
+
+	if (v_overshoot_fixed())
+		return 0;
+
+	setpoint = (I_PFM_MA - IOFFSET_MA) / ISTEP_MA;
+	rc = write_byte(the_chip->spmi,
+			the_chip->ps_base + REG_PWM_CL, &setpoint);
+	pr_debug("wrote 0x%02x->[%d 0x%04x] rc = %d\n", setpoint,
+			the_chip->spmi->sid,
+			the_chip->ps_base + REG_PWM_CL, rc);
+	return rc;
+}
+EXPORT_SYMBOL(krait_pmic_post_pfm_entry);
+
+#define I_PWM_MA		3500
+/**
+ * krait_pmic_post_pwm_entry - workarounds after entering pwm mode
+ *
+ * CONTEXT: Can be called in atomic context
+ *
+ * RETURNS: 0 on success, error code on failure
+ */
+int krait_pmic_post_pwm_entry(void)
+{
+	u8 setpoint;
+	int rc;
+
+	if (the_chip == NULL) {
+		pr_debug("kait_regulator_pmic not ready yet\n");
+		return -ENXIO;
+	}
+
+	if (v_overshoot_fixed())
+		return 0;
+
+	udelay(50);
+	setpoint = (I_PWM_MA - IOFFSET_MA) / ISTEP_MA;
+
+	rc = write_byte(the_chip->spmi,
+			the_chip->ps_base + REG_PWM_CL, &setpoint);
+	pr_debug("wrote 0x%02x->[%d 0x%04x] rc = %d\n", setpoint,
+			the_chip->spmi->sid,
+			the_chip->ps_base + REG_PWM_CL, rc);
+	return rc;
+}
+EXPORT_SYMBOL(krait_pmic_post_pwm_entry);
+
+#define READ_BYTE(chip, addr, val, rc)				\
+do {								\
+	rc = read_byte(chip->spmi, (addr), &val);		\
+	if (rc)						\
+		pr_err("register read failed rc=%d\n", rc);	\
+} while (0)
+
+#define GANGED_VREG_COUNT	4
+static int gang_configuration_check(struct krait_vreg_pmic_chip *chip)
+{
+	u8 val;
+	int rc;
+	int i;
+
+	return 0;
+
+	READ_BYTE(chip, chip->ctrl_base + REG_V_CTL1, val, rc);
+	if (rc)
+		return rc;
+	BUG_ON(val != V_CTL1_VAL);
+
+	READ_BYTE(chip, chip->ctrl_base + REG_MODE_CTL, val, rc);
+	if (rc)
+		return rc;
+	/* The Auto mode should be off */
+	BUG_ON(val & AUTO_MODE_BIT);
+	/* The NPM mode should be on */
+	BUG_ON(!(val & NPM_MODE_BIT));
+
+	READ_BYTE(chip, chip->ctrl_base + REG_EN_CTL, val, rc);
+	if (rc)
+		return rc;
+	/* The en bit should be set */
+	BUG_ON(val & EN_BIT);
+
+	READ_BYTE(chip, chip->ctrl_base + REG_PD_CTL, val, rc);
+	if (rc)
+		return rc;
+	BUG_ON(val != PD_CTL_VAL);
+
+	READ_BYTE(chip, chip->ctrl_base + REG_MULTIPHASE_CTL, val, rc);
+	if (rc)
+		return rc;
+	BUG_ON(!(val & MULTIPHASE_EN_BIT));
+
+	READ_BYTE(chip, chip->ctrl_base + REG_PHASE_CTL, val, rc);
+	if (rc)
+		return rc;
+	BUG_ON(!(val & BALANCE_EN_BIT));
+
+	READ_BYTE(chip, chip->ctrl_base + REG_VS_CTL, val, rc);
+	if (rc)
+		return rc;
+	BUG_ON(val != VS_CTL_VAL);
+
+	for (i = 0; i < GANGED_VREG_COUNT; i++) {
+		READ_BYTE(chip,
+			chip->ctrl_base + i * 0x300 + REG_GANG_CTL2, val, rc);
+		if (rc)
+			return rc;
+
+		if (!(val & GANG_EN_BIT)) {
+			pr_err("buck = %d, ctrl gang not enabled\n", i);
+			BUG();
+		}
+	}
+
+	for (i = 0; i < GANGED_VREG_COUNT; i++) {
+		READ_BYTE(chip,
+			chip->ps_base + i * 0x300 + REG_GANG_CTL2, val, rc);
+		if (rc)
+			return rc;
+
+		if (!(val & GANG_EN_BIT)) {
+			pr_err("buck = %d, ps gang not enabled\n", i);
+			BUG();
+		}
+	}
+
+	for (i = 0; i < GANGED_VREG_COUNT; i++) {
+		READ_BYTE(chip,
+			chip->freq_base + i * 0x300 + REG_GANG_CTL2, val, rc);
+		if (rc)
+			return rc;
+
+		if (!(val & GANG_EN_BIT)) {
+			pr_err("buck = %d, freq gang not enabled\n", i);
+			BUG();
+		}
+	}
+	return 0;
+}
+
+static int __devinit krait_vreg_pmic_probe(struct spmi_device *spmi)
+{
+	u8 type, subtype;
+	int rc;
+	struct krait_vreg_pmic_chip *chip;
+	struct spmi_resource *spmi_resource;
+	struct resource *resource;
+
+	chip = devm_kzalloc(&spmi->dev, sizeof *chip, GFP_KERNEL);
+	if (chip == NULL) {
+		pr_err("kzalloc() failed.\n");
+		return -ENOMEM;
+	}
+
+	chip->spmi = spmi;
+
+	spmi_for_each_container_dev(spmi_resource, spmi) {
+		if (!spmi_resource) {
+			pr_err("spmi resource absent\n");
+			return -ENXIO;
+		}
+
+		resource = spmi_get_resource(spmi, spmi_resource,
+							IORESOURCE_MEM, 0);
+		if (!(resource && resource->start)) {
+			pr_err("node %s IO resource absent!\n",
+					spmi->dev.of_node->full_name);
+			return -ENXIO;
+		}
+
+		rc = read_byte(chip->spmi,
+				resource->start + REG_PERPH_TYPE,
+				&type);
+		if (rc) {
+			pr_err("Peripheral type read failed rc=%d\n", rc);
+			return -ENXIO;
+		}
+
+		rc = read_byte(chip->spmi,
+				resource->start + REG_PERPH_SUBTYPE,
+				&subtype);
+		if (rc) {
+			pr_err("Peripheral subtype read failed rc=%d\n", rc);
+			return -ENXIO;
+		}
+
+		if (type == CTRL_TYPE_VAL && subtype == CTRL_SUBTYPE_VAL)
+			chip->ctrl_base = resource->start;
+		else if (type == PS_TYPE_VAL && subtype == PS_SUBTYPE_VAL)
+			chip->ps_base = resource->start;
+		else if (type == FREQ_TYPE_VAL && subtype == FREQ_SUBTYPE_VAL)
+			chip->freq_base = resource->start;
+	}
+
+	if (chip->ctrl_base == 0) {
+		pr_err("ctrl base address missing\n");
+		return -ENXIO;
+	}
+
+	if (chip->ps_base == 0) {
+		pr_err("ps base address missing\n");
+		return -ENXIO;
+	}
+
+	if (chip->freq_base == 0) {
+		pr_err("freq base address missing\n");
+		return -ENXIO;
+	}
+
+	READ_BYTE(chip, chip->ctrl_base + REG_DIG_MAJOR,
+			chip->ctrl_dig_major, rc);
+	if (rc)
+		return rc;
+
+	READ_BYTE(chip, chip->ctrl_base + REG_DIG_MINOR,
+			chip->ctrl_dig_minor, rc);
+	if (rc)
+		return rc;
+
+	gang_configuration_check(chip);
+
+	the_chip = chip;
+	return 0;
+}
+
+static struct spmi_driver qpnp_revid_driver = {
+	.probe	= krait_vreg_pmic_probe,
+	.driver	= {
+		.name		= KRAIT_REG_PMIC_DEV_NAME,
+		.owner		= THIS_MODULE,
+		.of_match_table	= krait_vreg_pmic_match_table,
+	},
+};
+
+static int __init qpnp_revid_init(void)
+{
+	return spmi_driver_register(&qpnp_revid_driver);
+}
+
+static void __exit qpnp_revid_exit(void)
+{
+	return spmi_driver_unregister(&qpnp_revid_driver);
+}
+
+module_init(qpnp_revid_init);
+module_exit(qpnp_revid_exit);
+
+MODULE_DESCRIPTION("KRAIT REGULATOR PMIC DRIVER");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/gpu/msm/adreno_trace.c b/arch/arm/mach-msm/krait-regulator-pmic.h
similarity index 70%
copy from drivers/gpu/msm/adreno_trace.c
copy to arch/arm/mach-msm/krait-regulator-pmic.h
index 607ba8c..06ca3ea 100644
--- a/drivers/gpu/msm/adreno_trace.c
+++ b/arch/arm/mach-msm/krait-regulator-pmic.h
@@ -8,11 +8,11 @@
  * 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 "adreno.h"
-
-/* Instantiate tracepoints */
-#define CREATE_TRACE_POINTS
-#include "adreno_trace.h"
+#ifndef __ARCH_ARM_MACH_MSM_KRAIT_REGULATOR_PMIC_H
+#define __ARCH_ARM_MACH_MSM_KRAIT_REGULATOR_PMIC_H
+bool krait_pmic_is_ready(void);
+int krait_pmic_post_pfm_entry(void);
+int krait_pmic_post_pwm_entry(void);
+#endif
diff --git a/arch/arm/mach-msm/krait-regulator.c b/arch/arm/mach-msm/krait-regulator.c
index 9c5f197..4fee0ae 100644
--- a/arch/arm/mach-msm/krait-regulator.c
+++ b/arch/arm/mach-msm/krait-regulator.c
@@ -29,7 +29,9 @@
 #include <linux/regulator/krait-regulator.h>
 #include <linux/debugfs.h>
 #include <linux/syscore_ops.h>
+#include <linux/cpu.h>
 #include <mach/msm_iomap.h>
+#include "krait-regulator-pmic.h"
 
 #include "spm.h"
 #include "pm.h"
@@ -222,8 +224,9 @@
 	int				cpu_num;
 	int				coeff1;
 	int				coeff2;
-	bool				online;
+	bool				reg_en;
 	int				online_at_probe;
+	bool				force_bhs;
 };
 
 DEFINE_PER_CPU(struct krait_power_vreg *, krait_vregs);
@@ -372,7 +375,7 @@
 		phase_scaling_factor = pvreg->efuse_phase_scaling_factor;
 
 	list_for_each_entry(kvreg, &pvreg->krait_power_vregs, link) {
-		if (!kvreg->online)
+		if (!kvreg->reg_en)
 			continue;
 
 		if (kvreg->mode == LDO_MODE) {
@@ -414,7 +417,7 @@
 	struct krait_power_vreg *kvreg;
 
 	list_for_each_entry(kvreg, &pvreg->krait_power_vregs, link) {
-		if (kvreg->online)
+		if (kvreg->reg_en)
 			online_total++;
 	}
 	return online_total;
@@ -427,7 +430,7 @@
 	struct pmic_gang_vreg *pvreg = from->pvreg;
 
 	list_for_each_entry(kvreg, &pvreg->krait_power_vregs, link) {
-		if (!kvreg->online)
+		if (!kvreg->reg_en)
 			continue;
 		load_total += kvreg->load;
 	}
@@ -474,16 +477,18 @@
 	}
 
 	/* First check if the coeff is low for PFM mode */
-	if (load_total <= pvreg->pfm_threshold && n_online == 1) {
+	if (load_total <= pvreg->pfm_threshold
+			&& n_online == 1
+			&& krait_pmic_is_ready()) {
 		if (!pvreg->pfm_mode) {
 			rc = msm_spm_enable_fts_lpm(PMIC_FTS_MODE_PFM);
 			if (rc) {
 				pr_err("%s PFM en failed load_t %d rc = %d\n",
 					from->name, load_total, rc);
 				return rc;
-			} else {
-				pvreg->pfm_mode = true;
 			}
+			krait_pmic_post_pfm_entry();
+			pvreg->pfm_mode = true;
 		}
 		return rc;
 	}
@@ -495,10 +500,10 @@
 			pr_err("%s PFM exit failed load %d rc = %d\n",
 				from->name, coeff_total, rc);
 			return rc;
-		} else {
-			pvreg->pfm_mode = false;
-			udelay(PWM_SETTLING_TIME_US);
 		}
+		pvreg->pfm_mode = false;
+		krait_pmic_post_pwm_entry();
+		udelay(PWM_SETTLING_TIME_US);
 	}
 
 	/* calculate phases */
@@ -565,7 +570,7 @@
 
 	mutex_lock(&pvreg->krait_power_vregs_lock);
 	kvreg->load = load_uA;
-	if (!kvreg->online) {
+	if (!kvreg->reg_en) {
 		mutex_unlock(&pvreg->krait_power_vregs_lock);
 		return kvreg->mode;
 	}
@@ -588,10 +593,10 @@
 	return kvreg->mode;
 }
 
-static int switch_to_using_hs(struct krait_power_vreg *kvreg)
+static void __switch_to_using_bhs(void *info)
 {
-	if (kvreg->mode == HS_MODE)
-		return 0;
+	struct krait_power_vreg *kvreg = info;
+
 	/* enable bhs */
 	if (version > KPSS_VERSION_2P0) {
 		krait_masked_write(kvreg, APC_PWR_GATE_MODE,
@@ -645,21 +650,18 @@
 
 	kvreg->mode = HS_MODE;
 	pr_debug("%s using BHS\n", kvreg->name);
-	return 0;
 }
 
-static int switch_to_using_ldo(struct krait_power_vreg *kvreg)
+static void __switch_to_using_ldo(void *info)
 {
-	if (kvreg->mode == LDO_MODE
-		&& get_krait_ldo_uv(kvreg) == kvreg->uV - kvreg->ldo_delta_uV)
-		return 0;
+	struct krait_power_vreg *kvreg = info;
 
 	/*
 	 * if the krait is in ldo mode and a voltage change is requested on the
 	 * ldo switch to using hs before changing ldo voltage
 	 */
 	if (kvreg->mode == LDO_MODE)
-		switch_to_using_hs(kvreg);
+		__switch_to_using_bhs(kvreg);
 
 	set_krait_ldo_uv(kvreg, kvreg->uV - kvreg->ldo_delta_uV);
 	if (version > KPSS_VERSION_2P0) {
@@ -698,7 +700,25 @@
 
 	kvreg->mode = LDO_MODE;
 	pr_debug("%s using LDO\n", kvreg->name);
-	return 0;
+}
+
+static int switch_to_using_ldo(struct krait_power_vreg *kvreg)
+{
+	if (kvreg->mode == LDO_MODE
+		&& get_krait_ldo_uv(kvreg) == kvreg->uV - kvreg->ldo_delta_uV)
+		return 0;
+
+	return smp_call_function_single(kvreg->cpu_num,
+			__switch_to_using_ldo, kvreg, 1);
+}
+
+static int switch_to_using_bhs(struct krait_power_vreg *kvreg)
+{
+	if (kvreg->mode == HS_MODE)
+		return 0;
+
+	return smp_call_function_single(kvreg->cpu_num,
+			__switch_to_using_bhs, kvreg, 1);
 }
 
 static int set_pmic_gang_voltage(struct pmic_gang_vreg *pvreg, int uV)
@@ -740,7 +760,7 @@
 
 	setpoint = DIV_ROUND_UP(uV, LV_RANGE_STEP);
 
-	rc = msm_spm_apcs_set_vdd(setpoint);
+	rc = msm_spm_set_vdd(0, setpoint); /* value of CPU is don't care */
 	if (rc < 0)
 		pr_err("could not set %duV setpt = 0x%x rc = %d\n",
 				uV, setpoint, rc);
@@ -750,6 +770,41 @@
 	return rc;
 }
 
+static int configure_ldo_or_hs_one(struct krait_power_vreg *kvreg, int vmax)
+{
+	int rc;
+
+	if (!kvreg->reg_en)
+		return 0;
+
+	if (kvreg->force_bhs)
+		/*
+		 * The cpu is in transitory phase where it is being
+		 * prepared to be offlined or onlined and is being
+		 * forced to run on BHS during that time
+		 */
+		return 0;
+
+	if (kvreg->uV <= kvreg->ldo_threshold_uV
+		&& kvreg->uV - kvreg->ldo_delta_uV + kvreg->headroom_uV
+			<= vmax) {
+		rc = switch_to_using_ldo(kvreg);
+		if (rc < 0) {
+			pr_err("could not switch %s to ldo rc = %d\n",
+						kvreg->name, rc);
+			return rc;
+		}
+	} else {
+		rc = switch_to_using_bhs(kvreg);
+		if (rc < 0) {
+			pr_err("could not switch %s to hs rc = %d\n",
+						kvreg->name, rc);
+			return rc;
+		}
+	}
+	return 0;
+}
+
 static int configure_ldo_or_hs_all(struct krait_power_vreg *from, int vmax)
 {
 	struct pmic_gang_vreg *pvreg = from->pvreg;
@@ -757,27 +812,12 @@
 	int rc = 0;
 
 	list_for_each_entry(kvreg, &pvreg->krait_power_vregs, link) {
-		if (!kvreg->online)
-			continue;
-		if (kvreg->uV <= kvreg->ldo_threshold_uV
-			&& kvreg->uV - kvreg->ldo_delta_uV + kvreg->headroom_uV
-				<= vmax) {
-			rc = switch_to_using_ldo(kvreg);
-			if (rc < 0) {
-				pr_err("could not switch %s to ldo rc = %d\n",
-							kvreg->name, rc);
-				return rc;
-			}
-		} else {
-			rc = switch_to_using_hs(kvreg);
-			if (rc < 0) {
-				pr_err("could not switch %s to hs rc = %d\n",
-							kvreg->name, rc);
-				return rc;
-			}
+		rc = configure_ldo_or_hs_one(kvreg, vmax);
+		if (rc) {
+			pr_err("could not switch %s\n", kvreg->name);
+			break;
 		}
 	}
-
 	return rc;
 }
 
@@ -856,7 +896,7 @@
 	struct krait_power_vreg *kvreg;
 
 	list_for_each_entry(kvreg, &pvreg->krait_power_vregs, link) {
-		if (!kvreg->online)
+		if (!kvreg->reg_en)
 			continue;
 
 		v = kvreg->uV;
@@ -896,7 +936,7 @@
 		rc = krait_voltage_decrease(kvreg, vmax);
 
 	if (rc < 0) {
-		dev_err(&rdev->dev, "%s failed to set %duV from %duV rc = %d\n",
+		pr_err("%s failed to set %duV from %duV rc = %d\n",
 				kvreg->name, requested_uV, orig_krait_uV, rc);
 	}
 
@@ -927,7 +967,7 @@
 	}
 
 	mutex_lock(&pvreg->krait_power_vregs_lock);
-	if (!kvreg->online) {
+	if (!kvreg->reg_en) {
 		kvreg->uV = min_uV;
 		mutex_unlock(&pvreg->krait_power_vregs_lock);
 		return 0;
@@ -943,7 +983,7 @@
 {
 	struct krait_power_vreg *kvreg = rdev_get_drvdata(rdev);
 
-	return kvreg->online;
+	return kvreg->reg_en;
 }
 
 static int krait_power_enable(struct regulator_dev *rdev)
@@ -953,8 +993,9 @@
 	int rc;
 
 	mutex_lock(&pvreg->krait_power_vregs_lock);
+	pr_debug("enable %s\n", kvreg->name);
 	__krait_power_mdd_enable(kvreg, true);
-	kvreg->online = true;
+	kvreg->reg_en = true;
 	rc = _get_optimum_mode(rdev, kvreg->uV, kvreg->uV, kvreg->load);
 	if (rc < 0)
 		goto en_err;
@@ -975,7 +1016,8 @@
 	int rc;
 
 	mutex_lock(&pvreg->krait_power_vregs_lock);
-	kvreg->online = false;
+	pr_debug("disable %s\n", kvreg->name);
+	kvreg->reg_en = false;
 
 	rc = _get_optimum_mode(rdev, kvreg->uV, kvreg->uV, kvreg->load);
 	if (rc < 0)
@@ -999,6 +1041,69 @@
 	.is_enabled		= krait_power_is_enabled,
 };
 
+static int krait_regulator_cpu_callback(struct notifier_block *nfb,
+					    unsigned long action, void *hcpu)
+{
+	int cpu = (int)hcpu;
+	struct krait_power_vreg *kvreg = per_cpu(krait_vregs, cpu);
+	struct pmic_gang_vreg *pvreg = kvreg->pvreg;
+
+	pr_debug("start state=0x%02x, cpu=%d is_online=%d\n",
+			(int)action, cpu, cpu_online(cpu));
+	switch (action & ~CPU_TASKS_FROZEN) {
+	case CPU_UP_PREPARE:
+		mutex_lock(&pvreg->krait_power_vregs_lock);
+		kvreg->force_bhs = true;
+		/*
+		 * cpu is offline at this point, force bhs on which ever cpu
+		 * this callback is running on
+		 */
+		pr_debug("%s force BHS locally\n", kvreg->name);
+		__switch_to_using_bhs(kvreg);
+		mutex_unlock(&pvreg->krait_power_vregs_lock);
+		break;
+	case CPU_UP_CANCELED:
+	case CPU_ONLINE:
+		mutex_lock(&pvreg->krait_power_vregs_lock);
+		kvreg->force_bhs = false;
+		/*
+		 * switch the cpu to proper bhs/ldo, the cpu is online at this
+		 * point. The gang voltage and mode votes for the cpu were
+		 * submitted in CPU_UP_PREPARE phase
+		 */
+		configure_ldo_or_hs_one(kvreg, pvreg->pmic_vmax_uV);
+		mutex_unlock(&pvreg->krait_power_vregs_lock);
+		break;
+	case CPU_DOWN_PREPARE:
+		mutex_lock(&pvreg->krait_power_vregs_lock);
+		kvreg->force_bhs = true;
+		/*
+		 * switch the cpu to run on bhs using smp function calls. Note
+		 * that the cpu is online at this point.
+		 */
+		pr_debug("%s force BHS remotely\n", kvreg->name);
+		switch_to_using_bhs(kvreg);
+		mutex_unlock(&pvreg->krait_power_vregs_lock);
+		break;
+	case CPU_DOWN_FAILED:
+		mutex_lock(&pvreg->krait_power_vregs_lock);
+		kvreg->force_bhs = false;
+		configure_ldo_or_hs_one(kvreg, pvreg->pmic_vmax_uV);
+		mutex_unlock(&pvreg->krait_power_vregs_lock);
+		break;
+	default:
+		break;
+	}
+
+	pr_debug("done state=0x%02x, cpu=%d is_online=%d\n",
+			(int)action, cpu, cpu_online(cpu));
+	return NOTIFY_OK;
+}
+
+static struct notifier_block krait_cpu_notifier = {
+	.notifier_call = krait_regulator_cpu_callback,
+};
+
 static struct dentry *dent;
 static int get_retention_dbg_uV(void *data, u64 *val)
 {
@@ -1481,11 +1586,14 @@
 				KRAIT_REGULATOR_DRIVER_NAME, rc);
 		return rc;
 	}
+
+	register_hotcpu_notifier(&krait_cpu_notifier);
 	return platform_driver_register(&krait_pdn_driver);
 }
 
 static void __exit krait_power_exit(void)
 {
+	unregister_hotcpu_notifier(&krait_cpu_notifier);
 	platform_driver_unregister(&krait_power_driver);
 	platform_driver_unregister(&krait_pdn_driver);
 }
diff --git a/arch/arm/mach-msm/mpm-of.c b/arch/arm/mach-msm/mpm-of.c
index a0746f9..e364393 100644
--- a/arch/arm/mach-msm/mpm-of.c
+++ b/arch/arm/mach-msm/mpm-of.c
@@ -219,12 +219,16 @@
 	hlist_for_each_entry(node, elem, &irq_hash[hashfn(d->hwirq)], node) {
 		if ((node->hwirq == d->hwirq)
 				&& (d->domain == node->domain)) {
-			/* Update the linux irq mapping */
-			msm_mpm_irqs_m2a[node->pin] = d->irq;
+			/*
+			 * Update the linux irq mapping. No update required for
+			 * bypass interrupts
+			 */
+			if (node->pin != 0xff)
+				msm_mpm_irqs_m2a[node->pin] = d->irq;
 			break;
 		}
 	}
-	return node ? node->pin : 0;
+	return elem ? node->pin : 0;
 }
 
 static int msm_mpm_enable_irq_exclusive(
diff --git a/arch/arm/mach-msm/msm_bus/msm_bus_arb.c b/arch/arm/mach-msm/msm_bus/msm_bus_arb.c
index 3ff7530..058e409 100644
--- a/arch/arm/mach-msm/msm_bus/msm_bus_arb.c
+++ b/arch/arm/mach-msm/msm_bus/msm_bus_arb.c
@@ -652,15 +652,6 @@
 			MSM_BUS_DBG("ab: %llu ib: %llu\n", curr_bw, curr_clk);
 		}
 
-		if (index == 0) {
-			/* This check protects the bus driver from clients
-			 * that can leave non-zero requests after
-			 * unregistering.
-			 * */
-			req_clk = 0;
-			req_bw = 0;
-		}
-
 		if (!pdata->active_only) {
 			ret = update_path(src, pnode, req_clk, req_bw,
 				curr_clk, curr_bw, 0, pdata->active_only);
@@ -782,11 +773,47 @@
  */
 void msm_bus_scale_unregister_client(uint32_t cl)
 {
+	int i;
 	struct msm_bus_client *client = (struct msm_bus_client *)(cl);
+	bool warn = false;
 	if (IS_ERR_OR_NULL(client))
 		return;
-	if (client->curr != 0)
+
+	for (i = 0; i < client->pdata->usecase->num_paths; i++) {
+		if ((client->pdata->usecase[0].vectors[i].ab) ||
+			(client->pdata->usecase[0].vectors[i].ib)) {
+			warn = true;
+			break;
+		}
+	}
+
+	if (warn) {
+		int num_paths = client->pdata->usecase->num_paths;
+		int ab[num_paths], ib[num_paths];
+		WARN(1, "%s called unregister with non-zero vectors\n",
+			client->pdata->name);
+
+		/*
+		 * Save client values and zero them out to
+		 * cleanly unregister
+		 */
+		for (i = 0; i < num_paths; i++) {
+			ab[i] = client->pdata->usecase[0].vectors[i].ab;
+			ib[i] = client->pdata->usecase[0].vectors[i].ib;
+			client->pdata->usecase[0].vectors[i].ab = 0;
+			client->pdata->usecase[0].vectors[i].ib = 0;
+		}
+
 		msm_bus_scale_client_update_request(cl, 0);
+
+		/* Restore client vectors if required for re-registering. */
+		for (i = 0; i < num_paths; i++) {
+			client->pdata->usecase[0].vectors[i].ab = ab[i];
+			client->pdata->usecase[0].vectors[i].ib = ib[i];
+		}
+	} else if (client->curr != 0)
+		msm_bus_scale_client_update_request(cl, 0);
+
 	MSM_BUS_DBG("Unregistering client %d\n", cl);
 	mutex_lock(&msm_bus_lock);
 	msm_bus_scale_client_reset_pnodes(cl);
diff --git a/arch/arm/mach-msm/msm_bus/msm_bus_bimc.c b/arch/arm/mach-msm/msm_bus/msm_bus_bimc.c
index bc15fe8..8b64653 100644
--- a/arch/arm/mach-msm/msm_bus/msm_bus_bimc.c
+++ b/arch/arm/mach-msm/msm_bus/msm_bus_bimc.c
@@ -1876,7 +1876,7 @@
 	struct msm_bus_bimc_info *binfo;
 	struct msm_bus_bimc_qos_bw qbw;
 	int i;
-	long int bw;
+	int64_t bw;
 	int ports = info->node_info->num_mports;
 	struct msm_bus_bimc_commit *sel_cd =
 		(struct msm_bus_bimc_commit *)sel_cdata;
@@ -1912,11 +1912,11 @@
 			qbw.bw = sel_cd->mas[info->node_info->masterp[i]].bw;
 			qbw.ws = info->node_info->ws;
 			/* Threshold low = 90% of bw */
-			qbw.thl = (90 * bw) / 100;
+			qbw.thl = div_s64((90 * bw), 100);
 			/* Threshold medium = bw */
 			qbw.thm = bw;
 			/* Threshold high = 10% more than bw */
-			qbw.thh = (110 * bw) / 100;
+			qbw.thh = div_s64((110 * bw), 100);
 			/* Check if info is a shared master.
 			 * If it is, mark it dirty
 			 * If it isn't, then set QOS Bandwidth
diff --git a/arch/arm/mach-msm/msm_bus/msm_bus_core.h b/arch/arm/mach-msm/msm_bus/msm_bus_core.h
index 87719e3..7e4a513 100644
--- a/arch/arm/mach-msm/msm_bus/msm_bus_core.h
+++ b/arch/arm/mach-msm/msm_bus/msm_bus_core.h
@@ -36,7 +36,8 @@
 	(((slv >= MSM_BUS_SLAVE_FIRST) && (slv <= MSM_BUS_SLAVE_LAST)) ? 1 : 0)
 
 #define INTERLEAVED_BW(fab_pdata, bw, ports) \
-	((fab_pdata->il_flag) ? msm_bus_div64((ports), (bw)) : (bw))
+	((fab_pdata->il_flag) ? ((bw < 0) \
+	? -msm_bus_div64((ports), (-bw)) : msm_bus_div64((ports), (bw))) : (bw))
 #define INTERLEAVED_VAL(fab_pdata, n) \
 	((fab_pdata->il_flag) ? (n) : 1)
 
diff --git a/arch/arm/mach-msm/msm_bus/msm_bus_id.c b/arch/arm/mach-msm/msm_bus/msm_bus_id.c
index 7e9883f..25a749a 100644
--- a/arch/arm/mach-msm/msm_bus/msm_bus_id.c
+++ b/arch/arm/mach-msm/msm_bus/msm_bus_id.c
@@ -35,16 +35,22 @@
 		if (!fabreg->info[i].gateway) {
 			fabreg->info[i].priv_id = fabid + fabreg->info[i].id;
 			if (fabreg->info[i].id < SLAVE_ID_KEY) {
-				WARN(fabreg->info[i].id >= MSM_BUS_MASTER_LAST,
-					"id %d exceeds array size!\n",
-					fabreg->info[i].id);
+				if (fabreg->info[i].id >= MSM_BUS_MASTER_LAST) {
+					WARN(1, "id %d exceeds array size!\n",
+						fabreg->info[i].id);
+					continue;
+				}
+
 				master_iids[fabreg->info[i].id] =
 					fabreg->info[i].priv_id;
 			} else {
-				WARN((fabreg->info[i].id - SLAVE_ID_KEY) >=
-					(MSM_BUS_SLAVE_LAST - SLAVE_ID_KEY),
-					"id %d exceeds array size!\n",
-					fabreg->info[i].id);
+				if ((fabreg->info[i].id - SLAVE_ID_KEY) >=
+					(MSM_BUS_SLAVE_LAST - SLAVE_ID_KEY)) {
+					WARN(1, "id %d exceeds array size!\n",
+						fabreg->info[i].id);
+					continue;
+				}
+
 				slave_iids[fabreg->info[i].id - (SLAVE_ID_KEY)]
 					= fabreg->info[i].priv_id;
 			}
diff --git a/arch/arm/mach-msm/msm_bus/msm_bus_noc.c b/arch/arm/mach-msm/msm_bus/msm_bus_noc.c
index d33c340..8f7b7f2 100644
--- a/arch/arm/mach-msm/msm_bus/msm_bus_noc.c
+++ b/arch/arm/mach-msm/msm_bus/msm_bus_noc.c
@@ -511,7 +511,7 @@
 	struct msm_bus_noc_info *ninfo;
 	struct msm_bus_noc_qos_bw qos_bw;
 	int i, ports;
-	long int bw;
+	int64_t bw;
 	struct msm_bus_noc_commit *sel_cd =
 		(struct msm_bus_noc_commit *)sel_cdata;
 
diff --git a/arch/arm/mach-msm/msm_cache_dump.c b/arch/arm/mach-msm/msm_cache_dump.c
index 86e8963..a5593bf 100644
--- a/arch/arm/mach-msm/msm_cache_dump.c
+++ b/arch/arm/mach-msm/msm_cache_dump.c
@@ -23,15 +23,16 @@
 #include <linux/notifier.h>
 #include <linux/of.h>
 #include <linux/of_device.h>
+#include <linux/dma-mapping.h>
 #include <mach/scm.h>
 #include <mach/msm_cache_dump.h>
-#include <mach/memory.h>
 #include <mach/msm_iomap.h>
 #include <mach/msm_memory_dump.h>
 
 #define L2_DUMP_OFFSET 0x14
 
-static unsigned long msm_cache_dump_addr;
+static dma_addr_t msm_cache_dump_addr;
+static void *msm_cache_dump_vaddr;
 
 /*
  * These should not actually be dereferenced. There's no
@@ -76,7 +77,6 @@
 		unsigned long buf;
 		unsigned long size;
 	} l1_cache_data;
-	void *temp;
 	u32 l1_size, l2_size;
 	unsigned long total_size;
 
@@ -102,19 +102,20 @@
 	};
 
 	total_size = l1_size + l2_size;
-	msm_cache_dump_addr = allocate_contiguous_ebi_nomap(total_size, SZ_4K);
+	msm_cache_dump_vaddr = (void *) dma_alloc_coherent(&pdev->dev,
+					total_size, &msm_cache_dump_addr,
+					GFP_KERNEL);
 
-	if (!msm_cache_dump_addr) {
+	if (!msm_cache_dump_vaddr) {
 		pr_err("%s: Could not get memory for cache dumping\n",
 			__func__);
 		return -ENOMEM;
 	}
 
-	temp = ioremap(msm_cache_dump_addr, total_size);
-	memset(temp, 0xFF, total_size);
+	memset(msm_cache_dump_vaddr, 0xFF, total_size);
 	/* Clean caches before sending buffer to TZ */
-	clean_caches((unsigned long) temp, total_size, msm_cache_dump_addr);
-	iounmap(temp);
+	clean_caches((unsigned long) msm_cache_dump_vaddr, total_size,
+			msm_cache_dump_addr);
 
 	l1_cache_data.buf = msm_cache_dump_addr;
 	l1_cache_data.size = l1_size;
@@ -126,8 +127,9 @@
 		pr_err("%s: could not register L1 buffer ret = %d.\n",
 			__func__, ret);
 
-	l1_dump = (struct l1_cache_dump *)msm_cache_dump_addr;
-	l2_dump = (struct l2_cache_dump *)(msm_cache_dump_addr + l1_size);
+	l1_dump = (struct l1_cache_dump *)(uint32_t)msm_cache_dump_addr;
+	l2_dump = (struct l2_cache_dump *)(uint32_t)(msm_cache_dump_addr
+								+ l1_size);
 
 #if defined(CONFIG_MSM_CACHE_DUMP_ON_PANIC)
 	l1_cache_data.buf = msm_cache_dump_addr + l1_size;
diff --git a/arch/arm/mach-msm/msm_rtb.c b/arch/arm/mach-msm/msm_rtb.c
index fdf39be..28b2195 100644
--- a/arch/arm/mach-msm/msm_rtb.c
+++ b/arch/arm/mach-msm/msm_rtb.c
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2012, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2013, The Linux Foundation. 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 and
@@ -89,7 +89,7 @@
 	.notifier_call  = msm_rtb_panic_notifier,
 };
 
-int msm_rtb_event_should_log(enum logk_event_type log_type)
+int notrace msm_rtb_event_should_log(enum logk_event_type log_type)
 {
 	return msm_rtb.initialized && msm_rtb.enabled &&
 		((1 << (log_type & ~LOGTYPE_NOPC)) & msm_rtb.filter);
@@ -203,7 +203,7 @@
 }
 #endif
 
-int uncached_logk_pc(enum logk_event_type log_type, void *caller,
+int notrace uncached_logk_pc(enum logk_event_type log_type, void *caller,
 				void *data)
 {
 	int i;
@@ -219,7 +219,7 @@
 }
 EXPORT_SYMBOL(uncached_logk_pc);
 
-noinline int uncached_logk(enum logk_event_type log_type, void *data)
+noinline int notrace uncached_logk(enum logk_event_type log_type, void *data)
 {
 	return uncached_logk_pc(log_type, __builtin_return_address(0), data);
 }
diff --git a/arch/arm/mach-msm/perf_trace_counters.c b/arch/arm/mach-msm/perf_trace_counters.c
index 65b0d28..8fa73ae 100644
--- a/arch/arm/mach-msm/perf_trace_counters.c
+++ b/arch/arm/mach-msm/perf_trace_counters.c
@@ -106,7 +106,7 @@
 	dir = debugfs_create_dir("perf_debug_tp", NULL);
 	if (!dir)
 		return -ENOMEM;
-	file = debugfs_create_file("enabled", 0777, dir,
+	file = debugfs_create_file("enabled", 0660, dir,
 		&value, &fops_perftp);
 	if (!file) {
 		debugfs_remove(dir);
diff --git a/arch/arm/mach-msm/peripheral-loader.c b/arch/arm/mach-msm/peripheral-loader.c
index 8a3ecb1..157dc01 100644
--- a/arch/arm/mach-msm/peripheral-loader.c
+++ b/arch/arm/mach-msm/peripheral-loader.c
@@ -482,6 +482,9 @@
 	if (ret)
 		return ret;
 
+	pil_info(desc, "loading from %pa to %pa\n", &priv->region_start,
+							&priv->region_end);
+
 	for (i = 0; i < mdt->hdr.e_phnum; i++) {
 		phdr = &mdt->phdr[i];
 		if (!segment_is_loadable(phdr))
@@ -573,7 +576,8 @@
 {
 	int clk_ready = 0;
 
-	if (of_find_property(desc->dev->of_node,
+	if (desc->ops->proxy_unvote &&
+		of_find_property(desc->dev->of_node,
 				"qcom,gpio-proxy-unvote",
 				NULL)) {
 		clk_ready = of_get_named_gpio(desc->dev->of_node,
@@ -780,7 +784,7 @@
 		 "Invalid proxy unvote callback or a proxy timeout of 0"
 		 " was specified or no proxy unvote IRQ was specified.\n");
 
-	if (desc->proxy_unvote_irq > 0 && desc->ops->proxy_unvote) {
+	if (desc->proxy_unvote_irq) {
 		ret = request_threaded_irq(desc->proxy_unvote_irq,
 				  NULL,
 				  proxy_unvote_intr_handler,
diff --git a/arch/arm/mach-msm/pil-q6v5-lpass.c b/arch/arm/mach-msm/pil-q6v5-lpass.c
index a9a6942..de15be5 100644
--- a/arch/arm/mach-msm/pil-q6v5-lpass.c
+++ b/arch/arm/mach-msm/pil-q6v5-lpass.c
@@ -378,9 +378,7 @@
 {
 	struct lpass_data *drv = subsys_to_drv(dev_id);
 
-	disable_irq_nosync(drv->subsys_desc.wdog_bite_irq);
 	schedule_work(&drv->work);
-
 	return IRQ_HANDLED;
 }
 
diff --git a/arch/arm/mach-msm/pil-venus.c b/arch/arm/mach-msm/pil-venus.c
index a7ebbf7..e826a44 100644
--- a/arch/arm/mach-msm/pil-venus.c
+++ b/arch/arm/mach-msm/pil-venus.c
@@ -65,7 +65,7 @@
 
 
 /* PIL proxy vote timeout */
-#define VENUS_PROXY_TIMEOUT				10000
+#define VENUS_PROXY_TIMEOUT				2000
 
 /* Poll interval in uS */
 #define POLL_INTERVAL_US				50
@@ -288,17 +288,6 @@
 	unsigned long iova;
 	u32 ver, cpa_start_addr, cpa_end_addr, fw_start_addr, fw_end_addr;
 
-	/*
-	 * GDSC needs to remain on till Venus is shutdown. So, enable
-	 * the GDSC here again to make sure it remains on beyond the
-	 * expiry of the proxy vote timer.
-	 */
-	rc = regulator_enable(drv->gdsc);
-	if (rc) {
-		dev_err(pil->dev, "GDSC enable failed\n");
-		return rc;
-	}
-
 	/* Get Venus version number */
 	if (!drv->hw_ver_checked) {
 		ver = readl_relaxed(wrapper_base + VENUS_WRAPPER_HW_VERSION);
@@ -344,7 +333,7 @@
 	rc = iommu_attach_device(drv->iommu_fw_domain, drv->iommu_fw_ctx);
 	if (rc) {
 		dev_err(pil->dev, "venus fw iommu attach failed\n");
-		goto err_iommu_attach;
+		return rc;
 	}
 
 	/* Map virtual addr space 0 - fw_sz to firmware physical addr space */
@@ -366,9 +355,6 @@
 err_iommu_map:
 	iommu_detach_device(drv->iommu_fw_domain, drv->iommu_fw_ctx);
 
-err_iommu_attach:
-	regulator_disable(drv->gdsc);
-
 	return rc;
 }
 
@@ -424,8 +410,6 @@
 
 	venus_clock_disable_unprepare(pil->dev);
 
-	regulator_disable(drv->gdsc);
-
 	drv->is_booted = 0;
 
 	return 0;
@@ -454,22 +438,8 @@
 static int pil_venus_reset_trusted(struct pil_desc *pil)
 {
 	int rc;
-	struct venus_data *drv = dev_get_drvdata(pil->dev);
-
-	/*
-	 * GDSC needs to remain on till Venus is shutdown. So, enable
-	 * the GDSC here again to make sure it remains on beyond the
-	 * expiry of the proxy vote timer.
-	 */
-	rc = regulator_enable(drv->gdsc);
-	if (rc) {
-		dev_err(pil->dev, "GDSC enable failed\n");
-		return rc;
-	}
 
 	rc = pas_auth_and_reset(PAS_VIDC);
-	if (rc)
-		regulator_disable(drv->gdsc);
 
 	return rc;
 }
@@ -477,7 +447,6 @@
 static int pil_venus_shutdown_trusted(struct pil_desc *pil)
 {
 	int rc;
-	struct venus_data *drv = dev_get_drvdata(pil->dev);
 
 	venus_clock_prepare_enable(pil->dev);
 
@@ -485,8 +454,6 @@
 
 	venus_clock_disable_unprepare(pil->dev);
 
-	regulator_disable(drv->gdsc);
-
 	return rc;
 }
 
diff --git a/arch/arm/mach-msm/qdsp6v2/adsp-loader.c b/arch/arm/mach-msm/qdsp6v2/adsp-loader.c
index e74fdf9..0506e7e 100644
--- a/arch/arm/mach-msm/qdsp6v2/adsp-loader.c
+++ b/arch/arm/mach-msm/qdsp6v2/adsp-loader.c
@@ -20,39 +20,60 @@
 #include <mach/subsystem_restart.h>
 #include <mach/qdsp6v2/apr.h>
 #include <linux/of_device.h>
+#include <linux/sysfs.h>
 
 #define Q6_PIL_GET_DELAY_MS 100
+#define BOOT_CMD 1
+
+static ssize_t adsp_boot_store(struct kobject *kobj,
+	struct kobj_attribute *attr,
+	const char *buf, size_t count);
 
 struct adsp_loader_private {
 	void *pil_h;
+	struct kobject *boot_adsp_obj;
+	struct attribute_group *attr_group;
 };
 
-static int adsp_loader_probe(struct platform_device *pdev)
+static struct kobj_attribute adsp_boot_attribute =
+	__ATTR(boot, 0220, NULL, adsp_boot_store);
+
+static struct attribute *attrs[] = {
+	&adsp_boot_attribute.attr,
+	NULL,
+};
+
+static struct platform_device *adsp_private;
+
+static void adsp_loader_do(struct platform_device *pdev)
 {
-	struct adsp_loader_private *priv;
-	int rc = 0;
+
+	struct adsp_loader_private *priv = NULL;
+
 	const char *adsp_dt = "qcom,adsp-state";
+	int rc = 0;
 	u32 adsp_state;
 
 	rc = of_property_read_u32(pdev->dev.of_node, adsp_dt, &adsp_state);
 	if (rc) {
 		dev_err(&pdev->dev,
 			"%s: ADSP state = %x\n", __func__, adsp_state);
-		return rc;
+		return;
 	}
 
 	if (adsp_state == APR_SUBSYS_DOWN) {
-		priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL);
-		if (!priv)
-			return -ENOMEM;
+		if (pdev) {
+			priv = platform_get_drvdata(pdev);
+		} else {
+			pr_err("%s: Private data get failed\n", __func__);
+			goto fail;
+		}
 
-		platform_set_drvdata(pdev, priv);
 
 		priv->pil_h = subsystem_get("adsp");
 		if (IS_ERR(priv->pil_h)) {
-			pr_err("%s: pil get adsp failed, error:%d\n",
-				__func__, rc);
-			devm_kfree(&pdev->dev, priv);
+			pr_err("%s: pil get failed,\n",
+				__func__);
 			goto fail;
 		}
 
@@ -60,25 +81,123 @@
 		apr_set_q6_state(APR_SUBSYS_LOADED);
 	} else if (adsp_state == APR_SUBSYS_LOADED) {
 		dev_dbg(&pdev->dev,
-			"%s:MDM9x25 ADSP state = %x\n", __func__, adsp_state);
+			"%s: ADSP state = %x\n", __func__, adsp_state);
 		apr_set_q6_state(APR_SUBSYS_LOADED);
 	}
 
-	/* Query for MMPM API */
 
 	pr_info("%s: Q6/ADSP image is loaded\n", __func__);
+	return;
 fail:
-	return rc;
+
+	pr_err("%s: Q6/ADSP image loading failed\n", __func__);
+	return;
+}
+
+
+static ssize_t adsp_boot_store(struct kobject *kobj,
+	struct kobj_attribute *attr,
+	const char *buf,
+	size_t count)
+{
+	int boot = 0;
+	sscanf(buf, "%du", &boot);
+
+	if (boot == BOOT_CMD) {
+		pr_debug("%s:going to call adsp_loader_do", __func__);
+		adsp_loader_do(adsp_private);
+	}
+	return count;
+}
+
+static int adsp_loader_init_sysfs(struct platform_device *pdev)
+{
+	int ret = -EINVAL;
+	struct adsp_loader_private *priv = NULL;
+	adsp_private = NULL;
+
+	priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL);
+	if (!priv) {
+		pr_err("%s: memory alloc failed\n", __func__);
+		ret = -ENOMEM;
+		goto error_return;
+	}
+
+	platform_set_drvdata(pdev, priv);
+
+	priv->pil_h = NULL;
+	priv->boot_adsp_obj = NULL;
+	priv->attr_group = devm_kzalloc(&pdev->dev,
+				sizeof(*(priv->attr_group)),
+				GFP_KERNEL);
+	if (!priv->attr_group) {
+		pr_err("%s: malloc attr_group failed\n",
+						__func__);
+		ret = -ENOMEM;
+		goto error_return;
+	}
+
+	priv->attr_group->attrs = attrs;
+
+	priv->boot_adsp_obj = kobject_create_and_add("boot_adsp", kernel_kobj);
+	if (!priv->boot_adsp_obj) {
+		pr_err("%s: sysfs create and add failed\n",
+						__func__);
+		ret = -ENOMEM;
+		goto error_return;
+	}
+
+	ret = sysfs_create_group(priv->boot_adsp_obj, priv->attr_group);
+	if (ret) {
+		pr_err("%s: sysfs create group failed %d\n", \
+							__func__, ret);
+		goto error_return;
+	}
+
+	adsp_private = pdev;
+
+	return 0;
+
+error_return:
+
+	if (priv->boot_adsp_obj) {
+		kobject_del(priv->boot_adsp_obj);
+		priv->boot_adsp_obj = NULL;
+	}
+
+	return ret;
 }
 
 static int adsp_loader_remove(struct platform_device *pdev)
 {
-	struct adsp_loader_private *priv;
+	struct adsp_loader_private *priv = NULL;
 
 	priv = platform_get_drvdata(pdev);
-	if (priv != NULL)
+
+	if (!priv)
+		return 0;
+
+	if (priv->pil_h) {
 		subsystem_put(priv->pil_h);
-	pr_info("%s: Q6/ADSP image is unloaded\n", __func__);
+		priv->pil_h = NULL;
+	}
+
+	if (priv->boot_adsp_obj) {
+		sysfs_remove_group(priv->boot_adsp_obj, priv->attr_group);
+		kobject_del(priv->boot_adsp_obj);
+		priv->boot_adsp_obj = NULL;
+	}
+
+	return 0;
+}
+
+static int adsp_loader_probe(struct platform_device *pdev)
+{
+	int ret = adsp_loader_init_sysfs(pdev);
+	if (ret != 0) {
+		pr_err("%s: Error in initing sysfs\n", __func__);
+		return ret;
+	}
 
 	return 0;
 }
diff --git a/arch/arm/mach-msm/qdsp6v2/audio_aac.c b/arch/arm/mach-msm/qdsp6v2/audio_aac.c
index f4eb318..caeb79d 100644
--- a/arch/arm/mach-msm/qdsp6v2/audio_aac.c
+++ b/arch/arm/mach-msm/qdsp6v2/audio_aac.c
@@ -262,6 +262,10 @@
 		goto fail;
 	}
 	rc = audio_aio_open(audio, file);
+	if (rc < 0) {
+		pr_err("audio_aio_open rc=%d\n", rc);
+		goto fail;
+	}
 
 #ifdef CONFIG_DEBUG_FS
 	snprintf(name, sizeof name, "msm_aac_%04x", audio->ac->session);
diff --git a/arch/arm/mach-msm/qdsp6v2/audio_amrnb.c b/arch/arm/mach-msm/qdsp6v2/audio_amrnb.c
index 056a161..fc023c1 100644
--- a/arch/arm/mach-msm/qdsp6v2/audio_amrnb.c
+++ b/arch/arm/mach-msm/qdsp6v2/audio_amrnb.c
@@ -2,7 +2,7 @@
  *
  * Copyright (C) 2008 Google, Inc.
  * Copyright (C) 2008 HTC Corporation
- * Copyright (c) 2011-2012, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2011-2013, 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
@@ -120,6 +120,10 @@
 		goto fail;
 	}
 	rc = audio_aio_open(audio, file);
+	if (rc < 0) {
+		pr_err("audio_aio_open rc=%d\n", rc);
+		goto fail;
+	}
 
 #ifdef CONFIG_DEBUG_FS
 	snprintf(name, sizeof name, "msm_amrnb_%04x", audio->ac->session);
diff --git a/arch/arm/mach-msm/qdsp6v2/audio_amrwb.c b/arch/arm/mach-msm/qdsp6v2/audio_amrwb.c
index 54ca4e8..256da4d 100644
--- a/arch/arm/mach-msm/qdsp6v2/audio_amrwb.c
+++ b/arch/arm/mach-msm/qdsp6v2/audio_amrwb.c
@@ -2,7 +2,7 @@
  *
  * Copyright (C) 2008 Google, Inc.
  * Copyright (C) 2008 HTC Corporation
- * Copyright (c) 2011-2012, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2011-2013, 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
@@ -122,6 +122,10 @@
 		goto fail;
 	}
 	rc = audio_aio_open(audio, file);
+	if (rc < 0) {
+		pr_err("audio_aio_open rc=%d\n", rc);
+		goto fail;
+	}
 
 #ifdef CONFIG_DEBUG_FS
 	snprintf(name, sizeof name, "msm_amrwb_%04x", audio->ac->session);
diff --git a/arch/arm/mach-msm/qdsp6v2/audio_amrwbplus.c b/arch/arm/mach-msm/qdsp6v2/audio_amrwbplus.c
index 2889c14..902e06d 100644
--- a/arch/arm/mach-msm/qdsp6v2/audio_amrwbplus.c
+++ b/arch/arm/mach-msm/qdsp6v2/audio_amrwbplus.c
@@ -2,7 +2,7 @@
  *
  * Copyright (C) 2008 Google, Inc.
  * Copyright (C) 2008 HTC Corporation
- * Copyright (c) 2010-2012, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2010-2013, 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
@@ -199,6 +199,10 @@
 		goto fail;
 	}
 	rc = audio_aio_open(audio, file);
+	if (rc < 0) {
+		pr_err("audio_aio_open rc=%d\n", rc);
+		goto fail;
+	}
 
 	config_debug_fs(audio);
 	pr_debug("%s: AMRWBPLUS dec success mode[%d]session[%d]\n", __func__,
diff --git a/arch/arm/mach-msm/qdsp6v2/audio_evrc.c b/arch/arm/mach-msm/qdsp6v2/audio_evrc.c
index 261642c..3498e69 100644
--- a/arch/arm/mach-msm/qdsp6v2/audio_evrc.c
+++ b/arch/arm/mach-msm/qdsp6v2/audio_evrc.c
@@ -2,7 +2,7 @@
  *
  * Copyright (C) 2008 Google, Inc.
  * Copyright (C) 2008 HTC Corporation
- * Copyright (c) 2011-2012, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2011-2013, 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
@@ -128,6 +128,10 @@
 		goto fail;
 	}
 	rc = audio_aio_open(audio, file);
+	if (rc < 0) {
+		pr_err("audio_aio_open rc=%d\n", rc);
+		goto fail;
+	}
 
 #ifdef CONFIG_DEBUG_FS
 	snprintf(name, sizeof name, "msm_evrc_%04x", audio->ac->session);
diff --git a/arch/arm/mach-msm/qdsp6v2/audio_mp3.c b/arch/arm/mach-msm/qdsp6v2/audio_mp3.c
index ebcca3c..d2f0270 100644
--- a/arch/arm/mach-msm/qdsp6v2/audio_mp3.c
+++ b/arch/arm/mach-msm/qdsp6v2/audio_mp3.c
@@ -128,6 +128,10 @@
 		goto fail;
 	}
 	rc = audio_aio_open(audio, file);
+	if (rc < 0) {
+		pr_err("audio_aio_open rc=%d\n", rc);
+		goto fail;
+	}
 
 #ifdef CONFIG_DEBUG_FS
 	snprintf(name, sizeof name, "msm_mp3_%04x", audio->ac->session);
diff --git a/arch/arm/mach-msm/qdsp6v2/audio_multi_aac.c b/arch/arm/mach-msm/qdsp6v2/audio_multi_aac.c
index 8153145..0a8ce8e 100644
--- a/arch/arm/mach-msm/qdsp6v2/audio_multi_aac.c
+++ b/arch/arm/mach-msm/qdsp6v2/audio_multi_aac.c
@@ -282,6 +282,10 @@
 		goto fail;
 	}
 	rc = audio_aio_open(audio, file);
+	if (rc < 0) {
+		pr_err("audio_aio_open rc=%d\n", rc);
+		goto fail;
+	}
 
 #ifdef CONFIG_DEBUG_FS
 	snprintf(name, sizeof name, "msm_multi_aac_%04x", audio->ac->session);
diff --git a/arch/arm/mach-msm/qdsp6v2/audio_qcelp.c b/arch/arm/mach-msm/qdsp6v2/audio_qcelp.c
index 69a9fcb..4993226 100644
--- a/arch/arm/mach-msm/qdsp6v2/audio_qcelp.c
+++ b/arch/arm/mach-msm/qdsp6v2/audio_qcelp.c
@@ -2,7 +2,7 @@
  *
  * Copyright (C) 2008 Google, Inc.
  * Copyright (C) 2008 HTC Corporation
- * Copyright (c) 2011-2012, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2011-2013, 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
@@ -133,6 +133,10 @@
 		goto fail;
 	}
 	rc = audio_aio_open(audio, file);
+	if (rc < 0) {
+		pr_err("audio_aio_open rc=%d\n", rc);
+		goto fail;
+	}
 
 #ifdef CONFIG_DEBUG_FS
 	snprintf(name, sizeof name, "msm_qcelp_%04x", audio->ac->session);
diff --git a/arch/arm/mach-msm/qdsp6v2/audio_utils_aio.c b/arch/arm/mach-msm/qdsp6v2/audio_utils_aio.c
index 8baac01..a1463bc 100644
--- a/arch/arm/mach-msm/qdsp6v2/audio_utils_aio.c
+++ b/arch/arm/mach-msm/qdsp6v2/audio_utils_aio.c
@@ -1095,6 +1095,7 @@
 	int rc = 0;
 	int i;
 	struct audio_aio_event *e_node = NULL;
+	struct list_head *ptr, *next;
 
 	/* Settings will be re-config at AUDIO_SET_CONFIG,
 	 * but at least we need to have initial config
@@ -1147,28 +1148,35 @@
 		else {
 			pr_err("%s[%p]:event pkt alloc failed\n",
 				__func__, audio);
-			break;
+			rc = -ENOMEM;
+			goto cleanup;
 		}
 	}
 	audio->client = msm_audio_ion_client_create(UINT_MAX,
 						    "Audio_Dec_Client");
 	if (IS_ERR_OR_NULL(audio->client)) {
 		pr_err("Unable to create ION client\n");
-		rc = -EACCES;
-		goto fail;
+		rc = -ENOMEM;
+		goto cleanup;
 	}
 	pr_debug("Ion client create in audio_aio_open %p", audio->client);
 
 	rc = register_volume_listener(audio);
 	if (rc < 0)
-		goto fail;
+		goto ion_cleanup;
 
 	return 0;
-
+ion_cleanup:
+	msm_audio_ion_client_destroy(audio->client);
+	audio->client = NULL;
+cleanup:
+	list_for_each_safe(ptr, next, &audio->free_event_queue) {
+		e_node = list_first_entry(&audio->free_event_queue,
+				   struct audio_aio_event, list);
+		list_del(&e_node->list);
+		kfree(e_node);
+	}
 fail:
-	q6asm_audio_client_free(audio->ac);
-	kfree(audio->codec_cfg);
-	kfree(audio);
 	return rc;
 }
 
diff --git a/arch/arm/mach-msm/qdsp6v2/audio_wma.c b/arch/arm/mach-msm/qdsp6v2/audio_wma.c
index 1d1da1a..5e3de86 100644
--- a/arch/arm/mach-msm/qdsp6v2/audio_wma.c
+++ b/arch/arm/mach-msm/qdsp6v2/audio_wma.c
@@ -2,7 +2,7 @@
  *
  * Copyright (C) 2008 Google, Inc.
  * Copyright (C) 2008 HTC Corporation
- * Copyright (c) 2009-2012, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2009-2013, 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
@@ -167,6 +167,10 @@
 		goto fail;
 	}
 	rc = audio_aio_open(audio, file);
+	if (rc < 0) {
+		pr_err("audio_aio_open rc=%d\n", rc);
+		goto fail;
+	}
 
 #ifdef CONFIG_DEBUG_FS
 	snprintf(name, sizeof name, "msm_wma_%04x", audio->ac->session);
diff --git a/arch/arm/mach-msm/qdsp6v2/audio_wmapro.c b/arch/arm/mach-msm/qdsp6v2/audio_wmapro.c
index 2b2d772..ce49cac 100644
--- a/arch/arm/mach-msm/qdsp6v2/audio_wmapro.c
+++ b/arch/arm/mach-msm/qdsp6v2/audio_wmapro.c
@@ -2,7 +2,7 @@
  *
  * Copyright (C) 2008 Google, Inc.
  * Copyright (C) 2008 HTC Corporation
- * Copyright (c) 2009-2012, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2009-2013, 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
@@ -227,6 +227,10 @@
 		goto fail;
 	}
 	rc = audio_aio_open(audio, file);
+	if (rc < 0) {
+		pr_err("audio_aio_open rc=%d\n", rc);
+		goto fail;
+	}
 
 #ifdef CONFIG_DEBUG_FS
 	snprintf(name, sizeof name, "msm_wmapro_%04x", audio->ac->session);
diff --git a/arch/arm/mach-msm/qdsp6v2/msm_audio_ion.c b/arch/arm/mach-msm/qdsp6v2/msm_audio_ion.c
index 0c71659..0a50bcc 100644
--- a/arch/arm/mach-msm/qdsp6v2/msm_audio_ion.c
+++ b/arch/arm/mach-msm/qdsp6v2/msm_audio_ion.c
@@ -53,7 +53,11 @@
 		pr_debug("%s:probe is not done, deferred\n", __func__);
 		return -EPROBE_DEFER;
 	}
-
+	if (!name || !client || !handle || !paddr || !vaddr
+		|| !bufsz || !pa_len) {
+		pr_err("%s: Invalid params\n", __func__);
+		return -EINVAL;
+	}
 	*client = msm_audio_ion_client_create(UINT_MAX, name);
 	if (IS_ERR_OR_NULL((void *)(*client))) {
 		pr_err("%s: ION create client for AUDIO failed\n", __func__);
@@ -102,9 +106,9 @@
 
 err_ion_handle:
 	ion_free(*client, *handle);
-	*handle = NULL;
 err_ion_client:
 	msm_audio_ion_client_destroy(*client);
+	*handle = NULL;
 	*client = NULL;
 err:
 	return -EINVAL;
@@ -116,10 +120,16 @@
 			ion_phys_addr_t *paddr, size_t *pa_len, void **vaddr)
 {
 	int rc = 0;
+	if (!name || !client || !handle || !paddr || !vaddr || !pa_len) {
+		pr_err("%s: Invalid params\n", __func__);
+		rc = -EINVAL;
+		goto err;
+	}
 
 	*client = msm_audio_ion_client_create(UINT_MAX, name);
 	if (IS_ERR_OR_NULL((void *)(*client))) {
 		pr_err("%s: ION create client for AUDIO failed\n", __func__);
+		rc = -EINVAL;
 		goto err;
 	}
 
@@ -132,8 +142,9 @@
 	if (IS_ERR_OR_NULL((void *) (*handle))) {
 		pr_err("%s: ion import dma buffer failed\n",
 				__func__);
-		goto err_ion_handle;
-		}
+		rc = -EINVAL;
+		goto err_destroy_client;
+	}
 
 	if (ionflag != NULL) {
 		rc = ion_handle_get_flags(*client, *handle, ionflag);
@@ -154,6 +165,7 @@
 	*vaddr = ion_map_kernel(*client, *handle);
 	if (IS_ERR_OR_NULL((void *)*vaddr)) {
 		pr_err("%s: ION memory mapping for AUDIO failed\n", __func__);
+		rc = -ENOMEM;
 		goto err_ion_handle;
 	}
 	pr_debug("%s: mapped address = %p, size=%d\n", __func__, *vaddr, bufsz);
@@ -162,13 +174,20 @@
 
 err_ion_handle:
 	ion_free(*client, *handle);
+err_destroy_client:
 	msm_audio_ion_client_destroy(*client);
+	*client = NULL;
+	*handle = NULL;
 err:
-	return -EINVAL;
+	return rc;
 }
 
 int msm_audio_ion_free(struct ion_client *client, struct ion_handle *handle)
 {
+	if (!client || !handle) {
+		pr_err("%s Invalid params\n", __func__);
+		return -EINVAL;
+	}
 	if (msm_audio_ion_data.smmu_enabled) {
 		/* Need to populate book kept infomation */
 		pr_debug("client=%p, domain=%p, domain_id=%d, group=%p",
diff --git a/arch/arm/mach-msm/qdsp6v2/rtac.c b/arch/arm/mach-msm/qdsp6v2/rtac.c
index 1881607..65543a4 100644
--- a/arch/arm/mach-msm/qdsp6v2/rtac.c
+++ b/arch/arm/mach-msm/qdsp6v2/rtac.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2011, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2011, 2013 The Linux Foundation. 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 and
@@ -42,6 +42,7 @@
 void rtac_set_voice_handle(u32 mode, void *handle) {}
 bool rtac_make_voice_callback(u32 mode, uint32_t *payload,
 		u32 payload_size) {return false; }
+int rtac_clear_mapping(uint32_t cal_type) {return false; }
 
 #else
 
@@ -123,6 +124,8 @@
 struct mutex			rtac_voice_mutex;
 struct mutex			rtac_voice_apr_mutex;
 
+int rtac_clear_mapping(uint32_t cal_type) {return false; }
+
 static int rtac_open(struct inode *inode, struct file *f)
 {
 	pr_debug("%s\n", __func__);
diff --git a/arch/arm/mach-msm/restart.c b/arch/arm/mach-msm/restart.c
index c85f7a1..37fd650 100644
--- a/arch/arm/mach-msm/restart.c
+++ b/arch/arm/mach-msm/restart.c
@@ -159,6 +159,21 @@
 }
 EXPORT_SYMBOL(msm_set_restart_mode);
 
+static bool scm_pmic_arbiter_disable_supported;
+/*
+ * Force the SPMI PMIC arbiter to shutdown so that no more SPMI transactions
+ * are sent from the MSM to the PMIC.  This is required in order to avoid an
+ * SPMI lockup on certain PMIC chips if PS_HOLD is lowered in the middle of
+ * an SPMI transaction.
+ */
+static void halt_spmi_pmic_arbiter(void)
+{
+	if (scm_pmic_arbiter_disable_supported) {
+		pr_crit("Calling SCM to disable SPMI PMIC arbiter\n");
+		scm_call_atomic1(SCM_SVC_PWR, SCM_IO_DISABLE_PMIC_ARBITER, 0);
+	}
+}
+
 static void __msm_power_off(int lower_pshold)
 {
 	printk(KERN_CRIT "Powering off the SoC\n");
@@ -169,10 +184,12 @@
 	qpnp_pon_system_pwr_off(PON_POWER_OFF_SHUTDOWN);
 
 	if (lower_pshold) {
-		if (!use_restart_v2())
+		if (!use_restart_v2()) {
 			__raw_writel(0, PSHOLD_CTL_SU);
-		else
+		} else {
+			halt_spmi_pmic_arbiter();
 			__raw_writel(0, MSM_MPM2_PSHOLD_BASE);
+		}
 
 		mdelay(10000);
 		printk(KERN_ERR "Powering off has failed\n");
@@ -298,6 +315,7 @@
 	} else {
 		/* Needed to bypass debug image on some chips */
 		msm_disable_wdog_debug();
+		halt_spmi_pmic_arbiter();
 		__raw_writel(0, MSM_MPM2_PSHOLD_BASE);
 	}
 
@@ -340,6 +358,9 @@
 	restart_reason = MSM_IMEM_BASE + RESTART_REASON_ADDR;
 	pm_power_off = msm_power_off;
 
+	if (scm_is_call_available(SCM_SVC_PWR, SCM_IO_DISABLE_PMIC_ARBITER) > 0)
+		scm_pmic_arbiter_disable_supported = true;
+
 	return 0;
 }
 early_initcall(msm_restart_init);
diff --git a/arch/arm/mach-msm/rpm-smd.c b/arch/arm/mach-msm/rpm-smd.c
index 2bae37a..ccab6e2 100644
--- a/arch/arm/mach-msm/rpm-smd.c
+++ b/arch/arm/mach-msm/rpm-smd.c
@@ -284,8 +284,10 @@
 	struct kvp *e, *n;
 
 	for_each_kvp(buf, n) {
+		bool found = false;
 		for_each_kvp(s->buf, e) {
 			if (n->k == e->k) {
+				found = true;
 				if (n->s == e->s) {
 					void *e_data = get_data(e);
 					void *n_data = get_data(n);
@@ -300,6 +302,11 @@
 				}
 				break;
 			}
+
+		}
+		if (!found) {
+			add_kvp(s->buf, n);
+			s->valid = true;
 		}
 	}
 }
diff --git a/arch/arm/mach-msm/rpm_master_stat.c b/arch/arm/mach-msm/rpm_master_stat.c
index 49a1039..3e1789f 100644
--- a/arch/arm/mach-msm/rpm_master_stat.c
+++ b/arch/arm/mach-msm/rpm_master_stat.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2012, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2012-2013, The Linux Foundation. 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 and
@@ -22,39 +22,57 @@
 #include <linux/slab.h>
 #include <linux/types.h>
 #include <linux/mm.h>
+#include <linux/of.h>
 #include <asm/uaccess.h>
 
 #include <mach/msm_iomap.h>
 #include "rpm_stats.h"
-#define MSG_RAM_SIZE_PER_MASTER	32
 
-enum {
-	NUMSHUTDOWNS,
-	ACTIVECORES,
-	MASTER_ID_MAX,
-};
+#define RPM_MASTERS_BUF_LEN 400
 
-static char *msm_rpm_master_stats_id_labels[MASTER_ID_MAX] = {
-	[NUMSHUTDOWNS] = "num_shutdowns",
-	[ACTIVECORES] = "active_cores",
-};
+#define SNPRINTF(buf, size, format, ...) \
+	do { \
+		if (size > 0) { \
+			int ret; \
+			ret = snprintf(buf, size, format, ## __VA_ARGS__); \
+			if (ret > size) { \
+				buf += size; \
+				size = 0; \
+			} else { \
+				buf += ret; \
+				size -= ret; \
+			} \
+		} \
+	} while (0)
 
+#define GET_MASTER_NAME(a, prvdata) \
+	((a >= prvdata->num_masters) ? "Invalid Master Name" : \
+	 prvdata->master_names[a])
+
+#define GET_FIELD(a) ((strnstr(#a, ".", 80) + 1))
 
 struct msm_rpm_master_stats {
-	unsigned long numshutdowns;
-	unsigned long active_cores;
+	uint32_t active_cores;
+	uint32_t numshutdowns;
+	uint64_t shutdown_req;
+	uint64_t wakeup_ind;
+	uint64_t bringup_req;
+	uint64_t bringup_ack;
+	uint32_t wakeup_reason; /* 0 = rude wakeup, 1 = scheduled wakeup */
+	uint32_t last_sleep_transition_duration;
+	uint32_t last_wake_transition_duration;
 };
 
 struct msm_rpm_master_stats_private_data {
 	void __iomem *reg_base;
 	u32 len;
 	char **master_names;
-	u32 nomasters;
-	char buf[256];
+	u32 num_masters;
+	char buf[RPM_MASTERS_BUF_LEN];
 	struct msm_rpm_master_stats_platform_data *platform_data;
 };
 
-static int msm_rpm_master_stats_file_close(struct inode *inode,
+int msm_rpm_master_stats_file_close(struct inode *inode,
 		struct file *file)
 {
 	struct msm_rpm_master_stats_private_data *private = file->private_data;
@@ -67,53 +85,138 @@
 }
 
 static int msm_rpm_master_copy_stats(
-		struct msm_rpm_master_stats_private_data *pdata)
+		struct msm_rpm_master_stats_private_data *prvdata)
 {
 	struct msm_rpm_master_stats record;
-	static int nomasters;
-	int count;
+	struct msm_rpm_master_stats_platform_data *pdata;
+	static int master_cnt;
+	int count, j = 0;
+	char *buf;
 	static DEFINE_MUTEX(msm_rpm_master_stats_mutex);
-	int j = 0;
 
 	mutex_lock(&msm_rpm_master_stats_mutex);
-	/*
-	 * iterrate possible nomasters times.
-	 * 8960, 8064 have 5 masters.
-	 * 8930 has 4 masters.
-	 * 9x15 has 3 masters.
-	 */
-	if (nomasters > pdata->nomasters - 1) {
-		nomasters = 0;
+
+	/* Iterate possible number of masters */
+	if (master_cnt > prvdata->num_masters - 1) {
+		master_cnt = 0;
 		mutex_unlock(&msm_rpm_master_stats_mutex);
 		return 0;
 	}
 
-	record.numshutdowns = readl_relaxed(pdata->reg_base +
-			(nomasters * MSG_RAM_SIZE_PER_MASTER));
-	record.active_cores = readl_relaxed(pdata->reg_base +
-				(nomasters * MSG_RAM_SIZE_PER_MASTER + 4));
+	pdata = prvdata->platform_data;
+	count = RPM_MASTERS_BUF_LEN;
+	buf = prvdata->buf;
 
-	count = snprintf(pdata->buf, sizeof(pdata->buf),
-		"%s\n\t%s:%lu\n\t%s:%lu\n",
-		pdata->master_names[nomasters],
-		msm_rpm_master_stats_id_labels[0],
-		record.numshutdowns,
-		msm_rpm_master_stats_id_labels[1],
-		record.active_cores);
+	if (prvdata->platform_data->version == 2) {
+		SNPRINTF(buf, count, "%s\n",
+				GET_MASTER_NAME(master_cnt, prvdata));
 
-	j = find_first_bit(&record.active_cores, BITS_PER_LONG);
+		record.shutdown_req = readll_relaxed(prvdata->reg_base +
+			(master_cnt * pdata->master_offset +
+			offsetof(struct msm_rpm_master_stats, shutdown_req)));
+
+		SNPRINTF(buf, count, "\t%s:0x%llX\n",
+			GET_FIELD(record.shutdown_req),
+			record.shutdown_req);
+
+		record.wakeup_ind = readll_relaxed(prvdata->reg_base +
+			(master_cnt * pdata->master_offset +
+			offsetof(struct msm_rpm_master_stats, wakeup_ind)));
+
+		SNPRINTF(buf, count, "\t%s:0x%llX\n",
+			GET_FIELD(record.wakeup_ind),
+			record.wakeup_ind);
+
+		record.bringup_req = readll_relaxed(prvdata->reg_base +
+			(master_cnt * pdata->master_offset +
+			offsetof(struct msm_rpm_master_stats, bringup_req)));
+
+		SNPRINTF(buf, count, "\t%s:0x%llX\n",
+			GET_FIELD(record.bringup_req),
+			record.bringup_req);
+
+		record.bringup_ack = readll_relaxed(prvdata->reg_base +
+			(master_cnt * pdata->master_offset +
+			offsetof(struct msm_rpm_master_stats, bringup_ack)));
+
+		SNPRINTF(buf, count, "\t%s:0x%llX\n",
+			GET_FIELD(record.bringup_ack),
+			record.bringup_ack);
+
+		record.last_sleep_transition_duration =
+				readl_relaxed(prvdata->reg_base +
+				(master_cnt * pdata->master_offset +
+				offsetof(struct msm_rpm_master_stats,
+				last_sleep_transition_duration)));
+
+		SNPRINTF(buf, count, "\t%s:0x%x\n",
+			GET_FIELD(record.last_sleep_transition_duration),
+			record.last_sleep_transition_duration);
+
+		record.last_wake_transition_duration =
+				readl_relaxed(prvdata->reg_base +
+				(master_cnt * pdata->master_offset +
+				offsetof(struct msm_rpm_master_stats,
+				last_wake_transition_duration)));
+
+		SNPRINTF(buf, count, "\t%s:0x%x\n",
+			GET_FIELD(record.last_wake_transition_duration),
+			record.last_wake_transition_duration);
+
+		record.wakeup_reason = readl_relaxed(prvdata->reg_base +
+					(master_cnt * pdata->master_offset +
+					offsetof(struct msm_rpm_master_stats,
+					wakeup_reason)));
+
+		SNPRINTF(buf, count, "\t%s:0x%x\n",
+			GET_FIELD(record.wakeup_reason),
+			record.wakeup_reason);
+
+		record.numshutdowns = readl_relaxed(prvdata->reg_base +
+			(master_cnt * pdata->master_offset +
+			 offsetof(struct msm_rpm_master_stats, numshutdowns)));
+
+		SNPRINTF(buf, count, "\t%s:0x%x\n",
+			GET_FIELD(record.numshutdowns),
+			record.numshutdowns);
+
+		record.active_cores = readl_relaxed(prvdata->reg_base +
+			(master_cnt * pdata->master_offset) +
+			offsetof(struct msm_rpm_master_stats, active_cores));
+
+		SNPRINTF(buf, count, "\t%s:0x%x\n",
+			GET_FIELD(record.active_cores),
+			record.active_cores);
+	} else {
+		SNPRINTF(buf, count, "%s\n",
+				GET_MASTER_NAME(master_cnt, prvdata));
+
+		record.numshutdowns = readl_relaxed(prvdata->reg_base +
+				(master_cnt * pdata->master_offset) + 0x0);
+
+		SNPRINTF(buf, count, "\t%s:0x%0x\n",
+			GET_FIELD(record.numshutdowns),
+			record.numshutdowns);
+
+		record.active_cores = readl_relaxed(prvdata->reg_base +
+				(master_cnt * pdata->master_offset) + 0x4);
+
+		SNPRINTF(buf, count, "\t%s:0x%0x\n",
+			GET_FIELD(record.active_cores),
+			record.active_cores);
+	}
+
+	j = find_first_bit((unsigned long *)&record.active_cores,
+							BITS_PER_LONG);
 	while (j < BITS_PER_LONG) {
-		count += snprintf(pdata->buf + count,
-			sizeof(pdata->buf) - count,
-			"\t\tcore%d\n", j);
-		j = find_next_bit(&record.active_cores,
+		SNPRINTF(buf, count, "\t\tcore%d\n", j);
+		j = find_next_bit((unsigned long *)&record.active_cores,
 				BITS_PER_LONG, j + 1);
 	}
 
-
-	nomasters++;
+	master_cnt++;
 	mutex_unlock(&msm_rpm_master_stats_mutex);
-	return count;
+	return RPM_MASTERS_BUF_LEN - count;
 }
 
 static int msm_rpm_master_stats_file_read(struct file *file, char __user *bufu,
@@ -151,7 +254,7 @@
 	pdata = inode->i_private;
 
 	file->private_data =
-		kmalloc(sizeof(struct msm_rpm_master_stats_private_data),
+		kzalloc(sizeof(struct msm_rpm_master_stats_private_data),
 			GFP_KERNEL);
 
 	if (!file->private_data)
@@ -159,7 +262,7 @@
 	prvdata = file->private_data;
 
 	prvdata->reg_base = ioremap(pdata->phys_addr_base,
-		pdata->phys_size);
+						pdata->phys_size);
 	if (!prvdata->reg_base) {
 		kfree(file->private_data);
 		prvdata = NULL;
@@ -170,7 +273,7 @@
 	}
 
 	prvdata->len = 0;
-	prvdata->nomasters = pdata->nomasters;
+	prvdata->num_masters = pdata->num_masters;
 	prvdata->master_names = pdata->masters;
 	prvdata->platform_data = pdata;
 	return 0;
@@ -184,27 +287,108 @@
 	.llseek   = no_llseek,
 };
 
+static struct msm_rpm_master_stats_platform_data
+			*msm_rpm_master_populate_pdata(struct device *dev)
+{
+	struct msm_rpm_master_stats_platform_data *pdata;
+	struct device_node *node = dev->of_node;
+	int rc = 0, i;
+
+	pdata = devm_kzalloc(dev, sizeof(*pdata), GFP_KERNEL);
+	if (!pdata) {
+		dev_err(dev, "could not allocate memory for platform data\n");
+		goto err;
+	}
+
+	rc = of_property_read_u32(node, "qcom,master-stats-version",
+							&pdata->version);
+	if (rc) {
+		dev_err(dev, "master-stats-version missing rc=%d\n", rc);
+		goto err;
+	}
+
+	rc = of_property_read_u32(node, "qcom,master-offset",
+							&pdata->master_offset);
+	if (rc) {
+		dev_err(dev, "master-offset missing rc=%d\n", rc);
+		goto err;
+	}
+
+	pdata->num_masters = of_property_count_strings(node, "qcom,masters");
+	if (pdata->num_masters < 0) {
+		dev_err(dev, "Failed to get number of masters =%d\n",
+						pdata->num_masters);
+		goto err;
+	}
+
+	pdata->masters = devm_kzalloc(dev, sizeof(char *) * pdata->num_masters,
+								GFP_KERNEL);
+	if (!pdata->masters) {
+		dev_err(dev, "%s:Failed to allocated memory\n", __func__);
+		goto err;
+	}
+
+	/*
+	 * Read master names from DT
+	 */
+	for (i = 0; i < pdata->num_masters; i++) {
+		const char *master_name;
+		of_property_read_string_index(node, "qcom,masters",
+							i, &master_name);
+		pdata->masters[i] = devm_kzalloc(dev, sizeof(char) *
+				strlen(master_name) + 1, GFP_KERNEL);
+		if (!pdata->masters[i]) {
+			dev_err(dev, "%s:Failed to get memory\n", __func__);
+			goto err;
+		}
+		strlcpy(pdata->masters[i], master_name,
+					strlen(master_name) + 1);
+	}
+	return pdata;
+err:
+	return NULL;
+}
+
 static  int __devinit msm_rpm_master_stats_probe(struct platform_device *pdev)
 {
 	struct dentry *dent;
 	struct msm_rpm_master_stats_platform_data *pdata;
-	struct resource *res;
+	struct resource *res = NULL;
 
-	pdata = pdev->dev.platform_data;
-	if (!pdata)
+	if (!pdev)
 		return -EINVAL;
 
+	if (pdev->dev.of_node)
+		pdata = msm_rpm_master_populate_pdata(&pdev->dev);
+	else
+		pdata = pdev->dev.platform_data;
+
+	if (!pdata) {
+		dev_err(&pdev->dev, "%s: Unable to get pdata\n", __func__);
+		return -ENOMEM;
+	}
+
 	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+
+	if (!res) {
+		dev_err(&pdev->dev,
+			"%s: Failed to get IO resource from platform device",
+			__func__);
+		return -ENXIO;
+	}
+
 	pdata->phys_addr_base = res->start;
 	pdata->phys_size = resource_size(res);
 
 	dent = debugfs_create_file("rpm_master_stats", S_IRUGO, NULL,
-			pdev->dev.platform_data, &msm_rpm_master_stats_fops);
+					pdata, &msm_rpm_master_stats_fops);
 
 	if (!dent) {
-		pr_err("%s: ERROR debugfs_create_file failed\n", __func__);
+		dev_err(&pdev->dev, "%s: ERROR debugfs_create_file failed\n",
+								__func__);
 		return -ENOMEM;
 	}
+
 	platform_set_drvdata(pdev, dent);
 	return 0;
 }
@@ -219,12 +403,18 @@
 	return 0;
 }
 
+static struct of_device_id rpm_master_table[] = {
+	{.compatible = "qcom,rpm-master-stats"},
+	{},
+};
+
 static struct platform_driver msm_rpm_master_stats_driver = {
 	.probe	= msm_rpm_master_stats_probe,
 	.remove = __devexit_p(msm_rpm_master_stats_remove),
 	.driver = {
-		.name = "msm_rpm_master_stat",
+		.name = "msm_rpm_master_stats",
 		.owner = THIS_MODULE,
+		.of_match_table = rpm_master_table,
 	},
 };
 
diff --git a/arch/arm/mach-msm/rpm_stats.h b/arch/arm/mach-msm/rpm_stats.h
index c1dfe34..34c1b99 100644
--- a/arch/arm/mach-msm/rpm_stats.h
+++ b/arch/arm/mach-msm/rpm_stats.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2011-2012, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2011-2013, The Linux Foundation. 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 and
@@ -31,9 +31,11 @@
 	 * it allocates 256 bytes for this use.
 	 * No of masters differs for different targets.
 	 * Based on the number of masters, linux rpm stat
-	 * driver reads (32 * nomasters) bytes to display
+	 * driver reads (32 * num_masters) bytes to display
 	 * master stats.
 	 */
-	 u32 nomasters;
+	 s32 num_masters;
+	 u32 master_offset;
+	 u32 version;
 };
 #endif
diff --git a/arch/arm/mach-msm/scm-pas.c b/arch/arm/mach-msm/scm-pas.c
index 57acdc4..c3e0752 100644
--- a/arch/arm/mach-msm/scm-pas.c
+++ b/arch/arm/mach-msm/scm-pas.c
@@ -16,6 +16,7 @@
 #include <linux/slab.h>
 #include <linux/string.h>
 #include <linux/clk.h>
+#include <linux/dma-mapping.h>
 
 #include <asm/cacheflush.h>
 
@@ -138,28 +139,30 @@
 	} request;
 	u32 scm_ret = 0;
 	void *mdata_buf;
+	dma_addr_t mdata_phys;
+	DEFINE_DMA_ATTRS(attrs);
 
 	ret = scm_pas_enable_bw();
 	if (ret)
 		return ret;
 
-	/* Make memory physically contiguous */
-	mdata_buf = kmemdup(metadata, size, GFP_KERNEL);
-
-	if (!mdata_buf)
+	dma_set_attr(DMA_ATTR_STRONGLY_ORDERED, &attrs);
+	mdata_buf = dma_alloc_attrs(NULL, size, &mdata_phys, GFP_KERNEL,
+					&attrs);
+	if (!mdata_buf) {
+		pr_err("Allocation for metadata failed.\n");
 		return -ENOMEM;
+	}
+
+	memcpy(mdata_buf, metadata, size);
 
 	request.proc = id;
-	request.image_addr = virt_to_phys(mdata_buf);
-
-	/* Flush metadata to ensure secure world doesn't read stale data */
-	__cpuc_flush_dcache_area(mdata_buf, size);
-	outer_flush_range(request.image_addr, request.image_addr + size);
+	request.image_addr = mdata_phys;
 
 	ret = scm_call(SCM_SVC_PIL, PAS_INIT_IMAGE_CMD, &request,
 			sizeof(request), &scm_ret, sizeof(scm_ret));
 
-	kfree(mdata_buf);
+	dma_free_attrs(NULL, size, mdata_buf, mdata_phys, &attrs);
 	scm_pas_disable_bw();
 
 	if (ret)
diff --git a/arch/arm/mach-msm/scm.c b/arch/arm/mach-msm/scm.c
index e9f44e3..266b759 100644
--- a/arch/arm/mach-msm/scm.c
+++ b/arch/arm/mach-msm/scm.c
@@ -31,6 +31,9 @@
 
 static DEFINE_MUTEX(scm_lock);
 
+#define SCM_BUF_LEN(__cmd_size, __resp_size)	\
+	(sizeof(struct scm_command) + sizeof(struct scm_response) + \
+		__cmd_size + __resp_size)
 /**
  * struct scm_command - one SCM command buffer
  * @len: total available memory for command and response
@@ -76,42 +79,6 @@
 };
 
 /**
- * alloc_scm_command() - Allocate an SCM command
- * @cmd_size: size of the command buffer
- * @resp_size: size of the response buffer
- *
- * Allocate an SCM command, including enough room for the command
- * and response headers as well as the command and response buffers.
- *
- * Returns a valid &scm_command on success or %NULL if the allocation fails.
- */
-static struct scm_command *alloc_scm_command(size_t cmd_size, size_t resp_size)
-{
-	struct scm_command *cmd;
-	size_t len = sizeof(*cmd) + sizeof(struct scm_response) + cmd_size +
-		resp_size;
-
-	cmd = kzalloc(PAGE_ALIGN(len), GFP_KERNEL);
-	if (cmd) {
-		cmd->len = len;
-		cmd->buf_offset = offsetof(struct scm_command, buf);
-		cmd->resp_hdr_offset = cmd->buf_offset + cmd_size;
-	}
-	return cmd;
-}
-
-/**
- * free_scm_command() - Free an SCM command
- * @cmd: command to free
- *
- * Free an SCM command.
- */
-static inline void free_scm_command(struct scm_command *cmd)
-{
-	kfree(cmd);
-}
-
-/**
  * scm_command_to_response() - Get a pointer to a scm_response
  * @cmd: command
  *
@@ -224,6 +191,92 @@
 }
 
 /**
+ * scm_call_common() - Send an SCM command
+ * @svc_id: service identifier
+ * @cmd_id: command identifier
+ * @cmd_buf: command buffer
+ * @cmd_len: length of the command buffer
+ * @resp_buf: response buffer
+ * @resp_len: length of the response buffer
+ * @scm_buf: internal scm structure used for passing data
+ * @scm_buf_len: length of the internal scm structure
+ *
+ * Core function to scm call. Initializes the given cmd structure with
+ * appropriate values and makes the actual scm call. Validation of cmd
+ * pointer and length must occur in the calling function.
+ *
+ * Returns the appropriate error code from the scm call
+ */
+
+static int scm_call_common(u32 svc_id, u32 cmd_id, const void *cmd_buf,
+				size_t cmd_len, void *resp_buf, size_t resp_len,
+				struct scm_command *scm_buf,
+				size_t scm_buf_length)
+{
+	int ret;
+	struct scm_response *rsp;
+	unsigned long start, end;
+
+	scm_buf->len = scm_buf_length;
+	scm_buf->buf_offset = offsetof(struct scm_command, buf);
+	scm_buf->resp_hdr_offset = scm_buf->buf_offset + cmd_len;
+	scm_buf->id = (svc_id << 10) | cmd_id;
+
+	if (cmd_buf)
+		memcpy(scm_get_command_buffer(scm_buf), cmd_buf, cmd_len);
+
+	mutex_lock(&scm_lock);
+	ret = __scm_call(scm_buf);
+	mutex_unlock(&scm_lock);
+	if (ret)
+		return ret;
+
+	rsp = scm_command_to_response(scm_buf);
+	start = (unsigned long)rsp;
+
+	do {
+		scm_inv_range(start, start + sizeof(*rsp));
+	} while (!rsp->is_complete);
+
+	end = (unsigned long)scm_get_response_buffer(rsp) + resp_len;
+	scm_inv_range(start, end);
+
+	if (resp_buf)
+		memcpy(resp_buf, scm_get_response_buffer(rsp), resp_len);
+
+	return ret;
+}
+
+/**
+ * scm_call_noalloc - Send an SCM command
+ *
+ * Same as scm_call except clients pass in a buffer (@scm_buf) to be used for
+ * scm internal structures. The buffer should be allocated with
+ * DEFINE_SCM_BUFFER to account for the proper alignment and size.
+ */
+int scm_call_noalloc(u32 svc_id, u32 cmd_id, const void *cmd_buf,
+		size_t cmd_len, void *resp_buf, size_t resp_len,
+		void *scm_buf, size_t scm_buf_len)
+{
+	int ret;
+	size_t len = SCM_BUF_LEN(cmd_len, resp_len);
+
+	if (cmd_len > scm_buf_len || resp_len > scm_buf_len ||
+	    len > scm_buf_len)
+		return -EINVAL;
+
+	if (!IS_ALIGNED((unsigned long)scm_buf, PAGE_SIZE))
+		return -EINVAL;
+
+	memset(scm_buf, 0, scm_buf_len);
+
+	ret = scm_call_common(svc_id, cmd_id, cmd_buf, cmd_len, resp_buf,
+				resp_len, scm_buf, len);
+	return ret;
+
+}
+
+/**
  * scm_call() - Send an SCM command
  * @svc_id: service identifier
  * @cmd_id: command identifier
@@ -244,39 +297,20 @@
 int scm_call(u32 svc_id, u32 cmd_id, const void *cmd_buf, size_t cmd_len,
 		void *resp_buf, size_t resp_len)
 {
-	int ret;
 	struct scm_command *cmd;
-	struct scm_response *rsp;
-	unsigned long start, end;
+	int ret;
+	size_t len = SCM_BUF_LEN(cmd_len, resp_len);
 
-	cmd = alloc_scm_command(cmd_len, resp_len);
+	if (cmd_len > len || resp_len > len)
+		return -EINVAL;
+
+	cmd = kzalloc(PAGE_ALIGN(len), GFP_KERNEL);
 	if (!cmd)
 		return -ENOMEM;
 
-	cmd->id = (svc_id << 10) | cmd_id;
-	if (cmd_buf)
-		memcpy(scm_get_command_buffer(cmd), cmd_buf, cmd_len);
-
-	mutex_lock(&scm_lock);
-	ret = __scm_call(cmd);
-	mutex_unlock(&scm_lock);
-	if (ret)
-		goto out;
-
-	rsp = scm_command_to_response(cmd);
-	start = (unsigned long)rsp;
-
-	do {
-		scm_inv_range(start, start + sizeof(*rsp));
-	} while (!rsp->is_complete);
-
-	end = (unsigned long)scm_get_response_buffer(rsp) + resp_len;
-	scm_inv_range(start, end);
-
-	if (resp_buf)
-		memcpy(resp_buf, scm_get_response_buffer(rsp), resp_len);
-out:
-	free_scm_command(cmd);
+	ret = scm_call_common(svc_id, cmd_id, cmd_buf, cmd_len, resp_buf,
+				resp_len, cmd, len);
+	kfree(cmd);
 	return ret;
 }
 EXPORT_SYMBOL(scm_call);
diff --git a/arch/arm/mach-msm/smd.c b/arch/arm/mach-msm/smd.c
index e148868..d34bdf2 100644
--- a/arch/arm/mach-msm/smd.c
+++ b/arch/arm/mach-msm/smd.c
@@ -55,24 +55,6 @@
 #include "modem_notifier.h"
 #include "smem_private.h"
 
-#if defined(CONFIG_ARCH_QSD8X50) || defined(CONFIG_ARCH_MSM8X60) \
-	|| defined(CONFIG_ARCH_MSM8960) || defined(CONFIG_ARCH_FSM9XXX) \
-	|| defined(CONFIG_ARCH_MSM9615)	|| defined(CONFIG_ARCH_APQ8064)
-#define CONFIG_QDSP6 1
-#endif
-
-#if defined(CONFIG_ARCH_MSM8X60) || defined(CONFIG_ARCH_MSM8960) \
-	|| defined(CONFIG_ARCH_APQ8064)
-#define CONFIG_DSPS 1
-#endif
-
-#if defined(CONFIG_ARCH_MSM8960) \
-	|| defined(CONFIG_ARCH_APQ8064)
-#define CONFIG_WCNSS 1
-#define CONFIG_DSPS_SMSM 1
-#endif
-
-#define MODULE_NAME "msm_smd"
 #define SMD_VERSION 0x00020000
 #define SMSM_SNAPSHOT_CNT 64
 #define SMSM_SNAPSHOT_SIZE ((SMSM_NUM_ENTRIES + 1) * 4)
@@ -86,14 +68,6 @@
 #define LEGACY_MODEM_SMSM_MASK (SMSM_RESET | SMSM_INIT | SMSM_SMDINIT \
 			| SMSM_RUN | SMSM_SYSTEM_DOWNLOAD)
 
-enum {
-	MSM_SMD_DEBUG = 1U << 0,
-	MSM_SMSM_DEBUG = 1U << 1,
-	MSM_SMD_INFO = 1U << 2,
-	MSM_SMSM_INFO = 1U << 3,
-	MSM_SMx_POWER_INFO = 1U << 4,
-};
-
 struct smsm_shared_info {
 	uint32_t *state;
 	uint32_t *intr_mask;
@@ -127,32 +101,14 @@
 	uint32_t intr_mask_clear;
 };
 
-struct interrupt_config_item {
-	/* must be initialized */
-	irqreturn_t (*irq_handler)(int req, void *data);
-	/* outgoing interrupt config (set from platform data) */
-	uint32_t out_bit_pos;
-	void __iomem *out_base;
-	uint32_t out_offset;
-	int irq_id;
-};
-
-struct interrupt_config {
-	struct interrupt_config_item smd;
-	struct interrupt_config_item smsm;
-};
-
-static irqreturn_t smd_modem_irq_handler(int irq, void *data);
-static irqreturn_t smsm_modem_irq_handler(int irq, void *data);
-static irqreturn_t smd_dsp_irq_handler(int irq, void *data);
-static irqreturn_t smsm_dsp_irq_handler(int irq, void *data);
-static irqreturn_t smd_dsps_irq_handler(int irq, void *data);
-static irqreturn_t smsm_dsps_irq_handler(int irq, void *data);
-static irqreturn_t smd_wcnss_irq_handler(int irq, void *data);
-static irqreturn_t smsm_wcnss_irq_handler(int irq, void *data);
-static irqreturn_t smd_rpm_irq_handler(int irq, void *data);
 static irqreturn_t smsm_irq_handler(int irq, void *data);
 
+/*
+ * Interrupt configuration consists of static configuration for the supported
+ * processors that is done here along with interrupt configuration that is
+ * added by the separate initialization modules (device tree, platform data, or
+ * hard coded).
+ */
 static struct interrupt_config private_intr_config[NUM_SMD_SUBSYSTEMS] = {
 	[SMD_MODEM] = {
 		.smd.irq_handler = smd_modem_irq_handler,
@@ -188,10 +144,10 @@
 	SMSM_APPS_DEM_I = 3,
 };
 
-static int msm_smd_debug_mask = MSM_SMx_POWER_INFO;
+int msm_smd_debug_mask = MSM_SMx_POWER_INFO | MSM_SMD_INFO;
 module_param_named(debug_mask, msm_smd_debug_mask,
 		   int, S_IRUGO | S_IWUSR | S_IWGRP);
-static void *smd_log_ctx;
+void *smd_log_ctx;
 #define NUM_LOG_PAGES 4
 
 #define IPC_LOG(level, x...) do { \
@@ -248,124 +204,9 @@
 
 static inline void smd_write_intr(unsigned int val,
 				const void __iomem *addr);
-
-#if defined(CONFIG_ARCH_MSM7X30)
-#define MSM_TRIG_A2M_SMD_INT     \
-			(smd_write_intr(1 << 0, MSM_APCS_GCC_BASE + 0x8))
-#define MSM_TRIG_A2Q6_SMD_INT    \
-			(smd_write_intr(1 << 8, MSM_APCS_GCC_BASE + 0x8))
-#define MSM_TRIG_A2M_SMSM_INT    \
-			(smd_write_intr(1 << 5, MSM_APCS_GCC_BASE + 0x8))
-#define MSM_TRIG_A2Q6_SMSM_INT   \
-			(smd_write_intr(1 << 8, MSM_APCS_GCC_BASE + 0x8))
-#define MSM_TRIG_A2DSPS_SMD_INT
-#define MSM_TRIG_A2DSPS_SMSM_INT
-#define MSM_TRIG_A2WCNSS_SMD_INT
-#define MSM_TRIG_A2WCNSS_SMSM_INT
-#elif defined(CONFIG_ARCH_MSM8X60)
-#define MSM_TRIG_A2M_SMD_INT     \
-			(smd_write_intr(1 << 3, MSM_GCC_BASE + 0x8))
-#define MSM_TRIG_A2Q6_SMD_INT    \
-			(smd_write_intr(1 << 15, MSM_GCC_BASE + 0x8))
-#define MSM_TRIG_A2M_SMSM_INT    \
-			(smd_write_intr(1 << 4, MSM_GCC_BASE + 0x8))
-#define MSM_TRIG_A2Q6_SMSM_INT   \
-			(smd_write_intr(1 << 14, MSM_GCC_BASE + 0x8))
-#define MSM_TRIG_A2DSPS_SMD_INT  \
-			(smd_write_intr(1, MSM_SIC_NON_SECURE_BASE + 0x4080))
-#define MSM_TRIG_A2DSPS_SMSM_INT
-#define MSM_TRIG_A2WCNSS_SMD_INT
-#define MSM_TRIG_A2WCNSS_SMSM_INT
-#elif defined(CONFIG_ARCH_MSM9615)
-#define MSM_TRIG_A2M_SMD_INT     \
-			(smd_write_intr(1 << 3, MSM_APCS_GCC_BASE + 0x8))
-#define MSM_TRIG_A2Q6_SMD_INT    \
-			(smd_write_intr(1 << 15, MSM_APCS_GCC_BASE + 0x8))
-#define MSM_TRIG_A2M_SMSM_INT    \
-			(smd_write_intr(1 << 4, MSM_APCS_GCC_BASE + 0x8))
-#define MSM_TRIG_A2Q6_SMSM_INT   \
-			(smd_write_intr(1 << 14, MSM_APCS_GCC_BASE + 0x8))
-#define MSM_TRIG_A2DSPS_SMD_INT
-#define MSM_TRIG_A2DSPS_SMSM_INT
-#define MSM_TRIG_A2WCNSS_SMD_INT
-#define MSM_TRIG_A2WCNSS_SMSM_INT
-#elif defined(CONFIG_ARCH_FSM9XXX)
-#define MSM_TRIG_A2Q6_SMD_INT	\
-			(smd_write_intr(1 << 10, MSM_GCC_BASE + 0x8))
-#define MSM_TRIG_A2Q6_SMSM_INT	\
-			(smd_write_intr(1 << 10, MSM_GCC_BASE + 0x8))
-#define MSM_TRIG_A2M_SMD_INT	\
-			(smd_write_intr(1 << 0, MSM_GCC_BASE + 0x8))
-#define MSM_TRIG_A2M_SMSM_INT	\
-			(smd_write_intr(1 << 5, MSM_GCC_BASE + 0x8))
-#define MSM_TRIG_A2DSPS_SMD_INT
-#define MSM_TRIG_A2DSPS_SMSM_INT
-#define MSM_TRIG_A2WCNSS_SMD_INT
-#define MSM_TRIG_A2WCNSS_SMSM_INT
-#elif defined(CONFIG_ARCH_MSM7X01A) || defined(CONFIG_ARCH_MSM7x25)
-#define MSM_TRIG_A2M_SMD_INT     \
-			(smd_write_intr(1, MSM_CSR_BASE + 0x400 + (0) * 4))
-#define MSM_TRIG_A2Q6_SMD_INT
-#define MSM_TRIG_A2M_SMSM_INT    \
-			(smd_write_intr(1, MSM_CSR_BASE + 0x400 + (5) * 4))
-#define MSM_TRIG_A2Q6_SMSM_INT
-#define MSM_TRIG_A2DSPS_SMD_INT
-#define MSM_TRIG_A2DSPS_SMSM_INT
-#define MSM_TRIG_A2WCNSS_SMD_INT
-#define MSM_TRIG_A2WCNSS_SMSM_INT
-#elif defined(CONFIG_ARCH_MSM7X27) || defined(CONFIG_ARCH_MSM7X27A)
-#define MSM_TRIG_A2M_SMD_INT     \
-			(smd_write_intr(1, MSM_CSR_BASE + 0x400 + (0) * 4))
-#define MSM_TRIG_A2Q6_SMD_INT
-#define MSM_TRIG_A2M_SMSM_INT    \
-			(smd_write_intr(1, MSM_CSR_BASE + 0x400 + (5) * 4))
-#define MSM_TRIG_A2Q6_SMSM_INT
-#define MSM_TRIG_A2DSPS_SMD_INT
-#define MSM_TRIG_A2DSPS_SMSM_INT
-#define MSM_TRIG_A2WCNSS_SMD_INT
-#define MSM_TRIG_A2WCNSS_SMSM_INT
-#else /* use platform device / device tree configuration */
-#define MSM_TRIG_A2M_SMD_INT
-#define MSM_TRIG_A2Q6_SMD_INT
-#define MSM_TRIG_A2M_SMSM_INT
-#define MSM_TRIG_A2Q6_SMSM_INT
-#define MSM_TRIG_A2DSPS_SMD_INT
-#define MSM_TRIG_A2DSPS_SMSM_INT
-#define MSM_TRIG_A2WCNSS_SMD_INT
-#define MSM_TRIG_A2WCNSS_SMSM_INT
-#endif
-
-/*
- * stub out legacy macros if they are not being used so that the legacy
- * code compiles even though it is not used
- *
- * these definitions should not be used in active code and will cause
- * an early failure
- */
-#ifndef INT_A9_M2A_0
-#define INT_A9_M2A_0 -1
-#endif
-#ifndef INT_A9_M2A_5
-#define INT_A9_M2A_5 -1
-#endif
-#ifndef INT_ADSP_A11
-#define INT_ADSP_A11 -1
-#endif
 #ifndef INT_ADSP_A11_SMSM
 #define INT_ADSP_A11_SMSM -1
 #endif
-#ifndef INT_DSPS_A11
-#define INT_DSPS_A11 -1
-#endif
-#ifndef INT_DSPS_A11_SMSM
-#define INT_DSPS_A11_SMSM -1
-#endif
-#ifndef INT_WCNSS_A11
-#define INT_WCNSS_A11 -1
-#endif
-#ifndef INT_WCNSS_A11_SMSM
-#define INT_WCNSS_A11_SMSM -1
-#endif
 
 #define SMD_LOOPBACK_CID 100
 
@@ -421,9 +262,6 @@
 		++interrupt_stats[SMD_MODEM].smd_out_config_count;
 		smd_write_intr(intr->out_bit_pos,
 		intr->out_base + intr->out_offset);
-	} else {
-		++interrupt_stats[SMD_MODEM].smd_out_hardcode_count;
-		MSM_TRIG_A2M_SMD_INT;
 	}
 }
 
@@ -437,9 +275,6 @@
 		++interrupt_stats[SMD_Q6].smd_out_config_count;
 		smd_write_intr(intr->out_bit_pos,
 		intr->out_base + intr->out_offset);
-	} else {
-		++interrupt_stats[SMD_Q6].smd_out_hardcode_count;
-		MSM_TRIG_A2Q6_SMD_INT;
 	}
 }
 
@@ -453,9 +288,6 @@
 		++interrupt_stats[SMD_DSPS].smd_out_config_count;
 		smd_write_intr(intr->out_bit_pos,
 		intr->out_base + intr->out_offset);
-	} else {
-		++interrupt_stats[SMD_DSPS].smd_out_hardcode_count;
-		MSM_TRIG_A2DSPS_SMD_INT;
 	}
 }
 
@@ -469,9 +301,6 @@
 		++interrupt_stats[SMD_WCNSS].smd_out_config_count;
 		smd_write_intr(intr->out_bit_pos,
 		intr->out_base + intr->out_offset);
-	} else {
-		++interrupt_stats[SMD_WCNSS].smd_out_hardcode_count;
-		MSM_TRIG_A2WCNSS_SMD_INT;
 	}
 }
 
@@ -492,13 +321,13 @@
 {
 	static const struct interrupt_config_item *intr
 		= &private_intr_config[SMD_MODEM].smsm;
+
+	SMx_POWER_INFO("SMSM Apps->%s", "MODEM");
+
 	if (intr->out_base) {
 		++interrupt_stats[SMD_MODEM].smsm_out_config_count;
 		smd_write_intr(intr->out_bit_pos,
 		intr->out_base + intr->out_offset);
-	} else {
-		++interrupt_stats[SMD_MODEM].smsm_out_hardcode_count;
-		MSM_TRIG_A2M_SMSM_INT;
 	}
 }
 
@@ -506,13 +335,13 @@
 {
 	static const struct interrupt_config_item *intr
 		= &private_intr_config[SMD_Q6].smsm;
+
+	SMx_POWER_INFO("SMSM Apps->%s", "ADSP");
+
 	if (intr->out_base) {
 		++interrupt_stats[SMD_Q6].smsm_out_config_count;
 		smd_write_intr(intr->out_bit_pos,
 		intr->out_base + intr->out_offset);
-	} else {
-		++interrupt_stats[SMD_Q6].smsm_out_hardcode_count;
-		MSM_TRIG_A2Q6_SMSM_INT;
 	}
 }
 
@@ -520,13 +349,13 @@
 {
 	static const struct interrupt_config_item *intr
 		= &private_intr_config[SMD_DSPS].smsm;
+
+	SMx_POWER_INFO("SMSM Apps->%s", "DSPS");
+
 	if (intr->out_base) {
 		++interrupt_stats[SMD_DSPS].smsm_out_config_count;
 		smd_write_intr(intr->out_bit_pos,
 		intr->out_base + intr->out_offset);
-	} else {
-		++interrupt_stats[SMD_DSPS].smsm_out_hardcode_count;
-		MSM_TRIG_A2DSPS_SMSM_INT;
 	}
 }
 
@@ -535,13 +364,12 @@
 	static const struct interrupt_config_item *intr
 		= &private_intr_config[SMD_WCNSS].smsm;
 
+	SMx_POWER_INFO("SMSM Apps->%s", "WCNSS");
+
 	if (intr->out_base) {
 		++interrupt_stats[SMD_WCNSS].smsm_out_config_count;
 		smd_write_intr(intr->out_bit_pos,
 		intr->out_base + intr->out_offset);
-	} else {
-		++interrupt_stats[SMD_WCNSS].smsm_out_hardcode_count;
-		MSM_TRIG_A2WCNSS_SMSM_INT;
 	}
 }
 
@@ -694,13 +522,6 @@
 	struct smd_half_channel_word_access ch1;
 };
 
-struct edge_to_pid {
-	uint32_t	local_pid;
-	uint32_t	remote_pid;
-	char		subsys_name[SMD_MAX_CH_NAME_LEN];
-	bool		initialized;
-};
-
 /**
  * Maps edge type to local and remote processor ID's.
  */
@@ -733,7 +554,7 @@
 	struct notifier_block nb;
 };
 
-static int disable_smsm_reset_handshake;
+int disable_smsm_reset_handshake;
 static struct platform_device loopback_tty_pdev = {.name = "LOOPBACK_TTY"};
 
 static LIST_HEAD(smd_ch_closed_list);
@@ -745,14 +566,17 @@
 static LIST_HEAD(smd_ch_list_wcnss);
 static LIST_HEAD(smd_ch_list_rpm);
 
-static unsigned char smd_ch_allocated[64];
+/* 2 total supported tables of channels */
+static unsigned char smd_ch_allocated[SMEM_NUM_SMD_STREAM_CHANNELS * 2];
 static struct work_struct probe_work;
 
 static void finalize_channel_close_fn(struct work_struct *work);
 static DECLARE_WORK(finalize_channel_close_work, finalize_channel_close_fn);
 static struct workqueue_struct *channel_close_wq;
 
-static int smd_alloc_channel(struct smd_alloc_elm *alloc_elm);
+#define PRI_ALLOC_TBL 1
+#define SEC_ALLOC_TBL 2
+static int smd_alloc_channel(struct smd_alloc_elm *alloc_elm, int table_id);
 
 static bool smd_edge_inited(int edge)
 {
@@ -763,26 +587,33 @@
    hence use a lock */
 static DEFINE_MUTEX(smd_probe_lock);
 
-static void smd_channel_probe_worker(struct work_struct *work)
+/**
+ * scan_alloc_table - Scans a specified SMD channel allocation table in SMEM for
+ *			newly created channels that need to be made locally
+ *			visable
+ *
+ * @shared: pointer to the table array in SMEM
+ * @smd_ch_allocated: pointer to an array indicating already allocated channels
+ * table_id: identifier for this channel allocation table
+ *
+ * The smd_probe_lock must be locked by the calling function.  Shared and
+ * smd_ch_allocated are assumed to be valid pointers.
+ */
+static void scan_alloc_table(struct smd_alloc_elm *shared,
+				char *smd_ch_allocated,
+				int table_id)
 {
-	struct smd_alloc_elm *shared;
 	unsigned n;
 	uint32_t type;
 
-	shared = smem_find(ID_CH_ALLOC_TBL, sizeof(*shared) * 64);
-
-	if (!shared) {
-		pr_err("%s: allocation table not initialized\n", __func__);
-		return;
-	}
-
-	mutex_lock(&smd_probe_lock);
-	for (n = 0; n < 64; n++) {
+	for (n = 0; n < SMEM_NUM_SMD_STREAM_CHANNELS; n++) {
 		if (smd_ch_allocated[n])
 			continue;
 
-		/* channel should be allocated only if APPS
-		   processor is involved */
+		/*
+		 * channel should be allocated only if APPS processor is
+		 * involved
+		 */
 		type = SMD_CHANNEL_TYPE(shared[n].type);
 		if (type >= ARRAY_SIZE(edge_to_pids) ||
 				edge_to_pids[type].local_pid != SMD_APPS)
@@ -793,15 +624,52 @@
 			continue;
 
 		if (!smd_initialized && !smd_edge_inited(type)) {
-			SMD_INFO("Probe skipping ch %d, edge not inited\n", n);
+			SMD_INFO(
+				"Probe skipping tbl %d, ch %d, edge not inited\n",
+				table_id, n);
 			continue;
 		}
 
-		if (!smd_alloc_channel(&shared[n]))
+		if (!smd_alloc_channel(&shared[n], table_id))
 			smd_ch_allocated[n] = 1;
 		else
-			SMD_INFO("Probe skipping ch %d, not allocated\n", n);
+			SMD_INFO(
+				"Probe skipping tbl %d, ch %d, not allocated\n",
+				table_id, n);
 	}
+}
+
+/**
+ * smd_channel_probe_worker() - Scan for newly created SMD channels and init
+ *				local structures so the channels are visable to
+ *				local clients
+ *
+ * @work: work_struct corresponding to an instance of this function running on
+ *		a workqueue.
+ */
+static void smd_channel_probe_worker(struct work_struct *work)
+{
+	struct smd_alloc_elm *shared;
+
+	shared = smem_find(ID_CH_ALLOC_TBL,
+				sizeof(*shared) * SMEM_NUM_SMD_STREAM_CHANNELS);
+
+	if (!shared) {
+		pr_err("%s: allocation table not initialized\n", __func__);
+		return;
+	}
+
+	mutex_lock(&smd_probe_lock);
+
+	scan_alloc_table(shared, smd_ch_allocated, PRI_ALLOC_TBL);
+
+	shared = smem_find(SMEM_CHANNEL_ALLOC_TBL_2,
+			sizeof(*shared) * SMEM_NUM_SMD_STREAM_CHANNELS);
+	if (shared)
+		scan_alloc_table(shared,
+			&(smd_ch_allocated[SMEM_NUM_SMD_STREAM_CHANNELS]),
+			SEC_ALLOC_TBL);
+
 	mutex_unlock(&smd_probe_lock);
 }
 
@@ -860,6 +728,29 @@
 	return ret;
 }
 
+/**
+ * smd_remote_ss_to_edge() - return edge type from remote ss type
+ * @name:	remote subsystem name
+ *
+ * Returns the edge type connected between the local subsystem(APPS)
+ * and remote subsystem @name.
+ */
+int smd_remote_ss_to_edge(const char *name)
+{
+	int i;
+
+	for (i = 0; i < ARRAY_SIZE(edge_to_pids); ++i) {
+		if (edge_to_pids[i].subsys_name[0] != 0x0) {
+			if (!strncmp(edge_to_pids[i].subsys_name, name,
+								strlen(name)))
+				return i;
+		}
+	}
+
+	return -EINVAL;
+}
+EXPORT_SYMBOL(smd_remote_ss_to_edge);
+
 /*
  * Returns a pointer to the subsystem name or NULL if no
  * subsystem name is available.
@@ -934,7 +825,7 @@
 	}
 }
 
-static void smd_channel_reset_state(struct smd_alloc_elm *shared,
+static void smd_channel_reset_state(struct smd_alloc_elm *shared, int table_id,
 		unsigned new_state, unsigned pid)
 {
 	unsigned n;
@@ -943,6 +834,19 @@
 	void *local_ch;
 	void *remote_ch;
 	int is_word_access;
+	unsigned base_id;
+
+	switch (table_id) {
+	case PRI_ALLOC_TBL:
+		base_id = SMEM_SMD_BASE_ID;
+		break;
+	case SEC_ALLOC_TBL:
+		base_id = SMEM_SMD_BASE_ID_2;
+		break;
+	default:
+		SMD_INFO("%s: invalid table_id:%d\n", __func__, table_id);
+		return;
+	}
 
 	for (n = 0; n < SMD_CHANNELS; n++) {
 		if (!shared[n].ref_count)
@@ -953,10 +857,10 @@
 		type = SMD_CHANNEL_TYPE(shared[n].type);
 		is_word_access = is_word_access_ch(type);
 		if (is_word_access)
-			shared2 = smem_alloc(SMEM_SMD_BASE_ID + n,
+			shared2 = smem_alloc(base_id + n,
 				sizeof(struct smd_shared_v2_word_access));
 		else
-			shared2 = smem_alloc(SMEM_SMD_BASE_ID + n,
+			shared2 = smem_alloc(base_id + n,
 				sizeof(struct smd_shared_v2));
 		if (!shared2)
 			continue;
@@ -979,16 +883,19 @@
 
 void smd_channel_reset(uint32_t restart_pid)
 {
-	struct smd_alloc_elm *shared;
+	struct smd_alloc_elm *shared_pri;
+	struct smd_alloc_elm *shared_sec;
 	unsigned long flags;
 
 	SMx_POWER_INFO("%s: starting reset\n", __func__);
 
-	shared = smem_find(ID_CH_ALLOC_TBL, sizeof(*shared) * 64);
-	if (!shared) {
+	shared_pri = smem_find(ID_CH_ALLOC_TBL, sizeof(*shared_pri) * 64);
+	if (!shared_pri) {
 		pr_err("%s: allocation table not initialized\n", __func__);
 		return;
 	}
+	shared_sec = smem_find(SMEM_CHANNEL_ALLOC_TBL_2,
+						sizeof(*shared_sec) * 64);
 
 	/* reset SMSM entry */
 	if (smsm_info.state) {
@@ -1012,7 +919,11 @@
 	/* change all remote states to CLOSING */
 	mutex_lock(&smd_probe_lock);
 	spin_lock_irqsave(&smd_lock, flags);
-	smd_channel_reset_state(shared, SMD_SS_CLOSING, restart_pid);
+	smd_channel_reset_state(shared_pri, PRI_ALLOC_TBL, SMD_SS_CLOSING,
+								restart_pid);
+	if (shared_sec)
+		smd_channel_reset_state(shared_sec, SEC_ALLOC_TBL,
+						SMD_SS_CLOSING, restart_pid);
 	spin_unlock_irqrestore(&smd_lock, flags);
 	mutex_unlock(&smd_probe_lock);
 
@@ -1028,7 +939,11 @@
 	/* change all remote states to CLOSED */
 	mutex_lock(&smd_probe_lock);
 	spin_lock_irqsave(&smd_lock, flags);
-	smd_channel_reset_state(shared, SMD_SS_CLOSED, restart_pid);
+	smd_channel_reset_state(shared_pri, PRI_ALLOC_TBL, SMD_SS_CLOSED,
+								restart_pid);
+	if (shared_sec)
+		smd_channel_reset_state(shared_sec, SEC_ALLOC_TBL,
+						SMD_SS_CLOSED, restart_pid);
 	spin_unlock_irqrestore(&smd_lock, flags);
 	mutex_unlock(&smd_probe_lock);
 
@@ -1384,7 +1299,7 @@
 	SMx_POWER_INFO("SMD Int %s->Apps\n", subsys);
 }
 
-static irqreturn_t smd_modem_irq_handler(int irq, void *data)
+irqreturn_t smd_modem_irq_handler(int irq, void *data)
 {
 	log_irq(SMD_APPS_MODEM);
 	++interrupt_stats[SMD_MODEM].smd_in_count;
@@ -1393,7 +1308,7 @@
 	return IRQ_HANDLED;
 }
 
-static irqreturn_t smd_dsp_irq_handler(int irq, void *data)
+irqreturn_t smd_dsp_irq_handler(int irq, void *data)
 {
 	log_irq(SMD_APPS_QDSP);
 	++interrupt_stats[SMD_Q6].smd_in_count;
@@ -1402,7 +1317,7 @@
 	return IRQ_HANDLED;
 }
 
-static irqreturn_t smd_dsps_irq_handler(int irq, void *data)
+irqreturn_t smd_dsps_irq_handler(int irq, void *data)
 {
 	log_irq(SMD_APPS_DSPS);
 	++interrupt_stats[SMD_DSPS].smd_in_count;
@@ -1411,7 +1326,7 @@
 	return IRQ_HANDLED;
 }
 
-static irqreturn_t smd_wcnss_irq_handler(int irq, void *data)
+irqreturn_t smd_wcnss_irq_handler(int irq, void *data)
 {
 	log_irq(SMD_APPS_WCNSS);
 	++interrupt_stats[SMD_WCNSS].smd_in_count;
@@ -1420,7 +1335,7 @@
 	return IRQ_HANDLED;
 }
 
-static irqreturn_t smd_rpm_irq_handler(int irq, void *data)
+irqreturn_t smd_rpm_irq_handler(int irq, void *data)
 {
 	log_irq(SMD_APPS_RPM);
 	++interrupt_stats[SMD_RPM].smd_in_count;
@@ -1661,15 +1576,41 @@
 }
 
 #if (defined(CONFIG_MSM_SMD_PKG4) || defined(CONFIG_MSM_SMD_PKG3))
-static int smd_alloc_v2(struct smd_channel *ch)
+/**
+ * smd_alloc_v2() - Init local channel structure with information stored in SMEM
+ *
+ * @ch: pointer to the local structure for this channel
+ * @table_id: the id of the table this channel resides in. 1 = first table, 2 =
+ *		second table, etc
+ * @returns: -EINVAL for failure; 0 for success
+ *
+ * ch must point to an allocated instance of struct smd_channel that is zeroed
+ * out, and has the n and type members already initialized to the correct values
+ */
+static int smd_alloc_v2(struct smd_channel *ch, int table_id)
 {
 	void *buffer;
 	unsigned buffer_sz;
+	unsigned base_id;
+	unsigned fifo_id;
+
+	switch (table_id) {
+	case PRI_ALLOC_TBL:
+		base_id = SMEM_SMD_BASE_ID;
+		fifo_id = SMEM_SMD_FIFO_BASE_ID;
+		break;
+	case SEC_ALLOC_TBL:
+		base_id = SMEM_SMD_BASE_ID_2;
+		fifo_id = SMEM_SMD_FIFO_BASE_ID_2;
+		break;
+	default:
+		SMD_INFO("Invalid table_id:%d passed to smd_alloc\n", table_id);
+		return -EINVAL;
+	}
 
 	if (is_word_access_ch(ch->type)) {
 		struct smd_shared_v2_word_access *shared2;
-		shared2 = smem_alloc(SMEM_SMD_BASE_ID + ch->n,
-						sizeof(*shared2));
+		shared2 = smem_alloc(base_id + ch->n, sizeof(*shared2));
 		if (!shared2) {
 			SMD_INFO("smem_alloc failed ch=%d\n", ch->n);
 			return -EINVAL;
@@ -1678,8 +1619,7 @@
 		ch->recv = &shared2->ch1;
 	} else {
 		struct smd_shared_v2 *shared2;
-		shared2 = smem_alloc(SMEM_SMD_BASE_ID + ch->n,
-							sizeof(*shared2));
+		shared2 = smem_alloc(base_id + ch->n, sizeof(*shared2));
 		if (!shared2) {
 			SMD_INFO("smem_alloc failed ch=%d\n", ch->n);
 			return -EINVAL;
@@ -1689,7 +1629,7 @@
 	}
 	ch->half_ch = get_half_ch_funcs(ch->type);
 
-	buffer = smem_get_entry(SMEM_SMD_FIFO_BASE_ID + ch->n, &buffer_sz);
+	buffer = smem_get_entry(fifo_id + ch->n, &buffer_sz);
 	if (!buffer) {
 		SMD_INFO("smem_get_entry failed\n");
 		return -EINVAL;
@@ -1714,7 +1654,7 @@
 }
 
 #else /* define v1 for older targets */
-static int smd_alloc_v2(struct smd_channel *ch)
+static int smd_alloc_v2(struct smd_channel *ch, int table_id)
 {
 	return -EINVAL;
 }
@@ -1738,7 +1678,16 @@
 
 #endif
 
-static int smd_alloc_channel(struct smd_alloc_elm *alloc_elm)
+/**
+ * smd_alloc_channel() - Create and init local structures for a newly allocated
+ *			SMD channel
+ *
+ * @alloc_elm: the allocation element stored in SMEM for this channel
+ * @table_id: the id of the table this channel resides in. 1 = first table, 2 =
+ *		seconds table, etc
+ * @returns: -1 for failure; 0 for success
+ */
+static int smd_alloc_channel(struct smd_alloc_elm *alloc_elm, int table_id)
 {
 	struct smd_channel *ch;
 
@@ -1750,7 +1699,7 @@
 	ch->n = alloc_elm->cid;
 	ch->type = SMD_CHANNEL_TYPE(alloc_elm->type);
 
-	if (smd_alloc_v2(ch) && smd_alloc_v1(ch)) {
+	if (smd_alloc_v2(ch, table_id) && smd_alloc_v1(ch)) {
 		kfree(ch);
 		return -1;
 	}
@@ -2712,28 +2661,28 @@
 	return IRQ_HANDLED;
 }
 
-static irqreturn_t smsm_modem_irq_handler(int irq, void *data)
+irqreturn_t smsm_modem_irq_handler(int irq, void *data)
 {
 	SMx_POWER_INFO("SMSM Int Modem->Apps\n");
 	++interrupt_stats[SMD_MODEM].smsm_in_count;
 	return smsm_irq_handler(irq, data);
 }
 
-static irqreturn_t smsm_dsp_irq_handler(int irq, void *data)
+irqreturn_t smsm_dsp_irq_handler(int irq, void *data)
 {
 	SMx_POWER_INFO("SMSM Int LPASS->Apps\n");
 	++interrupt_stats[SMD_Q6].smsm_in_count;
 	return smsm_irq_handler(irq, data);
 }
 
-static irqreturn_t smsm_dsps_irq_handler(int irq, void *data)
+irqreturn_t smsm_dsps_irq_handler(int irq, void *data)
 {
 	SMx_POWER_INFO("SMSM Int DSPS->Apps\n");
 	++interrupt_stats[SMD_DSPS].smsm_in_count;
 	return smsm_irq_handler(irq, data);
 }
 
-static irqreturn_t smsm_wcnss_irq_handler(int irq, void *data)
+irqreturn_t smsm_wcnss_irq_handler(int irq, void *data)
 {
 	SMx_POWER_INFO("SMSM Int WCNSS->Apps\n");
 	++interrupt_stats[SMD_WCNSS].smsm_in_count;
@@ -2825,7 +2774,8 @@
 	old_state = __raw_readl(SMSM_STATE_ADDR(smsm_entry));
 	new_state = (old_state & ~clear_mask) | set_mask;
 	__raw_writel(new_state, SMSM_STATE_ADDR(smsm_entry));
-	SMSM_DBG("smsm_change_state %x\n", new_state);
+	SMx_POWER_INFO("%s %d:%08x->%08x", __func__, smsm_entry,
+			old_state, new_state);
 	notify_other_smsm(SMSM_APPS_STATE, (old_state ^ new_state));
 
 	spin_unlock_irqrestore(&smem_lock, flags);
@@ -3090,523 +3040,6 @@
 }
 EXPORT_SYMBOL(smsm_state_cb_deregister);
 
-int smd_core_init(void)
-{
-	int r;
-	unsigned long flags = IRQF_TRIGGER_RISING;
-	SMD_INFO("smd_core_init()\n");
-
-	r = request_irq(INT_A9_M2A_0, smd_modem_irq_handler,
-			flags, "smd_dev", 0);
-	if (r < 0)
-		return r;
-	interrupt_stats[SMD_MODEM].smd_interrupt_id = INT_A9_M2A_0;
-	r = enable_irq_wake(INT_A9_M2A_0);
-	if (r < 0)
-		pr_err("smd_core_init: "
-		       "enable_irq_wake failed for INT_A9_M2A_0\n");
-
-	r = request_irq(INT_A9_M2A_5, smsm_modem_irq_handler,
-			flags, "smsm_dev", 0);
-	if (r < 0) {
-		free_irq(INT_A9_M2A_0, 0);
-		return r;
-	}
-	interrupt_stats[SMD_MODEM].smsm_interrupt_id = INT_A9_M2A_5;
-	r = enable_irq_wake(INT_A9_M2A_5);
-	if (r < 0)
-		pr_err("smd_core_init: "
-		       "enable_irq_wake failed for INT_A9_M2A_5\n");
-
-#if defined(CONFIG_QDSP6)
-#if (INT_ADSP_A11 == INT_ADSP_A11_SMSM)
-		flags |= IRQF_SHARED;
-#endif
-	r = request_irq(INT_ADSP_A11, smd_dsp_irq_handler,
-			flags, "smd_dev", smd_dsp_irq_handler);
-	if (r < 0) {
-		free_irq(INT_A9_M2A_0, 0);
-		free_irq(INT_A9_M2A_5, 0);
-		return r;
-	}
-
-	interrupt_stats[SMD_Q6].smd_interrupt_id = INT_ADSP_A11;
-	r = request_irq(INT_ADSP_A11_SMSM, smsm_dsp_irq_handler,
-			flags, "smsm_dev", smsm_dsp_irq_handler);
-	if (r < 0) {
-		free_irq(INT_A9_M2A_0, 0);
-		free_irq(INT_A9_M2A_5, 0);
-		free_irq(INT_ADSP_A11, smd_dsp_irq_handler);
-		return r;
-	}
-
-	interrupt_stats[SMD_Q6].smsm_interrupt_id = INT_ADSP_A11_SMSM;
-	r = enable_irq_wake(INT_ADSP_A11);
-	if (r < 0)
-		pr_err("smd_core_init: "
-		       "enable_irq_wake failed for INT_ADSP_A11\n");
-
-#if (INT_ADSP_A11 != INT_ADSP_A11_SMSM)
-	r = enable_irq_wake(INT_ADSP_A11_SMSM);
-	if (r < 0)
-		pr_err("smd_core_init: enable_irq_wake "
-		       "failed for INT_ADSP_A11_SMSM\n");
-#endif
-	flags &= ~IRQF_SHARED;
-#endif
-
-#if defined(CONFIG_DSPS)
-	r = request_irq(INT_DSPS_A11, smd_dsps_irq_handler,
-			flags, "smd_dev", smd_dsps_irq_handler);
-	if (r < 0) {
-		free_irq(INT_A9_M2A_0, 0);
-		free_irq(INT_A9_M2A_5, 0);
-		free_irq(INT_ADSP_A11, smd_dsp_irq_handler);
-		free_irq(INT_ADSP_A11_SMSM, smsm_dsp_irq_handler);
-		return r;
-	}
-
-	interrupt_stats[SMD_DSPS].smd_interrupt_id = INT_DSPS_A11;
-	r = enable_irq_wake(INT_DSPS_A11);
-	if (r < 0)
-		pr_err("smd_core_init: "
-		       "enable_irq_wake failed for INT_ADSP_A11\n");
-#endif
-
-#if defined(CONFIG_WCNSS)
-	r = request_irq(INT_WCNSS_A11, smd_wcnss_irq_handler,
-			flags, "smd_dev", smd_wcnss_irq_handler);
-	if (r < 0) {
-		free_irq(INT_A9_M2A_0, 0);
-		free_irq(INT_A9_M2A_5, 0);
-		free_irq(INT_ADSP_A11, smd_dsp_irq_handler);
-		free_irq(INT_ADSP_A11_SMSM, smsm_dsp_irq_handler);
-		free_irq(INT_DSPS_A11, smd_dsps_irq_handler);
-		return r;
-	}
-
-	interrupt_stats[SMD_WCNSS].smd_interrupt_id = INT_WCNSS_A11;
-	r = enable_irq_wake(INT_WCNSS_A11);
-	if (r < 0)
-		pr_err("smd_core_init: "
-		       "enable_irq_wake failed for INT_WCNSS_A11\n");
-
-	r = request_irq(INT_WCNSS_A11_SMSM, smsm_wcnss_irq_handler,
-			flags, "smsm_dev", smsm_wcnss_irq_handler);
-	if (r < 0) {
-		free_irq(INT_A9_M2A_0, 0);
-		free_irq(INT_A9_M2A_5, 0);
-		free_irq(INT_ADSP_A11, smd_dsp_irq_handler);
-		free_irq(INT_ADSP_A11_SMSM, smsm_dsp_irq_handler);
-		free_irq(INT_DSPS_A11, smd_dsps_irq_handler);
-		free_irq(INT_WCNSS_A11, smd_wcnss_irq_handler);
-		return r;
-	}
-
-	interrupt_stats[SMD_WCNSS].smsm_interrupt_id = INT_WCNSS_A11_SMSM;
-	r = enable_irq_wake(INT_WCNSS_A11_SMSM);
-	if (r < 0)
-		pr_err("smd_core_init: "
-		       "enable_irq_wake failed for INT_WCNSS_A11_SMSM\n");
-#endif
-
-#if defined(CONFIG_DSPS_SMSM)
-	r = request_irq(INT_DSPS_A11_SMSM, smsm_dsps_irq_handler,
-			flags, "smsm_dev", smsm_dsps_irq_handler);
-	if (r < 0) {
-		free_irq(INT_A9_M2A_0, 0);
-		free_irq(INT_A9_M2A_5, 0);
-		free_irq(INT_ADSP_A11, smd_dsp_irq_handler);
-		free_irq(INT_ADSP_A11_SMSM, smsm_dsp_irq_handler);
-		free_irq(INT_DSPS_A11, smd_dsps_irq_handler);
-		free_irq(INT_WCNSS_A11, smd_wcnss_irq_handler);
-		free_irq(INT_WCNSS_A11_SMSM, smsm_wcnss_irq_handler);
-		return r;
-	}
-
-	interrupt_stats[SMD_DSPS].smsm_interrupt_id = INT_DSPS_A11_SMSM;
-	r = enable_irq_wake(INT_DSPS_A11_SMSM);
-	if (r < 0)
-		pr_err("smd_core_init: "
-		       "enable_irq_wake failed for INT_DSPS_A11_SMSM\n");
-#endif
-	SMD_INFO("smd_core_init() done\n");
-
-	return 0;
-}
-
-static int intr_init(struct interrupt_config_item *private_irq,
-			struct smd_irq_config *platform_irq,
-			struct platform_device *pdev
-			)
-{
-	int irq_id;
-	int ret;
-	int ret_wake;
-
-	private_irq->out_bit_pos = platform_irq->out_bit_pos;
-	private_irq->out_offset = platform_irq->out_offset;
-	private_irq->out_base = platform_irq->out_base;
-
-	irq_id = platform_get_irq_byname(
-					pdev,
-					platform_irq->irq_name
-				);
-	SMD_DBG("smd: %s: register irq: %s id: %d\n", __func__,
-				platform_irq->irq_name, irq_id);
-	ret = request_irq(irq_id,
-				private_irq->irq_handler,
-				platform_irq->flags,
-				platform_irq->device_name,
-				(void *)platform_irq->dev_id
-			);
-	if (ret < 0) {
-		platform_irq->irq_id = ret;
-		private_irq->irq_id = ret;
-	} else {
-		platform_irq->irq_id = irq_id;
-		private_irq->irq_id = irq_id;
-		ret_wake = enable_irq_wake(irq_id);
-		if (ret_wake < 0) {
-			pr_err("smd: enable_irq_wake failed on %s",
-					platform_irq->irq_name);
-		}
-	}
-
-	return ret;
-}
-
-int smd_core_platform_init(struct platform_device *pdev)
-{
-	int i;
-	int ret;
-	uint32_t num_ss;
-	struct smd_platform *smd_platform_data;
-	struct smd_subsystem_config *smd_ss_config_list;
-	struct smd_subsystem_config *cfg;
-	int err_ret = 0;
-
-	smd_platform_data = pdev->dev.platform_data;
-	num_ss = smd_platform_data->num_ss_configs;
-	smd_ss_config_list = smd_platform_data->smd_ss_configs;
-
-	if (smd_platform_data->smd_ssr_config)
-		disable_smsm_reset_handshake = smd_platform_data->
-			   smd_ssr_config->disable_smsm_reset_handshake;
-
-	for (i = 0; i < num_ss; i++) {
-		cfg = &smd_ss_config_list[i];
-
-		ret = intr_init(
-			&private_intr_config[cfg->irq_config_id].smd,
-			&cfg->smd_int,
-			pdev
-			);
-
-		if (ret < 0) {
-			err_ret = ret;
-			pr_err("smd: register irq failed on %s\n",
-				cfg->smd_int.irq_name);
-			goto intr_failed;
-		}
-
-		interrupt_stats[cfg->irq_config_id].smd_interrupt_id
-						 = cfg->smd_int.irq_id;
-		/* only init smsm structs if this edge supports smsm */
-		if (cfg->smsm_int.irq_id)
-			ret = intr_init(
-				&private_intr_config[cfg->irq_config_id].smsm,
-				&cfg->smsm_int,
-				pdev
-				);
-
-		if (ret < 0) {
-			err_ret = ret;
-			pr_err("smd: register irq failed on %s\n",
-				cfg->smsm_int.irq_name);
-			goto intr_failed;
-		}
-
-		if (cfg->smsm_int.irq_id)
-			interrupt_stats[cfg->irq_config_id].smsm_interrupt_id
-						 = cfg->smsm_int.irq_id;
-		if (cfg->subsys_name)
-			strlcpy(edge_to_pids[cfg->edge].subsys_name,
-				cfg->subsys_name, SMD_MAX_CH_NAME_LEN);
-	}
-
-	SMD_INFO("smd_core_platform_init() done\n");
-
-	return 0;
-
-intr_failed:
-	pr_err("smd: deregistering IRQs\n");
-	for (i = 0; i < num_ss; ++i) {
-		cfg = &smd_ss_config_list[i];
-
-		if (cfg->smd_int.irq_id >= 0)
-			free_irq(cfg->smd_int.irq_id,
-				(void *)cfg->smd_int.dev_id
-				);
-		if (cfg->smsm_int.irq_id >= 0)
-			free_irq(cfg->smsm_int.irq_id,
-				(void *)cfg->smsm_int.dev_id
-				);
-	}
-	return err_ret;
-}
-
-static int msm_smsm_probe(struct platform_device *pdev)
-{
-	uint32_t edge;
-	char *key;
-	int ret;
-	uint32_t irq_offset;
-	uint32_t irq_bitmask;
-	uint32_t irq_line;
-	struct interrupt_config_item *private_irq;
-	struct device_node *node;
-	void *irq_out_base;
-	resource_size_t irq_out_size;
-	struct platform_device *parent_pdev;
-	struct resource *r;
-
-	disable_smsm_reset_handshake = 1;
-
-	node = pdev->dev.of_node;
-
-	if (!pdev->dev.parent) {
-		pr_err("%s: missing link to parent device\n", __func__);
-		return -ENODEV;
-	}
-
-	parent_pdev = to_platform_device(pdev->dev.parent);
-
-	key = "irq-reg-base";
-	r = platform_get_resource_byname(parent_pdev, IORESOURCE_MEM, key);
-	if (!r)
-		goto missing_key;
-	irq_out_size = resource_size(r);
-	irq_out_base = ioremap_nocache(r->start, irq_out_size);
-	if (!irq_out_base) {
-		pr_err("%s: ioremap_nocache() of irq_out_base addr:%pr size:%pr\n",
-				__func__, &r->start, &irq_out_size);
-		return -ENOMEM;
-	}
-	SMSM_DBG("%s: %s = %p", __func__, key, irq_out_base);
-
-	key = "qcom,smsm-edge";
-	ret = of_property_read_u32(node, key, &edge);
-	if (ret)
-		goto missing_key;
-	SMSM_DBG("%s: %s = %d", __func__, key, edge);
-
-	key = "qcom,smsm-irq-offset";
-	ret = of_property_read_u32(node, key, &irq_offset);
-	if (ret)
-		goto missing_key;
-	SMSM_DBG("%s: %s = %x", __func__, key, irq_offset);
-
-	key = "qcom,smsm-irq-bitmask";
-	ret = of_property_read_u32(node, key, &irq_bitmask);
-	if (ret)
-		goto missing_key;
-	SMSM_DBG("%s: %s = %x", __func__, key, irq_bitmask);
-
-	key = "interrupts";
-	irq_line = irq_of_parse_and_map(node, 0);
-	if (!irq_line)
-		goto missing_key;
-	SMSM_DBG("%s: %s = %d", __func__, key, irq_line);
-
-	private_irq = &private_intr_config[edge_to_pids[edge].remote_pid].smsm;
-	private_irq->out_bit_pos = irq_bitmask;
-	private_irq->out_offset = irq_offset;
-	private_irq->out_base = irq_out_base;
-	private_irq->irq_id = irq_line;
-
-	ret = request_irq(irq_line,
-				private_irq->irq_handler,
-				IRQF_TRIGGER_RISING,
-				"smsm_dev",
-				NULL);
-	if (ret < 0) {
-		pr_err("%s: request_irq() failed on %d\n", __func__, irq_line);
-		return ret;
-	} else {
-		ret = enable_irq_wake(irq_line);
-		if (ret < 0)
-			pr_err("%s: enable_irq_wake() failed on %d\n", __func__,
-					irq_line);
-	}
-
-	if (smsm_init())
-		pr_err("smsm_init() failed\n");
-
-	smsm_irq_handler(0, 0);
-
-	return 0;
-
-missing_key:
-	pr_err("%s: missing key: %s", __func__, key);
-	return -ENODEV;
-}
-
-static int msm_smd_probe(struct platform_device *pdev)
-{
-	uint32_t edge;
-	char *key;
-	int ret;
-	uint32_t irq_offset;
-	uint32_t irq_bitmask;
-	uint32_t irq_line;
-	unsigned long irq_flags = IRQF_TRIGGER_RISING;
-	const char *pilstr;
-	struct interrupt_config_item *private_irq;
-	struct device_node *node;
-	void *irq_out_base;
-	resource_size_t irq_out_size;
-	struct platform_device *parent_pdev;
-	struct resource *r;
-
-	node = pdev->dev.of_node;
-
-	if (!pdev->dev.parent) {
-		pr_err("%s: missing link to parent device\n", __func__);
-		return -ENODEV;
-	}
-
-	parent_pdev = to_platform_device(pdev->dev.parent);
-
-	key = "irq-reg-base";
-	r = platform_get_resource_byname(parent_pdev, IORESOURCE_MEM, key);
-	if (!r)
-		goto missing_key;
-	irq_out_size = resource_size(r);
-	irq_out_base = ioremap_nocache(r->start, irq_out_size);
-	if (!irq_out_base) {
-		pr_err("%s: ioremap_nocache() of irq_out_base addr:%pr size:%pr\n",
-				__func__, &r->start, &irq_out_size);
-		return -ENOMEM;
-	}
-	SMD_DBG("%s: %s = %p", __func__, key, irq_out_base);
-
-	key = "qcom,smd-edge";
-	ret = of_property_read_u32(node, key, &edge);
-	if (ret)
-		goto missing_key;
-	SMD_DBG("%s: %s = %d", __func__, key, edge);
-
-	key = "qcom,smd-irq-offset";
-	ret = of_property_read_u32(node, key, &irq_offset);
-	if (ret)
-		goto missing_key;
-	SMD_DBG("%s: %s = %x", __func__, key, irq_offset);
-
-	key = "qcom,smd-irq-bitmask";
-	ret = of_property_read_u32(node, key, &irq_bitmask);
-	if (ret)
-		goto missing_key;
-	SMD_DBG("%s: %s = %x", __func__, key, irq_bitmask);
-
-	key = "interrupts";
-	irq_line = irq_of_parse_and_map(node, 0);
-	if (!irq_line)
-		goto missing_key;
-	SMD_DBG("%s: %s = %d", __func__, key, irq_line);
-
-	key = "qcom,pil-string";
-	pilstr = of_get_property(node, key, NULL);
-	if (pilstr)
-		SMD_DBG("%s: %s = %s", __func__, key, pilstr);
-
-	key = "qcom,irq-no-suspend";
-	ret = of_property_read_bool(node, key);
-	if (ret)
-		irq_flags |= IRQF_NO_SUSPEND;
-
-	private_irq = &private_intr_config[edge_to_pids[edge].remote_pid].smd;
-	private_irq->out_bit_pos = irq_bitmask;
-	private_irq->out_offset = irq_offset;
-	private_irq->out_base = irq_out_base;
-	private_irq->irq_id = irq_line;
-
-	ret = request_irq(irq_line,
-				private_irq->irq_handler,
-				irq_flags,
-				"smd_dev",
-				NULL);
-	if (ret < 0) {
-		pr_err("%s: request_irq() failed on %d\n", __func__, irq_line);
-		return ret;
-	} else {
-		ret = enable_irq_wake(irq_line);
-		if (ret < 0)
-			pr_err("%s: enable_irq_wake() failed on %d\n", __func__,
-					irq_line);
-	}
-
-	if (pilstr)
-		strlcpy(edge_to_pids[edge].subsys_name, pilstr,
-						SMD_MAX_CH_NAME_LEN);
-
-	edge_to_pids[edge].initialized = true;
-
-	schedule_work(&probe_work);
-
-	return 0;
-
-missing_key:
-	pr_err("%s: missing key: %s", __func__, key);
-	return -ENODEV;
-}
-
-static int msm_smd_probe_legacy(struct platform_device *pdev)
-{
-	int ret;
-
-	if (!smem_initialized_check())
-		return -ENODEV;
-
-	SMD_INFO("smd probe\n");
-
-	if (smsm_init()) {
-		pr_err("smsm_init() failed\n");
-		return -1;
-	}
-
-	if (pdev) {
-		if (pdev->dev.of_node) {
-			pr_err("%s: invalid device tree init\n", __func__);
-			return -ENODEV;
-		} else if (pdev->dev.platform_data) {
-			ret = smd_core_platform_init(pdev);
-			if (ret) {
-				pr_err(
-				"SMD: smd_core_platform_init() failed\n");
-				return -ENODEV;
-			}
-		} else {
-			ret = smd_core_init();
-			if (ret) {
-				pr_err("smd_core_init() failed\n");
-				return -ENODEV;
-			}
-		}
-	} else {
-		pr_err("SMD: PDEV not found\n");
-		return -ENODEV;
-	}
-
-	smd_initialized = 1;
-
-	smd_alloc_loopback_channel();
-	smsm_irq_handler(0, 0);
-	tasklet_schedule(&smd_fake_irq_tasklet);
-
-	return 0;
-}
-
 static int restart_notifier_cb(struct notifier_block *this,
 				  unsigned long code,
 				  void *data);
@@ -3650,6 +3083,137 @@
 	return NOTIFY_DONE;
 }
 
+/**
+ * smd_post_init() - SMD post initialization
+ * @is_leagcy:	1 for Leagcy/platform device init sequence
+ *		0 for device tree init sequence
+ *
+ * This function is used by the legacy and device tree initialization
+ * to complete the SMD init sequence.
+ */
+void smd_post_init(bool is_legacy)
+{
+	if (is_legacy) {
+		smd_initialized = 1;
+		smd_alloc_loopback_channel();
+		tasklet_schedule(&smd_fake_irq_tasklet);
+	} else {
+		schedule_work(&probe_work);
+	}
+}
+
+/**
+ * smsm_post_init() - SMSM post initialization
+ * @returns:	0 for success, standard Linux error code otherwise
+ *
+ * This function is used by the legacy and device tree initialization
+ * to complete the SMSM init sequence.
+ */
+int smsm_post_init(void)
+{
+	int ret;
+
+	ret = smsm_init();
+	if (ret) {
+		pr_err("smsm_init() failed ret = %d\n", ret);
+		return ret;
+	}
+	smsm_irq_handler(0, 0);
+
+	return ret;
+}
+
+/**
+ * smd_get_intr_config() - Get interrupt configuration structure
+ * @edge:	edge type identifes local and remote processor
+ * @returns:	pointer to interrupt configuration
+ *
+ * This function returns the interrupt configuration of remote processor
+ * based on the edge type.
+ */
+struct interrupt_config *smd_get_intr_config(uint32_t edge)
+{
+	if (edge >= ARRAY_SIZE(edge_to_pids))
+		return NULL;
+	return &private_intr_config[edge_to_pids[edge].remote_pid];
+}
+
+/**
+ * smd_get_edge_remote_pid() - Get the remote processor ID
+ * @edge:	edge type identifes local and remote processor
+ * @returns:	remote processor ID
+ *
+ * This function returns remote processor ID based on edge type.
+ */
+int smd_edge_to_remote_pid(uint32_t edge)
+{
+	if (edge >= ARRAY_SIZE(edge_to_pids))
+		return -EINVAL;
+	return edge_to_pids[edge].remote_pid;
+}
+
+/**
+ * smd_set_edge_subsys_name() - Set the subsystem name
+ * @edge:		edge type identifies local and remote processor
+ * @sussys_name:	pointer to subsystem name
+ *
+ * This function is used to set the subsystem name for given edge type.
+ */
+void smd_set_edge_subsys_name(uint32_t edge, const char *subsys_name)
+{
+	if (edge <= ARRAY_SIZE(edge_to_pids))
+		strlcpy(edge_to_pids[edge].subsys_name,
+			subsys_name, SMD_MAX_CH_NAME_LEN);
+	else
+		pr_err("%s: Invalid edge type[%d]\n", __func__, edge);
+}
+
+/**
+ * smd_set_edge_initialized() - Set the edge initialized status
+ * @edge:	edge type identifies local and remote processor
+ *
+ * This function set the initialized varibale based on edge type.
+ */
+void smd_set_edge_initialized(uint32_t edge)
+{
+	if (edge <= ARRAY_SIZE(edge_to_pids))
+		edge_to_pids[edge].initialized = true;
+	else
+		pr_err("%s: Invalid edge type[%d]\n", __func__, edge);
+}
+
+/**
+ * smd_cfg_smd_intr() - Set the SMD interrupt configuration
+ * @proc:	remote processor ID
+ * @mask:	bit position in IRQ register
+ * @ptr:	IRQ register
+ *
+ * This function is called in Legacy init sequence and used to set
+ * the SMD interrupt configurations for particular processor.
+ */
+void smd_cfg_smd_intr(uint32_t proc, uint32_t mask, void *ptr)
+{
+	private_intr_config[proc].smd.out_bit_pos = mask;
+	private_intr_config[proc].smd.out_base = ptr;
+	private_intr_config[proc].smd.out_offset = 0;
+}
+
+/*
+ * smd_cfg_smsm_intr() -  Set the SMSM interrupt configuration
+ * @proc:	remote processor ID
+ * @mask:	bit position in IRQ register
+ * @ptr:	IRQ register
+ *
+ * This function is called in Legacy init sequence and used to set
+ * the SMSM interrupt configurations for particular processor.
+ */
+void smd_cfg_smsm_intr(uint32_t proc, uint32_t mask, void *ptr)
+{
+	private_intr_config[proc].smsm.out_bit_pos = mask;
+	private_intr_config[proc].smsm.out_base = ptr;
+	private_intr_config[proc].smsm.out_offset = 0;
+}
+
 static __init int modem_restart_late_init(void)
 {
 	int i;
@@ -3667,42 +3231,6 @@
 }
 late_initcall(modem_restart_late_init);
 
-static struct of_device_id msm_smd_match_table[] = {
-	{ .compatible = "qcom,smd" },
-	{},
-};
-
-static struct platform_driver msm_smd_driver = {
-	.probe = msm_smd_probe,
-	.driver = {
-		.name = "msm_smd_dt",
-		.owner = THIS_MODULE,
-		.of_match_table = msm_smd_match_table,
-	},
-};
-
-static struct of_device_id msm_smsm_match_table[] = {
-	{ .compatible = "qcom,smsm" },
-	{},
-};
-
-static struct platform_driver msm_smsm_driver = {
-	.probe = msm_smsm_probe,
-	.driver = {
-		.name = "msm_smsm",
-		.owner = THIS_MODULE,
-		.of_match_table = msm_smsm_match_table,
-	},
-};
-
-static struct platform_driver msm_smd_driver_legacy = {
-	.probe = msm_smd_probe_legacy,
-	.driver = {
-		.name = MODULE_NAME,
-		.owner = THIS_MODULE,
-	},
-};
-
 int __init msm_smd_init(void)
 {
 	static bool registered;
@@ -3727,27 +3255,12 @@
 		return -ENOMEM;
 	}
 
-	rc = platform_driver_register(&msm_smd_driver_legacy);
-	if (rc) {
-		pr_err("%s: msm_smd_driver_legacy register failed %d\n",
-			__func__, rc);
-		return rc;
-	}
-
-	rc = platform_driver_register(&msm_smd_driver);
+	rc = msm_smd_driver_register();
 	if (rc) {
 		pr_err("%s: msm_smd_driver register failed %d\n",
 			__func__, rc);
 		return rc;
 	}
-
-	rc = platform_driver_register(&msm_smsm_driver);
-	if (rc) {
-		pr_err("%s: msm_smsm_driver register failed %d\n",
-			__func__, rc);
-		return rc;
-	}
-
 	return 0;
 }
 
diff --git a/arch/arm/mach-msm/smd_init_dt.c b/arch/arm/mach-msm/smd_init_dt.c
new file mode 100644
index 0000000..d888a72
--- /dev/null
+++ b/arch/arm/mach-msm/smd_init_dt.c
@@ -0,0 +1,322 @@
+/* arch/arm/mach-msm/smd_init_dt.c
+ *
+ * Copyright (c) 2013, 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.
+ *
+ */
+#ifdef CONFIG_OF
+#include <linux/platform_device.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/of_irq.h>
+#include <linux/interrupt.h>
+#include <linux/io.h>
+
+#include <mach/msm_ipc_logging.h>
+#include <smd_private.h>
+
+#define MODULE_NAME "msm_smd"
+#define IPC_LOG(level, x...) do { \
+	if (smd_log_ctx) \
+		ipc_log_string(smd_log_ctx, x); \
+	else \
+		printk(level x); \
+	} while (0)
+
+#if defined(CONFIG_MSM_SMD_DEBUG)
+#define SMD_DBG(x...) do {				\
+		if (msm_smd_debug_mask & MSM_SMD_DEBUG) \
+			IPC_LOG(KERN_DEBUG, x);		\
+	} while (0)
+
+#define SMSM_DBG(x...) do {					\
+		if (msm_smd_debug_mask & MSM_SMSM_DEBUG)	\
+			IPC_LOG(KERN_DEBUG, x);		\
+	} while (0)
+#else
+#define SMD_DBG(x...) do { } while (0)
+#define SMSM_DBG(x...) do { } while (0)
+#endif
+
+static int msm_smsm_probe(struct platform_device *pdev)
+{
+	uint32_t edge;
+	char *key;
+	int ret;
+	uint32_t irq_offset;
+	uint32_t irq_bitmask;
+	uint32_t irq_line;
+	struct interrupt_config_item *private_irq;
+	struct device_node *node;
+	void *irq_out_base;
+	resource_size_t irq_out_size;
+	struct platform_device *parent_pdev;
+	struct resource *r;
+	struct interrupt_config *private_intr_config;
+	uint32_t remote_pid;
+
+	disable_smsm_reset_handshake = 1;
+
+	node = pdev->dev.of_node;
+
+	if (!pdev->dev.parent) {
+		pr_err("%s: missing link to parent device\n", __func__);
+		return -ENODEV;
+	}
+
+	parent_pdev = to_platform_device(pdev->dev.parent);
+
+	key = "irq-reg-base";
+	r = platform_get_resource_byname(parent_pdev, IORESOURCE_MEM, key);
+	if (!r)
+		goto missing_key;
+	irq_out_size = resource_size(r);
+	irq_out_base = ioremap_nocache(r->start, irq_out_size);
+	if (!irq_out_base) {
+		pr_err("%s: ioremap_nocache() of irq_out_base addr:%pr size:%pr\n",
+				__func__, &r->start, &irq_out_size);
+		return -ENOMEM;
+	}
+	SMSM_DBG("%s: %s = %p", __func__, key, irq_out_base);
+
+	key = "qcom,smsm-edge";
+	ret = of_property_read_u32(node, key, &edge);
+	if (ret)
+		goto missing_key;
+	SMSM_DBG("%s: %s = %d", __func__, key, edge);
+
+	key = "qcom,smsm-irq-offset";
+	ret = of_property_read_u32(node, key, &irq_offset);
+	if (ret)
+		goto missing_key;
+	SMSM_DBG("%s: %s = %x", __func__, key, irq_offset);
+
+	key = "qcom,smsm-irq-bitmask";
+	ret = of_property_read_u32(node, key, &irq_bitmask);
+	if (ret)
+		goto missing_key;
+	SMSM_DBG("%s: %s = %x", __func__, key, irq_bitmask);
+
+	key = "interrupts";
+	irq_line = irq_of_parse_and_map(node, 0);
+	if (!irq_line)
+		goto missing_key;
+	SMSM_DBG("%s: %s = %d", __func__, key, irq_line);
+
+	private_intr_config = smd_get_intr_config(edge);
+	if (!private_intr_config) {
+		pr_err("%s: invalid edge\n", __func__);
+		return -ENODEV;
+	}
+	private_irq = &private_intr_config->smsm;
+	private_irq->out_bit_pos = irq_bitmask;
+	private_irq->out_offset = irq_offset;
+	private_irq->out_base = irq_out_base;
+	private_irq->irq_id = irq_line;
+	remote_pid = smd_edge_to_remote_pid(edge);
+	interrupt_stats[remote_pid].smsm_interrupt_id = irq_line;
+
+	ret = request_irq(irq_line,
+				private_irq->irq_handler,
+				IRQF_TRIGGER_RISING,
+				"smsm_dev",
+				NULL);
+	if (ret < 0) {
+		pr_err("%s: request_irq() failed on %d\n", __func__, irq_line);
+		return ret;
+	} else {
+		ret = enable_irq_wake(irq_line);
+		if (ret < 0)
+			pr_err("%s: enable_irq_wake() failed on %d\n", __func__,
+					irq_line);
+	}
+
+	ret = smsm_post_init();
+	if (ret) {
+		pr_err("smd_post_init() failed ret=%d\n", ret);
+		return ret;
+	}
+
+	return 0;
+
+missing_key:
+	pr_err("%s: missing key: %s", __func__, key);
+	return -ENODEV;
+}
+
+static int msm_smd_probe(struct platform_device *pdev)
+{
+	uint32_t edge;
+	char *key;
+	int ret;
+	uint32_t irq_offset;
+	uint32_t irq_bitmask;
+	uint32_t irq_line;
+	unsigned long irq_flags = IRQF_TRIGGER_RISING;
+	const char *pilstr;
+	struct interrupt_config_item *private_irq;
+	struct device_node *node;
+	void *irq_out_base;
+	resource_size_t irq_out_size;
+	struct platform_device *parent_pdev;
+	struct resource *r;
+	struct interrupt_config *private_intr_config;
+	uint32_t remote_pid;
+
+	node = pdev->dev.of_node;
+
+	if (!pdev->dev.parent) {
+		pr_err("%s: missing link to parent device\n", __func__);
+		return -ENODEV;
+	}
+
+	parent_pdev = to_platform_device(pdev->dev.parent);
+
+	key = "irq-reg-base";
+	r = platform_get_resource_byname(parent_pdev, IORESOURCE_MEM, key);
+	if (!r)
+		goto missing_key;
+	irq_out_size = resource_size(r);
+	irq_out_base = ioremap_nocache(r->start, irq_out_size);
+	if (!irq_out_base) {
+		pr_err("%s: ioremap_nocache() of irq_out_base addr:%pr size:%pr\n",
+				__func__, &r->start, &irq_out_size);
+		return -ENOMEM;
+	}
+	SMD_DBG("%s: %s = %p", __func__, key, irq_out_base);
+
+	key = "qcom,smd-edge";
+	ret = of_property_read_u32(node, key, &edge);
+	if (ret)
+		goto missing_key;
+	SMD_DBG("%s: %s = %d", __func__, key, edge);
+
+	key = "qcom,smd-irq-offset";
+	ret = of_property_read_u32(node, key, &irq_offset);
+	if (ret)
+		goto missing_key;
+	SMD_DBG("%s: %s = %x", __func__, key, irq_offset);
+
+	key = "qcom,smd-irq-bitmask";
+	ret = of_property_read_u32(node, key, &irq_bitmask);
+	if (ret)
+		goto missing_key;
+	SMD_DBG("%s: %s = %x", __func__, key, irq_bitmask);
+
+	key = "interrupts";
+	irq_line = irq_of_parse_and_map(node, 0);
+	if (!irq_line)
+		goto missing_key;
+	SMD_DBG("%s: %s = %d", __func__, key, irq_line);
+
+	key = "qcom,pil-string";
+	pilstr = of_get_property(node, key, NULL);
+	if (pilstr)
+		SMD_DBG("%s: %s = %s", __func__, key, pilstr);
+
+	key = "qcom,irq-no-suspend";
+	ret = of_property_read_bool(node, key);
+	if (ret)
+		irq_flags |= IRQF_NO_SUSPEND;
+
+	private_intr_config = smd_get_intr_config(edge);
+	if (!private_intr_config) {
+		pr_err("%s: invalid edge\n", __func__);
+		return -ENODEV;
+	}
+	private_irq = &private_intr_config->smd;
+	private_irq->out_bit_pos = irq_bitmask;
+	private_irq->out_offset = irq_offset;
+	private_irq->out_base = irq_out_base;
+	private_irq->irq_id = irq_line;
+	remote_pid = smd_edge_to_remote_pid(edge);
+	interrupt_stats[remote_pid].smd_interrupt_id = irq_line;
+
+	ret = request_irq(irq_line,
+				private_irq->irq_handler,
+				irq_flags,
+				"smd_dev",
+				NULL);
+	if (ret < 0) {
+		pr_err("%s: request_irq() failed on %d\n", __func__, irq_line);
+		return ret;
+	} else {
+		ret = enable_irq_wake(irq_line);
+		if (ret < 0)
+			pr_err("%s: enable_irq_wake() failed on %d\n", __func__,
+					irq_line);
+	}
+
+	if (pilstr)
+		smd_set_edge_subsys_name(edge, pilstr);
+
+	smd_set_edge_initialized(edge);
+	smd_post_init(0);
+	return 0;
+
+missing_key:
+	pr_err("%s: missing key: %s", __func__, key);
+	return -ENODEV;
+}
+
+static struct of_device_id msm_smd_match_table[] = {
+	{ .compatible = "qcom,smd" },
+	{},
+};
+
+static struct platform_driver msm_smd_driver = {
+	.probe = msm_smd_probe,
+	.driver = {
+		.name = MODULE_NAME ,
+		.owner = THIS_MODULE,
+		.of_match_table = msm_smd_match_table,
+	},
+};
+
+static struct of_device_id msm_smsm_match_table[] = {
+	{ .compatible = "qcom,smsm" },
+	{},
+};
+
+static struct platform_driver msm_smsm_driver = {
+	.probe = msm_smsm_probe,
+	.driver = {
+		.name = "msm_smsm",
+		.owner = THIS_MODULE,
+		.of_match_table = msm_smsm_match_table,
+	},
+};
+
+int msm_smd_driver_register(void)
+{
+	int rc;
+
+	rc = platform_driver_register(&msm_smd_driver);
+	if (rc) {
+		pr_err("%s: smd_driver register failed %d\n",
+			__func__, rc);
+		return rc;
+	}
+
+	rc = platform_driver_register(&msm_smsm_driver);
+	if (rc) {
+		pr_err("%s: msm_smsm_driver register failed %d\n",
+			__func__, rc);
+		return rc;
+	}
+
+	return 0;
+}
+EXPORT_SYMBOL(msm_smd_driver_register);
+
+MODULE_DESCRIPTION("MSM SMD Device Tree Init");
+MODULE_LICENSE("GPL v2");
+#endif
diff --git a/arch/arm/mach-msm/smd_init_plat.c b/arch/arm/mach-msm/smd_init_plat.c
new file mode 100644
index 0000000..c6f6cd9
--- /dev/null
+++ b/arch/arm/mach-msm/smd_init_plat.c
@@ -0,0 +1,535 @@
+/* arch/arm/mach-msm/smd_init_plat.c
+ *
+ * Copyright (c) 2013, 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 CONFIG_OF
+#include <linux/platform_device.h>
+#include <linux/module.h>
+#include <linux/interrupt.h>
+#include <linux/io.h>
+#include <linux/slab.h>
+
+#include <mach/msm_iomap.h>
+#include <mach/msm_ipc_logging.h>
+#include <smd_private.h>
+
+#define MODULE_NAME "msm_smd"
+#define IPC_LOG(level, x...) do { \
+	if (smd_log_ctx) \
+		ipc_log_string(smd_log_ctx, x); \
+	else \
+		printk(level x); \
+	} while (0)
+
+#if defined(CONFIG_MSM_SMD_DEBUG)
+#define SMD_DBG(x...) do {				\
+		if (msm_smd_debug_mask & MSM_SMD_DEBUG) \
+			IPC_LOG(KERN_DEBUG, x);		\
+	} while (0)
+
+#define SMD_INFO(x...) do {				\
+		if (msm_smd_debug_mask & MSM_SMD_INFO)	\
+			IPC_LOG(KERN_INFO, x);		\
+	} while (0)
+#else
+#define SMD_DBG(x...) do { } while (0)
+#define SMD_INFO(x...) do { } while (0)
+#endif
+
+#if defined(CONFIG_ARCH_QSD8X50) || defined(CONFIG_ARCH_MSM8X60) \
+	|| defined(CONFIG_ARCH_MSM8960) || defined(CONFIG_ARCH_FSM9XXX) \
+	|| defined(CONFIG_ARCH_MSM9615)	|| defined(CONFIG_ARCH_APQ8064)
+#define CONFIG_QDSP6 1
+#endif
+
+#if defined(CONFIG_ARCH_MSM8X60) || defined(CONFIG_ARCH_MSM8960) \
+	|| defined(CONFIG_ARCH_APQ8064)
+#define CONFIG_DSPS 1
+#endif
+
+#if defined(CONFIG_ARCH_MSM8960) \
+	|| defined(CONFIG_ARCH_APQ8064)
+#define CONFIG_WCNSS 1
+#define CONFIG_DSPS_SMSM 1
+#endif
+
+#if defined(CONFIG_ARCH_MSM7X30)
+#define MSM_CFG_A2M_SMD_INT     \
+		(smd_cfg_smd_intr(SMD_MODEM, 1 << 0, MSM_APCS_GCC_BASE + 0x8))
+#define MSM_CFG_A2Q6_SMD_INT    \
+		(smd_cfg_smd_intr(SMD_Q6, 1 << 8, MSM_APCS_GCC_BASE + 0x8))
+#define MSM_CFG_A2M_SMSM_INT    \
+		(smd_cfg_smsm_intr(SMD_MODEM, 1 << 5, MSM_APCS_GCC_BASE + 0x8))
+#define MSM_CFG_A2Q6_SMSM_INT   \
+		(smd_cfg_smsm_intr(SMD_Q6, 1 << 8, MSM_APCS_GCC_BASE + 0x8))
+#define MSM_CFG_A2DSPS_SMD_INT
+#define MSM_CFG_A2DSPS_SMSM_INT
+#define MSM_CFG_A2WCNSS_SMD_INT
+#define MSM_CFG_A2WCNSS_SMSM_INT
+#elif defined(CONFIG_ARCH_MSM8X60)
+#define MSM_CFG_A2M_SMD_INT     \
+		(smd_cfg_smd_intr(SMD_MODEM, 1 << 3, MSM_GCC_BASE + 0x8))
+#define MSM_CFG_A2Q6_SMD_INT    \
+		(smd_cfg_smd_intr(SMD_Q6, 1 << 15, MSM_GCC_BASE + 0x8))
+#define MSM_CFG_A2M_SMSM_INT    \
+		(smd_cfg_smsm_intr(SMD_MODEM, 1 << 4, MSM_GCC_BASE + 0x8))
+#define MSM_CFG_A2Q6_SMSM_INT   \
+		(smd_cfg_smsm_intr(SMD_Q6, 1 << 14, MSM_GCC_BASE + 0x8))
+#define MSM_CFG_A2DSPS_SMD_INT  \
+		(smd_cfg_smd_intr(SMD_DSPS, 1,		\
+					MSM_SIC_NON_SECURE_BASE + 0x4080))
+#define MSM_CFG_A2DSPS_SMSM_INT
+#define MSM_CFG_A2WCNSS_SMD_INT
+#define MSM_CFG_A2WCNSS_SMSM_INT
+#elif defined(CONFIG_ARCH_MSM9615)
+#define MSM_CFG_A2M_SMD_INT     \
+		(smd_cfg_smd_intr(SMD_MODEM, 1 << 3, MSM_APCS_GCC_BASE + 0x8))
+#define MSM_CFG_A2Q6_SMD_INT    \
+		(smd_cfg_smd_intr(SMD_Q6, 1 << 15, MSM_APCS_GCC_BASE + 0x8))
+#define MSM_CFG_A2M_SMSM_INT    \
+		(smd_cfg_smsm_intr(SMD_MODEM, 1 << 4, MSM_APCS_GCC_BASE + 0x8))
+#define MSM_CFG_A2Q6_SMSM_INT   \
+		(smd_cfg_smsm_intr(SMD_Q6, 1 << 14, MSM_APCS_GCC_BASE + 0x8))
+#define MSM_CFG_A2DSPS_SMD_INT
+#define MSM_CFG_A2DSPS_SMSM_INT
+#define MSM_CFG_A2WCNSS_SMD_INT
+#define MSM_CFG_A2WCNSS_SMSM_INT
+#elif defined(CONFIG_ARCH_FSM9XXX)
+#define MSM_CFG_A2Q6_SMD_INT	\
+		(smd_cfg_smd_intr(SMD_Q6, 1 << 10, MSM_GCC_BASE + 0x8))
+#define MSM_CFG_A2Q6_SMSM_INT	\
+		(smd_cfg_smsm_intr(SMD_Q6, 1 << 10, MSM_GCC_BASE + 0x8))
+#define MSM_CFG_A2M_SMD_INT	\
+		(smd_cfg_smd_intr(SMD_MODEM, 1 << 0, MSM_GCC_BASE + 0x8))
+#define MSM_CFG_A2M_SMSM_INT	\
+		(smd_cfg_smsm_intr(SMD_MODEM, 1 << 5, MSM_GCC_BASE + 0x8))
+#define MSM_CFG_A2DSPS_SMD_INT
+#define MSM_CFG_A2DSPS_SMSM_INT
+#define MSM_CFG_A2WCNSS_SMD_INT
+#define MSM_CFG_A2WCNSS_SMSM_INT
+#elif defined(CONFIG_ARCH_MSM7X01A) || defined(CONFIG_ARCH_MSM7x25)
+#define MSM_CFG_A2M_SMD_INT     \
+		(smd_cfg_smd_intr(SMD_MODEM, 1, MSM_CSR_BASE + 0x400 + (0) * 4))
+#define MSM_CFG_A2Q6_SMD_INT
+#define MSM_CFG_A2M_SMSM_INT    \
+		(smd_cfg_smsm_intr(SMD_MODEM, 1,	\
+					MSM_CSR_BASE + 0x400 + (5) * 4))
+#define MSM_CFG_A2Q6_SMSM_INT
+#define MSM_CFG_A2DSPS_SMD_INT
+#define MSM_CFG_A2DSPS_SMSM_INT
+#define MSM_CFG_A2WCNSS_SMD_INT
+#define MSM_CFG_A2WCNSS_SMSM_INT
+#elif defined(CONFIG_ARCH_MSM7X27) || defined(CONFIG_ARCH_MSM7X27A)
+#define MSM_CFG_A2M_SMD_INT     \
+		(smd_cfg_smd_intr(SMD_MODEM, 1, MSM_CSR_BASE + 0x400 + (0) * 4))
+#define MSM_CFG_A2Q6_SMD_INT
+#define MSM_CFG_A2M_SMSM_INT    \
+		(smd_cfg_smsm_intr(SMD_MODEM, 1,	\
+					MSM_CSR_BASE + 0x400 + (5) * 4))
+#define MSM_CFG_A2Q6_SMSM_INT
+#define MSM_CFG_A2DSPS_SMD_INT
+#define MSM_CFG_A2DSPS_SMSM_INT
+#define MSM_CFG_A2WCNSS_SMD_INT
+#define MSM_CFG_A2WCNSS_SMSM_INT
+#else /* use platform device / device tree configuration */
+#define MSM_CFG_A2M_SMD_INT
+#define MSM_CFG_A2Q6_SMD_INT
+#define MSM_CFG_A2M_SMSM_INT
+#define MSM_CFG_A2Q6_SMSM_INT
+#define MSM_CFG_A2DSPS_SMD_INT
+#define MSM_CFG_A2DSPS_SMSM_INT
+#define MSM_CFG_A2WCNSS_SMD_INT
+#define MSM_CFG_A2WCNSS_SMSM_INT
+#endif
+
+/*
+ * stub out legacy macros if they are not being used so that the legacy
+ * code compiles even though it is not used
+ *
+ * these definitions should not be used in active code and will cause
+ * an early failure
+ */
+#ifndef INT_A9_M2A_0
+#define INT_A9_M2A_0 -1
+#endif
+#ifndef INT_A9_M2A_5
+#define INT_A9_M2A_5 -1
+#endif
+#ifndef INT_ADSP_A11
+#define INT_ADSP_A11 -1
+#endif
+#ifndef INT_ADSP_A11_SMSM
+#define INT_ADSP_A11_SMSM -1
+#endif
+#ifndef INT_DSPS_A11
+#define INT_DSPS_A11 -1
+#endif
+#ifndef INT_DSPS_A11_SMSM
+#define INT_DSPS_A11_SMSM -1
+#endif
+#ifndef INT_WCNSS_A11
+#define INT_WCNSS_A11 -1
+#endif
+#ifndef INT_WCNSS_A11_SMSM
+#define INT_WCNSS_A11_SMSM -1
+#endif
+
+static int intr_init(struct interrupt_config_item *private_irq,
+			struct smd_irq_config *platform_irq,
+			struct platform_device *pdev
+			)
+{
+	int irq_id;
+	int ret;
+	int ret_wake;
+
+	private_irq->out_bit_pos = platform_irq->out_bit_pos;
+	private_irq->out_offset = platform_irq->out_offset;
+	private_irq->out_base = platform_irq->out_base;
+
+	irq_id = platform_get_irq_byname(
+					pdev,
+					platform_irq->irq_name
+				);
+	SMD_DBG("smd: %s: register irq: %s id: %d\n", __func__,
+				platform_irq->irq_name, irq_id);
+	ret = request_irq(irq_id,
+				private_irq->irq_handler,
+				platform_irq->flags,
+				platform_irq->device_name,
+				(void *)platform_irq->dev_id
+			);
+	if (ret < 0) {
+		platform_irq->irq_id = ret;
+		private_irq->irq_id = ret;
+	} else {
+		platform_irq->irq_id = irq_id;
+		private_irq->irq_id = irq_id;
+		ret_wake = enable_irq_wake(irq_id);
+		if (ret_wake < 0) {
+			pr_err("smd: enable_irq_wake failed on %s",
+					platform_irq->irq_name);
+		}
+	}
+
+	return ret;
+}
+
+int smd_core_init(void)
+{
+	int r;
+	unsigned long flags = IRQF_TRIGGER_RISING;
+	SMD_INFO("smd_core_init()\n");
+
+	MSM_CFG_A2M_SMD_INT;
+	MSM_CFG_A2Q6_SMD_INT;
+	MSM_CFG_A2M_SMSM_INT;
+	MSM_CFG_A2Q6_SMSM_INT;
+	MSM_CFG_A2DSPS_SMD_INT;
+	MSM_CFG_A2DSPS_SMSM_INT;
+	MSM_CFG_A2WCNSS_SMD_INT;
+	MSM_CFG_A2WCNSS_SMSM_INT;
+
+	r = request_irq(INT_A9_M2A_0, smd_modem_irq_handler,
+			flags, "smd_dev", 0);
+	if (r < 0)
+		return r;
+	interrupt_stats[SMD_MODEM].smd_interrupt_id = INT_A9_M2A_0;
+	r = enable_irq_wake(INT_A9_M2A_0);
+	if (r < 0)
+		pr_err("%s: enable_irq_wake failed for INT_A9_M2A_0\n",
+			__func__);
+
+	r = request_irq(INT_A9_M2A_5, smsm_modem_irq_handler,
+			flags, "smsm_dev", 0);
+	if (r < 0) {
+		free_irq(INT_A9_M2A_0, 0);
+		return r;
+	}
+	interrupt_stats[SMD_MODEM].smsm_interrupt_id = INT_A9_M2A_5;
+	r = enable_irq_wake(INT_A9_M2A_5);
+	if (r < 0)
+		pr_err("%s: enable_irq_wake failed for INT_A9_M2A_5\n",
+			__func__);
+
+#if defined(CONFIG_QDSP6)
+#if (INT_ADSP_A11 == INT_ADSP_A11_SMSM)
+		flags |= IRQF_SHARED;
+#endif
+	r = request_irq(INT_ADSP_A11, smd_dsp_irq_handler,
+			flags, "smd_dev", smd_dsp_irq_handler);
+	if (r < 0) {
+		free_irq(INT_A9_M2A_0, 0);
+		free_irq(INT_A9_M2A_5, 0);
+		return r;
+	}
+
+	interrupt_stats[SMD_Q6].smd_interrupt_id = INT_ADSP_A11;
+	r = request_irq(INT_ADSP_A11_SMSM, smsm_dsp_irq_handler,
+			flags, "smsm_dev", smsm_dsp_irq_handler);
+	if (r < 0) {
+		free_irq(INT_A9_M2A_0, 0);
+		free_irq(INT_A9_M2A_5, 0);
+		free_irq(INT_ADSP_A11, smd_dsp_irq_handler);
+		return r;
+	}
+
+	interrupt_stats[SMD_Q6].smsm_interrupt_id = INT_ADSP_A11_SMSM;
+	r = enable_irq_wake(INT_ADSP_A11);
+	if (r < 0)
+		pr_err("%s: enable_irq_wake failed for INT_ADSP_A11\n",
+			__func__);
+
+#if (INT_ADSP_A11 != INT_ADSP_A11_SMSM)
+	r = enable_irq_wake(INT_ADSP_A11_SMSM);
+	if (r < 0)
+		pr_err("%s: enable_irq_wake failed for INT_ADSP_A11_SMSM\n",
+			__func__);
+#endif
+	flags &= ~IRQF_SHARED;
+#endif
+
+#if defined(CONFIG_DSPS)
+	r = request_irq(INT_DSPS_A11, smd_dsps_irq_handler,
+			flags, "smd_dev", smd_dsps_irq_handler);
+	if (r < 0) {
+		free_irq(INT_A9_M2A_0, 0);
+		free_irq(INT_A9_M2A_5, 0);
+		free_irq(INT_ADSP_A11, smd_dsp_irq_handler);
+		free_irq(INT_ADSP_A11_SMSM, smsm_dsp_irq_handler);
+		return r;
+	}
+
+	interrupt_stats[SMD_DSPS].smd_interrupt_id = INT_DSPS_A11;
+	r = enable_irq_wake(INT_DSPS_A11);
+	if (r < 0)
+		pr_err("%s: enable_irq_wake failed for INT_ADSP_A11\n",
+			__func__);
+#endif
+
+#if defined(CONFIG_WCNSS)
+	r = request_irq(INT_WCNSS_A11, smd_wcnss_irq_handler,
+			flags, "smd_dev", smd_wcnss_irq_handler);
+	if (r < 0) {
+		free_irq(INT_A9_M2A_0, 0);
+		free_irq(INT_A9_M2A_5, 0);
+		free_irq(INT_ADSP_A11, smd_dsp_irq_handler);
+		free_irq(INT_ADSP_A11_SMSM, smsm_dsp_irq_handler);
+		free_irq(INT_DSPS_A11, smd_dsps_irq_handler);
+		return r;
+	}
+
+	interrupt_stats[SMD_WCNSS].smd_interrupt_id = INT_WCNSS_A11;
+	r = enable_irq_wake(INT_WCNSS_A11);
+	if (r < 0)
+		pr_err("%s: enable_irq_wake failed for INT_WCNSS_A11\n",
+			__func__);
+
+	r = request_irq(INT_WCNSS_A11_SMSM, smsm_wcnss_irq_handler,
+			flags, "smsm_dev", smsm_wcnss_irq_handler);
+	if (r < 0) {
+		free_irq(INT_A9_M2A_0, 0);
+		free_irq(INT_A9_M2A_5, 0);
+		free_irq(INT_ADSP_A11, smd_dsp_irq_handler);
+		free_irq(INT_ADSP_A11_SMSM, smsm_dsp_irq_handler);
+		free_irq(INT_DSPS_A11, smd_dsps_irq_handler);
+		free_irq(INT_WCNSS_A11, smd_wcnss_irq_handler);
+		return r;
+	}
+
+	interrupt_stats[SMD_WCNSS].smsm_interrupt_id = INT_WCNSS_A11_SMSM;
+	r = enable_irq_wake(INT_WCNSS_A11_SMSM);
+	if (r < 0)
+		pr_err("%s: enable_irq_wake failed for INT_WCNSS_A11_SMSM\n",
+			__func__);
+#endif
+
+#if defined(CONFIG_DSPS_SMSM)
+	r = request_irq(INT_DSPS_A11_SMSM, smsm_dsps_irq_handler,
+			flags, "smsm_dev", smsm_dsps_irq_handler);
+	if (r < 0) {
+		free_irq(INT_A9_M2A_0, 0);
+		free_irq(INT_A9_M2A_5, 0);
+		free_irq(INT_ADSP_A11, smd_dsp_irq_handler);
+		free_irq(INT_ADSP_A11_SMSM, smsm_dsp_irq_handler);
+		free_irq(INT_DSPS_A11, smd_dsps_irq_handler);
+		free_irq(INT_WCNSS_A11, smd_wcnss_irq_handler);
+		free_irq(INT_WCNSS_A11_SMSM, smsm_wcnss_irq_handler);
+		return r;
+	}
+
+	interrupt_stats[SMD_DSPS].smsm_interrupt_id = INT_DSPS_A11_SMSM;
+	r = enable_irq_wake(INT_DSPS_A11_SMSM);
+	if (r < 0)
+		pr_err("%s: enable_irq_wake failed for INT_DSPS_A11_SMSM\n",
+			__func__);
+#endif
+	SMD_INFO("smd_core_init() done\n");
+
+	return 0;
+}
+
+int smd_core_platform_init(struct platform_device *pdev)
+{
+	int i;
+	int ret;
+	uint32_t num_ss;
+	struct smd_platform *smd_platform_data;
+	struct smd_subsystem_config *smd_ss_config_list;
+	struct smd_subsystem_config *cfg;
+	struct interrupt_config *private_intr_config;
+	int err_ret = 0;
+
+	smd_platform_data = pdev->dev.platform_data;
+	num_ss = smd_platform_data->num_ss_configs;
+	smd_ss_config_list = smd_platform_data->smd_ss_configs;
+
+	if (smd_platform_data->smd_ssr_config)
+		disable_smsm_reset_handshake = smd_platform_data->
+			   smd_ssr_config->disable_smsm_reset_handshake;
+
+	for (i = 0; i < num_ss; i++) {
+		cfg = &smd_ss_config_list[i];
+		private_intr_config = smd_get_intr_config(cfg->edge);
+		if (!private_intr_config) {
+			pr_err("%s: invalid edge\n", __func__);
+			goto intr_failed;
+		}
+
+		ret = intr_init(
+			&private_intr_config->smd,
+			&cfg->smd_int,
+			pdev
+			);
+
+		if (ret < 0) {
+			err_ret = ret;
+			pr_err("smd: register irq failed on %s\n",
+				cfg->smd_int.irq_name);
+			goto intr_failed;
+		}
+
+		interrupt_stats[cfg->irq_config_id].smd_interrupt_id
+						 = cfg->smd_int.irq_id;
+		/* only init smsm structs if this edge supports smsm */
+		if (cfg->smsm_int.irq_id)
+			ret = intr_init(
+				&private_intr_config->smsm,
+				&cfg->smsm_int,
+				pdev
+				);
+
+		if (ret < 0) {
+			err_ret = ret;
+			pr_err("smd: register irq failed on %s\n",
+				cfg->smsm_int.irq_name);
+			goto intr_failed;
+		}
+
+		if (cfg->smsm_int.irq_id)
+			interrupt_stats[cfg->irq_config_id].smsm_interrupt_id
+						 = cfg->smsm_int.irq_id;
+		if (cfg->subsys_name)
+			smd_set_edge_subsys_name(cfg->edge, cfg->subsys_name);
+
+		smd_set_edge_initialized(cfg->edge);
+	}
+
+	SMD_INFO("smd_core_platform_init() done\n");
+
+	return 0;
+
+intr_failed:
+	pr_err("smd: deregistering IRQs\n");
+	for (i = 0; i < num_ss; ++i) {
+		cfg = &smd_ss_config_list[i];
+
+		if (cfg->smd_int.irq_id >= 0)
+			free_irq(cfg->smd_int.irq_id,
+				(void *)cfg->smd_int.dev_id
+				);
+		if (cfg->smsm_int.irq_id >= 0)
+			free_irq(cfg->smsm_int.irq_id,
+				(void *)cfg->smsm_int.dev_id
+				);
+	}
+	return err_ret;
+}
+
+static int msm_smd_probe_legacy(struct platform_device *pdev)
+{
+	int ret;
+
+	if (!smem_initialized_check())
+		return -ENODEV;
+
+	SMD_INFO("smd probe\n");
+	if (pdev) {
+		if (pdev->dev.of_node) {
+			pr_err("%s: invalid device tree init\n", __func__);
+			return -ENODEV;
+		} else if (pdev->dev.platform_data) {
+			ret = smd_core_platform_init(pdev);
+			if (ret) {
+				pr_err(
+				"SMD: smd_core_platform_init() failed\n");
+				return -ENODEV;
+			}
+		} else {
+			ret = smd_core_init();
+			if (ret) {
+				pr_err("smd_core_init() failed\n");
+				return -ENODEV;
+			}
+		}
+	} else {
+		pr_err("SMD: PDEV not found\n");
+		return -ENODEV;
+	}
+
+	ret = smsm_post_init();
+	if (ret) {
+		pr_err("smd_post_init() failed ret = %d\n", ret);
+		return ret;
+	}
+	smd_post_init(1);
+
+	return 0;
+}
+
+static struct platform_driver msm_smd_driver_legacy = {
+	.probe = msm_smd_probe_legacy,
+	.driver = {
+		.name = MODULE_NAME,
+		.owner = THIS_MODULE,
+	},
+};
+
+int msm_smd_driver_register(void)
+{
+
+	int rc;
+
+	rc = platform_driver_register(&msm_smd_driver_legacy);
+	if (rc) {
+		pr_err("%s: smd_driver register failed %d\n",
+			__func__, rc);
+		return rc;
+	}
+	return 0;
+}
+EXPORT_SYMBOL(msm_smd_driver_register);
+
+MODULE_DESCRIPTION("MSM SMD Legacy/Platform Device Init");
+MODULE_LICENSE("GPL v2");
+#endif
diff --git a/arch/arm/mach-msm/smd_private.h b/arch/arm/mach-msm/smd_private.h
index 2096063..4664197 100644
--- a/arch/arm/mach-msm/smd_private.h
+++ b/arch/arm/mach-msm/smd_private.h
@@ -21,6 +21,7 @@
 #include <linux/errno.h>
 #include <linux/remote_spinlock.h>
 #include <linux/platform_device.h>
+#include <linux/interrupt.h>
 #include <mach/msm_smsm.h>
 #include <mach/msm_smd.h>
 
@@ -213,4 +214,60 @@
 	uint32_t smsm_interrupt_id;
 };
 extern struct interrupt_stat interrupt_stats[NUM_SMD_SUBSYSTEMS];
+
+struct interrupt_config_item {
+	/* must be initialized */
+	irqreturn_t (*irq_handler)(int req, void *data);
+	/* outgoing interrupt config (set from platform data) */
+	uint32_t out_bit_pos;
+	void __iomem *out_base;
+	uint32_t out_offset;
+	int irq_id;
+};
+
+enum {
+	MSM_SMD_DEBUG = 1U << 0,
+	MSM_SMSM_DEBUG = 1U << 1,
+	MSM_SMD_INFO = 1U << 2,
+	MSM_SMSM_INFO = 1U << 3,
+	MSM_SMx_POWER_INFO = 1U << 4,
+};
+
+struct interrupt_config {
+	struct interrupt_config_item smd;
+	struct interrupt_config_item smsm;
+};
+
+struct edge_to_pid {
+	uint32_t	local_pid;
+	uint32_t	remote_pid;
+	char		subsys_name[SMD_MAX_CH_NAME_LEN];
+	bool		initialized;
+};
+
+extern void *smd_log_ctx;
+extern int msm_smd_debug_mask;
+extern int disable_smsm_reset_handshake;
+extern bool smem_initialized_check(void);
+
+extern irqreturn_t smd_modem_irq_handler(int irq, void *data);
+extern irqreturn_t smsm_modem_irq_handler(int irq, void *data);
+extern irqreturn_t smd_dsp_irq_handler(int irq, void *data);
+extern irqreturn_t smsm_dsp_irq_handler(int irq, void *data);
+extern irqreturn_t smd_dsps_irq_handler(int irq, void *data);
+extern irqreturn_t smsm_dsps_irq_handler(int irq, void *data);
+extern irqreturn_t smd_wcnss_irq_handler(int irq, void *data);
+extern irqreturn_t smsm_wcnss_irq_handler(int irq, void *data);
+extern irqreturn_t smd_rpm_irq_handler(int irq, void *data);
+
+extern int msm_smd_driver_register(void);
+extern void smd_post_init(bool is_legacy);
+extern int smsm_post_init(void);
+
+extern struct interrupt_config *smd_get_intr_config(uint32_t edge);
+extern int smd_edge_to_remote_pid(uint32_t edge);
+extern void smd_set_edge_subsys_name(uint32_t edge, const char *subsys_name);
+extern void smd_set_edge_initialized(uint32_t edge);
+extern void smd_cfg_smd_intr(uint32_t proc, uint32_t mask, void *ptr);
+extern void smd_cfg_smsm_intr(uint32_t proc, uint32_t mask, void *ptr);
 #endif
diff --git a/arch/arm/mach-msm/smd_tty.c b/arch/arm/mach-msm/smd_tty.c
index 3461e49..428d5b0 100644
--- a/arch/arm/mach-msm/smd_tty.c
+++ b/arch/arm/mach-msm/smd_tty.c
@@ -21,7 +21,7 @@
 #include <linux/device.h>
 #include <linux/interrupt.h>
 #include <linux/delay.h>
-#include <linux/wakelock.h>
+#include <linux/pm.h>
 #include <linux/platform_device.h>
 #include <linux/sched.h>
 
@@ -36,9 +36,12 @@
 
 #include "smd_private.h"
 
+#define MODULE_NAME "msm_smdtty"
 #define MAX_SMD_TTYS 37
 #define MAX_TTY_BUF_SIZE 2048
+#define TTY_PUSH_WS_DELAY 500
 #define MAX_RA_WAKE_LOCK_NAME_LEN 32
+#define SMD_TTY_PROBE_WAIT_TIMEOUT 3000
 #define SMD_TTY_LOG_PAGES 2
 
 #define SMD_TTY_INFO(buf...) \
@@ -56,28 +59,65 @@
 } while (0)
 
 static void *smd_tty_log_ctx;
-static DEFINE_MUTEX(smd_tty_lock);
 
+static struct delayed_work smd_tty_probe_work;
+static int smd_tty_probe_done;
+
+/**
+ * struct smd_tty_info - context for an individual SMD TTY device
+ *
+ * @ch:  SMD channel handle
+ * @port:  TTY port context structure
+ * @device_ptr:  TTY device pointer
+ * @pending_ws:  pending-data wakeup source
+ * @tty_tsklt:  read tasklet
+ * @buf_req_timer:  RX buffer retry timer
+ * @ch_allocated:  completion set when SMD channel is allocated
+ * @driver:  SMD channel platform driver context structure
+ * @pil:  Peripheral Image Loader handle
+ * @edge:  SMD edge associated with port
+ * @ch_name:  SMD channel name associated with port
+ * @dev_name:  SMD platform device name associated with port
+ *
+ * @open_lock_lha1: open/close lock - used to serialize open/close operations
+ * @open_wait:  Timeout in seconds to wait for SMD port to be created / opened
+ *
+ * @reset_lock_lha2: lock for reset and open state
+ * @in_reset:  True if SMD channel is closed / in SSR
+ * @in_reset_updated:  reset state changed
+ * @is_open:  True if SMD port is open
+ * @ch_opened_wait_queue:  SMD port open/close wait queue
+ *
+ * @ra_lock_lha3:  Read-available lock - used to synchronize reads from SMD
+ * @ra_wakeup_source_name: Name of the read-available wakeup source
+ * @ra_wakeup_source:  Read-available wakeup source
+ */
 struct smd_tty_info {
 	smd_channel_t *ch;
 	struct tty_port port;
 	struct device *device_ptr;
-	struct wake_lock wake_lock;
+	struct wakeup_source pending_ws;
 	struct tasklet_struct tty_tsklt;
 	struct timer_list buf_req_timer;
 	struct completion ch_allocated;
 	struct platform_driver driver;
 	void *pil;
+	uint32_t edge;
+	char ch_name[SMD_MAX_CH_NAME_LEN];
+	char dev_name[SMD_MAX_CH_NAME_LEN];
+
+	struct mutex open_lock_lha1;
+	unsigned int open_wait;
+
+	spinlock_t reset_lock_lha2;
 	int in_reset;
 	int in_reset_updated;
 	int is_open;
-	unsigned int open_wait;
 	wait_queue_head_t ch_opened_wait_queue;
-	spinlock_t reset_lock;
-	spinlock_t ra_lock;		/* Read Available Lock*/
-	char ra_wake_lock_name[MAX_RA_WAKE_LOCK_NAME_LEN];
-	struct wake_lock ra_wake_lock;	/* Read Available Wakelock */
-	struct smd_config *smd;
+
+	spinlock_t ra_lock_lha3;
+	char ra_wakeup_source_name[MAX_RA_WAKE_LOCK_NAME_LEN];
+	struct wakeup_source ra_wakeup_source;
 };
 
 /**
@@ -95,6 +135,12 @@
 	uint32_t edge;
 };
 
+/**
+ * struct smd_config smd_configs[]: Legacy configuration
+ *
+ * An array of all SMD tty channel supported in legacy targets.
+ * Future targets use either platform device or device tree configuration.
+ */
 static struct smd_config smd_configs[] = {
 	{0, "DS", NULL, SMD_APPS_MODEM},
 	{1, "APPS_FM", NULL, SMD_APPS_WCNSS},
@@ -104,6 +150,7 @@
 	{5, "APPS_RIVA_ANT_CMD", NULL, SMD_APPS_WCNSS},
 	{6, "APPS_RIVA_ANT_DATA", NULL, SMD_APPS_WCNSS},
 	{7, "DATA1", NULL, SMD_APPS_MODEM},
+	{8, "DATA4", NULL, SMD_APPS_MODEM},
 	{11, "DATA11", NULL, SMD_APPS_MODEM},
 	{21, "DATA21", NULL, SMD_APPS_MODEM},
 	{27, "GPSNMEA", NULL, SMD_APPS_MODEM},
@@ -125,13 +172,13 @@
 	struct smd_tty_info *info = (struct smd_tty_info *)param;
 	unsigned long flags;
 
-	spin_lock_irqsave(&info->reset_lock, flags);
+	spin_lock_irqsave(&info->reset_lock_lha2, flags);
 	if (info->is_open) {
-		spin_unlock_irqrestore(&info->reset_lock, flags);
+		spin_unlock_irqrestore(&info->reset_lock_lha2, flags);
 		tasklet_hi_schedule(&info->tty_tsklt);
 		return;
 	}
-	spin_unlock_irqrestore(&info->reset_lock, flags);
+	spin_unlock_irqrestore(&info->reset_lock_lha2, flags);
 }
 
 static ssize_t open_timeout_store(struct device *dev,
@@ -153,7 +200,9 @@
 		return -EINVAL;
 	}
 	if (!kstrtoul(buf, 10, &wait)) {
+		mutex_lock(&smd_tty[num_dev].open_lock_lha1);
 		smd_tty[num_dev].open_wait = wait;
+		mutex_unlock(&smd_tty[num_dev].open_lock_lha1);
 		return n;
 	} else {
 		SMD_TTY_INFO("[%s]: Unable to convert %s to an int",
@@ -166,6 +215,7 @@
 			struct device_attribute *attr, char *buf)
 {
 	unsigned int num_dev;
+	unsigned int open_wait;
 
 	if (dev == NULL) {
 		SMD_TTY_INFO("%s: Invalid Device passed", __func__);
@@ -180,8 +230,11 @@
 		return -EINVAL;
 	}
 
-	return snprintf(buf, PAGE_SIZE, "%d\n",
-			smd_tty[num_dev].open_wait);
+	mutex_lock(&smd_tty[num_dev].open_lock_lha1);
+	open_wait = smd_tty[num_dev].open_wait;
+	mutex_unlock(&smd_tty[num_dev].open_lock_lha1);
+
+	return snprintf(buf, PAGE_SIZE, "%d\n", open_wait);
 }
 
 static DEVICE_ATTR
@@ -207,14 +260,14 @@
 		}
 
 		if (test_bit(TTY_THROTTLED, &tty->flags)) break;
-		spin_lock_irqsave(&info->ra_lock, flags);
+		spin_lock_irqsave(&info->ra_lock_lha3, flags);
 		avail = smd_read_avail(info->ch);
 		if (avail == 0) {
-			wake_unlock(&info->ra_wake_lock);
-			spin_unlock_irqrestore(&info->ra_lock, flags);
+			__pm_relax(&info->ra_wakeup_source);
+			spin_unlock_irqrestore(&info->ra_lock_lha3, flags);
 			break;
 		}
-		spin_unlock_irqrestore(&info->ra_lock, flags);
+		spin_unlock_irqrestore(&info->ra_lock_lha3, flags);
 
 		if (avail > MAX_TTY_BUF_SIZE)
 			avail = MAX_TTY_BUF_SIZE;
@@ -237,7 +290,13 @@
 				__func__, info->ch->name);
 		}
 
-		wake_lock_timeout(&info->wake_lock, HZ / 2);
+		/*
+		 * Keep system awake long enough to allow the TTY
+		 * framework to pass the flip buffer to any waiting
+		 * userspace clients.
+		 */
+		__pm_wakeup_event(&info->pending_ws, TTY_PUSH_WS_DELAY);
+
 		tty_flip_buffer_push(tty);
 	}
 
@@ -254,12 +313,12 @@
 
 	switch (event) {
 	case SMD_EVENT_DATA:
-		spin_lock_irqsave(&info->reset_lock, flags);
+		spin_lock_irqsave(&info->reset_lock_lha2, flags);
 		if (!info->is_open) {
-			spin_unlock_irqrestore(&info->reset_lock, flags);
+			spin_unlock_irqrestore(&info->reset_lock_lha2, flags);
 			break;
 		}
-		spin_unlock_irqrestore(&info->reset_lock, flags);
+		spin_unlock_irqrestore(&info->reset_lock_lha2, flags);
 		/* There may be clients (tty framework) that are blocked
 		 * waiting for space to write data, so if a possible read
 		 * interrupt came in wake anyone waiting and disable the
@@ -272,37 +331,45 @@
 				wake_up_interruptible(&tty->write_wait);
 			tty_kref_put(tty);
 		}
-		spin_lock_irqsave(&info->ra_lock, flags);
+		spin_lock_irqsave(&info->ra_lock_lha3, flags);
 		if (smd_read_avail(info->ch)) {
-			wake_lock(&info->ra_wake_lock);
+			__pm_stay_awake(&info->ra_wakeup_source);
 			tasklet_hi_schedule(&info->tty_tsklt);
 		}
-		spin_unlock_irqrestore(&info->ra_lock, flags);
+		spin_unlock_irqrestore(&info->ra_lock_lha3, flags);
 		break;
 
 	case SMD_EVENT_OPEN:
-		spin_lock_irqsave(&info->reset_lock, flags);
+		tty = tty_port_tty_get(&info->port);
+		spin_lock_irqsave(&info->reset_lock_lha2, flags);
+		if (tty)
+			clear_bit(TTY_OTHER_CLOSED, &tty->flags);
 		info->in_reset = 0;
 		info->in_reset_updated = 1;
 		info->is_open = 1;
 		wake_up_interruptible(&info->ch_opened_wait_queue);
-		spin_unlock_irqrestore(&info->reset_lock, flags);
+		spin_unlock_irqrestore(&info->reset_lock_lha2, flags);
+		tty_kref_put(tty);
 		break;
 
 	case SMD_EVENT_CLOSE:
-		spin_lock_irqsave(&info->reset_lock, flags);
+		spin_lock_irqsave(&info->reset_lock_lha2, flags);
 		info->in_reset = 1;
 		info->in_reset_updated = 1;
 		info->is_open = 0;
 		wake_up_interruptible(&info->ch_opened_wait_queue);
-		spin_unlock_irqrestore(&info->reset_lock, flags);
-		/* schedule task to send TTY_BREAK */
-		tasklet_hi_schedule(&info->tty_tsklt);
+		spin_unlock_irqrestore(&info->reset_lock_lha2, flags);
 
 		tty = tty_port_tty_get(&info->port);
-		if (tty->index == LOOPBACK_IDX)
-			schedule_delayed_work(&loopback_work,
-					msecs_to_jiffies(1000));
+		if (tty) {
+			/* send TTY_BREAK through read tasklet */
+			set_bit(TTY_OTHER_CLOSED, &tty->flags);
+			tasklet_hi_schedule(&info->tty_tsklt);
+
+			if (tty->index == LOOPBACK_IDX)
+				schedule_delayed_work(&loopback_work,
+						msecs_to_jiffies(1000));
+		}
 		tty_kref_put(tty);
 		break;
 	}
@@ -326,21 +393,21 @@
 	const char *peripheral = NULL;
 
 
-	if (n >= MAX_SMD_TTYS || !smd_tty[n].smd)
+	if (n >= MAX_SMD_TTYS || !smd_tty[n].ch_name)
 		return -ENODEV;
 
 	info = smd_tty + n;
 
-	mutex_lock(&smd_tty_lock);
+	mutex_lock(&info->open_lock_lha1);
 	tty->driver_data = info;
 
-	peripheral = smd_edge_to_subsystem(smd_tty[n].smd->edge);
+	peripheral = smd_edge_to_subsystem(smd_tty[n].edge);
 	if (peripheral) {
 		info->pil = subsystem_get(peripheral);
 		if (IS_ERR(info->pil)) {
 			SMD_TTY_INFO(
 				"%s failed on smd_tty device :%s subsystem_get failed for %s",
-				__func__, smd_tty[n].smd->port_name,
+				__func__, info->ch_name,
 				peripheral);
 
 			/*
@@ -379,32 +446,31 @@
 			if (res == 0) {
 				SMD_TTY_INFO(
 					"Timed out waiting for SMD channel %s",
-					smd_tty[n].smd->port_name);
+					info->ch_name);
 				res = -ETIMEDOUT;
 				goto release_pil;
 			} else if (res < 0) {
 				SMD_TTY_INFO(
 					"Error waiting for SMD channel %s : %d\n",
-					smd_tty[n].smd->port_name, res);
+					info->ch_name, res);
 				goto release_pil;
 			}
 		}
 	}
 
 	tasklet_init(&info->tty_tsklt, smd_tty_read, (unsigned long)info);
-	wake_lock_init(&info->wake_lock, WAKE_LOCK_SUSPEND,
-			smd_tty[n].smd->port_name);
-	scnprintf(info->ra_wake_lock_name, MAX_RA_WAKE_LOCK_NAME_LEN,
-		  "SMD_TTY_%s_RA", smd_tty[n].smd->port_name);
-	wake_lock_init(&info->ra_wake_lock, WAKE_LOCK_SUSPEND,
-			info->ra_wake_lock_name);
+	wakeup_source_init(&info->pending_ws, info->ch_name);
+	scnprintf(info->ra_wakeup_source_name, MAX_RA_WAKE_LOCK_NAME_LEN,
+		  "SMD_TTY_%s_RA", info->ch_name);
+	wakeup_source_init(&info->ra_wakeup_source,
+			info->ra_wakeup_source_name);
 
-	res = smd_named_open_on_edge(smd_tty[n].smd->port_name,
-				     smd_tty[n].smd->edge, &info->ch, info,
+	res = smd_named_open_on_edge(info->ch_name,
+				     smd_tty[n].edge, &info->ch, info,
 				     smd_tty_notify);
 	if (res < 0) {
 		SMD_TTY_INFO("%s: %s open failed %d\n",
-			      __func__, smd_tty[n].smd->port_name, res);
+			      __func__, info->ch_name, res);
 		goto release_wl_tl;
 	}
 
@@ -414,13 +480,13 @@
 		res = -ETIMEDOUT;
 	if (res < 0) {
 		SMD_TTY_INFO("%s: wait for %s smd_open failed %d\n",
-			      __func__, smd_tty[n].smd->port_name, res);
+			      __func__, info->ch_name, res);
 		goto close_ch;
 	}
 	SMD_TTY_INFO("%s with PID %u opened port %s",
-		      current->comm, current->pid, smd_tty[n].smd->port_name);
+		      current->comm, current->pid, info->ch_name);
 	smd_disable_read_intr(info->ch);
-	mutex_unlock(&smd_tty_lock);
+	mutex_unlock(&info->open_lock_lha1);
 	return 0;
 
 close_ch:
@@ -429,13 +495,13 @@
 
 release_wl_tl:
 	tasklet_kill(&info->tty_tsklt);
-	wake_lock_destroy(&info->wake_lock);
-	wake_lock_destroy(&info->ra_wake_lock);
+	wakeup_source_trash(&info->pending_ws);
+	wakeup_source_trash(&info->ra_wakeup_source);
 
 release_pil:
 	subsystem_put(info->pil);
 out:
-	mutex_unlock(&smd_tty_lock);
+	mutex_unlock(&info->open_lock_lha1);
 
 	return res;
 }
@@ -452,19 +518,19 @@
 		return;
 	}
 
-	mutex_lock(&smd_tty_lock);
+	mutex_lock(&info->open_lock_lha1);
 
-	spin_lock_irqsave(&info->reset_lock, flags);
+	spin_lock_irqsave(&info->reset_lock_lha2, flags);
 	info->is_open = 0;
-	spin_unlock_irqrestore(&info->reset_lock, flags);
+	spin_unlock_irqrestore(&info->reset_lock_lha2, flags);
 
 	tasklet_kill(&info->tty_tsklt);
-	wake_lock_destroy(&info->wake_lock);
-	wake_lock_destroy(&info->ra_wake_lock);
+	wakeup_source_trash(&info->pending_ws);
+	wakeup_source_trash(&info->ra_wakeup_source);
 
 	SMD_TTY_INFO("%s with PID %u closed port %s",
 			current->comm, current->pid,
-			info->smd->port_name);
+			info->ch_name);
 	tty->driver_data = NULL;
 	del_timer(&info->buf_req_timer);
 
@@ -472,7 +538,7 @@
 	info->ch = NULL;
 	subsystem_put(info->pil);
 
-	mutex_unlock(&smd_tty_lock);
+	mutex_unlock(&info->open_lock_lha1);
 	tty_kref_put(tty);
 }
 
@@ -513,7 +579,7 @@
 	if (len > avail)
 		len = avail;
 	SMD_TTY_INFO("[WRITE]: PID %u -> port %s %x bytes",
-			current->pid, info->smd->port_name, len);
+			current->pid, info->ch_name, len);
 
 	return smd_write(info->ch, buf, len);
 }
@@ -535,13 +601,13 @@
 	struct smd_tty_info *info = tty->driver_data;
 	unsigned long flags;
 
-	spin_lock_irqsave(&info->reset_lock, flags);
+	spin_lock_irqsave(&info->reset_lock_lha2, flags);
 	if (info->is_open) {
-		spin_unlock_irqrestore(&info->reset_lock, flags);
+		spin_unlock_irqrestore(&info->reset_lock_lha2, flags);
 		tasklet_hi_schedule(&info->tty_tsklt);
 		return;
 	}
-	spin_unlock_irqrestore(&info->reset_lock, flags);
+	spin_unlock_irqrestore(&info->reset_lock_lha2, flags);
 }
 
 /*
@@ -558,7 +624,7 @@
 
 	tiocm = smd_tiocmget(info->ch);
 
-	spin_lock_irqsave(&info->reset_lock, flags);
+	spin_lock_irqsave(&info->reset_lock_lha2, flags);
 	tiocm |= (info->in_reset ? TIOCM_OUT1 : 0);
 	if (info->in_reset_updated) {
 		tiocm |= TIOCM_OUT2;
@@ -566,7 +632,7 @@
 	}
 	SMD_TTY_INFO("PID %u --> %s TIOCM is %x ",
 			current->pid, __func__, tiocm);
-	spin_unlock_irqrestore(&info->reset_lock, flags);
+	spin_unlock_irqrestore(&info->reset_lock_lha2, flags);
 
 	return tiocm;
 }
@@ -613,18 +679,15 @@
 static int smd_tty_dummy_probe(struct platform_device *pdev)
 {
 	int n;
-	int idx;
 
-	for (n = 0; n < ARRAY_SIZE(smd_configs); ++n) {
-		idx = smd_configs[n].tty_dev_index;
-
-		if (!smd_configs[n].dev_name)
+	for (n = 0; n < MAX_SMD_TTYS; ++n) {
+		if (!smd_tty[n].dev_name)
 			continue;
 
-		if (pdev->id == smd_configs[n].edge &&
-			!strncmp(pdev->name, smd_configs[n].dev_name,
+		if (pdev->id == smd_tty[n].edge &&
+			!strncmp(pdev->name, smd_tty[n].dev_name,
 					SMD_MAX_CH_NAME_LEN)) {
-			complete_all(&smd_tty[idx].ch_allocated);
+			complete_all(&smd_tty[n].ch_allocated);
 			return 0;
 		}
 	}
@@ -649,14 +712,10 @@
 
 static struct tty_driver *smd_tty_driver;
 
-static int __init smd_tty_init(void)
+static int smd_tty_register_driver(void)
 {
 	int ret;
-	int n;
-	int idx;
-	struct tty_port *port;
 
-	smd_tty_log_init();
 	smd_tty_driver = alloc_tty_driver(MAX_SMD_TTYS);
 	if (smd_tty_driver == 0) {
 		SMD_TTY_ERR("%s - Driver allocation failed", __func__);
@@ -683,14 +742,69 @@
 	if (ret) {
 		put_tty_driver(smd_tty_driver);
 		SMD_TTY_ERR("%s: driver registration failed %d", __func__, ret);
+	}
+
+	return ret;
+}
+
+static int smd_tty_device_init(int idx)
+{
+	int ret;
+	struct tty_port *port;
+
+	port = &smd_tty[idx].port;
+	tty_port_init(port);
+	port->ops = &smd_tty_port_ops;
+	/* TODO: For kernel >= 3.7 use tty_port_register_device */
+	smd_tty[idx].device_ptr = tty_register_device(smd_tty_driver, idx, 0);
+	init_completion(&smd_tty[idx].ch_allocated);
+	mutex_init(&smd_tty[idx].open_lock_lha1);
+
+	/* register platform device */
+	smd_tty[idx].driver.probe = smd_tty_dummy_probe;
+	smd_tty[idx].driver.driver.name = smd_tty[idx].dev_name;
+	smd_tty[idx].driver.driver.owner = THIS_MODULE;
+	spin_lock_init(&smd_tty[idx].reset_lock_lha2);
+	spin_lock_init(&smd_tty[idx].ra_lock_lha3);
+	smd_tty[idx].is_open = 0;
+	setup_timer(&smd_tty[idx].buf_req_timer, buf_req_retry,
+			(unsigned long)&smd_tty[idx]);
+	init_waitqueue_head(&smd_tty[idx].ch_opened_wait_queue);
+	ret = platform_driver_register(&smd_tty[idx].driver);
+	if (ret)
+		return ret;
+
+	if (device_create_file(smd_tty[idx].device_ptr, &dev_attr_open_timeout))
+		SMD_TTY_ERR("%s: Unable to create device attributes for %s",
+			__func__, smd_configs[idx].port_name);
+	return ret;
+}
+
+static int smd_tty_core_init(void)
+{
+	int ret;
+	int n;
+	int idx;
+
+	ret = smd_tty_register_driver();
+	if (ret) {
+		pr_err("%s: driver registration failed %d\n", __func__, ret);
 		return ret;
 	}
 
 	for (n = 0; n < ARRAY_SIZE(smd_configs); ++n) {
 		idx = smd_configs[n].tty_dev_index;
+		smd_tty[idx].edge = smd_configs[n].edge;
 
-		if (smd_configs[n].dev_name == NULL)
-			smd_configs[n].dev_name = smd_configs[n].port_name;
+		strlcpy(smd_tty[idx].ch_name, smd_configs[n].port_name,
+							SMD_MAX_CH_NAME_LEN);
+		if (smd_configs[n].dev_name == NULL) {
+			strlcpy(smd_tty[idx].dev_name, smd_tty[idx].ch_name,
+							SMD_MAX_CH_NAME_LEN);
+		} else {
+			strlcpy(smd_tty[idx].dev_name, smd_configs[n].dev_name,
+							SMD_MAX_CH_NAME_LEN);
+		}
 
 		if (idx == DS_IDX) {
 			/*
@@ -713,39 +827,13 @@
 				continue;
 		}
 
-		port = &smd_tty[idx].port;
-		tty_port_init(port);
-		port->ops = &smd_tty_port_ops;
-		/* TODO: For kernel >= 3.7 use tty_port_register_device */
-		smd_tty[idx].device_ptr =
-			tty_register_device(smd_tty_driver, idx, 0);
-		if (device_create_file(smd_tty[idx].device_ptr,
-					&dev_attr_open_timeout))
-			SMD_TTY_ERR(
-				"%s: Unable to create device attributes for %s",
-				__func__, smd_configs[n].port_name);
-
-		init_completion(&smd_tty[idx].ch_allocated);
-
-		/* register platform device */
-		smd_tty[idx].driver.probe = smd_tty_dummy_probe;
-		smd_tty[idx].driver.driver.name = smd_configs[n].dev_name;
-		smd_tty[idx].driver.driver.owner = THIS_MODULE;
-		spin_lock_init(&smd_tty[idx].reset_lock);
-		spin_lock_init(&smd_tty[idx].ra_lock);
-		smd_tty[idx].is_open = 0;
-		setup_timer(&smd_tty[idx].buf_req_timer, buf_req_retry,
-				(unsigned long)&smd_tty[idx]);
-		init_waitqueue_head(&smd_tty[idx].ch_opened_wait_queue);
-		ret = platform_driver_register(&smd_tty[idx].driver);
-
+		ret = smd_tty_device_init(idx);
 		if (ret) {
 			SMD_TTY_ERR(
 				"%s: init failed %d (%d)", __func__, idx, ret);
 			smd_tty[idx].driver.probe = NULL;
 			goto out;
 		}
-		smd_tty[idx].smd = &smd_configs[n];
 	}
 	INIT_DELAYED_WORK(&loopback_work, loopback_probe_worker);
 	return 0;
@@ -766,4 +854,155 @@
 	return ret;
 }
 
+static int smd_tty_devicetree_init(struct platform_device *pdev)
+{
+	int ret;
+	int idx;
+	int edge;
+	char *key;
+	const char *ch_name;
+	const char *dev_name;
+	const char *remote_ss;
+	struct device_node *node;
+
+	ret = smd_tty_register_driver();
+	if (ret) {
+		SMD_TTY_ERR("%s: driver registration failed %d\n",
+						__func__, ret);
+		return ret;
+	}
+
+	for_each_child_of_node(pdev->dev.of_node, node) {
+
+		ret = of_alias_get_id(node, "smd");
+		SMD_TTY_INFO("%s:adding smd%d\n", __func__, ret);
+
+		if (ret < 0 || ret >= MAX_SMD_TTYS)
+			goto error;
+		idx = ret;
+
+		key = "qcom,smdtty-remote";
+		remote_ss = of_get_property(node, key, NULL);
+		if (!remote_ss)
+			goto error;
+
+		edge = smd_remote_ss_to_edge(remote_ss);
+		if (edge < 0)
+			goto error;
+		smd_tty[idx].edge = edge;
+
+		key = "qcom,smdtty-port-name";
+		ch_name = of_get_property(node, key, NULL);
+		if (!ch_name)
+			goto error;
+		strlcpy(smd_tty[idx].ch_name, ch_name,
+					SMD_MAX_CH_NAME_LEN);
+
+		key = "qcom,smdtty-dev-name";
+		dev_name = of_get_property(node, key, NULL);
+		if (!dev_name) {
+			strlcpy(smd_tty[idx].dev_name, smd_tty[idx].ch_name,
+							SMD_MAX_CH_NAME_LEN);
+		} else {
+			strlcpy(smd_tty[idx].dev_name, dev_name,
+						SMD_MAX_CH_NAME_LEN);
+		}
+
+		ret = smd_tty_device_init(idx);
+		if (ret) {
+			SMD_TTY_ERR("%s: init failed %d (%d)\n", __func__,
+								idx, ret);
+			smd_tty[idx].driver.probe = NULL;
+			goto error;
+		}
+	}
+	INIT_DELAYED_WORK(&loopback_work, loopback_probe_worker);
+
+	return 0;
+
+error:
+	SMD_TTY_ERR("%s: unregister platform device\n", __func__);
+	/*Unregister platform devices*/
+	for_each_child_of_node(pdev->dev.of_node, node) {
+
+		key = "qcom,smdtty-dev-idx";
+		ret = of_property_read_u32(node, key, &idx);
+		if (ret || idx >= MAX_SMD_TTYS)
+			goto out;
+
+		if (smd_tty[idx].driver.probe) {
+			platform_driver_unregister(&smd_tty[idx].driver);
+			tty_unregister_device(smd_tty_driver, idx);
+		}
+	}
+out:
+	tty_unregister_driver(smd_tty_driver);
+	put_tty_driver(smd_tty_driver);
+	return ret;
+}
+
+static int __devinit msm_smd_tty_probe(struct platform_device *pdev)
+{
+	int ret;
+
+	if (pdev) {
+		if (pdev->dev.of_node) {
+			ret = smd_tty_devicetree_init(pdev);
+			if (ret) {
+				SMD_TTY_ERR("%s: device tree init failed\n",
+								__func__);
+				return ret;
+			}
+		}
+	}
+
+	smd_tty_probe_done = 1;
+	return 0;
+}
+
+static void smd_tty_probe_worker(struct work_struct *work)
+{
+	int ret;
+	if (!smd_tty_probe_done) {
+		ret = smd_tty_core_init();
+		if (ret < 0)
+			SMD_TTY_ERR("smd_tty_core_init failed ret = %d\n", ret);
+	}
+
+}
+
+static struct of_device_id msm_smd_tty_match_table[] = {
+	{ .compatible = "qcom,smdtty" },
+	{},
+};
+
+static struct platform_driver msm_smd_tty_driver = {
+	.probe = msm_smd_tty_probe,
+	.driver = {
+		.name = MODULE_NAME,
+		.owner = THIS_MODULE,
+		.of_match_table = msm_smd_tty_match_table,
+	 },
+};
+
+
+static int __init smd_tty_init(void)
+{
+	int rc;
+
+	smd_tty_log_init();
+	rc = platform_driver_register(&msm_smd_tty_driver);
+	if (rc) {
+		SMD_TTY_ERR("%s: msm_smd_tty_driver register failed %d\n",
+								__func__, rc);
+		return rc;
+	}
+
+	INIT_DELAYED_WORK(&smd_tty_probe_work, smd_tty_probe_worker);
+	schedule_delayed_work(&smd_tty_probe_work,
+				msecs_to_jiffies(SMD_TTY_PROBE_WAIT_TIMEOUT));
+
+	return 0;
+}
+
 module_init(smd_tty_init);
diff --git a/arch/arm/mach-msm/smp2p.c b/arch/arm/mach-msm/smp2p.c
index 4b69cf0..df241f8 100644
--- a/arch/arm/mach-msm/smp2p.c
+++ b/arch/arm/mach-msm/smp2p.c
@@ -53,6 +53,9 @@
  * @smem_edge_out: Pointer to outbound smem item.
  * @smem_edge_state: State of the outbound edge.
  * @ops_ptr: Pointer to internal version-specific SMEM item access functions.
+ *
+ * @feature_ssr_ack_enabled: SSR ACK Support Enabled
+ * @restart_ack: Current cached state of the local ack bit
  */
 struct smp2p_out_list_item {
 	spinlock_t out_item_lock_lha1;
@@ -61,11 +64,14 @@
 	struct smp2p_smem __iomem *smem_edge_out;
 	enum msm_smp2p_edge_state smem_edge_state;
 	struct smp2p_version_if *ops_ptr;
+
+	bool feature_ssr_ack_enabled;
+	bool restart_ack;
 };
 static struct smp2p_out_list_item out_list[SMP2P_NUM_PROCS];
 
 static void *log_ctx;
-static int smp2p_debug_mask = MSM_SMP2P_INFO;
+static int smp2p_debug_mask = MSM_SMP2P_INFO | MSM_SMP2P_DEBUG;
 module_param_named(debug_mask, smp2p_debug_mask,
 		   int, S_IRUGO | S_IWUSR | S_IWGRP);
 
@@ -115,6 +121,7 @@
  *
  * @is_supported: True if this version is supported by SMP2P
  * @negotiate_features: Returns (sub)set of supported features
+ * @negotiation_complete:  Called when negotiation has been completed
  * @find_entry: Finds existing / next empty entry
  * @create_entry: Creates a new entry
  * @read_entry: Reads the value of an entry
@@ -128,6 +135,7 @@
 	/* common functions */
 	bool is_supported;
 	uint32_t (*negotiate_features)(uint32_t features);
+	void (*negotiation_complete)(struct smp2p_out_list_item *);
 	void (*find_entry)(struct smp2p_smem __iomem *item,
 			uint32_t entries_total,	char *name,
 			uint32_t **entry_ptr, int *empty_spot);
@@ -148,6 +156,7 @@
 
 /* v0 (uninitialized SMEM item) interface functions */
 static uint32_t smp2p_negotiate_features_v0(uint32_t features);
+static void smp2p_negotiation_complete_v0(struct smp2p_out_list_item *out_item);
 static void smp2p_find_entry_v0(struct smp2p_smem __iomem *item,
 		uint32_t entries_total, char *name, uint32_t **entry_ptr,
 		int *empty_spot);
@@ -160,6 +169,7 @@
 
 /* v1 interface functions */
 static uint32_t smp2p_negotiate_features_v1(uint32_t features);
+static void smp2p_negotiation_complete_v1(struct smp2p_out_list_item *out_item);
 static void smp2p_find_entry_v1(struct smp2p_smem __iomem *item,
 		uint32_t entries_total, char *name, uint32_t **entry_ptr,
 		int *empty_spot);
@@ -174,6 +184,7 @@
 static struct smp2p_version_if version_if[] = {
 	[0] = {
 		.negotiate_features = smp2p_negotiate_features_v0,
+		.negotiation_complete = smp2p_negotiation_complete_v0,
 		.find_entry = smp2p_find_entry_v0,
 		.create_entry = smp2p_out_create_v0,
 		.read_entry = smp2p_out_read_v0,
@@ -184,6 +195,7 @@
 	[1] = {
 		.is_supported = true,
 		.negotiate_features = smp2p_negotiate_features_v1,
+		.negotiation_complete = smp2p_negotiation_complete_v1,
 		.find_entry = smp2p_find_entry_v1,
 		.create_entry = smp2p_out_create_v1,
 		.read_entry = smp2p_out_read_v1,
@@ -399,15 +411,76 @@
 }
 
 /**
- * smp2p_negotiate_features_v0 - Initial feature negotiation.
+ * smp2p_ssr_ack_needed - Returns true if SSR ACK required
+ *
+ * @rpid: Remote processor ID
+ *
+ * Must be called with out_item_lock_lha1 and in_item_lock_lhb1 locked.
+ */
+static bool smp2p_ssr_ack_needed(uint32_t rpid)
+{
+	bool ssr_done;
+
+	if (!out_list[rpid].feature_ssr_ack_enabled)
+		return false;
+
+	ssr_done = SMP2P_GET_RESTART_DONE(in_list[rpid].smem_edge_in->flags);
+	if (ssr_done != out_list[rpid].restart_ack)
+		return true;
+
+	return false;
+}
+
+/**
+ * smp2p_do_ssr_ack - Handles SSR ACK
+ *
+ * @rpid: Remote processor ID
+ *
+ * Must be called with out_item_lock_lha1 and in_item_lock_lhb1 locked.
+ */
+static void smp2p_do_ssr_ack(uint32_t rpid)
+{
+	bool ack;
+
+	if (!smp2p_ssr_ack_needed(rpid))
+		return;
+
+	ack = !out_list[rpid].restart_ack;
+	SMP2P_INFO("%s: ssr ack pid %d: %d -> %d\n", __func__, rpid,
+			out_list[rpid].restart_ack, ack);
+	out_list[rpid].restart_ack = ack;
+	SMP2P_SET_RESTART_ACK(out_list[rpid].smem_edge_out->flags, ack);
+	smp2p_send_interrupt(rpid);
+}
+
+/**
+ * smp2p_negotiate_features_v1 - Initial feature negotiation.
  *
  * @features: Inbound feature set.
  * @returns: Supported features (will be a same/subset of @features).
  */
 static uint32_t smp2p_negotiate_features_v1(uint32_t features)
 {
-	/* no supported features */
-	return 0;
+	return SMP2P_FEATURE_SSR_ACK;
+}
+
+/**
+ * smp2p_negotiation_complete_v1 - Negotiation completed
+ *
+ * @out_item:   Pointer to the output item structure
+ *
+ * Can be used to do final configuration based upon the negotiated feature set.
+ *
+ * Must be called with out_item_lock_lha1 locked.
+ */
+static void smp2p_negotiation_complete_v1(struct smp2p_out_list_item *out_item)
+{
+	uint32_t features;
+
+	features = SMP2P_GET_FEATURES(out_item->smem_edge_out->feature_version);
+
+	if (features & SMP2P_FEATURE_SSR_ACK)
+		out_item->feature_ssr_ack_enabled = true;
 }
 
 /**
@@ -707,6 +780,20 @@
 }
 
 /**
+ * smp2p_negotiation_complete_v0 - Negotiation completed
+ *
+ * @out_item:   Pointer to the output item structure
+ *
+ * Can be used to do final configuration based upon the negotiated feature set.
+ */
+static void smp2p_negotiation_complete_v0(struct smp2p_out_list_item *out_item)
+{
+	SMP2P_ERR("%s: invalid negotiation complete for v0 pid %d\n",
+		__func__,
+		SMP2P_GET_REMOTE_PID(out_item->smem_edge_out->rem_loc_proc_id));
+}
+
+/**
  * smp2p_find_entry_v0 - Stub function.
  *
  * @item: Pointer to the smem item.
@@ -885,7 +972,7 @@
 	SMP2P_SET_FEATURES(header_ptr->feature_version, features);
 	SMP2P_SET_ENT_TOTAL(header_ptr->valid_total_ent, SMP2P_MAX_ENTRY);
 	SMP2P_SET_ENT_VALID(header_ptr->valid_total_ent, 0);
-	header_ptr->reserved = 0;
+	header_ptr->flags = 0;
 
 	/* ensure that all fields are valid before version is written */
 	wmb();
@@ -992,8 +1079,9 @@
 		struct msm_smp2p_out *pos;
 
 		/* negotiation complete */
-		out_item->smem_edge_state = SMP2P_EDGE_STATE_OPENED;
 		out_item->ops_ptr = &version_if[l_version];
+		out_item->ops_ptr->negotiation_complete(out_item);
+		out_item->smem_edge_state = SMP2P_EDGE_STATE_OPENED;
 		SMP2P_INFO(
 			"%s: negotiation complete pid %d: State %d->%d F0x%08x\n",
 			__func__, remote_pid, prev_state,
@@ -1528,9 +1616,41 @@
 		smp2p_do_negotiation(remote_pid, &out_list[remote_pid]);
 
 	if (out_list[remote_pid].smem_edge_state == SMP2P_EDGE_STATE_OPENED) {
+		bool do_restart_ack;
+
+		/*
+		 * Follow double-check pattern for restart ack since:
+		 * 1) we must notify clients of the X->0 transition
+		 *    that is part of the restart
+		 * 2) lock cannot be held during the
+		 *    smp2p_in_edge_notify() call because clients may do
+		 *    re-entrant calls into our APIs.
+		 *
+		 * smp2p_do_ssr_ack() will only do the ack if it is
+		 * necessary to handle the race condition exposed by
+		 * unlocking the spinlocks.
+		 */
+		spin_lock(&in_list[remote_pid].in_item_lock_lhb1);
+		do_restart_ack = smp2p_ssr_ack_needed(remote_pid);
+		spin_unlock(&in_list[remote_pid].in_item_lock_lhb1);
 		spin_unlock_irqrestore(&out_list[remote_pid].out_item_lock_lha1,
 			flags);
+
 		smp2p_in_edge_notify(remote_pid);
+
+		if (do_restart_ack) {
+			spin_lock_irqsave(
+				&out_list[remote_pid].out_item_lock_lha1,
+				flags);
+			spin_lock(&in_list[remote_pid].in_item_lock_lhb1);
+
+			smp2p_do_ssr_ack(remote_pid);
+
+			spin_unlock(&in_list[remote_pid].in_item_lock_lhb1);
+			spin_unlock_irqrestore(
+				&out_list[remote_pid].out_item_lock_lha1,
+				flags);
+		}
 	} else {
 		spin_unlock_irqrestore(&out_list[remote_pid].out_item_lock_lha1,
 			flags);
@@ -1565,6 +1685,8 @@
 	out_list[rpid].smem_edge_out = NULL;
 	out_list[rpid].ops_ptr = &version_if[0];
 	out_list[rpid].smem_edge_state = SMP2P_EDGE_STATE_CLOSED;
+	out_list[rpid].feature_ssr_ack_enabled = false;
+	out_list[rpid].restart_ack = false;
 
 	in_list[rpid].smem_edge_in = NULL;
 	in_list[rpid].item_size = 0;
@@ -1699,6 +1821,8 @@
 		out_list[i].smem_edge_out = NULL;
 		out_list[i].smem_edge_state = SMP2P_EDGE_STATE_CLOSED;
 		out_list[i].ops_ptr = &version_if[0];
+		out_list[i].feature_ssr_ack_enabled = false;
+		out_list[i].restart_ack = false;
 
 		spin_lock_init(&in_list[i].in_item_lock_lhb1);
 		INIT_LIST_HEAD(&in_list[i].list);
diff --git a/arch/arm/mach-msm/smp2p_debug.c b/arch/arm/mach-msm/smp2p_debug.c
index a493cbe..f4ff42d 100644
--- a/arch/arm/mach-msm/smp2p_debug.c
+++ b/arch/arm/mach-msm/smp2p_debug.c
@@ -141,9 +141,11 @@
 	}
 
 	i += scnprintf(buf + i, max - i,
-		"Entries Valid/Max: %d/%d",
+		"Entries #/Max: %d/%d Flags: %c%c",
 		SMP2P_GET_ENT_VALID(item_ptr->valid_total_ent),
-		SMP2P_GET_ENT_TOTAL(item_ptr->valid_total_ent)
+		SMP2P_GET_ENT_TOTAL(item_ptr->valid_total_ent),
+		item_ptr->flags & SMP2P_FLAGS_RESTART_ACK_MASK ? 'A' : 'a',
+		item_ptr->flags & SMP2P_FLAGS_RESTART_DONE_MASK ? 'D' : 'd'
 		);
 
 	return i;
diff --git a/arch/arm/mach-msm/smp2p_gpio.c b/arch/arm/mach-msm/smp2p_gpio.c
index 2a85e5f..5f70e0c 100644
--- a/arch/arm/mach-msm/smp2p_gpio.c
+++ b/arch/arm/mach-msm/smp2p_gpio.c
@@ -420,7 +420,7 @@
 		spin_unlock_irqrestore(&chip->irq_lock, flags);
 
 		if (trigger_interrrupt) {
-			SMP2P_GPIO(
+			SMP2P_INFO(
 				"'%s':%d GPIO bit %d virq %d (%s,%s) - edge %s triggering\n",
 				chip->name, chip->remote_pid, i,
 				chip->irq_base + i,
diff --git a/arch/arm/mach-msm/smp2p_private.h b/arch/arm/mach-msm/smp2p_private.h
index b9a5cfe..8e0d7a3 100644
--- a/arch/arm/mach-msm/smp2p_private.h
+++ b/arch/arm/mach-msm/smp2p_private.h
@@ -20,8 +20,7 @@
 #include "smp2p_private_api.h"
 
 #define SMP2P_MAX_ENTRY 16
-#define SMP2P_LOCAL_VERSION 1
-#define SMP2P_LOCAL_FEATURE  0x0
+#define SMP2P_FEATURE_SSR_ACK 0x1
 
 /* SMEM Item Header Macros */
 #define SMP2P_MAGIC 0x504D5324
@@ -37,6 +36,10 @@
 #define SMP2P_ENT_TOTAL_BIT 0
 #define SMP2P_ENT_VALID_MASK 0xffff0000
 #define SMP2P_ENT_VALID_BIT 16
+#define SMP2P_FLAGS_RESTART_DONE_BIT 0
+#define SMP2P_FLAGS_RESTART_DONE_MASK 0x1
+#define SMP2P_FLAGS_RESTART_ACK_BIT 1
+#define SMP2P_FLAGS_RESTART_ACK_MASK 0x2
 
 #define SMP2P_GET_BITS(hdr_val, mask, bit) \
 	(((hdr_val) & (mask)) >> (bit))
@@ -77,6 +80,20 @@
 	SMP2P_SET_BITS(hdr,  SMP2P_ENT_VALID_MASK, SMP2P_ENT_VALID_BIT,\
 		entries)
 
+#define SMP2P_GET_RESTART_DONE(hdr) \
+	SMP2P_GET_BITS(hdr, SMP2P_FLAGS_RESTART_DONE_MASK, \
+			SMP2P_FLAGS_RESTART_DONE_BIT)
+#define SMP2P_SET_RESTART_DONE(hdr, value) \
+	SMP2P_SET_BITS(hdr, SMP2P_FLAGS_RESTART_DONE_MASK, \
+			SMP2P_FLAGS_RESTART_DONE_BIT, value)
+
+#define SMP2P_GET_RESTART_ACK(hdr) \
+	SMP2P_GET_BITS(hdr, SMP2P_FLAGS_RESTART_ACK_MASK, \
+			SMP2P_FLAGS_RESTART_ACK_BIT)
+#define SMP2P_SET_RESTART_ACK(hdr, value) \
+	SMP2P_SET_BITS(hdr, SMP2P_FLAGS_RESTART_ACK_MASK, \
+			SMP2P_FLAGS_RESTART_ACK_BIT, value)
+
 /* Loopback Command Macros */
 #define SMP2P_RMT_CMD_TYPE_MASK 0x80000000
 #define SMP2P_RMT_CMD_TYPE_BIT 31
@@ -162,12 +179,21 @@
 	SMP2P_EDGE_STATE_FAILED = 0xff,
 };
 
+/**
+ * struct smp2p_smem - SMP2P SMEM Item Header
+ *
+ * @magic:  Set to "$SMP" -- used for identification / debug purposes
+ * @feature_version:  Feature and version fields
+ * @rem_loc_proc_id:  Remote (31:16) and Local (15:0) processor IDs
+ * @valid_total_ent:  Valid (31:16) and total (15:0) entries
+ * @flags:  Flags (bits 31:2 reserved)
+ */
 struct smp2p_smem {
 	uint32_t magic;
 	uint32_t feature_version;
 	uint32_t rem_loc_proc_id;
 	uint32_t valid_total_ent;
-	uint32_t reserved;
+	uint32_t flags;
 };
 
 struct smp2p_entry_v1 {
diff --git a/arch/arm/mach-msm/smp2p_test.c b/arch/arm/mach-msm/smp2p_test.c
index 18c9bfd..2f86df4 100644
--- a/arch/arm/mach-msm/smp2p_test.c
+++ b/arch/arm/mach-msm/smp2p_test.c
@@ -16,6 +16,7 @@
 #include <linux/jiffies.h>
 #include <linux/delay.h>
 #include <linux/completion.h>
+#include <mach/subsystem_restart.h>
 #include "smp2p_private.h"
 #include "smp2p_test_common.h"
 
@@ -77,7 +78,7 @@
 		rmp->remote_item.header.valid_total_ent, SMP2P_MAX_ENTRY);
 		SMP2P_SET_ENT_VALID(
 		rmp->remote_item.header.valid_total_ent, 0);
-		rmp->remote_item.header.reserved = 0x0;
+		rmp->remote_item.header.flags = 0x0;
 		msm_smp2p_set_remote_mock_exists(true);
 		rmp->tx_interrupt();
 
@@ -161,7 +162,7 @@
 			SMP2P_MAX_ENTRY);
 		SMP2P_SET_ENT_VALID(
 		rmp->remote_item.header.valid_total_ent, 0);
-		rmp->remote_item.header.reserved = 0x0;
+		rmp->remote_item.header.flags = 0x0;
 
 		msm_smp2p_set_remote_mock_exists(true);
 
@@ -251,7 +252,7 @@
 		rmp->remote_item.header.valid_total_ent, SMP2P_MAX_ENTRY);
 		SMP2P_SET_ENT_VALID(
 		rmp->remote_item.header.valid_total_ent, 0);
-		rmp->remote_item.header.reserved = 0x0;
+		rmp->remote_item.header.flags = 0x0;
 
 		msm_smp2p_set_remote_mock_exists(false);
 		UT_ASSERT_PTR(NULL, ==,
@@ -369,7 +370,7 @@
 		rmp->remote_item.header.valid_total_ent, SMP2P_MAX_ENTRY);
 		SMP2P_SET_ENT_VALID(
 		rmp->remote_item.header.valid_total_ent, 1);
-		rmp->remote_item.header.reserved = 0x0;
+		rmp->remote_item.header.flags = 0x0;
 		msm_smp2p_set_remote_mock_exists(true);
 
 		/* Create test entry and attach loopback server */
@@ -794,7 +795,7 @@
 		rmp->remote_item.header.valid_total_ent, SMP2P_MAX_ENTRY);
 		SMP2P_SET_ENT_VALID(
 		rmp->remote_item.header.valid_total_ent, 0);
-		rmp->remote_item.header.reserved = 0x0;
+		rmp->remote_item.header.flags = 0x0;
 		msm_smp2p_set_remote_mock_exists(true);
 
 		/* Create Max Entries in the remote mock object */
@@ -892,7 +893,7 @@
 		rmp->remote_item.header.valid_total_ent, 1);
 		SMP2P_SET_ENT_VALID(
 		rmp->remote_item.header.valid_total_ent, 0);
-		rmp->remote_item.header.reserved = 0x0;
+		rmp->remote_item.header.flags = 0x0;
 		msm_smp2p_set_remote_mock_exists(true);
 
 		/* Create an Entry in the remote mock object */
@@ -953,6 +954,217 @@
 	}
 }
 
+/**
+ * smp2p_ut_local_ssr_ack - Verify SSR Done/ACK Feature
+ *
+ * @s: pointer to output file
+ */
+static void smp2p_ut_local_ssr_ack(struct seq_file *s)
+{
+	int failed = 0;
+	struct msm_smp2p_remote_mock *rmp = NULL;
+	int ret;
+
+	seq_printf(s, "Running %s\n", __func__);
+	do {
+		struct smp2p_smem *rhdr;
+		struct smp2p_smem *lhdr;
+		int negotiation_state;
+
+		/* initialize v1 without SMP2P_FEATURE_SSR_ACK enabled */
+		ret = smp2p_reset_mock_edge();
+		UT_ASSERT_INT(ret, ==, 0);
+		rmp = msm_smp2p_get_remote_mock();
+		UT_ASSERT_PTR(rmp, !=, NULL);
+		rhdr = &rmp->remote_item.header;
+
+		rmp->rx_interrupt_count = 0;
+		memset(&rmp->remote_item, 0, sizeof(struct smp2p_smem_item));
+		rhdr->magic = SMP2P_MAGIC;
+		SMP2P_SET_LOCAL_PID(rhdr->rem_loc_proc_id,
+				SMP2P_REMOTE_MOCK_PROC);
+		SMP2P_SET_REMOTE_PID(rhdr->rem_loc_proc_id, SMP2P_APPS_PROC);
+		SMP2P_SET_VERSION(rhdr->feature_version, 1);
+		SMP2P_SET_FEATURES(rhdr->feature_version, 0);
+		SMP2P_SET_ENT_TOTAL(rhdr->valid_total_ent, SMP2P_MAX_ENTRY);
+		SMP2P_SET_ENT_VALID(rhdr->valid_total_ent, 0);
+		rhdr->flags = 0x0;
+		msm_smp2p_set_remote_mock_exists(true);
+		rmp->tx_interrupt();
+
+		/* verify edge is open */
+		lhdr = smp2p_get_out_item(SMP2P_REMOTE_MOCK_PROC,
+					&negotiation_state);
+		UT_ASSERT_PTR(NULL, !=, lhdr);
+		UT_ASSERT_INT(negotiation_state, ==, SMP2P_EDGE_STATE_OPENED);
+		UT_ASSERT_INT(rmp->rx_interrupt_count, ==, 1);
+
+		/* verify no response to ack feature */
+		rmp->rx_interrupt_count = 0;
+		SMP2P_SET_RESTART_DONE(rhdr->flags, 1);
+		rmp->tx_interrupt();
+		UT_ASSERT_INT(0, ==, SMP2P_GET_RESTART_DONE(lhdr->flags));
+		UT_ASSERT_INT(0, ==, SMP2P_GET_RESTART_ACK(lhdr->flags));
+		UT_ASSERT_INT(rmp->rx_interrupt_count, ==, 0);
+
+		/* initialize v1 with SMP2P_FEATURE_SSR_ACK enabled */
+		ret = smp2p_reset_mock_edge();
+		UT_ASSERT_INT(ret, ==, 0);
+		rmp = msm_smp2p_get_remote_mock();
+		UT_ASSERT_PTR(rmp, !=, NULL);
+		rhdr = &rmp->remote_item.header;
+
+		rmp->rx_interrupt_count = 0;
+		memset(&rmp->remote_item, 0, sizeof(struct smp2p_smem_item));
+		rhdr->magic = SMP2P_MAGIC;
+		SMP2P_SET_LOCAL_PID(rhdr->rem_loc_proc_id,
+				SMP2P_REMOTE_MOCK_PROC);
+		SMP2P_SET_REMOTE_PID(rhdr->rem_loc_proc_id, SMP2P_APPS_PROC);
+		SMP2P_SET_VERSION(rhdr->feature_version, 1);
+		SMP2P_SET_FEATURES(rhdr->feature_version,
+				SMP2P_FEATURE_SSR_ACK);
+		SMP2P_SET_ENT_TOTAL(rhdr->valid_total_ent, SMP2P_MAX_ENTRY);
+		SMP2P_SET_ENT_VALID(rhdr->valid_total_ent, 0);
+		rmp->rx_interrupt_count = 0;
+		rhdr->flags = 0x0;
+		msm_smp2p_set_remote_mock_exists(true);
+		rmp->tx_interrupt();
+
+		/* verify edge is open */
+		lhdr = smp2p_get_out_item(SMP2P_REMOTE_MOCK_PROC,
+					&negotiation_state);
+		UT_ASSERT_PTR(NULL, !=, lhdr);
+		UT_ASSERT_INT(negotiation_state, ==, SMP2P_EDGE_STATE_OPENED);
+		UT_ASSERT_INT(rmp->rx_interrupt_count, ==, 1);
+
+		/* verify response to ack feature */
+		rmp->rx_interrupt_count = 0;
+		SMP2P_SET_RESTART_DONE(rhdr->flags, 1);
+		rmp->tx_interrupt();
+		UT_ASSERT_INT(0, ==, SMP2P_GET_RESTART_DONE(lhdr->flags));
+		UT_ASSERT_INT(1, ==, SMP2P_GET_RESTART_ACK(lhdr->flags));
+		UT_ASSERT_INT(rmp->rx_interrupt_count, ==, 1);
+
+		rmp->rx_interrupt_count = 0;
+		SMP2P_SET_RESTART_DONE(rhdr->flags, 0);
+		rmp->tx_interrupt();
+		UT_ASSERT_INT(0, ==, SMP2P_GET_RESTART_DONE(lhdr->flags));
+		UT_ASSERT_INT(0, ==, SMP2P_GET_RESTART_ACK(lhdr->flags));
+		UT_ASSERT_INT(rmp->rx_interrupt_count, ==, 1);
+
+		seq_puts(s, "\tOK\n");
+	} while (0);
+
+	if (failed) {
+		pr_err("%s: Failed\n", __func__);
+		seq_puts(s, "\tFailed\n");
+	}
+}
+
+/**
+ * smp2p_ut_local_ssr_ack - Verify SSR Done/ACK Feature
+ *
+ * @s: pointer to output file
+ * @rpid: Remote processor ID
+ * @int_cfg: Interrupt config
+ */
+static void smp2p_ut_remotesubsys_ssr_ack(struct seq_file *s, uint32_t rpid,
+		struct smp2p_interrupt_config *int_cfg)
+{
+	int failed = 0;
+
+	seq_printf(s, "Running %s\n", __func__);
+	do {
+		struct smp2p_smem *rhdr;
+		struct smp2p_smem *lhdr;
+		int negotiation_state;
+		bool ssr_ack_enabled;
+		uint32_t ssr_done_start;
+
+		lhdr = smp2p_get_out_item(rpid, &negotiation_state);
+		UT_ASSERT_PTR(NULL, !=, lhdr);
+		UT_ASSERT_INT(SMP2P_EDGE_STATE_OPENED, ==, negotiation_state);
+
+		rhdr = smp2p_get_in_item(rpid);
+		UT_ASSERT_PTR(NULL, !=, rhdr);
+
+		/* get initial state of SSR flags */
+		if (SMP2P_GET_FEATURES(rhdr->feature_version)
+				& SMP2P_FEATURE_SSR_ACK)
+			ssr_ack_enabled = true;
+		else
+			ssr_ack_enabled = false;
+
+		ssr_done_start = SMP2P_GET_RESTART_DONE(rhdr->flags);
+		UT_ASSERT_INT(ssr_done_start, ==,
+				SMP2P_GET_RESTART_ACK(lhdr->flags));
+
+		/* trigger restart */
+		seq_printf(s, "Restarting '%s'\n", int_cfg->name);
+		subsystem_restart(int_cfg->name);
+		msleep(10*1000);
+
+		/* verify ack signaling */
+		if (ssr_ack_enabled) {
+			ssr_done_start ^= 1;
+			UT_ASSERT_INT(ssr_done_start, ==,
+					SMP2P_GET_RESTART_ACK(lhdr->flags));
+			UT_ASSERT_INT(ssr_done_start, ==,
+					SMP2P_GET_RESTART_DONE(rhdr->flags));
+			UT_ASSERT_INT(0, ==,
+					SMP2P_GET_RESTART_DONE(lhdr->flags));
+			seq_puts(s, "\tSSR ACK Enabled and Toggled\n");
+		} else {
+			UT_ASSERT_INT(0, ==,
+					SMP2P_GET_RESTART_DONE(lhdr->flags));
+			UT_ASSERT_INT(0, ==,
+					SMP2P_GET_RESTART_ACK(lhdr->flags));
+
+			UT_ASSERT_INT(0, ==,
+					SMP2P_GET_RESTART_DONE(rhdr->flags));
+			UT_ASSERT_INT(0, ==,
+					SMP2P_GET_RESTART_ACK(rhdr->flags));
+			seq_puts(s, "\tSSR ACK Disabled\n");
+		}
+
+		seq_puts(s, "\tOK\n");
+	} while (0);
+
+	if (failed) {
+		pr_err("%s: Failed\n", __func__);
+		seq_puts(s, "\tFailed\n");
+	}
+}
+
+/**
+ * smp2p_ut_remote_ssr_ack - Verify SSR Done/ACK Feature
+ *
+ * @s: pointer to output file
+ *
+ * Triggers SSR for each subsystem.
+ */
+static void smp2p_ut_remote_ssr_ack(struct seq_file *s)
+{
+	struct smp2p_interrupt_config *int_cfg;
+	int pid;
+
+	int_cfg = smp2p_get_interrupt_config();
+	if (!int_cfg) {
+		seq_puts(s,
+			"Remote processor config unavailable\n");
+		return;
+	}
+
+	for (pid = 0; pid < SMP2P_NUM_PROCS; ++pid) {
+		if (!int_cfg[pid].is_configured)
+			continue;
+
+		msm_smp2p_deinit_rmt_lpb_proc(pid);
+		smp2p_ut_remotesubsys_ssr_ack(s, pid, &int_cfg[pid]);
+		msm_smp2p_init_rmt_lpb_proc(pid);
+	}
+}
+
 static struct dentry *dent;
 
 static int debugfs_show(struct seq_file *s, void *data)
@@ -1019,6 +1231,10 @@
 			smp2p_ut_remote_out_max_entries);
 	smp2p_debug_create("ut_local_in_multiple",
 			smp2p_ut_local_in_multiple);
+	smp2p_debug_create("ut_local_ssr_ack",
+			smp2p_ut_local_ssr_ack);
+	smp2p_debug_create("ut_remote_ssr_ack",
+			smp2p_ut_remote_ssr_ack);
 
 	return 0;
 }
diff --git a/arch/arm/mach-msm/socinfo.c b/arch/arm/mach-msm/socinfo.c
index 6cb04c7..888cd5e 100644
--- a/arch/arm/mach-msm/socinfo.c
+++ b/arch/arm/mach-msm/socinfo.c
@@ -75,6 +75,7 @@
 	PLATFORM_SUBTYPE_SKUAA = 0x1,
 	PLATFORM_SUBTYPE_SKUF = 0x2,
 	PLATFORM_SUBTYPE_SKUAB = 0x3,
+	PLATFORM_SUBTYPE_SKUG = 0x5,
 	PLATFORM_SUBTYPE_QRD_INVALID,
 };
 
@@ -83,6 +84,8 @@
 	[PLATFORM_SUBTYPE_SKUAA] = "SKUAA",
 	[PLATFORM_SUBTYPE_SKUF] = "SKUF",
 	[PLATFORM_SUBTYPE_SKUAB] = "SKUAB",
+	[PLATFORM_SUBTYPE_SKUG] = "SKUG",
+	[PLATFORM_SUBTYPE_QRD_INVALID] = "INVALID",
 };
 
 enum {
@@ -363,6 +366,12 @@
 	[199] = MSM_CPU_8226,
 	[200] = MSM_CPU_8226,
 	[205] = MSM_CPU_8226,
+	[219] = MSM_CPU_8226,
+	[220] = MSM_CPU_8226,
+	[221] = MSM_CPU_8226,
+	[222] = MSM_CPU_8226,
+	[223] = MSM_CPU_8226,
+	[224] = MSM_CPU_8226,
 
 	/* 8092 IDs */
 	[146] = MSM_CPU_8092,
@@ -666,7 +675,7 @@
 		if (hw_subtype >= PLATFORM_SUBTYPE_QRD_INVALID) {
 			pr_err("%s: Invalid hardware platform sub type for qrd found\n",
 				__func__);
-			hw_subtype = PLATFORM_SUBTYPE_QRD;
+			hw_subtype = PLATFORM_SUBTYPE_QRD_INVALID;
 		}
 		return snprintf(buf, PAGE_SIZE, "%-.32s\n",
 					qrd_hw_platform_subtype[hw_subtype]);
@@ -788,6 +797,16 @@
 {
 	uint32_t hw_subtype;
 	hw_subtype = socinfo_get_platform_subtype();
+	if (HW_PLATFORM_QRD == socinfo_get_platform_type()) {
+		if (hw_subtype >= PLATFORM_SUBTYPE_QRD_INVALID) {
+			pr_err("%s: Invalid hardware platform sub type for qrd found\n",
+				__func__);
+			hw_subtype = PLATFORM_SUBTYPE_QRD_INVALID;
+		}
+		return snprintf(buf, PAGE_SIZE, "%-.32s\n",
+					qrd_hw_platform_subtype[hw_subtype]);
+	}
+
 	return snprintf(buf, PAGE_SIZE, "%-.32s\n",
 		hw_platform_subtype[hw_subtype]);
 }
diff --git a/arch/arm/mach-msm/spm-regulator.c b/arch/arm/mach-msm/spm-regulator.c
index 244a779..628e1ee 100644
--- a/arch/arm/mach-msm/spm-regulator.c
+++ b/arch/arm/mach-msm/spm-regulator.c
@@ -21,6 +21,7 @@
 #include <linux/of_device.h>
 #include <linux/slab.h>
 #include <linux/spmi.h>
+#include <linux/string.h>
 #include <linux/regulator/driver.h>
 #include <linux/regulator/machine.h>
 #include <linux/regulator/of_regulator.h>
@@ -120,7 +121,7 @@
 			return rc;
 	}
 
-	rc = msm_spm_apcs_set_vdd(vreg->vlevel);
+	rc = msm_spm_set_vdd(0, vreg->vlevel); /* value of CPU is don't care */
 	if (rc) {
 		pr_err("%s: msm_spm_set_vdd failed %d\n", vreg->rdesc.name, rc);
 		return rc;
@@ -313,13 +314,38 @@
 
 static int qpnp_fts2_init_mode(struct spm_vreg *vreg)
 {
+	const char *mode_name;
 	int rc;
 
-	rc = spmi_ext_register_readl(vreg->spmi_dev->ctrl, vreg->spmi_dev->sid,
-		vreg->spmi_base_addr + QPNP_FTS2_REG_MODE, &vreg->init_mode, 1);
-	if (rc)
-		dev_err(&vreg->spmi_dev->dev, "%s: could not read mode register, rc=%d\n",
-			__func__, rc);
+	rc = of_property_read_string(vreg->spmi_dev->dev.of_node, "qcom,mode",
+					&mode_name);
+	if (!rc) {
+		if (strcmp("pwm", mode_name) == 0) {
+			vreg->init_mode = QPNP_FTS2_MODE_PWM;
+		} else if (strcmp("auto", mode_name) == 0) {
+			vreg->init_mode = QPNP_FTS2_MODE_AUTO;
+		} else {
+			dev_err(&vreg->spmi_dev->dev, "%s: unknown regulator mode: %s\n",
+				__func__, mode_name);
+			return -EINVAL;
+		}
+
+		rc = spmi_ext_register_writel(vreg->spmi_dev->ctrl,
+			vreg->spmi_dev->sid,
+			vreg->spmi_base_addr + QPNP_FTS2_REG_MODE,
+			&vreg->init_mode, 1);
+		if (rc)
+			dev_err(&vreg->spmi_dev->dev, "%s: could not write mode register, rc=%d\n",
+				__func__, rc);
+	} else {
+		rc = spmi_ext_register_readl(vreg->spmi_dev->ctrl,
+			vreg->spmi_dev->sid,
+			vreg->spmi_base_addr + QPNP_FTS2_REG_MODE,
+			&vreg->init_mode, 1);
+		if (rc)
+			dev_err(&vreg->spmi_dev->dev, "%s: could not read mode register, rc=%d\n",
+				__func__, rc);
+	}
 
 	return rc;
 }
diff --git a/arch/arm/mach-msm/spm.h b/arch/arm/mach-msm/spm.h
index 77b7bf7..3207011 100644
--- a/arch/arm/mach-msm/spm.h
+++ b/arch/arm/mach-msm/spm.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2010-2012, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2010-2013, The Linux Foundation. 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 and
@@ -150,7 +150,6 @@
 /* Public functions */
 
 int msm_spm_l2_set_low_power_mode(unsigned int mode, bool notify_rpm);
-int msm_spm_apcs_set_vdd(unsigned int vlevel);
 int msm_spm_apcs_set_phase(unsigned int phase_cnt);
 int msm_spm_enable_fts_lpm(uint32_t mode);
 
@@ -166,20 +165,17 @@
 {
 	return -ENOSYS;
 }
+
 static inline int msm_spm_l2_init(struct msm_spm_platform_data *data)
 {
 	return -ENOSYS;
 }
+
 static inline void msm_spm_l2_reinit(void)
 {
 	/* empty */
 }
 
-static inline int msm_spm_apcs_set_vdd(unsigned int vlevel)
-{
-	return -ENOSYS;
-}
-
 static inline int msm_spm_apcs_set_phase(unsigned int phase_cnt)
 {
 	return -ENOSYS;
diff --git a/arch/arm/mach-msm/spm_devices.c b/arch/arm/mach-msm/spm_devices.c
index fc05fce..3ac1348 100644
--- a/arch/arm/mach-msm/spm_devices.c
+++ b/arch/arm/mach-msm/spm_devices.c
@@ -48,18 +48,29 @@
 
 static struct msm_spm_device msm_spm_l2_device;
 static DEFINE_PER_CPU_SHARED_ALIGNED(struct msm_spm_device, msm_cpu_spm_device);
-
+static bool msm_spm_L2_apcs_master;
 
 static void msm_spm_smp_set_vdd(void *data)
 {
 	struct msm_spm_device *dev;
 	struct msm_spm_vdd_info *info = (struct msm_spm_vdd_info *)data;
 
-	dev = &per_cpu(msm_cpu_spm_device, info->cpu);
+	if (msm_spm_L2_apcs_master)
+		dev = &msm_spm_l2_device;
+	else
+		dev = &per_cpu(msm_cpu_spm_device, info->cpu);
+
 	if (!dev->initialized)
 		return;
+
+	if (msm_spm_L2_apcs_master)
+		get_cpu();
+
 	dev->cpu_vdd = info->vlevel;
 	info->err = msm_spm_drv_set_vdd(&dev->reg_data, info->vlevel);
+
+	if (msm_spm_L2_apcs_master)
+		put_cpu();
 }
 
 /**
@@ -76,7 +87,8 @@
 	info.vlevel = vlevel;
 	info.err = -ENODEV;
 
-	if ((smp_processor_id() != cpu) && cpu_online(cpu)) {
+	if (!msm_spm_L2_apcs_master && (smp_processor_id() != cpu) &&
+			cpu_online(cpu)) {
 		/**
 		 * We do not want to set the voltage of another core from
 		 * this core, as its possible that we may race the vdd change
@@ -111,7 +123,10 @@
 {
 	struct msm_spm_device *dev;
 
-	dev = &per_cpu(msm_cpu_spm_device, cpu);
+	if (msm_spm_L2_apcs_master)
+		dev = &msm_spm_l2_device;
+	else
+		dev = &per_cpu(msm_cpu_spm_device, cpu);
 	return dev->cpu_vdd;
 }
 EXPORT_SYMBOL(msm_spm_get_vdd);
@@ -293,18 +308,6 @@
 EXPORT_SYMBOL(msm_spm_l2_reinit);
 
 /**
- * msm_spm_apcs_set_vdd(): Set Apps processor core sub-system voltage
- * @vlevel: Encoded PMIC data.
- */
-int msm_spm_apcs_set_vdd(unsigned int vlevel)
-{
-	if (!msm_spm_l2_device.initialized)
-		return -ENXIO;
-	return msm_spm_drv_set_vdd(&msm_spm_l2_device.reg_data, vlevel);
-}
-EXPORT_SYMBOL(msm_spm_apcs_set_vdd);
-
-/**
  * msm_spm_apcs_set_phase(): Set number of SMPS phases.
  * phase_cnt: Number of phases to be set active
  */
@@ -468,6 +471,10 @@
 		ret = of_property_read_u32(node, key, &val);
 		if (!ret)
 			spm_data.pfm_port = val;
+
+		key = "qcom,L2-spm-is-apcs-master";
+		msm_spm_L2_apcs_master =
+			of_property_read_bool(pdev->dev.of_node, key);
 	}
 
 	for (i = 0; i < ARRAY_SIZE(spm_of_data); i++) {
diff --git a/arch/arm/mm/init.c b/arch/arm/mm/init.c
index 4a6943c..34ae4e6 100644
--- a/arch/arm/mm/init.c
+++ b/arch/arm/mm/init.c
@@ -949,6 +949,14 @@
 				    "TCM link");
 #endif
 
+#ifdef CONFIG_STRICT_MEMORY_RWX
+	poison_init_mem((char *)__arch_info_begin,
+		__init_end - (char *)__arch_info_begin);
+	reclaimed_initmem = free_area(__phys_to_pfn(__pa(__arch_info_begin)),
+				    __phys_to_pfn(__pa(__init_end)),
+				    "init");
+	totalram_pages += reclaimed_initmem;
+#else
 	poison_init_mem(__init_begin, __init_end - __init_begin);
 	if (!machine_is_integrator() && !machine_is_cintegrator()) {
 		reclaimed_initmem = free_area(__phys_to_pfn(__pa(__init_begin)),
@@ -956,6 +964,7 @@
 					    "init");
 		totalram_pages += reclaimed_initmem;
 	}
+#endif
 }
 
 #ifdef CONFIG_BLK_DEV_INITRD
diff --git a/arch/arm/mm/mmu.c b/arch/arm/mm/mmu.c
index 717a6fe..509f59d 100644
--- a/arch/arm/mm/mmu.c
+++ b/arch/arm/mm/mmu.c
@@ -1394,8 +1394,6 @@
 }
 EXPORT_SYMBOL(mem_text_write_kernel_word);
 
-extern char __init_data[];
-
 static void __init map_lowmem(void)
 {
 	struct memblock_region *reg;
@@ -1425,7 +1423,7 @@
 #ifdef CONFIG_STRICT_MEMORY_RWX
 		if (start <= __pa(_text) && __pa(_text) < end) {
 			map.length = SECTION_SIZE;
-			map.type = MT_MEMORY;
+			map.type = MT_MEMORY_RW;
 
 			create_mapping(&map);
 
@@ -1445,14 +1443,15 @@
 
 			map.pfn = __phys_to_pfn(__pa(__init_begin));
 			map.virtual = (unsigned long)__init_begin;
-			map.length = __init_data - __init_begin;
-			map.type = MT_MEMORY;
+			map.length = (char *)__arch_info_begin - __init_begin;
+			map.type = MT_MEMORY_RX;
 
 			create_mapping(&map);
 
-			map.pfn = __phys_to_pfn(__pa(__init_data));
-			map.virtual = (unsigned long)__init_data;
-			map.length = __phys_to_virt(end) - (unsigned int)__init_data;
+			map.pfn = __phys_to_pfn(__pa(__arch_info_begin));
+			map.virtual = (unsigned long)__arch_info_begin;
+			map.length = __phys_to_virt(end) -
+				(unsigned long)__arch_info_begin;
 			map.type = MT_MEMORY_RW;
 		} else {
 			map.length = end - start;
diff --git a/block/blk-core.c b/block/blk-core.c
index 40d9b35..123f79a 100644
--- a/block/blk-core.c
+++ b/block/blk-core.c
@@ -2058,8 +2058,10 @@
 			 * not be passed by new incoming requests
 			 */
 			rq->cmd_flags |= REQ_STARTED;
-			if (rq->cmd_flags & REQ_URGENT)
+			if (rq->cmd_flags & REQ_URGENT) {
+				WARN_ON(q->dispatched_urgent);
 				q->dispatched_urgent = true;
+			}
 			trace_block_rq_issue(q, rq);
 		}
 
diff --git a/block/cfq-iosched.c b/block/cfq-iosched.c
index b4711cb..32629e2 100644
--- a/block/cfq-iosched.c
+++ b/block/cfq-iosched.c
@@ -239,9 +239,6 @@
 	unsigned long workload_expires;
 	struct cfq_group *serving_group;
 
-	unsigned int nr_urgent_pending;
-	unsigned int nr_urgent_in_flight;
-
 	/*
 	 * Each priority tree is sorted by next_request position.  These
 	 * trees are used when determining if two or more queues are
@@ -2094,14 +2091,6 @@
 	(RQ_CFQG(rq))->dispatched++;
 	elv_dispatch_sort(q, rq);
 
-	if (rq->cmd_flags & REQ_URGENT) {
-		if (!cfqd->nr_urgent_pending)
-			WARN_ON(1);
-		else
-			cfqd->nr_urgent_pending--;
-		cfqd->nr_urgent_in_flight++;
-	}
-
 	cfqd->rq_in_flight[cfq_cfqq_sync(cfqq)]++;
 	cfqq->nr_sectors += blk_rq_sectors(rq);
 	cfq_blkiocg_update_dispatch_stats(&cfqq->cfqg->blkg, blk_rq_bytes(rq),
@@ -3205,69 +3194,6 @@
 	}
 }
 
-/*
- * Called when a request (rq) is reinserted (to cfqq). Check if there's
- * something we should do about it
- */
-static void
-cfq_rq_requeued(struct cfq_data *cfqd, struct cfq_queue *cfqq,
-		struct request *rq)
-{
-	struct cfq_io_cq *cic = RQ_CIC(rq);
-
-	cfqd->rq_queued++;
-	if (rq->cmd_flags & REQ_PRIO)
-		cfqq->prio_pending++;
-
-	cfqq->dispatched--;
-	(RQ_CFQG(rq))->dispatched--;
-
-	cfqd->rq_in_flight[cfq_cfqq_sync(cfqq)]--;
-
-	cfq_update_io_thinktime(cfqd, cfqq, cic);
-	cfq_update_io_seektime(cfqd, cfqq, rq);
-	cfq_update_idle_window(cfqd, cfqq, cic);
-
-	cfqq->last_request_pos = blk_rq_pos(rq) + blk_rq_sectors(rq);
-
-	if (cfqq == cfqd->active_queue) {
-		if (cfq_cfqq_wait_request(cfqq)) {
-			if (blk_rq_bytes(rq) > PAGE_CACHE_SIZE ||
-			    cfqd->busy_queues > 1) {
-				cfq_del_timer(cfqd, cfqq);
-				cfq_clear_cfqq_wait_request(cfqq);
-			} else {
-				cfq_blkiocg_update_idle_time_stats(
-						&cfqq->cfqg->blkg);
-				cfq_mark_cfqq_must_dispatch(cfqq);
-			}
-		}
-	} else if (cfq_should_preempt(cfqd, cfqq, rq)) {
-		cfq_preempt_queue(cfqd, cfqq);
-	}
-}
-
-static int cfq_reinsert_request(struct request_queue *q, struct request *rq)
-{
-	struct cfq_data *cfqd = q->elevator->elevator_data;
-	struct cfq_queue *cfqq = RQ_CFQQ(rq);
-
-	if (!cfqq || cfqq->cfqd != cfqd)
-		return -EIO;
-
-	cfq_log_cfqq(cfqd, cfqq, "re-insert_request");
-	list_add(&rq->queuelist, &cfqq->fifo);
-	cfq_add_rq_rb(rq);
-
-	cfq_rq_requeued(cfqd, cfqq, rq);
-	if (rq->cmd_flags & REQ_URGENT) {
-			if (cfqd->nr_urgent_in_flight)
-				cfqd->nr_urgent_in_flight--;
-			cfqd->nr_urgent_pending++;
-	}
-	return 0;
-}
-
 static void cfq_insert_request(struct request_queue *q, struct request *rq)
 {
 	struct cfq_data *cfqd = q->elevator->elevator_data;
@@ -3282,45 +3208,7 @@
 	cfq_blkiocg_update_io_add_stats(&(RQ_CFQG(rq))->blkg,
 			&cfqd->serving_group->blkg, rq_data_dir(rq),
 			rq_is_sync(rq));
-
 	cfq_rq_enqueued(cfqd, cfqq, rq);
-
-	if (rq->cmd_flags & REQ_URGENT) {
-		WARN_ON(1);
-		blk_dump_rq_flags(rq, "");
-		rq->cmd_flags &= ~REQ_URGENT;
-	}
-
-	/* Request is considered URGENT if:
-	 * 1. The queue being served is of a lower IO priority then the new
-	 *    request
-	 * OR:
-	 * 2. The workload being performed is ASYNC
-	 * Only READ requests may be considered as URGENT
-	 */
-	if ((cfqd->active_queue &&
-		 cfqq->ioprio_class < cfqd->active_queue->ioprio_class) ||
-		(cfqd->serving_type == ASYNC_WORKLOAD &&
-		 rq_data_dir(rq) == READ)) {
-		rq->cmd_flags |= REQ_URGENT;
-		cfqd->nr_urgent_pending++;
-	}
-}
-
-
-/**
- * cfq_urgent_pending() - Return TRUE if there is an urgent
- *			  request on scheduler
- * @q:	requests queue
- */
-static bool cfq_urgent_pending(struct request_queue *q)
-{
-	struct cfq_data *cfqd = q->elevator->elevator_data;
-
-	if (cfqd->nr_urgent_pending && !cfqd->nr_urgent_in_flight)
-		return true;
-
-	return false;
 }
 
 /*
@@ -3404,14 +3292,6 @@
 	const int sync = rq_is_sync(rq);
 	unsigned long now;
 
-	if (rq->cmd_flags & REQ_URGENT) {
-		if (!cfqd->nr_urgent_in_flight)
-			WARN_ON(1);
-		else
-			cfqd->nr_urgent_in_flight--;
-		rq->cmd_flags &= ~REQ_URGENT;
-	}
-
 	now = jiffies;
 	cfq_log_cfqq(cfqd, cfqq, "complete rqnoidle %d",
 		     !!(rq->cmd_flags & REQ_NOIDLE));
@@ -3979,8 +3859,6 @@
 		.elevator_bio_merged_fn =	cfq_bio_merged,
 		.elevator_dispatch_fn =		cfq_dispatch_requests,
 		.elevator_add_req_fn =		cfq_insert_request,
-		.elevator_reinsert_req_fn	= cfq_reinsert_request,
-		.elevator_is_urgent_fn		= cfq_urgent_pending,
 		.elevator_activate_req_fn =	cfq_activate_request,
 		.elevator_deactivate_req_fn =	cfq_deactivate_request,
 		.elevator_completed_req_fn =	cfq_completed_request,
diff --git a/block/elevator.c b/block/elevator.c
index 55f1f1e..44193a8 100644
--- a/block/elevator.c
+++ b/block/elevator.c
@@ -842,6 +842,7 @@
 
 	if (rq->cmd_flags & REQ_URGENT) {
 		q->notified_urgent = false;
+		WARN_ON(!q->dispatched_urgent);
 		q->dispatched_urgent = false;
 	}
 	/*
diff --git a/block/row-iosched.c b/block/row-iosched.c
index 8e19c94..dfb46b4 100644
--- a/block/row-iosched.c
+++ b/block/row-iosched.c
@@ -396,7 +396,6 @@
 				"added urgent request (total on queue=%d)",
 				rqueue->nr_req);
 			rq->cmd_flags |= REQ_URGENT;
-			WARN_ON(rqueue->nr_req > 1);
 			rd->pending_urgent_rq = rq;
 		}
 	} else
diff --git a/drivers/base/sync.c b/drivers/base/sync.c
index 2e35996..abde6d9 100644
--- a/drivers/base/sync.c
+++ b/drivers/base/sync.c
@@ -34,7 +34,7 @@
 static void sync_fence_signal_pt(struct sync_pt *pt);
 static int _sync_pt_has_signaled(struct sync_pt *pt);
 static void sync_fence_free(struct kref *kref);
-static void sync_dump(void);
+static void sync_dump(struct sync_fence *fence);
 
 static LIST_HEAD(sync_timeline_list_head);
 static DEFINE_SPINLOCK(sync_timeline_list_lock);
@@ -611,7 +611,7 @@
 
 	if (fence->status < 0) {
 		pr_info("fence error %d on [%p]\n", fence->status, fence);
-		sync_dump();
+		sync_dump(fence);
 		return fence->status;
 	}
 
@@ -619,7 +619,7 @@
 		if (timeout > 0) {
 			pr_info("fence timeout on [%p] after %dms\n", fence,
 				jiffies_to_msecs(timeout));
-			sync_dump();
+			sync_dump(fence);
 		}
 		return -ETIME;
 	}
@@ -986,7 +986,7 @@
 
 #define DUMP_CHUNK 256
 static char sync_dump_buf[64 * 1024];
-void sync_dump(void)
+static void sync_dump(struct sync_fence *fence)
 {
        struct seq_file s = {
                .buf = sync_dump_buf,
@@ -994,7 +994,9 @@
        };
        int i;
 
-       sync_debugfs_show(&s, NULL);
+       seq_printf(&s, "fence:\n--------------\n");
+       sync_print_fence(&s, fence);
+       seq_printf(&s, "\n");
 
        for (i = 0; i < s.count; i += DUMP_CHUNK) {
                if ((s.count - i) > DUMP_CHUNK) {
@@ -1009,7 +1011,7 @@
        }
 }
 #else
-static void sync_dump(void)
+static void sync_dump(struct sync_fence *fence)
 {
 }
 #endif
diff --git a/drivers/bif/bif-core.c b/drivers/bif/bif-core.c
index e11e6ba4..7bc9af2 100644
--- a/drivers/bif/bif-core.c
+++ b/drivers/bif/bif-core.c
@@ -2827,6 +2827,7 @@
 	struct bif_ctrl_dev *bdev = ERR_PTR(-EINVAL);
 	struct bif_slave_dev *sdev;
 	bool battery_present = false;
+	bool slaves_present = false;
 	int rc, rid_ohm;
 
 	if (!bif_desc) {
@@ -2901,12 +2902,21 @@
 	list_for_each_entry(sdev, &bif_sdev_list, list) {
 		if (sdev->present) {
 			battery_present = true;
+			slaves_present = true;
 			break;
 		}
 	}
 
 	BLOCKING_INIT_NOTIFIER_HEAD(&bdev->bus_change_notifier);
 
+	/* Disable the BIF bus master if no slaves are found. */
+	if (!slaves_present) {
+		rc = bdev->desc->ops->set_bus_state(bdev,
+			BIF_BUS_STATE_MASTER_DISABLED);
+		if (rc < 0)
+			pr_err("Could not disble BIF master, rc=%d\n", rc);
+	}
+
 	if (battery_present) {
 		bdev->battery_present = true;
 		rc = blocking_notifier_call_chain(&bdev->bus_change_notifier,
diff --git a/drivers/bif/qpnp-bsi.c b/drivers/bif/qpnp-bsi.c
index 9d0abd2..19a560a 100644
--- a/drivers/bif/qpnp-bsi.c
+++ b/drivers/bif/qpnp-bsi.c
@@ -1162,6 +1162,7 @@
 			+ QPNP_BSI_POWER_UP_LOW_DELAY_US);
 		break;
 	case BIF_BUS_STATE_POWER_DOWN:
+	case BIF_BUS_STATE_MASTER_DISABLED:
 		msleep(QPNP_BSI_MAX_SLAVE_POWER_UP_DELAY_MS);
 		break;
 	}
@@ -1180,13 +1181,34 @@
 {
 	struct qpnp_bsi_chip *chip = bdev_get_drvdata(bdev);
 	int rc = 0;
+	u8 reg;
 
 	if (state == chip->state)
 		return 0;
 
+	if (chip->state == BIF_BUS_STATE_MASTER_DISABLED) {
+		/*
+		 * Enable the BSI peripheral when transitioning from a disabled
+		 * bus state to any of the active bus states so that BIF
+		 * transactions can take place.
+		 */
+		reg = QPNP_BSI_ENABLE;
+		rc = qpnp_bsi_write(chip, QPNP_BSI_REG_ENABLE, &reg, 1);
+		if (rc) {
+			dev_err(&chip->spmi_dev->dev, "%s: qpnp_bsi_write() failed, rc=%d\n",
+				__func__, rc);
+			return rc;
+		}
+	}
+
 	switch (state) {
 	case BIF_BUS_STATE_MASTER_DISABLED:
-		pr_info("master disable not yet supported.\n");
+		/* Disable the BSI peripheral. */
+		reg = QPNP_BSI_DISABLE;
+		rc = qpnp_bsi_write(chip, QPNP_BSI_REG_ENABLE, &reg, 1);
+		if (rc)
+			dev_err(&chip->spmi_dev->dev, "%s: qpnp_bsi_write() failed, rc=%d\n",
+				__func__, rc);
 		break;
 	case BIF_BUS_STATE_POWER_DOWN:
 		rc = qpnp_bsi_bus_transaction(bdev, BIF_TRANS_BC, BIF_CMD_PDWN);
@@ -1624,7 +1646,7 @@
 	struct device *dev = &spmi->dev;
 	struct qpnp_bsi_chip *chip;
 	int rc;
-	u8 type[2], reg;
+	u8 type[2];
 
 	if (!spmi->dev.of_node) {
 		dev_err(dev, "%s: device node missing\n", __func__);
@@ -1655,7 +1677,7 @@
 
 	chip->spmi_dev		= spmi;
 	chip->bdesc.ops		= &qpnp_bsi_ops;
-	chip->state		= BIF_BUS_STATE_POWER_DOWN;
+	chip->state		= BIF_BUS_STATE_MASTER_DISABLED;
 	chip->com_mode		= QPNP_BSI_COM_MODE_IRQ;
 
 	rc = qpnp_bsi_read(chip, QPNP_BSI_REG_TYPE, type, 2);
@@ -1691,15 +1713,6 @@
 		goto cleanup_irqs;
 	}
 
-	/* Enable the BSI module. */
-	reg = QPNP_BSI_ENABLE;
-	rc = qpnp_bsi_write(chip, QPNP_BSI_REG_ENABLE, &reg, 1);
-	if (rc) {
-		dev_err(dev, "%s: qpnp_bsi_write() failed, rc=%d\n",
-			__func__, rc);
-		goto cleanup_irqs;
-	}
-
 	chip->bdev = bif_ctrl_register(&chip->bdesc, dev, chip,
 					spmi->dev.of_node);
 	if (IS_ERR(chip->bdev)) {
diff --git a/drivers/char/adsprpc.c b/drivers/char/adsprpc.c
index a740be6..4507f80 100644
--- a/drivers/char/adsprpc.c
+++ b/drivers/char/adsprpc.c
@@ -232,7 +232,7 @@
 	buf->virt = 0;
 	heap = me->smmu.enabled ? ION_HEAP(ION_IOMMU_HEAP_ID) :
 		ION_HEAP(ION_ADSP_HEAP_ID) | ION_HEAP(ION_AUDIO_HEAP_ID);
-	buf->handle = ion_alloc(clnt, buf->size, SZ_4K, heap, 0);
+	buf->handle = ion_alloc(clnt, buf->size, SZ_4K, heap, ION_FLAG_CACHED);
 	VERIFY(err, 0 == IS_ERR_OR_NULL(buf->handle));
 	if (err)
 		goto bail;
diff --git a/drivers/char/diag/diag_dci.c b/drivers/char/diag/diag_dci.c
index a779b24..97dc26d 100644
--- a/drivers/char/diag/diag_dci.c
+++ b/drivers/char/diag/diag_dci.c
@@ -209,9 +209,16 @@
 		event_id_packet = *(uint16_t *)(buf + temp_len);
 		event_id = event_id_packet & 0x0FFF; /* extract 12 bits */
 		if (event_id_packet & 0x8000) {
+			/* The packet has the two smallest byte of the
+			 * timestamp
+			 */
 			timestamp_len = 2;
-			memset(timestamp, 0, 8);
 		} else {
+			/* The packet has the full timestamp. The first event
+			 * will always have full timestamp. Save it in the
+			 * timestamp buffer and use it for subsequent events if
+			 * necessary.
+			 */
 			timestamp_len = 8;
 			memcpy(timestamp, buf + temp_len + 2, timestamp_len);
 		}
@@ -459,6 +466,7 @@
 	if ((read_len + 9) >= USER_SPACE_DATA) {
 		pr_err("diag: dci: Invalid length while forming dci pkt in %s",
 								__func__);
+		mutex_unlock(&driver->dci_mutex);
 		return -EIO;
 	}
 
diff --git a/drivers/char/diag/diag_debugfs.c b/drivers/char/diag/diag_debugfs.c
index a24fc54..c4f762d 100644
--- a/drivers/char/diag/diag_debugfs.c
+++ b/drivers/char/diag/diag_debugfs.c
@@ -86,6 +86,25 @@
 		"Lpass hdlc encoding: %d\n"
 		"RIVA hdlc encoding: %d\n"
 		"Modem CMD hdlc encoding: %d\n"
+		"Modem DATA in_buf_1_size: %d\n"
+		"Modem DATA in_buf_2_size: %d\n"
+		"ADSP DATA in_buf_1_size: %d\n"
+		"ADSP DATA in_buf_2_size: %d\n"
+		"RIVA DATA in_buf_1_size: %d\n"
+		"RIVA DATA in_buf_2_size: %d\n"
+		"Modem DATA in_buf_1_raw_size: %d\n"
+		"Modem DATA in_buf_2_raw_size: %d\n"
+		"ADSP DATA in_buf_1_raw_size: %d\n"
+		"ADSP DATA in_buf_2_raw_size: %d\n"
+		"RIVA DATA in_buf_1_raw_size: %d\n"
+		"RIVA DATA in_buf_2_raw_size: %d\n"
+		"Modem CMD in_buf_1_size: %d\n"
+		"Modem CMD in_buf_1_raw_size: %d\n"
+		"Modem CNTL in_buf_1_size: %d\n"
+		"ADSP CNTL in_buf_1_size: %d\n"
+		"RIVA CNTL in_buf_1_size: %d\n"
+		"Modem DCI in_buf_1_size: %d\n"
+		"Modem DCI CMD in_buf_1_size: %d\n"
 		"logging_mode: %d\n"
 		"real_time_mode: %d\n",
 		(unsigned int)driver->smd_data[MODEM_DATA].ch,
@@ -133,6 +152,25 @@
 		driver->smd_data[LPASS_DATA].encode_hdlc,
 		driver->smd_data[WCNSS_DATA].encode_hdlc,
 		driver->smd_cmd[MODEM_DATA].encode_hdlc,
+		(unsigned int)driver->smd_data[MODEM_DATA].buf_in_1_size,
+		(unsigned int)driver->smd_data[MODEM_DATA].buf_in_2_size,
+		(unsigned int)driver->smd_data[LPASS_DATA].buf_in_1_size,
+		(unsigned int)driver->smd_data[LPASS_DATA].buf_in_2_size,
+		(unsigned int)driver->smd_data[WCNSS_DATA].buf_in_1_size,
+		(unsigned int)driver->smd_data[WCNSS_DATA].buf_in_2_size,
+		(unsigned int)driver->smd_data[MODEM_DATA].buf_in_1_raw_size,
+		(unsigned int)driver->smd_data[MODEM_DATA].buf_in_2_raw_size,
+		(unsigned int)driver->smd_data[LPASS_DATA].buf_in_1_raw_size,
+		(unsigned int)driver->smd_data[LPASS_DATA].buf_in_2_raw_size,
+		(unsigned int)driver->smd_data[WCNSS_DATA].buf_in_1_raw_size,
+		(unsigned int)driver->smd_data[WCNSS_DATA].buf_in_2_raw_size,
+		(unsigned int)driver->smd_cmd[MODEM_DATA].buf_in_1_size,
+		(unsigned int)driver->smd_cmd[MODEM_DATA].buf_in_1_raw_size,
+		(unsigned int)driver->smd_cntl[MODEM_DATA].buf_in_1_size,
+		(unsigned int)driver->smd_cntl[LPASS_DATA].buf_in_1_size,
+		(unsigned int)driver->smd_cntl[WCNSS_DATA].buf_in_1_size,
+		(unsigned int)driver->smd_dci[MODEM_DATA].buf_in_1_size,
+		(unsigned int)driver->smd_dci_cmd[MODEM_DATA].buf_in_1_size,
 		driver->logging_mode,
 		driver->real_time_mode);
 
@@ -350,19 +388,21 @@
 		bytes_written = scnprintf(buf+bytes_in_buffer, bytes_remaining,
 			"i: %3d, cmd_code: %4x, subsys_id: %4x, "
 			"client: %2d, cmd_code_lo: %4x, "
-			"cmd_code_hi: %4x, process_id: %5d\n",
+			"cmd_code_hi: %4x, process_id: %5d %s\n",
 			i,
 			driver->table[i].cmd_code,
 			driver->table[i].subsys_id,
 			driver->table[i].client_id,
 			driver->table[i].cmd_code_lo,
 			driver->table[i].cmd_code_hi,
-			driver->table[i].process_id);
+			driver->table[i].process_id,
+			(diag_find_polling_reg(i) ? "<- Polling cmd reg" : ""));
 
 		bytes_in_buffer += bytes_written;
 
 		/* Check if there is room to add another table entry */
 		bytes_remaining = buf_size - bytes_in_buffer;
+
 		if (bytes_remaining < bytes_written)
 			break;
 	}
diff --git a/drivers/char/diag/diag_masks.c b/drivers/char/diag/diag_masks.c
index c91095e..69e6250 100644
--- a/drivers/char/diag/diag_masks.c
+++ b/drivers/char/diag/diag_masks.c
@@ -19,12 +19,15 @@
 #include "diagfwd_cntl.h"
 #include "diag_masks.h"
 
-int diag_event_config;
 int diag_event_num_bytes;
 
+#define DIAG_CTRL_MASK_INVALID		0
+#define DIAG_CTRL_MASK_ALL_DISABLED	1
+#define DIAG_CTRL_MASK_ALL_ENABLED	2
+#define DIAG_CTRL_MASK_VALID		3
+
 #define ALL_EQUIP_ID		100
 #define ALL_SSID		-1
-#define MAX_SSID_PER_RANGE	100
 
 #define FEATURE_MASK_LEN_BYTES		2
 
@@ -106,6 +109,8 @@
 	uint8_t *parse_ptr, *ptr = driver->msg_masks;
 
 	mutex_lock(&driver->diagchar_mutex);
+	driver->msg_status = rt_mask ? DIAG_CTRL_MASK_ALL_ENABLED :
+						DIAG_CTRL_MASK_ALL_DISABLED;
 	while (*(uint32_t *)(ptr + 4)) {
 		first_ssid = *(uint32_t *)ptr;
 		ptr += 8; /* increment by 8 to skip 'last' */
@@ -129,9 +134,9 @@
 	uint8_t *ptr = driver->msg_masks;
 	uint8_t *ptr_buffer_start = &(*(driver->msg_masks));
 	uint8_t *ptr_buffer_end = &(*(driver->msg_masks)) + MSG_MASK_SIZE;
+	uint32_t copy_len = (end - start + 1) * sizeof(int);
 
 	mutex_lock(&driver->diagchar_mutex);
-
 	/* First SSID can be zero : So check that last is non-zero */
 	while (*(uint32_t *)(ptr + 4)) {
 		first = *(uint32_t *)ptr;
@@ -148,11 +153,19 @@
 				actual_last = end;
 				*(uint32_t *)(actual_last_ptr) = end;
 			}
+			if (actual_last-first >= MAX_SSID_PER_RANGE) {
+				pr_err("diag: In %s, truncating ssid range, %d-%d to max allowed: %d",
+						__func__, first, actual_last,
+						MAX_SSID_PER_RANGE);
+				copy_len = MAX_SSID_PER_RANGE;
+				actual_last = first + MAX_SSID_PER_RANGE;
+				*(uint32_t *)actual_last_ptr = actual_last;
+			}
 			if (CHK_OVERFLOW(ptr_buffer_start, ptr, ptr_buffer_end,
-					  (((end - start)+1)*4))) {
+								copy_len)) {
 				pr_debug("diag: update ssid start %d, end %d\n",
 								 start, end);
-				memcpy(ptr, buf , ((end - start)+1)*4);
+				memcpy(ptr, buf, copy_len);
 			} else
 				pr_alert("diag: Not enough space MSG_MASK\n");
 			found = 1;
@@ -177,6 +190,7 @@
 		} else
 			pr_alert("diag: Not enough buffer space for MSG_MASK\n");
 	}
+	driver->msg_status = DIAG_CTRL_MASK_VALID;
 	mutex_unlock(&driver->diagchar_mutex);
 	diag_print_mask_table();
 }
@@ -186,28 +200,29 @@
 	uint8_t *ptr = driver->event_masks;
 
 	mutex_lock(&driver->diagchar_mutex);
-	if (toggle)
+	if (toggle) {
+		driver->event_status = DIAG_CTRL_MASK_ALL_ENABLED;
 		memset(ptr, 0xFF, EVENT_MASK_SIZE);
-	else
+	} else {
+		driver->event_status = DIAG_CTRL_MASK_ALL_DISABLED;
 		memset(ptr, 0, EVENT_MASK_SIZE);
+	}
 	mutex_unlock(&driver->diagchar_mutex);
 }
 
 
-static void diag_update_event_mask(uint8_t *buf, int toggle, int num_bytes)
+static void diag_update_event_mask(uint8_t *buf, int num_bytes)
 {
 	uint8_t *ptr = driver->event_masks;
 	uint8_t *temp = buf + 2;
 
 	mutex_lock(&driver->diagchar_mutex);
-	if (!toggle)
-		memset(ptr, 0 , EVENT_MASK_SIZE);
-	else
-		if (CHK_OVERFLOW(ptr, ptr,
-				 ptr+EVENT_MASK_SIZE, num_bytes))
-			memcpy(ptr, temp , num_bytes);
-		else
-			printk(KERN_CRIT "Not enough buffer space for EVENT_MASK\n");
+	if (CHK_OVERFLOW(ptr, ptr, ptr+EVENT_MASK_SIZE, num_bytes)) {
+		memcpy(ptr, temp, num_bytes);
+		driver->event_status = DIAG_CTRL_MASK_VALID;
+	} else {
+		pr_err("diag: In %s, not enough buffer space\n", __func__);
+	}
 	mutex_unlock(&driver->diagchar_mutex);
 }
 
@@ -226,6 +241,7 @@
 			    (parse_ptr->num_items + 7)/8);
 		parse_ptr++;
 	}
+	driver->log_status = DIAG_CTRL_MASK_ALL_DISABLED;
 	mutex_unlock(&driver->diagchar_mutex);
 }
 
@@ -282,10 +298,13 @@
 	}
 	ptr_data = driver->log_masks + offset;
 	if (CHK_OVERFLOW(driver->log_masks, ptr_data, driver->log_masks
-					 + LOG_MASK_SIZE, (num_items+7)/8))
-		memcpy(ptr_data, temp , (num_items+7)/8);
-	else
+					 + LOG_MASK_SIZE, (num_items+7)/8)) {
+		memcpy(ptr_data, temp, (num_items+7)/8);
+		driver->log_status = DIAG_CTRL_MASK_VALID;
+	} else {
 		pr_err("diag: Not enough buffer space for LOG_MASK\n");
+		driver->log_status = DIAG_CTRL_MASK_INVALID;
+	}
 	mutex_unlock(&driver->diagchar_mutex);
 }
 
@@ -300,11 +319,11 @@
 		return;
 	}
 
+	diag_send_feature_mask_update(smd_info);
 	diag_send_msg_mask_update(smd_info->ch, ALL_SSID, ALL_SSID,
 						smd_info->peripheral);
 	diag_send_log_mask_update(smd_info->ch, ALL_EQUIP_ID);
 	diag_send_event_mask_update(smd_info->ch, diag_event_num_bytes);
-	diag_send_feature_mask_update(smd_info);
 
 	if (smd_info->notify_context == SMD_EVENT_OPEN)
 		diag_send_diag_mode_update_by_smd(smd_info,
@@ -330,15 +349,36 @@
 		driver->log_mask->num_items = ptr->num_items;
 		driver->log_mask->data_len  = 11 + size;
 		driver->log_mask->stream_id = 1; /* 2, if dual stream */
-		driver->log_mask->status = 3; /* status for valid mask */
 		driver->log_mask->equip_id = ptr->equip_id;
-		driver->log_mask->log_mask_size = size;
+		driver->log_mask->status = driver->log_status;
+		switch (driver->log_status) {
+		case DIAG_CTRL_MASK_ALL_DISABLED:
+			driver->log_mask->log_mask_size = 0;
+			break;
+		case DIAG_CTRL_MASK_ALL_ENABLED:
+			driver->log_mask->log_mask_size = 0;
+			break;
+		case DIAG_CTRL_MASK_VALID:
+			driver->log_mask->log_mask_size = size;
+			break;
+		default:
+			/* Log status is not set or the buffer is corrupted */
+			pr_err("diag: In %s, invalid status %d", __func__,
+							driver->log_status);
+			driver->log_mask->status = DIAG_CTRL_MASK_INVALID;
+		}
+
+		if (driver->log_mask->status == DIAG_CTRL_MASK_INVALID) {
+			mutex_unlock(&driver->diag_cntl_mutex);
+			return;
+		}
 		/* send only desired update, NOT ALL */
 		if (equip_id == ALL_EQUIP_ID || equip_id ==
 					 driver->log_mask->equip_id) {
 			memcpy(buf, driver->log_mask, header_size);
-			memcpy(buf+header_size, driver->log_masks+ptr->index,
-									 size);
+			if (driver->log_status == DIAG_CTRL_MASK_VALID)
+				memcpy(buf + header_size,
+				       driver->log_masks+ptr->index, size);
 			if (ch) {
 				while (retry_count < 3) {
 					wr_size = smd_write(ch, buf,
@@ -380,11 +420,34 @@
 	driver->event_mask->cmd_type = DIAG_CTRL_MSG_EVENT_MASK;
 	driver->event_mask->data_len = 7 + num_bytes;
 	driver->event_mask->stream_id = 1; /* 2, if dual stream */
-	driver->event_mask->status = 3; /* status for valid mask */
-	driver->event_mask->event_config = diag_event_config; /* event config */
-	driver->event_mask->event_mask_size = num_bytes;
+	driver->event_mask->status = driver->event_status;
+
+	switch (driver->event_status) {
+	case DIAG_CTRL_MASK_ALL_DISABLED:
+		driver->event_mask->event_config = 0;
+		driver->event_mask->event_mask_size = 0;
+		break;
+	case DIAG_CTRL_MASK_ALL_ENABLED:
+		driver->event_mask->event_config = 1;
+		driver->event_mask->event_mask_size = 0;
+		break;
+	case DIAG_CTRL_MASK_VALID:
+		driver->event_mask->event_config = 1;
+		driver->event_mask->event_mask_size = num_bytes;
+		memcpy(buf + header_size, driver->event_masks, num_bytes);
+		break;
+	default:
+		/* Event status is not set yet or the buffer is corrupted */
+		pr_err("diag: In %s, invalid status %d", __func__,
+							driver->event_status);
+		driver->event_mask->status = DIAG_CTRL_MASK_INVALID;
+	}
+
+	if (driver->event_mask->status == DIAG_CTRL_MASK_INVALID) {
+		mutex_unlock(&driver->diag_cntl_mutex);
+		return;
+	}
 	memcpy(buf, driver->event_mask, header_size);
-	memcpy(buf+header_size, driver->event_masks, num_bytes);
 	if (ch) {
 		while (retry_count < 3) {
 			wr_size = smd_write(ch, buf, header_size + num_bytes);
@@ -418,44 +481,78 @@
 		ptr += 4;
 		actual_last = *(uint32_t *)ptr;
 		ptr += 4;
-		if ((updated_ssid_first >= first && updated_ssid_last <=
-			 actual_last) || (updated_ssid_first == ALL_SSID)) {
-			/* send f3 mask update */
-			driver->msg_mask->cmd_type = DIAG_CTRL_MSG_F3_MASK;
-			driver->msg_mask->msg_mask_size = actual_last -
-								 first + 1;
-			driver->msg_mask->data_len = 11 +
-					 4 * (driver->msg_mask->msg_mask_size);
-			driver->msg_mask->stream_id = 1; /* 2, if dual stream */
-			driver->msg_mask->status = 3; /* status valid mask */
-			driver->msg_mask->msg_mode = 0; /* Legcay mode */
-			driver->msg_mask->ssid_first = first;
-			driver->msg_mask->ssid_last = actual_last;
-			memcpy(buf, driver->msg_mask, header_size);
+		if (!((updated_ssid_first >= first && updated_ssid_last <=
+			 actual_last) || (updated_ssid_first == ALL_SSID))) {
+			ptr += MAX_SSID_PER_RANGE*4;
+			continue;
+		}
+		/* send f3 mask update */
+		driver->msg_mask->cmd_type = DIAG_CTRL_MSG_F3_MASK;
+		driver->msg_mask->status = driver->msg_status;
+		switch (driver->msg_status) {
+		case DIAG_CTRL_MASK_ALL_DISABLED:
+			driver->msg_mask->msg_mask_size = 0;
+			break;
+		case DIAG_CTRL_MASK_ALL_ENABLED:
+			driver->msg_mask->msg_mask_size = 1;
 			memcpy(buf+header_size, ptr,
 				 4 * (driver->msg_mask->msg_mask_size));
-			if (ch) {
-				while (retry_count < 3) {
-					size = smd_write(ch, buf, header_size +
-					 4*(driver->msg_mask->msg_mask_size));
-					if (size == -ENOMEM) {
-						retry_count++;
-						usleep_range(10000, 10100);
-					} else
-						break;
-				}
-				if (size != header_size +
-					 4*(driver->msg_mask->msg_mask_size))
-					pr_err("diag: proc %d, msg mask update fail %d, tried %d\n",
-						proc, size, (header_size +
-					4*(driver->msg_mask->msg_mask_size)));
-				else
-					pr_debug("diag: sending mask update for ssid first %d, last %d on PROC %d\n",
-						first, actual_last, proc);
-			} else
-				pr_err("diag: proc %d, ch invalid msg mask update\n",
-					proc);
+			break;
+		case DIAG_CTRL_MASK_VALID:
+			driver->msg_mask->msg_mask_size = actual_last -
+								first + 1;
+			/* Limit the msg_mask_size to MAX_SSID_PER_RANGE */
+			if (driver->msg_mask->msg_mask_size >
+							MAX_SSID_PER_RANGE) {
+				pr_err("diag: in %s, Invalid msg mask size %d, max: %d",
+					__func__,
+				       driver->msg_mask->msg_mask_size,
+				       MAX_SSID_PER_RANGE);
+				driver->msg_mask->msg_mask_size =
+							MAX_SSID_PER_RANGE;
+			}
+			memcpy(buf+header_size, ptr,
+				 4 * (driver->msg_mask->msg_mask_size));
+			break;
+		default:
+			/* Msg status is not set or the buffer is corrupted */
+			pr_err("diag: In %s, invalid status %d", __func__,
+							driver->msg_status);
+			driver->msg_mask->status = DIAG_CTRL_MASK_INVALID;
 		}
+
+		if (driver->msg_mask->status == DIAG_CTRL_MASK_INVALID) {
+			mutex_unlock(&driver->diag_cntl_mutex);
+			return;
+		}
+		driver->msg_mask->data_len = 11 +
+					4 * (driver->msg_mask->msg_mask_size);
+		driver->msg_mask->stream_id = 1; /* 2, if dual stream */
+		driver->msg_mask->msg_mode = 0; /* Legcay mode */
+		driver->msg_mask->ssid_first = first;
+		driver->msg_mask->ssid_last = actual_last;
+		memcpy(buf, driver->msg_mask, header_size);
+		if (ch) {
+			while (retry_count < 3) {
+				size = smd_write(ch, buf, header_size +
+				 4*(driver->msg_mask->msg_mask_size));
+				if (size == -ENOMEM) {
+					retry_count++;
+					usleep_range(10000, 10100);
+				} else
+					break;
+			}
+			if (size != header_size +
+				 4*(driver->msg_mask->msg_mask_size))
+				pr_err("diag: proc %d, msg mask update fail %d, tried %d\n",
+					proc, size, (header_size +
+				4*(driver->msg_mask->msg_mask_size)));
+			else
+				pr_debug("diag: sending mask update for ssid first %d, last %d on PROC %d\n",
+					first, actual_last, proc);
+		} else
+			pr_err("diag: proc %d, ch invalid msg mask update\n",
+								proc);
 		ptr += MAX_SSID_PER_RANGE*4;
 	}
 	mutex_unlock(&driver->diag_cntl_mutex);
@@ -706,8 +803,8 @@
 #endif
 	} else if (*buf == 0x82) {	/* event mask change */
 		buf += 4;
-		diag_event_num_bytes =  (*(uint16_t *)buf)/8+1;
-		diag_update_event_mask(buf, 1, (*(uint16_t *)buf)/8+1);
+		diag_event_num_bytes = (*(uint16_t *)buf)/8+1;
+		diag_update_event_mask(buf, diag_event_num_bytes);
 		diag_update_userspace_clients(EVENT_MASKS_TYPE);
 #if defined(CONFIG_DIAG_OVER_USB)
 		if (chk_apps_only()) {
@@ -729,7 +826,6 @@
 		}
 #endif
 	} else if (*buf == 0x60) {
-		diag_event_config = *(buf+1);
 		diag_toggle_event_mask(*(buf+1));
 		diag_update_userspace_clients(EVENT_MASKS_TYPE);
 #if defined(CONFIG_DIAG_OVER_USB)
@@ -764,6 +860,10 @@
 
 void diag_masks_init(void)
 {
+	driver->event_status = DIAG_CTRL_MASK_INVALID;
+	driver->msg_status = DIAG_CTRL_MASK_INVALID;
+	driver->log_status = DIAG_CTRL_MASK_INVALID;
+
 	if (driver->event_mask == NULL) {
 		driver->event_mask = kzalloc(sizeof(
 			struct diag_ctrl_event_mask), GFP_KERNEL);
diff --git a/drivers/char/diag/diagchar.h b/drivers/char/diag/diagchar.h
index 7ef1d80..e0a428d 100644
--- a/drivers/char/diag/diagchar.h
+++ b/drivers/char/diag/diagchar.h
@@ -64,6 +64,8 @@
 #define NUM_MEMORY_POOLS	4
 #endif
 
+#define MAX_SSID_PER_RANGE	200
+
 #define MODEM_DATA		0
 #define LPASS_DATA		1
 #define WCNSS_DATA		2
@@ -73,7 +75,13 @@
 #define HSIC_2_DATA		6
 #define SMUX_DATA		10
 #define APPS_PROC		1
-#define MSG_MASK_SIZE 10000
+/*
+ * Each row contains First (uint32_t), Last (uint32_t), Actual
+ * last (uint32_t) values along with the range of SSIDs
+ * (MAX_SSID_PER_RANGE*uint32_t).
+ * And there are MSG_MASK_TBL_CNT rows.
+ */
+#define MSG_MASK_SIZE		((MAX_SSID_PER_RANGE+3) * 4 * MSG_MASK_TBL_CNT)
 #define LOG_MASK_SIZE 8000
 #define EVENT_MASK_SIZE 1000
 #define USER_SPACE_DATA 8192
@@ -233,6 +241,12 @@
 	unsigned char *buf_in_1_raw;
 	unsigned char *buf_in_2_raw;
 
+	unsigned int buf_in_1_size;
+	unsigned int buf_in_2_size;
+
+	unsigned int buf_in_1_raw_size;
+	unsigned int buf_in_2_raw_size;
+
 	struct diag_request *write_ptr_1;
 	struct diag_request *write_ptr_2;
 
@@ -362,9 +376,12 @@
 	struct work_struct diag_drain_work;
 	struct workqueue_struct *diag_cntl_wq;
 	uint8_t *msg_masks;
+	uint8_t msg_status;
 	uint8_t *log_masks;
+	uint8_t log_status;
 	int log_masks_length;
 	uint8_t *event_masks;
+	uint8_t event_status;
 	uint8_t log_on_demand_support;
 	struct diag_master_table *table;
 	uint8_t *pkt_buf;
@@ -412,5 +429,6 @@
 extern uint16_t wrap_count;
 
 void diag_get_timestamp(char *time_str);
+int diag_find_polling_reg(int i);
 
 #endif
diff --git a/drivers/char/diag/diagchar_core.c b/drivers/char/diag/diagchar_core.c
index 24d7fac..19ff6f4 100644
--- a/drivers/char/diag/diagchar_core.c
+++ b/drivers/char/diag/diagchar_core.c
@@ -327,17 +327,19 @@
 	subsys_id = driver->table[i].subsys_id;
 	cmd_code_lo = driver->table[i].cmd_code_lo;
 	cmd_code_hi = driver->table[i].cmd_code_hi;
-	if (driver->table[i].cmd_code == 0x0C)
-		return 1;
-	else if (driver->table[i].cmd_code == 0xFF) {
-		if (subsys_id == 0x04 && cmd_code_hi == 0x0E &&
-			 cmd_code_lo == 0x0E)
+
+	if (driver->table[i].cmd_code == 0xFF) {
+		if (subsys_id == 0xFF && cmd_code_hi >= 0x0C &&
+			 cmd_code_lo <= 0x0C)
 			return 1;
-		else if (subsys_id == 0x08 && cmd_code_hi == 0x02 &&
-			 cmd_code_lo == 0x02)
+		if (subsys_id == 0x04 && cmd_code_hi >= 0x0E &&
+			 cmd_code_lo <= 0x0E)
 			return 1;
-		else if (subsys_id == 0x32 && cmd_code_hi == 0x03  &&
-			 cmd_code_lo == 0x03)
+		else if (subsys_id == 0x08 && cmd_code_hi >= 0x02 &&
+			 cmd_code_lo <= 0x02)
+			return 1;
+		else if (subsys_id == 0x32 && cmd_code_hi >= 0x03  &&
+			 cmd_code_lo <= 0x03)
 			return 1;
 	}
 	return 0;
@@ -356,7 +358,8 @@
 	}
 	/* re-scan the registration table */
 	for (i = 0; i < diag_max_reg; i++) {
-		if (diag_find_polling_reg(i) == 1) {
+		if (driver->table[i].process_id != 0 &&
+				diag_find_polling_reg(i) == 1) {
 			driver->polling_reg_flag = 1;
 			break;
 		}
@@ -1271,17 +1274,6 @@
 						data->write_ptr_1->length);
 					data->in_busy_1 = 0;
 				}
-				if (data->in_busy_2 == 1) {
-					num_data++;
-					/*Copy the length of data being passed*/
-					COPY_USER_SPACE_OR_EXIT(buf+ret,
-						(data->write_ptr_2->length), 4);
-					/*Copy the actual data being passed*/
-					COPY_USER_SPACE_OR_EXIT(buf+ret,
-						*(data->buf_in_2),
-						data->write_ptr_2->length);
-					data->in_busy_2 = 0;
-				}
 			}
 		}
 #ifdef CONFIG_DIAG_SDIO_PIPE
diff --git a/drivers/char/diag/diagchar_hdlc.c b/drivers/char/diag/diagchar_hdlc.c
index 2369c4d..7b24591 100644
--- a/drivers/char/diag/diagchar_hdlc.c
+++ b/drivers/char/diag/diagchar_hdlc.c
@@ -18,6 +18,7 @@
 #include <linux/fs.h>
 #include <linux/device.h>
 #include <linux/uaccess.h>
+#include <linux/ratelimit.h>
 #include <linux/crc-ccitt.h>
 #include "diagchar_hdlc.h"
 #include "diagchar.h"
@@ -234,3 +235,37 @@
 
 	return pkt_bnd;
 }
+
+int crc_check(uint8_t *buf, uint16_t len)
+{
+	uint16_t crc = CRC_16_L_SEED;
+	uint8_t sent_crc[2] = {0, 0};
+
+	/*
+	 * The minimum length of a valid incoming packet is 4. 1 byte
+	 * of data and 3 bytes for CRC
+	 */
+	if (!buf || len < 4) {
+		pr_err_ratelimited("diag: In %s, invalid packet or length, buf: 0x%x, len: %d",
+				   __func__, (int)buf, len);
+		return -EIO;
+	}
+
+	/*
+	 * Run CRC check for the original input. Skip the last 3 CRC
+	 * bytes
+	 */
+	crc = crc_ccitt(crc, buf, len-3);
+	crc ^= CRC_16_L_SEED;
+
+	/* Check the computed CRC against the original CRC bytes. */
+	sent_crc[0] = buf[len-3];
+	sent_crc[1] = buf[len-2];
+	if (crc != *((uint16_t *)sent_crc)) {
+		pr_debug("diag: In %s, crc mismatch. expected: %x, sent %x.\n",
+				__func__, crc, *((uint16_t *)sent_crc));
+		return -EIO;
+	}
+
+	return 0;
+}
diff --git a/drivers/char/diag/diagchar_hdlc.h b/drivers/char/diag/diagchar_hdlc.h
index e3378ac..2ba46f5 100644
--- a/drivers/char/diag/diagchar_hdlc.h
+++ b/drivers/char/diag/diagchar_hdlc.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2008-2009, 2012, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2008-2009, 2012-2013, The Linux Foundation. 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 and
@@ -53,6 +53,8 @@
 
 int diag_hdlc_decode(struct diag_hdlc_decode_type *hdlc);
 
+int crc_check(uint8_t *buf, uint16_t len);
+
 #define ESC_CHAR     0x7D
 #define ESC_MASK     0x20
 
diff --git a/drivers/char/diag/diagfwd.c b/drivers/char/diag/diagfwd.c
index a1f6b2c..c74ab99 100644
--- a/drivers/char/diag/diagfwd.c
+++ b/drivers/char/diag/diagfwd.c
@@ -56,6 +56,8 @@
 #define STM_RSP_SMD_COMPLY_INDEX	9
 #define STM_RSP_NUM_BYTES		10
 
+#define SMD_DRAIN_BUF_SIZE 4096
+
 int diag_debug_buf_idx;
 unsigned char diag_debug_buf[1024];
 /* Number of entries in table of buffers */
@@ -329,34 +331,34 @@
 	unsigned char *temp_buf;
 
 	if (max_size > IN_BUF_SIZE) {
-		if (max_size < MAX_IN_BUF_SIZE) {
-			pr_err("diag: In %s, SMD sending packet of %d bytes that may expand to %d bytes, peripheral: %d\n",
+		if (max_size > MAX_IN_BUF_SIZE) {
+			pr_err_ratelimited("diag: In %s, SMD sending packet of %d bytes that may expand to %d bytes, peripheral: %d\n",
 				__func__, total_recd, max_size,
 				smd_info->peripheral);
-			if (buf == smd_info->buf_in_1_raw) {
+			max_size = MAX_IN_BUF_SIZE;
+		}
+		if (buf == smd_info->buf_in_1_raw) {
+			/* Only realloc if we need to increase the size */
+			if (smd_info->buf_in_1_size < max_size) {
 				temp_buf = krealloc(smd_info->buf_in_1,
-							max_size, GFP_KERNEL);
+					max_size, GFP_KERNEL);
 				if (temp_buf) {
 					smd_info->buf_in_1 = temp_buf;
-					buf_size = max_size;
-				} else {
-					buf_size = 0;
-				}
-			} else {
-				temp_buf = krealloc(smd_info->buf_in_2,
-							max_size, GFP_KERNEL);
-				if (temp_buf) {
-					smd_info->buf_in_2 = temp_buf;
-					buf_size = max_size;
-				} else {
-					buf_size = 0;
+					smd_info->buf_in_1_size = max_size;
 				}
 			}
+			buf_size = smd_info->buf_in_1_size;
 		} else {
-			pr_err("diag: In %s, SMD sending packet of size %d. HDCL encoding can expand to more than %d bytes, peripheral: %d. Discarding.\n",
-				__func__, max_size, MAX_IN_BUF_SIZE,
-				smd_info->peripheral);
-			buf_size = 0;
+			/* Only realloc if we need to increase the size */
+			if (smd_info->buf_in_2_size < max_size) {
+				temp_buf = krealloc(smd_info->buf_in_2,
+					max_size, GFP_KERNEL);
+				if (temp_buf) {
+					smd_info->buf_in_2 = temp_buf;
+					smd_info->buf_in_2_size = max_size;
+				}
+			}
+			buf_size = smd_info->buf_in_2_size;
 		}
 	}
 
@@ -544,12 +546,96 @@
 	return 0;
 }
 
+static int diag_smd_resize_buf(struct diag_smd_info *smd_info, void **buf,
+			       unsigned int *buf_size,
+			       unsigned int requested_size)
+{
+	int success = 0;
+	void *temp_buf = NULL;
+	unsigned int new_buf_size = requested_size;
+
+	if (!smd_info)
+		return success;
+
+	if (requested_size <= MAX_IN_BUF_SIZE) {
+		pr_debug("diag: In %s, SMD peripheral: %d sending in packets up to %d bytes\n",
+			__func__, smd_info->peripheral, requested_size);
+	} else {
+		pr_err_ratelimited("diag: In %s, SMD peripheral: %d, Packet size sent: %d, Max size supported (%d) exceeded. Data beyond max size will be lost\n",
+			__func__, smd_info->peripheral, requested_size,
+			MAX_IN_BUF_SIZE);
+		new_buf_size = MAX_IN_BUF_SIZE;
+	}
+
+	/* Only resize if the buffer can be increased in size */
+	if (new_buf_size <= *buf_size) {
+		success = 1;
+		return success;
+	}
+
+	temp_buf = krealloc(*buf, new_buf_size, GFP_KERNEL);
+
+	if (temp_buf) {
+		/* Match the buffer and reset the pointer and size */
+		if (smd_info->encode_hdlc) {
+			/*
+			 * This smd channel is supporting HDLC encoding
+			 * on the apps
+			 */
+			void *temp_hdlc = NULL;
+			if (*buf == smd_info->buf_in_1_raw) {
+				smd_info->buf_in_1_raw = temp_buf;
+				smd_info->buf_in_1_raw_size = new_buf_size;
+				temp_hdlc = krealloc(smd_info->buf_in_1,
+							MAX_IN_BUF_SIZE,
+							GFP_KERNEL);
+				if (temp_hdlc) {
+					smd_info->buf_in_1 = temp_hdlc;
+					smd_info->buf_in_1_size =
+							MAX_IN_BUF_SIZE;
+				}
+			} else if (*buf == smd_info->buf_in_2_raw) {
+				smd_info->buf_in_2_raw = temp_buf;
+				smd_info->buf_in_2_raw_size = new_buf_size;
+				temp_hdlc = krealloc(smd_info->buf_in_2,
+							MAX_IN_BUF_SIZE,
+							GFP_KERNEL);
+				if (temp_hdlc) {
+					smd_info->buf_in_2 = temp_hdlc;
+					smd_info->buf_in_2_size =
+							MAX_IN_BUF_SIZE;
+				}
+			}
+		} else {
+			if (*buf == smd_info->buf_in_1) {
+				smd_info->buf_in_1 = temp_buf;
+				smd_info->buf_in_1_size = new_buf_size;
+			} else if (*buf == smd_info->buf_in_2) {
+				smd_info->buf_in_2 = temp_buf;
+				smd_info->buf_in_2_size = new_buf_size;
+			}
+		}
+		*buf = temp_buf;
+		*buf_size = new_buf_size;
+		success = 1;
+	} else {
+		pr_err_ratelimited("diag: In %s, SMD peripheral: %d. packet size sent: %d, resize to support failed. Data beyond %d will be lost\n",
+			__func__, smd_info->peripheral, requested_size,
+			*buf_size);
+	}
+
+	return success;
+}
+
 void diag_smd_send_req(struct diag_smd_info *smd_info)
 {
 	void *buf = NULL, *temp_buf = NULL;
 	int total_recd = 0, r = 0, pkt_len;
 	int loop_count = 0;
 	int notify = 0;
+	int buf_size = 0;
+	int resize_success = 0;
+	int buf_full = 0;
 
 	if (!smd_info) {
 		pr_err("diag: In %s, no smd info. Not able to read.\n",
@@ -561,27 +647,38 @@
 	if (smd_info->type == SMD_DATA_TYPE) {
 		/* If the data is raw and not hdlc encoded */
 		if (smd_info->encode_hdlc) {
-			if (!smd_info->in_busy_1)
+			if (!smd_info->in_busy_1) {
 				buf = smd_info->buf_in_1_raw;
-			else if (!smd_info->in_busy_2)
+				buf_size = smd_info->buf_in_1_raw_size;
+			} else if (!smd_info->in_busy_2) {
 				buf = smd_info->buf_in_2_raw;
+				buf_size = smd_info->buf_in_2_raw_size;
+			}
 		} else {
-			if (!smd_info->in_busy_1)
+			if (!smd_info->in_busy_1) {
 				buf = smd_info->buf_in_1;
-			else if (!smd_info->in_busy_2)
+				buf_size = smd_info->buf_in_1_size;
+			} else if (!smd_info->in_busy_2) {
 				buf = smd_info->buf_in_2;
+				buf_size = smd_info->buf_in_2_size;
+			}
 		}
 	} else if (smd_info->type == SMD_CMD_TYPE) {
 		/* If the data is raw and not hdlc encoded */
 		if (smd_info->encode_hdlc) {
-			if (!smd_info->in_busy_1)
+			if (!smd_info->in_busy_1) {
 				buf = smd_info->buf_in_1_raw;
+				buf_size = smd_info->buf_in_1_raw_size;
+			}
 		} else {
-			if (!smd_info->in_busy_1)
+			if (!smd_info->in_busy_1) {
 				buf = smd_info->buf_in_1;
+				buf_size = smd_info->buf_in_1_size;
+			}
 		}
 	} else if (!smd_info->in_busy_1) {
 		buf = smd_info->buf_in_1;
+		buf_size = smd_info->buf_in_1_size;
 	}
 
 	if (!buf && (smd_info->type == SMD_DCI_TYPE ||
@@ -589,18 +686,21 @@
 		diag_dci_try_deactivate_wakeup_source(smd_info->ch);
 
 	if (smd_info->ch && buf) {
-		temp_buf = buf;
 		pkt_len = smd_cur_packet_size(smd_info->ch);
 
 		if (pkt_len == 0 && (smd_info->type == SMD_DCI_TYPE ||
 					smd_info->type == SMD_DCI_CMD_TYPE))
 			diag_dci_try_deactivate_wakeup_source(smd_info->ch);
 
+		if (pkt_len > buf_size)
+			resize_success = diag_smd_resize_buf(smd_info, &buf,
+							&buf_size, pkt_len);
+		temp_buf = buf;
 		while (pkt_len && (pkt_len != total_recd)) {
 			loop_count++;
 			r = smd_read_avail(smd_info->ch);
-			pr_debug("diag: In %s, received pkt %d %d\n",
-				__func__, r, total_recd);
+			pr_debug("diag: In %s, SMD peripheral: %d, received pkt %d %d\n",
+				__func__, smd_info->peripheral, r, total_recd);
 			if (!r) {
 				/* Nothing to read from SMD */
 				wait_event(driver->smd_wait_q,
@@ -608,31 +708,19 @@
 					smd_read_avail(smd_info->ch)));
 				/* If the smd channel is open */
 				if (smd_info->ch) {
-					pr_debug("diag: In %s, return from wait_event\n",
-						__func__);
+					pr_debug("diag: In %s, SMD peripheral: %d, return from wait_event\n",
+						__func__, smd_info->peripheral);
 					continue;
 				} else {
-					pr_debug("diag: In %s, return from wait_event ch closed\n",
-						__func__);
+					pr_debug("diag: In %s, SMD peripheral: %d, return from wait_event ch closed\n",
+						__func__, smd_info->peripheral);
 					goto fail_return;
 				}
 			}
-			total_recd += r;
-			if (total_recd > IN_BUF_SIZE) {
-				if (total_recd < MAX_IN_BUF_SIZE) {
-					pr_err("diag: In %s, SMD sending in packets up to %d bytes\n",
-						__func__, total_recd);
-					buf = krealloc(buf, total_recd,
-						GFP_KERNEL);
-				} else {
-					pr_err("diag: In %s, SMD sending in packets more than %d bytes\n",
-						__func__, MAX_IN_BUF_SIZE);
-					goto fail_return;
-				}
-			}
+
 			if (pkt_len < r) {
-				pr_err("diag: In %s, SMD sending incorrect pkt\n",
-					__func__);
+				pr_err("diag: In %s, SMD peripheral: %d, sending incorrect pkt\n",
+					__func__, smd_info->peripheral);
 				goto fail_return;
 			}
 			if (pkt_len > r) {
@@ -641,17 +729,59 @@
 				smd_info->peripheral, smd_info->type);
 			}
 
-			/* keep reading for complete packet */
-			smd_read(smd_info->ch, temp_buf, r);
-			temp_buf += r;
+			/* Protect from going beyond the end of the buffer */
+			if (total_recd < buf_size) {
+				if (total_recd + r > buf_size) {
+					r = buf_size - total_recd;
+					buf_full = 1;
+				}
+
+				total_recd += r;
+
+				/* Keep reading for complete packet */
+				smd_read(smd_info->ch, temp_buf, r);
+				temp_buf += r;
+			} else {
+				/*
+				 * This block handles the very rare case of a
+				 * packet that is greater in length than what
+				 * we can support. In this case, we
+				 * incrementally drain the remaining portion
+				 * of the packet that will not fit in the
+				 * buffer, so that the entire packet is read
+				 * from the smd.
+				 */
+				int drain_bytes = (r > SMD_DRAIN_BUF_SIZE) ?
+							SMD_DRAIN_BUF_SIZE : r;
+				unsigned char *drain_buf = kzalloc(drain_bytes,
+								GFP_KERNEL);
+				if (drain_buf) {
+					total_recd += drain_bytes;
+					smd_read(smd_info->ch, drain_buf,
+							drain_bytes);
+					kfree(drain_buf);
+				} else {
+					pr_err("diag: In %s, SMD peripheral: %d, unable to allocate drain buffer\n",
+						__func__, smd_info->peripheral);
+					break;
+				}
+			}
 		}
 		if (!driver->real_time_mode && smd_info->type == SMD_DATA_TYPE)
 			process_lock_on_read(&smd_info->nrt_lock, pkt_len);
 
 		if (total_recd > 0) {
 			if (!buf) {
-				pr_err("diag: Out of diagmem for Modem\n");
+				pr_err("diag: In %s, SMD peripheral: %d, Out of diagmem for Modem\n",
+					__func__, smd_info->peripheral);
 			} else if (smd_info->process_smd_read_data) {
+				/*
+				 * If the buffer was totally filled, reset
+				 * total_recd appropriately
+				 */
+				if (buf_full)
+					total_recd = buf_size;
+
 				notify = smd_info->process_smd_read_data(
 						smd_info, buf, total_recd);
 				/* Poll SMD channels to check for data */
@@ -1514,7 +1644,7 @@
 void diag_process_hdlc(void *data, unsigned len)
 {
 	struct diag_hdlc_decode_type hdlc;
-	int ret, type = 0;
+	int ret, type = 0, crc_chk = 0;
 
 	mutex_lock(&driver->diag_hdlc_mutex);
 
@@ -1528,6 +1658,16 @@
 	hdlc.escaping = 0;
 
 	ret = diag_hdlc_decode(&hdlc);
+	if (ret) {
+		crc_chk = crc_check(hdlc.dest_ptr, hdlc.dest_idx);
+		if (crc_chk) {
+			/* CRC check failed. */
+			pr_err_ratelimited("diag: In %s, bad CRC. Dropping packet\n",
+								__func__);
+			mutex_unlock(&driver->diag_hdlc_mutex);
+			return;
+		}
+	}
 
 	/*
 	 * If the message is 3 bytes or less in length then the message is
@@ -1550,9 +1690,8 @@
 			return;
 		}
 	} else if (driver->debug_flag) {
-		printk(KERN_ERR "Packet dropped due to bad HDLC coding/CRC"
-				" errors or partial packet received, packet"
-				" length = %d\n", len);
+		pr_err("diag: In %s, partial packet received, dropping packet, len: %d\n",
+								__func__, len);
 		print_hex_dump(KERN_DEBUG, "Dropped Packet Data: ", 16, 1,
 					   DUMP_PREFIX_ADDRESS, data, len, 1);
 		driver->debug_flag = 0;
@@ -2098,6 +2237,7 @@
 		smd_info->buf_in_1 = kzalloc(IN_BUF_SIZE, GFP_KERNEL);
 		if (smd_info->buf_in_1 == NULL)
 			goto err;
+		smd_info->buf_in_1_size = IN_BUF_SIZE;
 		kmemleak_not_leak(smd_info->buf_in_1);
 	}
 
@@ -2115,6 +2255,7 @@
 			smd_info->buf_in_2 = kzalloc(IN_BUF_SIZE, GFP_KERNEL);
 			if (smd_info->buf_in_2 == NULL)
 				goto err;
+			smd_info->buf_in_2_size = IN_BUF_SIZE;
 			kmemleak_not_leak(smd_info->buf_in_2);
 		}
 		if (smd_info->write_ptr_2 == NULL) {
@@ -2132,6 +2273,7 @@
 								GFP_KERNEL);
 				if (smd_info->buf_in_1_raw == NULL)
 					goto err;
+				smd_info->buf_in_1_raw_size = IN_BUF_SIZE;
 				kmemleak_not_leak(smd_info->buf_in_1_raw);
 			}
 			if (smd_info->buf_in_2_raw == NULL) {
@@ -2139,6 +2281,7 @@
 								GFP_KERNEL);
 				if (smd_info->buf_in_2_raw == NULL)
 					goto err;
+				smd_info->buf_in_2_raw_size = IN_BUF_SIZE;
 				kmemleak_not_leak(smd_info->buf_in_2_raw);
 			}
 		}
@@ -2152,6 +2295,7 @@
 								GFP_KERNEL);
 			if (smd_info->buf_in_1_raw == NULL)
 				goto err;
+			smd_info->buf_in_1_raw_size = IN_BUF_SIZE;
 			kmemleak_not_leak(smd_info->buf_in_1_raw);
 		}
 	}
diff --git a/drivers/coresight/coresight-csr.c b/drivers/coresight/coresight-csr.c
index 6efab5b..6b20b20 100644
--- a/drivers/coresight/coresight-csr.c
+++ b/drivers/coresight/coresight-csr.c
@@ -94,7 +94,7 @@
 	csr_writel(drvdata, usbbamctrl, CSR_USBBAMCTRL);
 
 	usbflshctrl = csr_readl(drvdata, CSR_USBFLSHCTRL);
-	usbflshctrl = (usbflshctrl & ~0x3FFFC) | (0x1000 << 2);
+	usbflshctrl = (usbflshctrl & ~0x3FFFC) | (0xFFFF << 2);
 	csr_writel(drvdata, usbflshctrl, CSR_USBFLSHCTRL);
 	usbflshctrl |= 0x2;
 	csr_writel(drvdata, usbflshctrl, CSR_USBFLSHCTRL);
@@ -136,7 +136,7 @@
 }
 EXPORT_SYMBOL(msm_qdss_csr_disable_flush);
 
-int coresight_csr_hwctrl_set(phys_addr_t addr, uint32_t val)
+int coresight_csr_hwctrl_set(uint64_t addr, uint32_t val)
 {
 	struct csr_drvdata *drvdata = csrdrvdata;
 	int ret = 0;
diff --git a/drivers/coresight/coresight-cti.c b/drivers/coresight/coresight-cti.c
index d139583..6f7f743 100644
--- a/drivers/coresight/coresight-cti.c
+++ b/drivers/coresight/coresight-cti.c
@@ -295,6 +295,41 @@
 }
 EXPORT_SYMBOL(coresight_cti_unmap_trigout);
 
+static void __cti_reset(struct cti_drvdata *drvdata)
+{
+	int trig;
+
+	if (!drvdata->refcnt)
+		return;
+
+	CTI_UNLOCK(drvdata);
+
+	for (trig = 0; trig < CTI_MAX_TRIGGERS; trig++) {
+		cti_writel(drvdata, 0, CTIINEN(trig));
+		cti_writel(drvdata, 0, CTIOUTEN(trig));
+	}
+
+	CTI_LOCK(drvdata);
+
+	cti_disable(drvdata);
+	drvdata->refcnt = 0;
+}
+
+void coresight_cti_reset(struct coresight_cti *cti)
+{
+	struct cti_drvdata *drvdata;
+
+	if (IS_ERR_OR_NULL(cti))
+		return;
+
+	drvdata = to_cti_drvdata(cti);
+
+	mutex_lock(&drvdata->mutex);
+	__cti_reset(drvdata);
+	mutex_unlock(&drvdata->mutex);
+}
+EXPORT_SYMBOL(coresight_cti_reset);
+
 struct coresight_cti *coresight_cti_get(const char *name)
 {
 	struct coresight_cti *cti;
@@ -387,11 +422,106 @@
 }
 static DEVICE_ATTR(unmap_trigout, S_IWUSR, NULL, cti_store_unmap_trigout);
 
+static ssize_t cti_store_reset(struct device *dev,
+			       struct device_attribute *attr,
+			       const char *buf, size_t size)
+{
+	struct cti_drvdata *drvdata = dev_get_drvdata(dev->parent);
+	unsigned long val;
+
+	if (sscanf(buf, "%lx", &val) != 1)
+		return -EINVAL;
+
+	if (!val)
+		return -EINVAL;
+
+	coresight_cti_reset(&drvdata->cti);
+	return size;
+}
+static DEVICE_ATTR(reset, S_IWUSR, NULL, cti_store_reset);
+
+static ssize_t cti_show_trigin(struct device *dev,
+			       struct device_attribute *attr, char *buf)
+{
+	struct cti_drvdata *drvdata = dev_get_drvdata(dev->parent);
+	unsigned long trig, ch;
+	uint32_t ctien;
+	ssize_t size = 0;
+
+	mutex_lock(&cti_lock);
+	if (!drvdata->refcnt)
+		goto err;
+
+	for (trig = 0; trig < CTI_MAX_TRIGGERS; trig++) {
+		ctien = cti_readl(drvdata, CTIINEN(trig));
+		for (ch = 0; ch < CTI_MAX_CHANNELS; ch++) {
+			if (ctien & (1 << ch)) {
+				/* Ensure we do not write more than PAGE_SIZE
+				 * bytes of data including \n character and null
+				 * terminator
+				 */
+				size += scnprintf(&buf[size], PAGE_SIZE - size -
+						  1, " %#lx %#lx,", trig, ch);
+				if (size >= PAGE_SIZE - 2) {
+					dev_err(dev, "show buffer full\n");
+					goto err;
+				}
+
+			}
+		}
+	}
+err:
+	size += scnprintf(&buf[size], 2, "\n");
+	mutex_unlock(&cti_lock);
+	return size;
+}
+static DEVICE_ATTR(show_trigin, S_IRUGO, cti_show_trigin, NULL);
+
+static ssize_t cti_show_trigout(struct device *dev,
+				struct device_attribute *attr, char *buf)
+{
+	struct cti_drvdata *drvdata = dev_get_drvdata(dev->parent);
+	unsigned long trig, ch;
+	uint32_t ctien;
+	ssize_t size = 0;
+
+	mutex_lock(&cti_lock);
+	if (!drvdata->refcnt)
+		goto err;
+
+	for (trig = 0; trig < CTI_MAX_TRIGGERS; trig++) {
+		ctien = cti_readl(drvdata, CTIOUTEN(trig));
+		for (ch = 0; ch < CTI_MAX_CHANNELS; ch++) {
+			if (ctien & (1 << ch)) {
+				/* Ensure we do not write more than PAGE_SIZE
+				 * bytes of data including \n character and null
+				 * terminator
+				 */
+				size += scnprintf(&buf[size], PAGE_SIZE - size -
+						  1, " %#lx %#lx,", trig, ch);
+				if (size >= PAGE_SIZE - 2) {
+					dev_err(dev, "show buffer full\n");
+					goto err;
+				}
+
+			}
+		}
+	}
+err:
+	size += scnprintf(&buf[size], 2, "\n");
+	mutex_unlock(&cti_lock);
+	return size;
+}
+static DEVICE_ATTR(show_trigout, S_IRUGO, cti_show_trigout, NULL);
+
 static struct attribute *cti_attrs[] = {
 	&dev_attr_map_trigin.attr,
 	&dev_attr_map_trigout.attr,
 	&dev_attr_unmap_trigin.attr,
 	&dev_attr_unmap_trigout.attr,
+	&dev_attr_reset.attr,
+	&dev_attr_show_trigin.attr,
+	&dev_attr_show_trigout.attr,
 	NULL,
 };
 
diff --git a/drivers/coresight/coresight-hwevent.c b/drivers/coresight/coresight-hwevent.c
index 269d56e..4f75bcd 100644
--- a/drivers/coresight/coresight-hwevent.c
+++ b/drivers/coresight/coresight-hwevent.c
@@ -130,11 +130,11 @@
 {
 	struct hwevent_drvdata *drvdata = dev_get_drvdata(dev->parent);
 	void *hwereg;
-	phys_addr_t addr;
-	uint32_t val;
+	unsigned long long addr;
+	unsigned long val;
 	int ret, i;
 
-	if (sscanf(buf, "%x %x", &addr, &val) != 2)
+	if (sscanf(buf, "%llx %lx", &addr, &val) != 2)
 		return -EINVAL;
 
 	mutex_lock(&drvdata->mutex);
@@ -153,7 +153,7 @@
 					      drvdata->hmux[i].end -
 					      drvdata->hmux[i].start);
 			if (!hwereg) {
-				dev_err(dev, "unable to map address 0x%x\n",
+				dev_err(dev, "unable to map address 0x%llx\n",
 					addr);
 				ret = -ENOMEM;
 				goto err;
diff --git a/drivers/coresight/coresight-priv.h b/drivers/coresight/coresight-priv.h
index 3ad1f34..fae1232 100644
--- a/drivers/coresight/coresight-priv.h
+++ b/drivers/coresight/coresight-priv.h
@@ -47,13 +47,13 @@
 extern void msm_qdss_csr_enable_bam_to_usb(void);
 extern void msm_qdss_csr_disable_bam_to_usb(void);
 extern void msm_qdss_csr_disable_flush(void);
-extern int coresight_csr_hwctrl_set(phys_addr_t addr, uint32_t val);
+extern int coresight_csr_hwctrl_set(uint64_t addr, uint32_t val);
 extern void coresight_csr_set_byte_cntr(uint32_t);
 #else
 static inline void msm_qdss_csr_enable_bam_to_usb(void) {}
 static inline void msm_qdss_csr_disable_bam_to_usb(void) {}
 static inline void msm_qdss_csr_disable_flush(void) {}
-static inline int coresight_csr_hwctrl_set(phys_addr_t addr,
+static inline int coresight_csr_hwctrl_set(uint64_t addr,
 					   uint32_t val) { return -ENOSYS; }
 static inline void coresight_csr_set_byte_cntr(uint32_t val) {}
 #endif
diff --git a/drivers/coresight/coresight-tmc.c b/drivers/coresight/coresight-tmc.c
index c501700..8267293 100644
--- a/drivers/coresight/coresight-tmc.c
+++ b/drivers/coresight/coresight-tmc.c
@@ -22,7 +22,6 @@
 #include <linux/miscdevice.h>
 #include <linux/uaccess.h>
 #include <linux/slab.h>
-#include <linux/memory_alloc.h>
 #include <linux/delay.h>
 #include <linux/spinlock.h>
 #include <linux/clk.h>
@@ -35,7 +34,7 @@
 #include <linux/interrupt.h>
 #include <linux/cdev.h>
 #include <linux/usb/usb_qdss.h>
-#include <mach/memory.h>
+#include <linux/dma-mapping.h>
 #include <mach/sps.h>
 #include <mach/usb_bam.h>
 #include <mach/msm_memory_dump.h>
@@ -45,6 +44,8 @@
 #define tmc_writel(drvdata, val, off)	__raw_writel((val), drvdata->base + off)
 #define tmc_readl(drvdata, off)		__raw_readl(drvdata->base + off)
 
+#define tmc_readl_no_log(drvdata, off)	__raw_readl_no_log(drvdata->base + off)
+
 #define TMC_LOCK(drvdata)						\
 do {									\
 	mb();								\
@@ -152,7 +153,7 @@
 	bool			aborting;
 	char			*reg_buf;
 	char			*buf;
-	unsigned long		paddr;
+	dma_addr_t		paddr;
 	void __iomem		*vaddr;
 	uint32_t		size;
 	struct mutex		usb_lock;
@@ -271,9 +272,11 @@
 	axictl = (axictl & ~0x3) | 0x2;
 	tmc_writel(drvdata, axictl, TMC_AXICTL);
 
-	tmc_writel(drvdata, bamdata->data_fifo.phys_base, TMC_DBALO);
-	tmc_writel(drvdata, 0x0, TMC_DBAHI);
-	tmc_writel(drvdata, 0x103, TMC_FFCR);
+	tmc_writel(drvdata, (uint32_t)bamdata->data_fifo.phys_base, TMC_DBALO);
+	tmc_writel(drvdata, (((uint64_t)bamdata->data_fifo.phys_base) >> 32)
+		   & 0xFF, TMC_DBAHI);
+	/* Set FOnFlIn for periodic flush */
+	tmc_writel(drvdata, 0x133, TMC_FFCR);
 	tmc_writel(drvdata, drvdata->trigger_cntr, TMC_TRG);
 	__tmc_enable(drvdata);
 
@@ -339,7 +342,6 @@
 	TMC_UNLOCK(drvdata);
 
 	tmc_wait_for_flush(drvdata);
-	tmc_flush_and_stop(drvdata);
 	__tmc_disable(drvdata);
 
 	TMC_LOCK(drvdata);
@@ -468,8 +470,9 @@
 	axictl = (axictl & ~0x3) | 0x2;
 	tmc_writel(drvdata, axictl, TMC_AXICTL);
 
-	tmc_writel(drvdata, drvdata->paddr, TMC_DBALO);
-	tmc_writel(drvdata, 0x0, TMC_DBAHI);
+	tmc_writel(drvdata, (uint32_t)drvdata->paddr, TMC_DBALO);
+	tmc_writel(drvdata, (((uint64_t)drvdata->paddr) >> 32) & 0xFF,
+		   TMC_DBAHI);
 	tmc_writel(drvdata, 0x1133, TMC_FFCR);
 	tmc_writel(drvdata, drvdata->trigger_cntr, TMC_TRG);
 	__tmc_enable(drvdata);
@@ -651,7 +654,7 @@
 	bufp = drvdata->buf;
 	while (1) {
 		for (i = 0; i < memwords; i++) {
-			read_data = tmc_readl(drvdata, TMC_RRD);
+			read_data = tmc_readl_no_log(drvdata, TMC_RRD);
 			if (read_data == 0xFFFFFFFF)
 				goto out;
 			memcpy(bufp, &read_data, BYTES_PER_WORD);
@@ -1298,7 +1301,7 @@
 		return -EINVAL;
 	if ((drvdata->size / 8) < val)
 		return -EINVAL;
-	if (drvdata->size % (val * 8) != 0)
+	if (val && drvdata->size % (val * 8) != 0)
 		return -EINVAL;
 
 	drvdata->byte_cntr_value = val;
@@ -1451,14 +1454,17 @@
 
 	if (!drvdata->byte_cntr_present) {
 		dev_info(&pdev->dev, "Byte Counter feature absent\n");
-		return 0;
+		goto out;
 	}
 
 	drvdata->byte_cntr_irq = platform_get_irq_byname(pdev,
 							"byte-cntr-irq");
 	if (drvdata->byte_cntr_irq < 0) {
+		/* Even though this is an error condition, we do not fail
+		 * the probe as the byte counter feature is optional
+		 */
 		dev_err(&pdev->dev, "Byte-cntr-irq not specified\n");
-		return 0;
+		goto err;
 	}
 	ret = devm_request_irq(&pdev->dev, drvdata->byte_cntr_irq,
 			tmc_etr_byte_cntr_irq,
@@ -1466,7 +1472,7 @@
 			node_name, drvdata);
 	if (ret) {
 		dev_err(&pdev->dev, "Request irq failed\n");
-		return ret;
+		goto err;
 	}
 	init_waitqueue_head(&drvdata->wq);
 	node_size += strlen(node_name);
@@ -1477,10 +1483,14 @@
 	ret = tmc_etr_byte_cntr_dev_register(drvdata);
 	if (ret) {
 		dev_err(&pdev->dev, "Byte cntr node not registered\n");
-		return ret;
+		goto err;
 	}
 	dev_info(&pdev->dev, "Byte Counter feature enabled\n");
 	return 0;
+err:
+	drvdata->byte_cntr_present = false;
+out:
+	return ret;
 }
 
 static void tmc_etr_byte_cntr_exit(struct tmc_drvdata *drvdata)
@@ -1555,7 +1565,8 @@
 	if (drvdata->config_type == TMC_CONFIG_TYPE_ETR) {
 		if (pdev->dev.of_node) {
 			ret = of_property_read_u32(pdev->dev.of_node,
-				"qcom,memory-reservation-size", &drvdata->size);
+						   "qcom,memory-size",
+						   &drvdata->size);
 			if (ret) {
 				clk_disable_unprepare(drvdata->clk);
 				return ret;
@@ -1568,17 +1579,11 @@
 	clk_disable_unprepare(drvdata->clk);
 
 	if (drvdata->config_type == TMC_CONFIG_TYPE_ETR) {
-		drvdata->paddr = allocate_contiguous_ebi_nomap(drvdata->size,
-							       SZ_4K);
-		if (!drvdata->paddr)
+		drvdata->vaddr = dma_zalloc_coherent(&pdev->dev, drvdata->size,
+						     &drvdata->paddr,
+						     GFP_KERNEL);
+		if (!drvdata->vaddr)
 			return -ENOMEM;
-		drvdata->vaddr = devm_ioremap(dev, drvdata->paddr,
-					      drvdata->size);
-		if (!drvdata->vaddr) {
-			ret = -ENOMEM;
-			goto err0;
-		}
-		memset(drvdata->vaddr, 0, drvdata->size);
 		drvdata->buf = drvdata->vaddr;
 		drvdata->out_mode = TMC_ETR_OUT_MODE_MEM;
 		if (pdev->dev.of_node)
@@ -1718,7 +1723,10 @@
 err1:
 	tmc_etr_byte_cntr_exit(drvdata);
 err0:
-	free_contiguous_memory_by_paddr(drvdata->paddr);
+	if (drvdata->vaddr)
+		dma_free_coherent(&pdev->dev, drvdata->size,
+				  drvdata->vaddr,
+				  drvdata->paddr);
 	return ret;
 }
 
@@ -1730,7 +1738,9 @@
 	misc_deregister(&drvdata->miscdev);
 	coresight_unregister(drvdata->csdev);
 	tmc_etr_bam_exit(drvdata);
-	free_contiguous_memory_by_paddr(drvdata->paddr);
+	if (drvdata->vaddr)
+		dma_free_coherent(&pdev->dev, drvdata->size, drvdata->vaddr,
+				  drvdata->paddr);
 	return 0;
 }
 
diff --git a/drivers/coresight/coresight-tpiu.c b/drivers/coresight/coresight-tpiu.c
index 032327c..1121f57 100644
--- a/drivers/coresight/coresight-tpiu.c
+++ b/drivers/coresight/coresight-tpiu.c
@@ -88,6 +88,11 @@
 	unsigned int		reg_high;
 	unsigned int		reg_lpm;
 	unsigned int		reg_hpm;
+	struct regulator        *reg_io;
+	unsigned int            reg_low_io;
+	unsigned int            reg_high_io;
+	unsigned int            reg_lpm_io;
+	unsigned int            reg_hpm_io;
 	enum tpiu_set		set;
 	unsigned int		seta_gpiocnt;
 	unsigned int		*seta_gpios;
@@ -240,7 +245,7 @@
 {
 	int ret;
 
-	if (!drvdata->reg)
+	if (!drvdata->reg || !drvdata->reg_io)
 		return -EINVAL;
 
 	ret = tpiu_reg_set_optimum_mode(drvdata->reg, drvdata->reg_hpm);
@@ -253,6 +258,20 @@
 	ret = regulator_enable(drvdata->reg);
 	if (ret)
 		goto err1;
+	ret = tpiu_reg_set_optimum_mode(drvdata->reg_io, drvdata->reg_hpm_io);
+	if (ret < 0)
+		goto err2;
+	ret = tpiu_reg_set_voltage(drvdata->reg_io, drvdata->reg_low_io,
+				   drvdata->reg_high_io);
+	if (ret)
+		goto err3;
+	ret = regulator_enable(drvdata->reg_io);
+	if (ret)
+		goto err4;
+
+	ret = clk_set_rate(drvdata->clk, CORESIGHT_CLK_RATE_FIXED);
+	if (ret)
+		goto err5;
 
 	msm_tlmm_misc_reg_write(TLMM_SDC2_HDRV_PULL_CTL, 0x16D);
 	msm_tlmm_misc_reg_write(TLMM_ETM_MODE_REG, 1);
@@ -265,6 +284,14 @@
 	TPIU_LOCK(drvdata);
 
 	return 0;
+err5:
+	regulator_disable(drvdata->reg_io);
+err4:
+	tpiu_reg_set_voltage(drvdata->reg_io, 0, drvdata->reg_high_io);
+err3:
+	tpiu_reg_set_optimum_mode(drvdata->reg_io, 0);
+err2:
+	regulator_disable(drvdata->reg);
 err1:
 	tpiu_reg_set_voltage(drvdata->reg, 0, drvdata->reg_high);
 err0:
@@ -342,9 +369,15 @@
 
 	msm_tlmm_misc_reg_write(TLMM_ETM_MODE_REG, 0);
 
+	clk_set_rate(drvdata->clk, CORESIGHT_CLK_RATE_TRACE);
+
 	regulator_disable(drvdata->reg);
-	tpiu_reg_set_optimum_mode(drvdata->reg, 0);
 	tpiu_reg_set_voltage(drvdata->reg, 0, drvdata->reg_high);
+	tpiu_reg_set_optimum_mode(drvdata->reg, 0);
+
+	regulator_disable(drvdata->reg_io);
+	tpiu_reg_set_voltage(drvdata->reg_io, 0, drvdata->reg_high_io);
+	tpiu_reg_set_optimum_mode(drvdata->reg_io, 0);
 }
 
 static void tpiu_disable(struct coresight_device *csdev)
@@ -566,6 +599,33 @@
 		dev_err(dev, "sdc voltage supply not specified or available\n");
 	}
 
+	reg_node = of_parse_phandle(node, "vdd-io-supply", 0);
+	if (reg_node) {
+		drvdata->reg_io = devm_regulator_get(dev, "vdd-io");
+		if (IS_ERR(drvdata->reg_io))
+			return PTR_ERR(drvdata->reg_io);
+
+		prop = of_get_property(node, "qcom,vdd-io-voltage-level", &len);
+		if (!prop || (len != (2 * sizeof(__be32)))) {
+			dev_err(dev, "sdc io voltage levels not specified\n");
+		} else {
+			drvdata->reg_low_io = be32_to_cpup(&prop[0]);
+			drvdata->reg_high_io = be32_to_cpup(&prop[1]);
+		}
+
+		prop = of_get_property(node, "qcom,vdd-io-current-level", &len);
+		if (!prop || (len != (2 * sizeof(__be32)))) {
+			dev_err(dev, "sdc io current levels not specified\n");
+		} else {
+			drvdata->reg_lpm_io = be32_to_cpup(&prop[0]);
+			drvdata->reg_hpm_io = be32_to_cpup(&prop[1]);
+		}
+		of_node_put(reg_node);
+	} else {
+		dev_err(dev,
+			"sdc io voltage supply not specified or available\n");
+	}
+
 	drvdata->out_mode = TPIU_OUT_MODE_MICTOR;
 	drvdata->set = TPIU_SET_B;
 
diff --git a/drivers/cpufreq/cpufreq_ondemand.c b/drivers/cpufreq/cpufreq_ondemand.c
index 96e759b..e6b2a3c 100644
--- a/drivers/cpufreq/cpufreq_ondemand.c
+++ b/drivers/cpufreq/cpufreq_ondemand.c
@@ -346,6 +346,7 @@
 	dbs_tuners_ins.sampling_rate = new_rate
 				     = max(new_rate, min_sampling_rate);
 
+	get_online_cpus();
 	for_each_online_cpu(cpu) {
 		struct cpufreq_policy *policy;
 		struct cpu_dbs_info_s *dbs_info;
@@ -380,6 +381,7 @@
 		}
 		mutex_unlock(&dbs_info->timer_mutex);
 	}
+	put_online_cpus();
 }
 
 static ssize_t store_sampling_rate(struct kobject *a, struct attribute *b,
@@ -584,8 +586,8 @@
 
 	dbs_tuners_ins.powersave_bias = input;
 
-	mutex_lock(&dbs_mutex);
 	get_online_cpus();
+	mutex_lock(&dbs_mutex);
 
 	if (!bypass) {
 		if (reenable_timer) {
@@ -661,8 +663,8 @@
 		}
 	}
 
-	put_online_cpus();
 	mutex_unlock(&dbs_mutex);
+	put_online_cpus();
 
 	return count;
 }
@@ -1198,7 +1200,28 @@
 }
 
 static const struct input_device_id dbs_ids[] = {
-	{ .driver_info = 1 },
+	/* multi-touch touchscreen */
+	{
+		.flags = INPUT_DEVICE_ID_MATCH_EVBIT |
+			INPUT_DEVICE_ID_MATCH_ABSBIT,
+		.evbit = { BIT_MASK(EV_ABS) },
+		.absbit = { [BIT_WORD(ABS_MT_POSITION_X)] =
+			BIT_MASK(ABS_MT_POSITION_X) |
+			BIT_MASK(ABS_MT_POSITION_Y) },
+	},
+	/* touchpad */
+	{
+		.flags = INPUT_DEVICE_ID_MATCH_KEYBIT |
+			INPUT_DEVICE_ID_MATCH_ABSBIT,
+		.keybit = { [BIT_WORD(BTN_TOUCH)] = BIT_MASK(BTN_TOUCH) },
+		.absbit = { [BIT_WORD(ABS_X)] =
+			BIT_MASK(ABS_X) | BIT_MASK(ABS_Y) },
+	},
+	/* Keypad */
+	{
+		.flags = INPUT_DEVICE_ID_MATCH_EVBIT,
+		.evbit = { BIT_MASK(EV_KEY) },
+	},
 	{ },
 };
 
diff --git a/drivers/crypto/msm/qcedev.c b/drivers/crypto/msm/qcedev.c
index 0e4b309..c726694 100644
--- a/drivers/crypto/msm/qcedev.c
+++ b/drivers/crypto/msm/qcedev.c
@@ -564,7 +564,7 @@
 
 	creq.qce_cb = qcedev_cipher_req_cb;
 	creq.areq = (void *)&qcedev_areq->cipher_req;
-
+	creq.flags = 0;
 	ret = qce_ablk_cipher_req(podev->qce, &creq);
 unsupported:
 	if (ret)
@@ -640,6 +640,7 @@
 	sreq.size = qcedev_areq->sha_req.sreq.nbytes;
 	sreq.src = qcedev_areq->sha_req.sreq.src;
 	sreq.areq = (void *)&qcedev_areq->sha_req;
+	sreq.flags = 0;
 
 	ret = qce_process_sha_req(podev->qce, &sreq);
 
diff --git a/drivers/crypto/msm/qcrypto.c b/drivers/crypto/msm/qcrypto.c
index c98cbba..ae57d6c 100644
--- a/drivers/crypto/msm/qcrypto.c
+++ b/drivers/crypto/msm/qcrypto.c
@@ -492,6 +492,7 @@
 	struct qcrypto_cipher_ctx *ctx = crypto_tfm_ctx(tfm);
 
 	q_alg = container_of(alg, struct qcrypto_alg, cipher_alg);
+	ctx->flags = 0;
 
 	/* update context with ptr to cp */
 	ctx->cp = q_alg->cp;
@@ -517,6 +518,8 @@
 	/* update context with ptr to cp */
 	sha_ctx->cp = q_alg->cp;
 	sha_ctx->sg = NULL;
+	sha_ctx->flags = 0;
+
 	sha_ctx->tmp_tbuf = kzalloc(SHA_MAX_BLOCK_SIZE +
 					SHA_MAX_DIGEST_SIZE, GFP_KERNEL);
 	if (sha_ctx->tmp_tbuf == NULL) {
diff --git a/drivers/gpio/gpio-msm-common.c b/drivers/gpio/gpio-msm-common.c
index 3115628..3d18809 100644
--- a/drivers/gpio/gpio-msm-common.c
+++ b/drivers/gpio/gpio-msm-common.c
@@ -84,6 +84,7 @@
 	{SDC1_HDRV_PULL_CTL, 13}, /* TLMM_PULL_SDC1_CLK  */
 	{SDC1_HDRV_PULL_CTL, 11}, /* TLMM_PULL_SDC1_CMD  */
 	{SDC1_HDRV_PULL_CTL, 9},  /* TLMM_PULL_SDC1_DATA */
+	{SDC1_HDRV_PULL_CTL, 15}, /* TLMM_PULL_SDC1_RCLK  */
 };
 
 /*
diff --git a/drivers/gpu/ion/ion_iommu_heap.c b/drivers/gpu/ion/ion_iommu_heap.c
index 1ea3cd2..d9e9e09 100644
--- a/drivers/gpu/ion/ion_iommu_heap.c
+++ b/drivers/gpu/ion/ion_iommu_heap.c
@@ -136,12 +136,18 @@
 	return NULL;
 }
 
-static int ion_iommu_buffer_zero(struct ion_iommu_priv_data *data)
+static int ion_iommu_buffer_zero(struct ion_iommu_priv_data *data,
+				bool is_cached)
 {
-	int i, j;
+	int i, j, k;
 	unsigned int npages_to_vmap;
 	unsigned int total_pages;
 	void *ptr = NULL;
+	/*
+	 * It's cheaper just to use writecombine memory and skip the
+	 * cache vs. using a cache memory and trying to flush it afterwards
+	 */
+	pgprot_t pgprot = pgprot_writecombine(pgprot_kernel);
 
 	/*
 	 * As an optimization, we manually zero out all of the
@@ -161,7 +167,7 @@
 		for (j = 0; j < MAX_VMAP_RETRIES && npages_to_vmap;
 			++j) {
 			ptr = vmap(&data->pages[i], npages_to_vmap,
-					VM_IOREMAP, pgprot_kernel);
+					VM_IOREMAP, pgprot);
 			if (ptr)
 				break;
 			else
@@ -171,6 +177,20 @@
 			return -ENOMEM;
 
 		memset(ptr, 0, npages_to_vmap * PAGE_SIZE);
+		if (is_cached) {
+			/*
+			 * invalidate the cache to pick up the zeroing
+			 */
+			for (k = 0; k < npages_to_vmap; k++) {
+				void *p = kmap_atomic(data->pages[i + k]);
+				phys_addr_t phys = page_to_phys(
+							data->pages[i + k]);
+
+				dmac_inv_range(p, p + PAGE_SIZE);
+				outer_inv_range(phys, phys + PAGE_SIZE);
+				kunmap_atomic(p);
+			}
+		}
 		vunmap(ptr);
 	}
 
@@ -269,7 +289,7 @@
 
 
 		if (flags & ION_FLAG_POOL_FORCE_ALLOC) {
-			ret = ion_iommu_buffer_zero(data);
+			ret = ion_iommu_buffer_zero(data, ION_IS_CACHED(flags));
 			if (ret) {
 				pr_err("Couldn't vmap the pages for zeroing\n");
 				goto err3;
@@ -328,7 +348,7 @@
 		return;
 
 	if (!(buffer->flags & ION_FLAG_POOL_FORCE_ALLOC))
-		ion_iommu_buffer_zero(data);
+		ion_iommu_buffer_zero(data, ION_IS_CACHED(buffer->flags));
 
 	for_each_sg(table->sgl, sg, table->nents, i) {
 		int order = get_order(sg_dma_len(sg));
diff --git a/drivers/gpu/msm/Makefile b/drivers/gpu/msm/Makefile
index aac183b..118e033 100644
--- a/drivers/gpu/msm/Makefile
+++ b/drivers/gpu/msm/Makefile
@@ -22,11 +22,9 @@
 msm_adreno-y += \
 	adreno_ringbuffer.o \
 	adreno_drawctxt.o \
-	adreno_dispatch.o \
 	adreno_postmortem.o \
 	adreno_snapshot.o \
 	adreno_coresight.o \
-	adreno_trace.o \
 	adreno_a2xx.o \
 	adreno_a2xx_trace.o \
 	adreno_a2xx_snapshot.o \
diff --git a/drivers/gpu/msm/a3xx_reg.h b/drivers/gpu/msm/a3xx_reg.h
index 0c398c4..b5945da 100644
--- a/drivers/gpu/msm/a3xx_reg.h
+++ b/drivers/gpu/msm/a3xx_reg.h
@@ -240,6 +240,7 @@
 #define A3XX_PC_PERFCOUNTER1_SELECT 0xC49
 #define A3XX_PC_PERFCOUNTER2_SELECT 0xC4A
 #define A3XX_PC_PERFCOUNTER3_SELECT 0xC4B
+#define A3XX_GRAS_TSE_DEBUG_ECO 0xC81
 #define A3XX_GRAS_PERFCOUNTER0_SELECT 0xC88
 #define A3XX_GRAS_PERFCOUNTER1_SELECT 0xC89
 #define A3XX_GRAS_PERFCOUNTER2_SELECT 0xC8A
@@ -269,8 +270,10 @@
 #define A3XX_GRAS_CL_USER_PLANE_Z5 0xCB6
 #define A3XX_GRAS_CL_USER_PLANE_W5 0xCB7
 #define A3XX_RB_GMEM_BASE_ADDR 0xCC0
+#define A3XX_RB_DEBUG_ECO_CONTROLS_ADDR 0xCC1
 #define A3XX_RB_PERFCOUNTER0_SELECT   0xCC6
 #define A3XX_RB_PERFCOUNTER1_SELECT   0xCC7
+#define A3XX_RB_FRAME_BUFFER_DIMENSION 0xCE0
 #define A3XX_HLSQ_PERFCOUNTER0_SELECT 0xE00
 #define A3XX_HLSQ_PERFCOUNTER1_SELECT 0xE01
 #define A3XX_HLSQ_PERFCOUNTER2_SELECT 0xE02
@@ -308,6 +311,9 @@
 #define A3XX_GRAS_CL_CLIP_CNTL 0x2040
 #define A3XX_GRAS_CL_GB_CLIP_ADJ 0x2044
 #define A3XX_GRAS_CL_VPORT_XOFFSET 0x2048
+#define A3XX_GRAS_CL_VPORT_XSCALE 0x2049
+#define A3XX_GRAS_CL_VPORT_YOFFSET 0x204A
+#define A3XX_GRAS_CL_VPORT_YSCALE 0x204B
 #define A3XX_GRAS_CL_VPORT_ZOFFSET 0x204C
 #define A3XX_GRAS_CL_VPORT_ZSCALE 0x204D
 #define A3XX_GRAS_SU_POINT_MINMAX 0x2068
@@ -323,30 +329,75 @@
 #define A3XX_RB_MODE_CONTROL 0x20C0
 #define A3XX_RB_RENDER_CONTROL 0x20C1
 #define A3XX_RB_MSAA_CONTROL 0x20C2
+#define A3XX_RB_ALPHA_REFERENCE 0x20C3
 #define A3XX_RB_MRT_CONTROL0 0x20C4
 #define A3XX_RB_MRT_BUF_INFO0 0x20C5
+#define A3XX_RB_MRT_BUF_BASE0 0x20C6
 #define A3XX_RB_MRT_BLEND_CONTROL0 0x20C7
+#define A3XX_RB_MRT_CONTROL1 0x20C8
+#define A3XX_RB_MRT_BUF_INFO1 0x20C9
+#define A3XX_RB_MRT_BUF_BASE1 0x20CA
 #define A3XX_RB_MRT_BLEND_CONTROL1 0x20CB
+#define A3XX_RB_MRT_CONTROL2 0x20CC
+#define A3XX_RB_MRT_BUF_INFO2 0x20CD
+#define A3XX_RB_MRT_BUF_BASE2 0x20CE
 #define A3XX_RB_MRT_BLEND_CONTROL2 0x20CF
+#define A3XX_RB_MRT_CONTROL3 0x20D0
+#define A3XX_RB_MRT_BUF_INFO3 0x20D1
+#define A3XX_RB_MRT_BUF_BASE3 0x20D2
 #define A3XX_RB_MRT_BLEND_CONTROL3 0x20D3
 #define A3XX_RB_BLEND_RED 0x20E4
+#define A3XX_RB_BLEND_GREEN 0x20E5
+#define A3XX_RB_BLEND_BLUE 0x20E6
+#define A3XX_RB_BLEND_ALPHA 0x20E7
+#define A3XX_RB_CLEAR_COLOR_DW0 0x20E8
+#define A3XX_RB_CLEAR_COLOR_DW1 0x20E9
+#define A3XX_RB_CLEAR_COLOR_DW2 0x20EA
+#define A3XX_RB_CLEAR_COLOR_DW3 0x20EB
 #define A3XX_RB_COPY_CONTROL 0x20EC
+#define A3XX_RB_COPY_DEST_BASE 0x20ED
+#define A3XX_RB_COPY_DEST_PITCH 0x20EE
 #define A3XX_RB_COPY_DEST_INFO 0x20EF
 #define A3XX_RB_DEPTH_CONTROL 0x2100
+#define A3XX_RB_DEPTH_CLEAR 0x2101
+#define A3XX_RB_DEPTH_BUF_INFO 0x2102
+#define A3XX_RB_DEPTH_BUF_PITCH 0x2103
 #define A3XX_RB_STENCIL_CONTROL 0x2104
+#define A3XX_RB_STENCIL_CLEAR 0x2105
+#define A3XX_RB_STENCIL_BUF_INFO 0x2106
+#define A3XX_RB_STENCIL_BUF_PITCH 0x2107
+#define A3XX_RB_STENCIL_REF_MASK 0x2108
+#define A3XX_RB_STENCIL_REF_MASK_BF 0x2109
+#define A3XX_RB_LRZ_VSC_CONTROL 0x210C
+#define A3XX_RB_WINDOW_OFFSET 0x210E
+#define A3XX_RB_SAMPLE_COUNT_CONTROL 0x2110
+#define A3XX_RB_SAMPLE_COUNT_ADDR 0x2111
+#define A3XX_RB_Z_CLAMP_MIN 0x2114
+#define A3XX_RB_Z_CLAMP_MAX 0x2115
 #define A3XX_PC_VSTREAM_CONTROL 0x21E4
 #define A3XX_PC_VERTEX_REUSE_BLOCK_CNTL 0x21EA
 #define A3XX_PC_PRIM_VTX_CNTL 0x21EC
 #define A3XX_PC_RESTART_INDEX 0x21ED
 #define A3XX_HLSQ_CONTROL_0_REG 0x2200
+#define A3XX_HLSQ_CONTROL_1_REG 0x2201
+#define A3XX_HLSQ_CONTROL_2_REG 0x2202
+#define A3XX_HLSQ_CONTROL_3_REG 0x2203
 #define A3XX_HLSQ_VS_CONTROL_REG 0x2204
+#define A3XX_HLSQ_FS_CONTROL_REG 0x2205
+#define A3XX_HLSQ_CONST_VSPRESV_RANGE_REG 0x2206
 #define A3XX_HLSQ_CONST_FSPRESV_RANGE_REG 0x2207
 #define A3XX_HLSQ_CL_NDRANGE_0_REG 0x220A
+#define A3XX_HLSQ_CL_NDRANGE_1_REG 0x220B
 #define A3XX_HLSQ_CL_NDRANGE_2_REG 0x220C
+#define A3XX_HLSQ_CL_NDRANGE_3_REG 0x220D
+#define A3XX_HLSQ_CL_NDRANGE_4_REG 0x220E
+#define A3XX_HLSQ_CL_NDRANGE_5_REG 0x220F
+#define A3XX_HLSQ_CL_NDRANGE_6_REG 0x2210
 #define A3XX_HLSQ_CL_CONTROL_0_REG 0x2211
 #define A3XX_HLSQ_CL_CONTROL_1_REG 0x2212
 #define A3XX_HLSQ_CL_KERNEL_CONST_REG 0x2214
 #define A3XX_HLSQ_CL_KERNEL_GROUP_X_REG 0x2215
+#define A3XX_HLSQ_CL_KERNEL_GROUP_Y_REG 0x2216
 #define A3XX_HLSQ_CL_KERNEL_GROUP_Z_REG 0x2217
 #define A3XX_HLSQ_CL_WG_OFFSET_REG 0x221A
 #define A3XX_VFD_CONTROL_0 0x2240
@@ -363,10 +414,21 @@
 #define A3XX_SP_VS_CTRL_REG0 0x22C4
 #define A3XX_SP_VS_CTRL_REG1 0x22C5
 #define A3XX_SP_VS_PARAM_REG 0x22C6
+#define A3XX_SP_VS_OUT_REG_0 0x22C7
+#define A3XX_SP_VS_OUT_REG_1 0x22C8
+#define A3XX_SP_VS_OUT_REG_2 0x22C9
+#define A3XX_SP_VS_OUT_REG_3 0x22CA
+#define A3XX_SP_VS_OUT_REG_4 0x22CB
+#define A3XX_SP_VS_OUT_REG_5 0x22CC
+#define A3XX_SP_VS_OUT_REG_6 0x22CD
 #define A3XX_SP_VS_OUT_REG_7 0x22CE
 #define A3XX_SP_VS_VPC_DST_REG_0 0x22D0
+#define A3XX_SP_VS_VPC_DST_REG_1 0x22D1
+#define A3XX_SP_VS_VPC_DST_REG_2 0x22D2
+#define A3XX_SP_VS_VPC_DST_REG_3 0x22D3
 #define A3XX_SP_VS_OBJ_OFFSET_REG 0x22D4
 #define A3XX_SP_VS_OBJ_START_REG 0x22D5
+#define A3XX_SP_VS_PVT_MEM_PARAM_REG 0x22D6
 #define A3XX_SP_VS_PVT_MEM_ADDR_REG 0x22D7
 #define A3XX_SP_VS_PVT_MEM_SIZE_REG 0x22D8
 #define A3XX_SP_VS_LENGTH_REG 0x22DF
@@ -374,13 +436,19 @@
 #define A3XX_SP_FS_CTRL_REG1 0x22E1
 #define A3XX_SP_FS_OBJ_OFFSET_REG 0x22E2
 #define A3XX_SP_FS_OBJ_START_REG 0x22E3
+#define A3XX_SP_FS_PVT_MEM_PARAM_REG 0x22E4
 #define A3XX_SP_FS_PVT_MEM_ADDR_REG 0x22E5
 #define A3XX_SP_FS_PVT_MEM_SIZE_REG 0x22E6
 #define A3XX_SP_FS_FLAT_SHAD_MODE_REG_0 0x22E8
 #define A3XX_SP_FS_FLAT_SHAD_MODE_REG_1 0x22E9
 #define A3XX_SP_FS_OUTPUT_REG 0x22EC
 #define A3XX_SP_FS_MRT_REG_0 0x22F0
+#define A3XX_SP_FS_MRT_REG_1 0x22F1
+#define A3XX_SP_FS_MRT_REG_2 0x22F2
+#define A3XX_SP_FS_MRT_REG_3 0x22F3
 #define A3XX_SP_FS_IMAGE_OUTPUT_REG_0 0x22F4
+#define A3XX_SP_FS_IMAGE_OUTPUT_REG_1 0x22F5
+#define A3XX_SP_FS_IMAGE_OUTPUT_REG_2 0x22F6
 #define A3XX_SP_FS_IMAGE_OUTPUT_REG_3 0x22F7
 #define A3XX_SP_FS_LENGTH_REG 0x22FF
 #define A3XX_TPL1_TP_VS_TEX_OFFSET 0x2340
diff --git a/drivers/gpu/msm/adreno.c b/drivers/gpu/msm/adreno.c
index a28bf33..cdf711c 100644
--- a/drivers/gpu/msm/adreno.c
+++ b/drivers/gpu/msm/adreno.c
@@ -32,7 +32,6 @@
 
 #include "adreno.h"
 #include "adreno_pm4types.h"
-#include "adreno_trace.h"
 
 #include "a2xx_reg.h"
 #include "a3xx_reg.h"
@@ -72,6 +71,8 @@
 	 | (MMU_CONFIG << MH_MMU_CONFIG__TC_R_CLNT_BEHAVIOR__SHIFT)	\
 	 | (MMU_CONFIG << MH_MMU_CONFIG__PA_W_CLNT_BEHAVIOR__SHIFT))
 
+#define KGSL_LOG_LEVEL_DEFAULT 3
+
 static const struct kgsl_functable adreno_functable;
 
 static struct adreno_device device_3d0 = {
@@ -101,6 +102,13 @@
 		.iomemname = KGSL_3D0_REG_MEMORY,
 		.shadermemname = KGSL_3D0_SHADER_MEMORY,
 		.ftbl = &adreno_functable,
+		.cmd_log = KGSL_LOG_LEVEL_DEFAULT,
+		.ctxt_log = KGSL_LOG_LEVEL_DEFAULT,
+		.drv_log = KGSL_LOG_LEVEL_DEFAULT,
+		.mem_log = KGSL_LOG_LEVEL_DEFAULT,
+		.pwr_log = KGSL_LOG_LEVEL_DEFAULT,
+		.ft_log = KGSL_LOG_LEVEL_DEFAULT,
+		.pm_dump_enable = 0,
 	},
 	.gmem_base = 0,
 	.gmem_size = SZ_256K,
@@ -114,6 +122,12 @@
 	.long_ib_detect = 1,
 };
 
+/* This set of registers are used for Hang detection
+ * If the values of these registers are same after
+ * KGSL_TIMEOUT_PART time, GPU hang is reported in
+ * kernel log.
+ */
+
 unsigned int ft_detect_regs[FT_DETECT_REGS_COUNT];
 
 /*
@@ -202,7 +216,7 @@
 		512, 0, 2, SZ_128K, 0x3FF037, 0x3FF016 },
 };
 
-static bool adreno_isidle(struct kgsl_device *device);
+static unsigned int adreno_isidle(struct kgsl_device *device);
 
 /**
  * adreno_perfcounter_init: Reserve kernel performance counters
@@ -587,9 +601,23 @@
 
 static irqreturn_t adreno_irq_handler(struct kgsl_device *device)
 {
+	irqreturn_t result;
 	struct adreno_device *adreno_dev = ADRENO_DEVICE(device);
 
-	return adreno_dev->gpudev->irq_handler(adreno_dev);
+	result = adreno_dev->gpudev->irq_handler(adreno_dev);
+
+	device->pwrctrl.irq_last = 1;
+	if (device->requested_state == KGSL_STATE_NONE) {
+		kgsl_pwrctrl_request_state(device, KGSL_STATE_NAP);
+		queue_work(device->work_queue, &device->idle_check_ws);
+	}
+
+	/* Reset the time-out in our idle timer */
+	mod_timer_pending(&device->idle_timer,
+		jiffies + device->pwrctrl.interval_timeout);
+	mod_timer_pending(&device->hang_timer,
+		(jiffies + msecs_to_jiffies(KGSL_TIMEOUT_PART)));
+	return result;
 }
 
 static void adreno_cleanup_pt(struct kgsl_device *device,
@@ -606,36 +634,44 @@
 
 	kgsl_mmu_unmap(pagetable, &adreno_dev->profile.shared_buffer);
 
+	kgsl_mmu_unmap(pagetable, &adreno_dev->pwron_fixup);
+
 	kgsl_mmu_unmap(pagetable, &device->mmu.setstate_memory);
 }
 
 static int adreno_setup_pt(struct kgsl_device *device,
 			struct kgsl_pagetable *pagetable)
 {
-	int result = 0;
+	int result;
 	struct adreno_device *adreno_dev = ADRENO_DEVICE(device);
 	struct adreno_ringbuffer *rb = &adreno_dev->ringbuffer;
 
 	result = kgsl_mmu_map_global(pagetable, &rb->buffer_desc);
-	if (result)
-		goto error;
 
-	result = kgsl_mmu_map_global(pagetable, &rb->memptrs_desc);
-	if (result)
-		goto unmap_buffer_desc;
+	if (!result)
+		result = kgsl_mmu_map_global(pagetable, &rb->memptrs_desc);
 
-	result = kgsl_mmu_map_global(pagetable, &device->memstore);
-	if (result)
-		goto unmap_memptrs_desc;
+	if (!result)
+		result = kgsl_mmu_map_global(pagetable, &device->memstore);
 
-	result = kgsl_mmu_map_global(pagetable,
-					&adreno_dev->profile.shared_buffer);
-	if (result)
-		goto unmap_profile_shared;
+	if (!result)
+		result = kgsl_mmu_map_global(pagetable,
+			&adreno_dev->profile.shared_buffer);
 
-	result = kgsl_mmu_map_global(pagetable, &device->mmu.setstate_memory);
-	if (result)
-		goto unmap_memstore_desc;
+	if (!result)
+		result = kgsl_mmu_map_global(pagetable,
+			&adreno_dev->pwron_fixup);
+
+
+	if (!result)
+		result = kgsl_mmu_map_global(pagetable,
+			&device->mmu.setstate_memory);
+
+	if (result) {
+		/* On error clean up what we have wrought */
+		adreno_cleanup_pt(device, pagetable);
+		return result;
+	}
 
 	/*
 	 * Set the mpu end to the last "normal" global memory we use.
@@ -644,22 +680,8 @@
 	 */
 	device->mh.mpu_range = device->mmu.setstate_memory.gpuaddr +
 				device->mmu.setstate_memory.size;
-	return result;
 
-unmap_profile_shared:
-	kgsl_mmu_unmap(pagetable, &adreno_dev->profile.shared_buffer);
-
-unmap_memstore_desc:
-	kgsl_mmu_unmap(pagetable, &device->memstore);
-
-unmap_memptrs_desc:
-	kgsl_mmu_unmap(pagetable, &rb->memptrs_desc);
-
-unmap_buffer_desc:
-	kgsl_mmu_unmap(pagetable, &rb->buffer_desc);
-
-error:
-	return result;
+	return 0;
 }
 
 static unsigned int _adreno_iommu_setstate_v0(struct kgsl_device *device,
@@ -783,6 +805,8 @@
 	int i;
 	unsigned int ttbr0, tlbiall, tlbstatus, tlbsync, mmu_ctrl;
 
+	cmds += adreno_add_idle_cmds(adreno_dev, cmds);
+
 	for (i = 0; i < num_iommu_units; i++) {
 		ttbr0_val = kgsl_mmu_get_default_ttbr0(&device->mmu,
 				i, KGSL_IOMMU_CONTEXT_USER);
@@ -870,8 +894,14 @@
 					KGSL_IOMMU_CTX_TLBSTATUS) >> 2;
 			cmds += adreno_wait_reg_eq(cmds, tlbstatus, 0,
 					KGSL_IOMMU_CTX_TLBSTATUS_SACTIVE, 0xF);
+			/* release all commands with wait_for_me */
+			*cmds++ = cp_type3_packet(CP_WAIT_FOR_ME, 1);
+			*cmds++ = 0;
 		}
 	}
+
+	cmds += adreno_add_idle_cmds(adreno_dev, cmds);
+
 	return cmds - cmds_orig;
 }
 
@@ -890,13 +920,12 @@
 static bool adreno_use_default_setstate(struct adreno_device *adreno_dev)
 {
 	return (adreno_isidle(&adreno_dev->dev) ||
-		adreno_dev->drawctxt_active == NULL ||
 		KGSL_STATE_ACTIVE != adreno_dev->dev.state ||
 		atomic_read(&adreno_dev->dev.active_cnt) == 0 ||
 		adreno_dev->dev.cff_dump_enable);
 }
 
-static int adreno_iommu_setstate(struct kgsl_device *device,
+static void adreno_iommu_setstate(struct kgsl_device *device,
 					unsigned int context_id,
 					uint32_t flags)
 {
@@ -909,24 +938,22 @@
 	struct kgsl_context *context;
 	struct adreno_context *adreno_ctx = NULL;
 	struct adreno_ringbuffer *rb = &adreno_dev->ringbuffer;
-	unsigned int result;
 
 	if (adreno_use_default_setstate(adreno_dev)) {
 		kgsl_mmu_device_setstate(&device->mmu, flags);
-		return 0;
+		return;
 	}
 	num_iommu_units = kgsl_mmu_get_num_iommu_units(&device->mmu);
 
 	context = kgsl_context_get(device, context_id);
 	if (context == NULL)
-		return -EINVAL;
+		return;
 
 	adreno_ctx = ADRENO_CONTEXT(context);
 
-	result = kgsl_mmu_enable_clk(&device->mmu, KGSL_IOMMU_CONTEXT_USER);
-
-	if (result)
-		goto done;
+	if (kgsl_mmu_enable_clk(&device->mmu,
+				KGSL_IOMMU_CONTEXT_USER))
+		return;
 
 	pt_val = kgsl_mmu_get_pt_base_addr(&device->mmu,
 				device->mmu.hwpagetable);
@@ -960,24 +987,14 @@
 	 * This returns the per context timestamp but we need to
 	 * use the global timestamp for iommu clock disablement
 	 */
-	result = adreno_ringbuffer_issuecmds(device, adreno_ctx,
-			KGSL_CMD_FLAGS_PMODE, &link[0], sizedwords);
+	adreno_ringbuffer_issuecmds(device, adreno_ctx, KGSL_CMD_FLAGS_PMODE,
+			&link[0], sizedwords);
 
-	/*
-	 * On error disable the IOMMU clock right away otherwise turn it off
-	 * after the command has been retired
-	 */
-	if (result)
-		kgsl_mmu_disable_clk_on_ts(&device->mmu, 0, false);
-	else
-		kgsl_mmu_disable_clk_on_ts(&device->mmu, rb->global_ts, true);
-
-done:
+	kgsl_mmu_disable_clk_on_ts(&device->mmu, rb->global_ts, true);
 	kgsl_context_put(context);
-	return result;
 }
 
-static int adreno_gpummu_setstate(struct kgsl_device *device,
+static void adreno_gpummu_setstate(struct kgsl_device *device,
 					unsigned int context_id,
 					uint32_t flags)
 {
@@ -988,7 +1005,6 @@
 	unsigned int mh_mmu_invalidate = 0x00000003; /*invalidate all and tc */
 	struct kgsl_context *context;
 	struct adreno_context *adreno_ctx = NULL;
-	int ret = 0;
 
 	/*
 	 * Fix target freeze issue by adding TLB flush for each submit
@@ -1005,8 +1021,7 @@
 	if (!adreno_use_default_setstate(adreno_dev)) {
 		context = kgsl_context_get(device, context_id);
 		if (context == NULL)
-			return -EINVAL;
-
+			return;
 		adreno_ctx = ADRENO_CONTEXT(context);
 
 		if (flags & KGSL_MMUFLAGS_PTUPDATE) {
@@ -1081,7 +1096,7 @@
 			sizedwords += 2;
 		}
 
-		ret = adreno_ringbuffer_issuecmds(device, adreno_ctx,
+		adreno_ringbuffer_issuecmds(device, adreno_ctx,
 					KGSL_CMD_FLAGS_PMODE,
 					&link[0], sizedwords);
 
@@ -1089,11 +1104,9 @@
 	} else {
 		kgsl_mmu_device_setstate(&device->mmu, flags);
 	}
-
-	return ret;
 }
 
-static int adreno_setstate(struct kgsl_device *device,
+static void adreno_setstate(struct kgsl_device *device,
 			unsigned int context_id,
 			uint32_t flags)
 {
@@ -1102,8 +1115,6 @@
 		return adreno_gpummu_setstate(device, context_id, flags);
 	else if (KGSL_MMU_TYPE_IOMMU == kgsl_mmu_get_mmutype())
 		return adreno_iommu_setstate(device, context_id, flags);
-
-	return 0;
 }
 
 static unsigned int
@@ -1579,10 +1590,6 @@
 	if (status)
 		goto error_close_rb;
 
-	status = adreno_dispatcher_init(adreno_dev);
-	if (status)
-		goto error_close_device;
-
 	adreno_debugfs_init(device);
 	adreno_profile_init(device);
 
@@ -1598,8 +1605,6 @@
 
 	return 0;
 
-error_close_device:
-	kgsl_device_platform_remove(device);
 error_close_rb:
 	adreno_ringbuffer_close(&adreno_dev->ringbuffer);
 error:
@@ -1622,7 +1627,6 @@
 	kgsl_pwrscale_detach_policy(device);
 	kgsl_pwrscale_close(device);
 
-	adreno_dispatcher_close(adreno_dev);
 	adreno_ringbuffer_close(&adreno_dev->ringbuffer);
 	kgsl_device_platform_remove(device);
 
@@ -1634,7 +1638,8 @@
 	struct adreno_device *adreno_dev = ADRENO_DEVICE(device);
 	int i;
 
-	kgsl_pwrctrl_set_state(device, KGSL_STATE_INIT);
+	if (KGSL_STATE_DUMP_AND_FT != device->state)
+		kgsl_pwrctrl_set_state(device, KGSL_STATE_INIT);
 
 	/* Power up the device */
 	kgsl_pwrctrl_enable(device);
@@ -1692,6 +1697,10 @@
 	/* Power down the device */
 	kgsl_pwrctrl_disable(device);
 
+	/* Certain targets need the fixup.  You know who you are */
+	if (adreno_is_a330v2(adreno_dev))
+		adreno_a3xx_pwron_fixup_init(adreno_dev);
+
 	return 0;
 }
 
@@ -1704,18 +1713,19 @@
 
 	kgsl_cffdump_open(device);
 
-	kgsl_pwrctrl_set_state(device, KGSL_STATE_INIT);
+	if (KGSL_STATE_DUMP_AND_FT != device->state)
+		kgsl_pwrctrl_set_state(device, KGSL_STATE_INIT);
 
 	regulator_left_on = (regulator_is_enabled(device->pwrctrl.gpu_reg) ||
 				(device->pwrctrl.gpu_cx &&
 				regulator_is_enabled(device->pwrctrl.gpu_cx)));
 
-	/* Clear any GPU faults that might have been left over */
-	adreno_set_gpu_fault(adreno_dev, 0);
-
 	/* Power up the device */
 	kgsl_pwrctrl_enable(device);
 
+	/* Set the bit to indicate that we've just powered on */
+	set_bit(ADRENO_DEVICE_PWRON, &adreno_dev->priv);
+
 	/* Set up a2xx special case */
 	if (adreno_is_a2xx(adreno_dev)) {
 		/*
@@ -1758,10 +1768,10 @@
 	if (status)
 		goto error_irq_off;
 
-	adreno_perfcounter_start(adreno_dev);
+	mod_timer(&device->hang_timer,
+		(jiffies + msecs_to_jiffies(KGSL_TIMEOUT_PART)));
 
-	/* Start the dispatcher */
-	adreno_dispatcher_start(adreno_dev);
+	adreno_perfcounter_start(adreno_dev);
 
 	device->reset_counter++;
 
@@ -1792,7 +1802,6 @@
 
 	adreno_dev->drawctxt_active = NULL;
 
-	adreno_dispatcher_stop(adreno_dev);
 	adreno_ringbuffer_stop(&adreno_dev->ringbuffer);
 
 	kgsl_mmu_stop(&device->mmu);
@@ -1800,6 +1809,7 @@
 	device->ftbl->irqctrl(device, 0);
 	kgsl_pwrctrl_irq(device, KGSL_PWRFLAGS_OFF);
 	del_timer_sync(&device->idle_timer);
+	del_timer_sync(&device->hang_timer);
 
 	adreno_ocmem_gmem_free(adreno_dev);
 
@@ -1811,48 +1821,918 @@
 	return 0;
 }
 
-/**
- * adreno_reset() - Helper function to reset the GPU
- * @device: Pointer to the KGSL device structure for the GPU
- *
- * Try to reset the GPU to recover from a fault.  First, try to do a low latency
- * soft reset.  If the soft reset fails for some reason, then bring out the big
- * guns and toggle the footswitch.
+/*
+ * Set the reset status of all contexts to
+ * INNOCENT_CONTEXT_RESET_EXT except for the bad context
+ * since thats the guilty party, if fault tolerance failed then
+ * mark all as guilty
  */
-int adreno_reset(struct kgsl_device *device)
+
+static int _mark_context_status(int id, void *ptr, void *data)
+{
+	unsigned int ft_status = *((unsigned int *) data);
+	struct kgsl_context *context = ptr;
+	struct adreno_context *adreno_context = ADRENO_CONTEXT(context);
+
+	if (ft_status) {
+		context->reset_status =
+				KGSL_CTX_STAT_GUILTY_CONTEXT_RESET_EXT;
+		adreno_context->flags |= CTXT_FLAGS_GPU_HANG;
+	} else if (KGSL_CTX_STAT_GUILTY_CONTEXT_RESET_EXT !=
+		context->reset_status) {
+		if (adreno_context->flags & (CTXT_FLAGS_GPU_HANG |
+			CTXT_FLAGS_GPU_HANG_FT))
+			context->reset_status =
+			KGSL_CTX_STAT_GUILTY_CONTEXT_RESET_EXT;
+		else
+			context->reset_status =
+			KGSL_CTX_STAT_INNOCENT_CONTEXT_RESET_EXT;
+	}
+
+	return 0;
+}
+
+static void adreno_mark_context_status(struct kgsl_device *device,
+					int ft_status)
+{
+	/* Mark the status for all the contexts in the device */
+
+	read_lock(&device->context_lock);
+	idr_for_each(&device->context_idr, _mark_context_status, &ft_status);
+	read_unlock(&device->context_lock);
+}
+
+/*
+ * For hung contexts set the current memstore value to the most recent issued
+ * timestamp - this resets the status and lets the system continue on
+ */
+
+static int _set_max_ts(int id, void *ptr, void *data)
+{
+	struct kgsl_device *device = data;
+	struct kgsl_context *context = ptr;
+	struct adreno_context *drawctxt = ADRENO_CONTEXT(context);
+
+	if (drawctxt && drawctxt->flags & CTXT_FLAGS_GPU_HANG) {
+		kgsl_sharedmem_writel(device, &device->memstore,
+			KGSL_MEMSTORE_OFFSET(context->id,
+			soptimestamp), drawctxt->timestamp);
+		kgsl_sharedmem_writel(device, &device->memstore,
+			KGSL_MEMSTORE_OFFSET(context->id,
+			eoptimestamp), drawctxt->timestamp);
+	}
+
+	return 0;
+}
+
+static void adreno_set_max_ts_for_bad_ctxs(struct kgsl_device *device)
+{
+	read_lock(&device->context_lock);
+	idr_for_each(&device->context_idr, _set_max_ts, device);
+	read_unlock(&device->context_lock);
+}
+
+static void adreno_destroy_ft_data(struct adreno_ft_data *ft_data)
+{
+	vfree(ft_data->rb_buffer);
+	vfree(ft_data->bad_rb_buffer);
+	vfree(ft_data->good_rb_buffer);
+}
+
+static int _find_start_of_cmd_seq(struct adreno_ringbuffer *rb,
+					unsigned int *ptr,
+					bool inc)
+{
+	int status = -EINVAL;
+	unsigned int val1;
+	unsigned int size = rb->buffer_desc.size;
+	unsigned int start_ptr = *ptr;
+
+	while ((start_ptr / sizeof(unsigned int)) != rb->wptr) {
+		if (inc)
+			start_ptr = adreno_ringbuffer_inc_wrapped(start_ptr,
+									size);
+		else
+			start_ptr = adreno_ringbuffer_dec_wrapped(start_ptr,
+									size);
+		kgsl_sharedmem_readl(&rb->buffer_desc, &val1, start_ptr);
+		/* Ensure above read is finished before next read */
+		rmb();
+		if (KGSL_CMD_IDENTIFIER == val1) {
+			if ((start_ptr / sizeof(unsigned int)) != rb->wptr)
+				start_ptr = adreno_ringbuffer_dec_wrapped(
+							start_ptr, size);
+				*ptr = start_ptr;
+				status = 0;
+				break;
+		}
+	}
+	return status;
+}
+
+static int _find_cmd_seq_after_eop_ts(struct adreno_ringbuffer *rb,
+					unsigned int *rb_rptr,
+					unsigned int global_eop,
+					bool inc)
+{
+	int status = -EINVAL;
+	unsigned int temp_rb_rptr = *rb_rptr;
+	unsigned int size = rb->buffer_desc.size;
+	unsigned int val[3];
+	int i = 0;
+	bool check = false;
+
+	if (inc && temp_rb_rptr / sizeof(unsigned int) != rb->wptr)
+		return status;
+
+	do {
+		/*
+		 * when decrementing we need to decrement first and
+		 * then read make sure we cover all the data
+		 */
+		if (!inc)
+			temp_rb_rptr = adreno_ringbuffer_dec_wrapped(
+					temp_rb_rptr, size);
+		kgsl_sharedmem_readl(&rb->buffer_desc, &val[i],
+					temp_rb_rptr);
+		/* Ensure above read is finished before next read */
+		rmb();
+
+		if (check && ((inc && val[i] == global_eop) ||
+			(!inc && (val[i] ==
+			cp_type3_packet(CP_MEM_WRITE, 2) ||
+			val[i] == CACHE_FLUSH_TS)))) {
+			/* decrement i, i.e i = (i - 1 + 3) % 3 if
+			 * we are going forward, else increment i */
+			i = (i + 2) % 3;
+			if (val[i] == rb->device->memstore.gpuaddr +
+				KGSL_MEMSTORE_OFFSET(KGSL_MEMSTORE_GLOBAL,
+						eoptimestamp)) {
+				int j = ((i + 2) % 3);
+				if ((inc && (val[j] == CACHE_FLUSH_TS ||
+						val[j] == cp_type3_packet(
+							CP_MEM_WRITE, 2))) ||
+					(!inc && val[j] == global_eop)) {
+						/* Found the global eop */
+						status = 0;
+						break;
+				}
+			}
+			/* if no match found then increment i again
+			 * since we decremented before matching */
+			i = (i + 1) % 3;
+		}
+		if (inc)
+			temp_rb_rptr = adreno_ringbuffer_inc_wrapped(
+						temp_rb_rptr, size);
+
+		i = (i + 1) % 3;
+		if (2 == i)
+			check = true;
+	} while (temp_rb_rptr / sizeof(unsigned int) != rb->wptr);
+	/* temp_rb_rptr points to the command stream after global eop,
+	 * move backward till the start of command sequence */
+	if (!status) {
+		status = _find_start_of_cmd_seq(rb, &temp_rb_rptr, false);
+		if (!status) {
+			*rb_rptr = temp_rb_rptr;
+			KGSL_FT_INFO(rb->device,
+			"Offset of cmd sequence after eop timestamp: 0x%x\n",
+			temp_rb_rptr / sizeof(unsigned int));
+		}
+	}
+	if (status)
+		KGSL_FT_ERR(rb->device,
+		"Failed to find the command sequence after eop timestamp %x\n",
+		global_eop);
+	return status;
+}
+
+static int _find_hanging_ib_sequence(struct adreno_ringbuffer *rb,
+				unsigned int *rb_rptr,
+				unsigned int ib1)
+{
+	int status = -EINVAL;
+	unsigned int temp_rb_rptr = *rb_rptr;
+	unsigned int size = rb->buffer_desc.size;
+	unsigned int val[2];
+	int i = 0;
+	bool check = false;
+	bool ctx_switch = false;
+
+	while (temp_rb_rptr / sizeof(unsigned int) != rb->wptr) {
+		kgsl_sharedmem_readl(&rb->buffer_desc, &val[i], temp_rb_rptr);
+		/* Ensure above read is finished before next read */
+		rmb();
+
+		if (check && val[i] == ib1) {
+			/* decrement i, i.e i = (i - 1 + 2) % 2 */
+			i = (i + 1) % 2;
+			if (adreno_cmd_is_ib(val[i])) {
+				/* go till start of command sequence */
+				status = _find_start_of_cmd_seq(rb,
+						&temp_rb_rptr, false);
+
+				KGSL_FT_INFO(rb->device,
+				"Found the hanging IB at offset 0x%x\n",
+				temp_rb_rptr / sizeof(unsigned int));
+				break;
+			}
+			/* if no match the increment i since we decremented
+			 * before checking */
+			i = (i + 1) % 2;
+		}
+		/* Make sure you do not encounter a context switch twice, we can
+		 * encounter it once for the bad context as the start of search
+		 * can point to the context switch */
+		if (val[i] == KGSL_CONTEXT_TO_MEM_IDENTIFIER) {
+			if (ctx_switch) {
+				KGSL_FT_ERR(rb->device,
+				"Context switch encountered before bad "
+				"IB found\n");
+				break;
+			}
+			ctx_switch = true;
+		}
+		i = (i + 1) % 2;
+		if (1 == i)
+			check = true;
+		temp_rb_rptr = adreno_ringbuffer_inc_wrapped(temp_rb_rptr,
+								size);
+	}
+	if  (!status)
+		*rb_rptr = temp_rb_rptr;
+	return status;
+}
+
+static void adreno_setup_ft_data(struct kgsl_device *device,
+					struct adreno_ft_data *ft_data)
 {
 	int ret = 0;
+	struct adreno_device *adreno_dev = ADRENO_DEVICE(device);
+	struct adreno_ringbuffer *rb = &adreno_dev->ringbuffer;
+	struct kgsl_context *context;
+	struct adreno_context *adreno_context;
+	unsigned int rb_rptr = rb->wptr * sizeof(unsigned int);
 
-	/* Try soft reset first */
-	if (adreno_soft_reset(device) != 0) {
+	memset(ft_data, 0, sizeof(*ft_data));
+	ft_data->start_of_replay_cmds = 0xFFFFFFFF;
+	ft_data->replay_for_snapshot = 0xFFFFFFFF;
+
+	adreno_readreg(adreno_dev, ADRENO_REG_CP_IB1_BASE, &ft_data->ib1);
+
+	kgsl_sharedmem_readl(&device->memstore, &ft_data->context_id,
+			KGSL_MEMSTORE_OFFSET(KGSL_MEMSTORE_GLOBAL,
+			current_context));
+
+	kgsl_sharedmem_readl(&device->memstore,
+			&ft_data->global_eop,
+			KGSL_MEMSTORE_OFFSET(KGSL_MEMSTORE_GLOBAL,
+			eoptimestamp));
+
+	/* Ensure context id and global eop ts read complete */
+	rmb();
+
+	ft_data->rb_buffer = vmalloc(rb->buffer_desc.size);
+	if (!ft_data->rb_buffer) {
+		KGSL_MEM_ERR(device, "vmalloc(%d) failed\n",
+				rb->buffer_desc.size);
+		return;
+	}
+
+	ft_data->bad_rb_buffer = vmalloc(rb->buffer_desc.size);
+	if (!ft_data->bad_rb_buffer) {
+		KGSL_MEM_ERR(device, "vmalloc(%d) failed\n",
+				rb->buffer_desc.size);
+		return;
+	}
+
+	ft_data->good_rb_buffer = vmalloc(rb->buffer_desc.size);
+	if (!ft_data->good_rb_buffer) {
+		KGSL_MEM_ERR(device, "vmalloc(%d) failed\n",
+				rb->buffer_desc.size);
+		return;
+	}
+	ft_data->status = 0;
+
+	/* find the start of bad command sequence in rb */
+	context = kgsl_context_get(device, ft_data->context_id);
+
+	ft_data->ft_policy = adreno_dev->ft_policy;
+
+	if (!ft_data->ft_policy)
+		ft_data->ft_policy = KGSL_FT_DEFAULT_POLICY;
+
+	/* Look for the command stream that is right after the global eop */
+	ret = _find_cmd_seq_after_eop_ts(rb, &rb_rptr,
+					ft_data->global_eop + 1, false);
+	if (ret) {
+		ft_data->ft_policy |= KGSL_FT_TEMP_DISABLE;
+		goto done;
+	} else {
+		ft_data->start_of_replay_cmds = rb_rptr;
+		ft_data->ft_policy &= ~KGSL_FT_TEMP_DISABLE;
+	}
+
+	if (context) {
+		adreno_context = ADRENO_CONTEXT(context);
+		if (adreno_context->flags & CTXT_FLAGS_PREAMBLE) {
+			if (ft_data->ib1) {
+				ret = _find_hanging_ib_sequence(rb,
+						&rb_rptr, ft_data->ib1);
+				if (ret) {
+					KGSL_FT_ERR(device,
+					"Start not found for replay IB seq\n");
+					goto done;
+				}
+				ft_data->start_of_replay_cmds = rb_rptr;
+				ft_data->replay_for_snapshot = rb_rptr;
+			}
+		}
+	}
+
+done:
+	kgsl_context_put(context);
+}
+
+static int
+_adreno_check_long_ib(struct kgsl_device *device)
+{
+	struct adreno_device *adreno_dev = ADRENO_DEVICE(device);
+	unsigned int curr_global_ts = 0;
+
+	/* check if the global ts is still the same */
+	kgsl_sharedmem_readl(&device->memstore,
+			&curr_global_ts,
+			KGSL_MEMSTORE_OFFSET(KGSL_MEMSTORE_GLOBAL,
+			eoptimestamp));
+	/* Ensure above read is finished before long ib check */
+	rmb();
+
+	/* Mark long ib as handled */
+	adreno_dev->long_ib = 0;
+
+	if (curr_global_ts == adreno_dev->long_ib_ts) {
+		KGSL_FT_ERR(device,
+			"IB ran too long, invalidate ctxt\n");
+		return 1;
+	} else {
+		/* Do nothing GPU has gone ahead */
+		KGSL_FT_INFO(device, "false long ib detection return\n");
+		return 0;
+	}
+}
+
+/**
+ * adreno_soft_reset() -  Do a soft reset of the GPU hardware
+ * @device: KGSL device to soft reset
+ *
+ * "soft reset" the GPU hardware - this is a fast path GPU reset
+ * The GPU hardware is reset but we never pull power so we can skip
+ * a lot of the standard adreno_stop/adreno_start sequence
+ */
+int adreno_soft_reset(struct kgsl_device *device)
+{
+	struct adreno_device *adreno_dev = ADRENO_DEVICE(device);
+	int ret;
+
+	/* If the jump table index is 0 soft reset is not supported */
+	if ((!adreno_dev->pm4_jt_idx) || (!adreno_dev->gpudev->soft_reset)) {
+		dev_WARN_ONCE(device->dev, 1, "Soft reset not supported");
+		return -EINVAL;
+	}
+
+	if (adreno_dev->drawctxt_active)
+		kgsl_context_put(&adreno_dev->drawctxt_active->base);
+
+	adreno_dev->drawctxt_active = NULL;
+
+	/* Stop the ringbuffer */
+	adreno_ringbuffer_stop(&adreno_dev->ringbuffer);
+
+	/* Delete the idle timer */
+	del_timer_sync(&device->idle_timer);
+
+	/* Make sure we are totally awake */
+	kgsl_pwrctrl_enable(device);
+
+	/* Reset the GPU */
+	adreno_dev->gpudev->soft_reset(adreno_dev);
+
+	/* Reinitialize the GPU */
+	adreno_dev->gpudev->start(adreno_dev);
+
+	/* Enable IRQ */
+	kgsl_pwrctrl_irq(device, KGSL_PWRFLAGS_ON);
+	device->ftbl->irqctrl(device, 1);
+
+	/*
+	 * Restart the ringbuffer - we can go down the warm start path because
+	 * power was never yanked
+	 */
+	ret = adreno_ringbuffer_warm_start(&adreno_dev->ringbuffer);
+	if (ret)
+		return ret;
+
+	device->reset_counter++;
+
+	return 0;
+}
+
+static int
+_adreno_ft_restart_device(struct kgsl_device *device,
+			   struct kgsl_context *context)
+{
+	/* If device soft reset fails try hard reset */
+	if (adreno_soft_reset(device))
 		KGSL_DEV_ERR_ONCE(device, "Device soft reset failed\n");
+	else
+		/* Soft reset is successful */
+		goto reset_done;
 
-		/* If it failed, then pull the power */
-		ret = adreno_stop(device);
-		if (ret)
-			return ret;
+	/* restart device */
+	if (adreno_stop(device)) {
+		KGSL_FT_ERR(device, "Device stop failed\n");
+		return 1;
+	}
 
-		ret = adreno_start(device);
+	if (adreno_init(device)) {
+		KGSL_FT_ERR(device, "Device init failed\n");
+		return 1;
+	}
 
-		if (ret)
-			return ret;
+	if (adreno_start(device)) {
+		KGSL_FT_ERR(device, "Device start failed\n");
+		return 1;
+	}
+
+reset_done:
+	if (context)
+		kgsl_mmu_setstate(&device->mmu, context->pagetable,
+				KGSL_MEMSTORE_GLOBAL);
+
+	/* If iommu is used then we need to make sure that the iommu clocks
+	 * are on since there could be commands in pipeline that touch iommu */
+	if (KGSL_MMU_TYPE_IOMMU == kgsl_mmu_get_mmutype()) {
+		if (kgsl_mmu_enable_clk(&device->mmu,
+				KGSL_IOMMU_CONTEXT_USER))
+			return 1;
+	}
+
+	return 0;
+}
+
+static inline void
+_adreno_debug_ft_info(struct kgsl_device *device,
+			struct adreno_ft_data *ft_data)
+{
+
+	/*
+	 * Dumping rb is a very useful tool to debug FT.
+	 * It will tell us if we are extracting the rb correctly
+	 * NOP'ing the right IB, skipping the EOF correctly etc.
+	 */
+	if (device->ft_log >= 7)  {
+
+		/* Print fault tolerance data here */
+		KGSL_FT_INFO(device, "Temp RB buffer size 0x%X\n",
+			ft_data->rb_size);
+		adreno_dump_rb(device, ft_data->rb_buffer,
+			ft_data->rb_size<<2, 0, ft_data->rb_size);
+
+		KGSL_FT_INFO(device, "Bad RB buffer size 0x%X\n",
+			ft_data->bad_rb_size);
+		adreno_dump_rb(device, ft_data->bad_rb_buffer,
+			ft_data->bad_rb_size<<2, 0, ft_data->bad_rb_size);
+
+		KGSL_FT_INFO(device, "Good RB buffer size 0x%X\n",
+			ft_data->good_rb_size);
+		adreno_dump_rb(device, ft_data->good_rb_buffer,
+			ft_data->good_rb_size<<2, 0, ft_data->good_rb_size);
+
+	}
+}
+
+static int
+_adreno_ft_resubmit_rb(struct kgsl_device *device,
+			struct adreno_ringbuffer *rb,
+			struct kgsl_context *context,
+			struct adreno_ft_data *ft_data,
+			unsigned int *buff, unsigned int size)
+{
+	unsigned int ret = 0;
+	unsigned int retry_num = 0;
+
+	_adreno_debug_ft_info(device, ft_data);
+
+	do {
+		ret = _adreno_ft_restart_device(device, context);
+		if (ret == 0)
+			break;
+		/*
+		 * If device restart fails sleep for 20ms before
+		 * attempting restart. This allows GPU HW to settle
+		 * and improve the chances of next restart to be
+		 * successful.
+		 */
+		msleep(20);
+		KGSL_FT_ERR(device, "Retry device restart %d\n", retry_num);
+		retry_num++;
+	} while (retry_num < 4);
+
+	if (ret) {
+		KGSL_FT_ERR(device, "Device restart failed\n");
+		BUG_ON(1);
+		goto done;
+	}
+
+	if (size) {
+
+		/* submit commands and wait for them to pass */
+		adreno_ringbuffer_restore(rb, buff, size);
+
+		ret = adreno_idle(device);
+	}
+
+done:
+	return ret;
+}
+
+
+static int
+_adreno_ft(struct kgsl_device *device,
+			struct adreno_ft_data *ft_data)
+{
+	int ret = 0, i;
+	struct adreno_device *adreno_dev = ADRENO_DEVICE(device);
+	struct adreno_ringbuffer *rb = &adreno_dev->ringbuffer;
+	struct kgsl_context *context;
+	struct adreno_context *adreno_context = NULL;
+	struct adreno_context *last_active_ctx = adreno_dev->drawctxt_active;
+	unsigned int long_ib = 0;
+	static int no_context_ft;
+	struct kgsl_mmu *mmu = &device->mmu;
+
+	context = kgsl_context_get(device, ft_data->context_id);
+
+	if (context == NULL) {
+		KGSL_FT_ERR(device, "Last context unknown id:%d\n",
+			ft_data->context_id);
+		if (no_context_ft) {
+			/*
+			 * If 2 consecutive no context ft occurred then
+			 * just reset GPU
+			 */
+			no_context_ft = 0;
+			goto play_good_cmds;
+		}
+	} else {
+		no_context_ft = 0;
+		adreno_context = ADRENO_CONTEXT(context);
+		adreno_context->flags |= CTXT_FLAGS_GPU_HANG;
+		/*
+		 * set the invalid ts flag to 0 for this context since we have
+		 * detected a hang for it
+		 */
+		context->wait_on_invalid_ts = false;
+
+		if (!(adreno_context->flags & CTXT_FLAGS_PER_CONTEXT_TS)) {
+			ft_data->status = 1;
+			KGSL_FT_ERR(device, "Fault tolerance not supported\n");
+			goto play_good_cmds;
+		}
+
+		/*
+		 *  This flag will be set by userspace for contexts
+		 *  that do not want to be fault tolerant (ex: OPENCL)
+		 */
+		if (adreno_context->flags & CTXT_FLAGS_NO_FAULT_TOLERANCE) {
+			ft_data->status = 1;
+			KGSL_FT_ERR(device,
+			"No FT set for this context play good cmds\n");
+			goto play_good_cmds;
+		}
+
+	}
+
+	/* Check if we detected a long running IB, if false return */
+	if ((adreno_context) && (adreno_dev->long_ib)) {
+		long_ib = _adreno_check_long_ib(device);
+		if (!long_ib) {
+			adreno_context->flags &= ~CTXT_FLAGS_GPU_HANG;
+			return 0;
+		}
 	}
 
 	/*
-	 * If active_cnt is non-zero then the system was active before
-	 * going into a reset - put it back in that state
+	 * Extract valid contents from rb which can still be executed after
+	 * hang
 	 */
+	adreno_ringbuffer_extract(rb, ft_data);
 
-	if (atomic_read(&device->active_cnt))
-		kgsl_pwrctrl_set_state(device, KGSL_STATE_ACTIVE);
+	/* If long IB detected do not attempt replay of bad cmds */
+	if (long_ib) {
+		ft_data->status = 1;
+		_adreno_debug_ft_info(device, ft_data);
+		goto play_good_cmds;
+	}
 
-	/* Set the page table back to the default page table */
-	kgsl_mmu_setstate(&device->mmu, device->mmu.defaultpagetable,
-			KGSL_MEMSTORE_GLOBAL);
+	if ((ft_data->ft_policy & KGSL_FT_DISABLE) ||
+		(ft_data->ft_policy & KGSL_FT_TEMP_DISABLE)) {
+		KGSL_FT_ERR(device, "NO FT policy play only good cmds\n");
+		ft_data->status = 1;
+		goto play_good_cmds;
+	}
 
+	/* Do not try to replay if hang is due to a pagefault */
+	if (context && test_bit(KGSL_CONTEXT_PAGEFAULT, &context->priv)) {
+		/* Resume MMU */
+		mmu->mmu_ops->mmu_pagefault_resume(mmu);
+		if ((ft_data->context_id == context->id) &&
+			(ft_data->global_eop == context->pagefault_ts)) {
+			ft_data->ft_policy &= ~KGSL_FT_REPLAY;
+			KGSL_FT_ERR(device, "MMU fault skipping replay\n");
+		}
+		clear_bit(KGSL_CONTEXT_PAGEFAULT, &context->priv);
+	}
+
+	if (ft_data->ft_policy & KGSL_FT_REPLAY) {
+		ret = _adreno_ft_resubmit_rb(device, rb, context, ft_data,
+				ft_data->bad_rb_buffer, ft_data->bad_rb_size);
+
+		if (ret) {
+			KGSL_FT_ERR(device, "Replay status: 1\n");
+			ft_data->status = 1;
+		} else
+			goto play_good_cmds;
+	}
+
+	if (ft_data->ft_policy & KGSL_FT_SKIPIB) {
+		for (i = 0; i < ft_data->bad_rb_size; i++) {
+			if ((ft_data->bad_rb_buffer[i] ==
+					CP_HDR_INDIRECT_BUFFER_PFD) &&
+				(ft_data->bad_rb_buffer[i+1] == ft_data->ib1)) {
+
+				ft_data->bad_rb_buffer[i] = cp_nop_packet(2);
+				ft_data->bad_rb_buffer[i+1] =
+							KGSL_NOP_IB_IDENTIFIER;
+				ft_data->bad_rb_buffer[i+2] =
+							KGSL_NOP_IB_IDENTIFIER;
+				break;
+			}
+		}
+
+		if ((i == (ft_data->bad_rb_size)) || (!ft_data->ib1)) {
+			KGSL_FT_ERR(device, "Bad IB to NOP not found\n");
+			ft_data->status = 1;
+			goto play_good_cmds;
+		}
+
+		ret = _adreno_ft_resubmit_rb(device, rb, context, ft_data,
+				ft_data->bad_rb_buffer, ft_data->bad_rb_size);
+
+		if (ret) {
+			KGSL_FT_ERR(device, "NOP faulty IB status: 1\n");
+			ft_data->status = 1;
+		} else {
+			ft_data->status = 0;
+			goto play_good_cmds;
+		}
+	}
+
+	if (ft_data->ft_policy & KGSL_FT_SKIPFRAME) {
+		for (i = 0; i < ft_data->bad_rb_size; i++) {
+			if (ft_data->bad_rb_buffer[i] ==
+					KGSL_END_OF_FRAME_IDENTIFIER) {
+				ft_data->bad_rb_buffer[0] = cp_nop_packet(i);
+				break;
+			}
+		}
+
+		/* EOF not found in RB, discard till EOF in
+		   next IB submission */
+		if (adreno_context && (i == ft_data->bad_rb_size)) {
+			adreno_context->flags |= CTXT_FLAGS_SKIP_EOF;
+			KGSL_FT_INFO(device,
+			"EOF not found in RB, skip next issueib till EOF\n");
+			ft_data->bad_rb_buffer[0] = cp_nop_packet(i);
+		}
+
+		ret = _adreno_ft_resubmit_rb(device, rb, context, ft_data,
+				ft_data->bad_rb_buffer, ft_data->bad_rb_size);
+
+		if (ret) {
+			KGSL_FT_ERR(device, "Skip EOF status: 1\n");
+			ft_data->status = 1;
+		} else {
+			ft_data->status = 0;
+			goto play_good_cmds;
+		}
+	}
+
+play_good_cmds:
+
+	if (ft_data->status)
+		KGSL_FT_ERR(device, "Bad context commands failed\n");
+	else {
+		KGSL_FT_INFO(device, "Bad context commands success\n");
+
+		if (adreno_context) {
+			adreno_context->flags = (adreno_context->flags &
+				~CTXT_FLAGS_GPU_HANG) | CTXT_FLAGS_GPU_HANG_FT;
+		}
+
+		if (last_active_ctx)
+			_kgsl_context_get(&last_active_ctx->base);
+
+		adreno_dev->drawctxt_active = last_active_ctx;
+	}
+
+	ret = _adreno_ft_resubmit_rb(device, rb, context, ft_data,
+			ft_data->good_rb_buffer, ft_data->good_rb_size);
+
+	if (ret) {
+		/*
+		 * If we fail here we can try to invalidate another
+		 * context and try fault tolerance again, although
+		 * we will only try ft with no context once to avoid
+		 * going into continuous loop of trying ft with no context
+		 */
+		if (!context)
+			no_context_ft = 1;
+		ret = -EAGAIN;
+		KGSL_FT_ERR(device, "Playing good commands unsuccessful\n");
+		goto done;
+	} else
+		KGSL_FT_INFO(device, "Playing good commands successful\n");
+
+	/* ringbuffer now has data from the last valid context id,
+	 * so restore the active_ctx to the last valid context */
+	if (ft_data->last_valid_ctx_id) {
+		struct kgsl_context *last_ctx = kgsl_context_get(device,
+			ft_data->last_valid_ctx_id);
+
+		adreno_dev->drawctxt_active = ADRENO_CONTEXT(last_ctx);
+	}
+
+done:
+	/* Turn off iommu clocks */
+	if (KGSL_MMU_TYPE_IOMMU == kgsl_mmu_get_mmutype())
+		kgsl_mmu_disable_clk_on_ts(&device->mmu, 0, false);
+
+	kgsl_context_put(context);
 	return ret;
 }
 
+static int
+adreno_ft(struct kgsl_device *device,
+			struct adreno_ft_data *ft_data)
+{
+	int ret = 0;
+	struct adreno_device *adreno_dev = ADRENO_DEVICE(device);
+	struct adreno_ringbuffer *rb = &adreno_dev->ringbuffer;
+
+	/*
+	 * If GPU FT is turned off do not run FT.
+	 * If GPU stall detection is suspected to be false,
+	 * we can use this option to confirm stall detection.
+	 */
+	if (ft_data->ft_policy & KGSL_FT_OFF) {
+		KGSL_FT_ERR(device, "GPU FT turned off\n");
+		return 0;
+	}
+
+	KGSL_FT_INFO(device,
+	"Start Parameters: IB1: 0x%X, "
+	"Bad context_id: %u, global_eop: 0x%x\n",
+	ft_data->ib1, ft_data->context_id, ft_data->global_eop);
+
+	KGSL_FT_INFO(device, "Last issued global timestamp: %x\n",
+			rb->global_ts);
+
+	/* We may need to replay commands multiple times based on whether
+	 * multiple contexts hang the GPU */
+	while (true) {
+
+		ret = _adreno_ft(device, ft_data);
+
+		if (-EAGAIN == ret) {
+			/* setup new fault tolerance parameters and retry, this
+			 * means more than 1 contexts are causing hang */
+			adreno_destroy_ft_data(ft_data);
+			adreno_setup_ft_data(device, ft_data);
+			KGSL_FT_INFO(device,
+			"Retry. Parameters: "
+			"IB1: 0x%X, Bad context_id: %u, global_eop: 0x%x\n",
+			ft_data->ib1, ft_data->context_id,
+			ft_data->global_eop);
+		} else {
+			break;
+		}
+	}
+
+	if (ret)
+		goto done;
+
+	/* Restore correct states after fault tolerance */
+	if (adreno_dev->drawctxt_active)
+		device->mmu.hwpagetable =
+			adreno_dev->drawctxt_active->base.pagetable;
+	else
+		device->mmu.hwpagetable = device->mmu.defaultpagetable;
+	kgsl_sharedmem_writel(device, &device->memstore,
+			KGSL_MEMSTORE_OFFSET(KGSL_MEMSTORE_GLOBAL,
+			eoptimestamp), rb->global_ts);
+
+	/* switch to NULL ctxt */
+	if (adreno_dev->drawctxt_active != NULL)
+		adreno_drawctxt_switch(adreno_dev, NULL, 0);
+
+done:
+	adreno_set_max_ts_for_bad_ctxs(device);
+	adreno_mark_context_status(device, ret);
+	KGSL_FT_ERR(device, "policy 0x%X status 0x%x\n",
+			ft_data->ft_policy, ret);
+	return ret;
+}
+
+int
+adreno_dump_and_exec_ft(struct kgsl_device *device)
+{
+	int result = -ETIMEDOUT;
+	struct adreno_ft_data ft_data;
+	struct adreno_device *adreno_dev = ADRENO_DEVICE(device);
+	struct kgsl_pwrctrl *pwr = &device->pwrctrl;
+	unsigned int curr_pwrlevel;
+
+	if (device->state == KGSL_STATE_HUNG)
+		goto done;
+	if (device->state == KGSL_STATE_DUMP_AND_FT) {
+		mutex_unlock(&device->mutex);
+		wait_for_completion(&device->ft_gate);
+		mutex_lock(&device->mutex);
+		if (device->state != KGSL_STATE_HUNG)
+			result = 0;
+	} else {
+		/*
+		 * While fault tolerance is happening we do not want the
+		 * idle_timer to fire and attempt to change any device state
+		 */
+		del_timer_sync(&device->idle_timer);
+
+		kgsl_pwrctrl_set_state(device, KGSL_STATE_DUMP_AND_FT);
+		INIT_COMPLETION(device->ft_gate);
+		/* Detected a hang */
+
+		kgsl_cffdump_hang(device);
+		/* Run fault tolerance at max power level */
+		curr_pwrlevel = pwr->active_pwrlevel;
+		kgsl_pwrctrl_pwrlevel_change(device, pwr->max_pwrlevel);
+
+		/* Get the fault tolerance data as soon as hang is detected */
+		adreno_setup_ft_data(device, &ft_data);
+
+		/*
+		 * If long ib is detected, do not attempt postmortem or
+		 * snapshot, if GPU is still executing commands
+		 * we will get errors
+		 */
+		if (!adreno_dev->long_ib) {
+			/*
+			 * Trigger an automatic dump of the state to
+			 * the console
+			 */
+			kgsl_postmortem_dump(device, 0);
+
+			/*
+			* Make a GPU snapshot.  For now, do it after the
+			* PM dump so we can at least be sure the PM dump
+			* will work as it always has
+			*/
+			kgsl_device_snapshot(device, 1);
+		}
+
+		result = adreno_ft(device, &ft_data);
+		adreno_destroy_ft_data(&ft_data);
+
+		/* restore power level */
+		kgsl_pwrctrl_pwrlevel_change(device, curr_pwrlevel);
+
+		if (result) {
+			kgsl_pwrctrl_set_state(device, KGSL_STATE_HUNG);
+		} else {
+			kgsl_pwrctrl_set_state(device, KGSL_STATE_ACTIVE);
+			mod_timer(&device->hang_timer,
+				(jiffies +
+				msecs_to_jiffies(KGSL_TIMEOUT_PART)));
+		}
+		complete_all(&device->ft_gate);
+	}
+done:
+	return result;
+}
+EXPORT_SYMBOL(adreno_dump_and_exec_ft);
+
 /**
  * _ft_sysfs_store() -  Common routine to write to FT sysfs files
  * @buf: value to write
@@ -2235,6 +3115,7 @@
 				adreno_dev->fast_hang_detect = 1;
 				kgsl_pwrscale_enable(device);
 			} else {
+				kgsl_pwrctrl_wake(device);
 				device->pwrctrl.ctrl_flags = KGSL_PWR_ON;
 				adreno_dev->fast_hang_detect = 0;
 				kgsl_pwrscale_disable(device);
@@ -2250,181 +3131,140 @@
 	return status;
 }
 
-/**
- * adreno_hw_isidle() - Check if the GPU core is idle
- * @device: Pointer to the KGSL device structure for the GPU
- *
- * Return true if the RBBM status register for the GPU type indicates that the
- * hardware is idle
- */
-static bool adreno_hw_isidle(struct kgsl_device *device)
-{
-	unsigned int reg_rbbm_status;
-	struct adreno_device *adreno_dev = ADRENO_DEVICE(device);
-
-	/* Don't consider ourselves idle if there is an IRQ pending */
-	if (adreno_dev->gpudev->irq_pending(adreno_dev))
-		return false;
-
-	adreno_readreg(adreno_dev, ADRENO_REG_RBBM_STATUS,
-		&reg_rbbm_status);
-
-	if (adreno_is_a2xx(adreno_dev)) {
-		if (reg_rbbm_status == 0x110)
-			return true;
-	} else if (adreno_is_a3xx(adreno_dev)) {
-		if (!(reg_rbbm_status & 0x80000000))
-			return true;
-	}
-
-	return false;
-}
-
-/**
- * adreno_soft_reset() -  Do a soft reset of the GPU hardware
- * @device: KGSL device to soft reset
- *
- * "soft reset" the GPU hardware - this is a fast path GPU reset
- * The GPU hardware is reset but we never pull power so we can skip
- * a lot of the standard adreno_stop/adreno_start sequence
- */
-int adreno_soft_reset(struct kgsl_device *device)
+static int adreno_ringbuffer_drain(struct kgsl_device *device,
+	unsigned int *regs)
 {
 	struct adreno_device *adreno_dev = ADRENO_DEVICE(device);
-	int ret;
+	struct adreno_ringbuffer *rb = &adreno_dev->ringbuffer;
+	unsigned long wait = jiffies;
+	unsigned long timeout = jiffies + msecs_to_jiffies(ADRENO_IDLE_TIMEOUT);
+	unsigned int rptr;
 
-	/* If the jump table index is 0 soft reset is not supported */
-	if ((!adreno_dev->pm4_jt_idx) || (!adreno_dev->gpudev->soft_reset)) {
-		dev_WARN_ONCE(device->dev, 1, "Soft reset not supported");
-		return -EINVAL;
-	}
+	do {
+		/*
+		 * Wait is "jiffies" first time in the loop to start
+		 * GPU stall detection immediately.
+		 */
+		if (time_after(jiffies, wait)) {
+			/* Check to see if the core is hung */
+			if (adreno_ft_detect(device, regs))
+				return -ETIMEDOUT;
 
-	if (adreno_dev->drawctxt_active)
-		kgsl_context_put(&adreno_dev->drawctxt_active->base);
-
-	adreno_dev->drawctxt_active = NULL;
-
-	/* Stop the ringbuffer */
-	adreno_ringbuffer_stop(&adreno_dev->ringbuffer);
-
-	if (kgsl_pwrctrl_isenabled(device))
-		device->ftbl->irqctrl(device, 0);
-
-	kgsl_pwrctrl_irq(device, KGSL_PWRFLAGS_OFF);
-
-	adreno_set_gpu_fault(adreno_dev, 0);
-
-	/* Delete the idle timer */
-	del_timer_sync(&device->idle_timer);
-
-	/* Make sure we are totally awake */
-	kgsl_pwrctrl_enable(device);
-
-	/* Reset the GPU */
-	adreno_dev->gpudev->soft_reset(adreno_dev);
-
-	/* Reinitialize the GPU */
-	adreno_dev->gpudev->start(adreno_dev);
-
-	/* Enable IRQ */
-	kgsl_pwrctrl_irq(device, KGSL_PWRFLAGS_ON);
-	device->ftbl->irqctrl(device, 1);
-
-	/*
-	 * Restart the ringbuffer - we can go down the warm start path because
-	 * power was never yanked
-	 */
-	ret = adreno_ringbuffer_warm_start(&adreno_dev->ringbuffer);
-	if (ret)
-		return ret;
-
-	device->reset_counter++;
+			wait = jiffies + msecs_to_jiffies(KGSL_TIMEOUT_PART);
+		}
+		rptr = adreno_get_rptr(rb);
+		if (time_after(jiffies, timeout)) {
+			KGSL_DRV_ERR(device, "rptr: %x, wptr: %x\n",
+				rptr, rb->wptr);
+			return -ETIMEDOUT;
+		}
+	} while (rptr != rb->wptr);
 
 	return 0;
 }
 
-/*
- * adreno_isidle() - return true if the GPU hardware is idle
- * @device: Pointer to the KGSL device structure for the GPU
- *
- * Return true if the GPU hardware is idle and there are no commands pending in
- * the ringbuffer
- */
-static bool adreno_isidle(struct kgsl_device *device)
-{
-	struct adreno_device *adreno_dev = ADRENO_DEVICE(device);
-	unsigned int rptr;
-
-	if (!kgsl_pwrctrl_isenabled(device))
-		return true;
-
-	rptr = adreno_get_rptr(&adreno_dev->ringbuffer);
-
-	if (rptr == adreno_dev->ringbuffer.wptr)
-		return adreno_hw_isidle(device);
-
-	return false;
-}
-
-/**
- * adreno_idle() - wait for the GPU hardware to go idle
- * @device: Pointer to the KGSL device structure for the GPU
- *
- * Wait up to ADRENO_IDLE_TIMEOUT milliseconds for the GPU hardware to go quiet.
- */
-
+/* Caller must hold the device mutex. */
 int adreno_idle(struct kgsl_device *device)
 {
+	unsigned long wait_time;
+	unsigned long wait_time_part;
+	unsigned int prev_reg_val[FT_DETECT_REGS_COUNT];
 	struct adreno_device *adreno_dev = ADRENO_DEVICE(device);
-	unsigned long wait = jiffies + msecs_to_jiffies(ADRENO_IDLE_TIMEOUT);
 
-	/*
-	 * Make sure the device mutex is held so the dispatcher can't send any
-	 * more commands to the hardware
-	 */
+	memset(prev_reg_val, 0, sizeof(prev_reg_val));
 
-	BUG_ON(!mutex_is_locked(&device->mutex));
+	kgsl_cffdump_regpoll(device,
+		adreno_getreg(adreno_dev, ADRENO_REG_RBBM_STATUS) << 2,
+		0x00000000, 0x80000000);
 
-	if (adreno_is_a3xx(adreno_dev))
-		kgsl_cffdump_regpoll(device,
-			adreno_getreg(adreno_dev, ADRENO_REG_RBBM_STATUS) << 2,
-			0x00000000, 0x80000000);
-	else
-		kgsl_cffdump_regpoll(device,
-			adreno_getreg(adreno_dev, ADRENO_REG_RBBM_STATUS) << 2,
-			0x110, 0x110);
+retry:
+	/* First, wait for the ringbuffer to drain */
+	if (adreno_ringbuffer_drain(device, prev_reg_val))
+		goto err;
 
-	while (time_before(jiffies, wait)) {
-		/*
-		 * If we fault, stop waiting and return an error. The dispatcher
-		 * will clean up the fault from the work queue, but we need to
-		 * make sure we don't block it by waiting for an idle that
-		 * will never come.
-		 */
+	/* now, wait for the GPU to finish its operations */
+	wait_time = jiffies + msecs_to_jiffies(ADRENO_IDLE_TIMEOUT);
+	wait_time_part = jiffies + msecs_to_jiffies(KGSL_TIMEOUT_PART);
 
-		if (adreno_gpu_fault(adreno_dev) != 0)
-			return -EDEADLK;
-
+	while (time_before(jiffies, wait_time)) {
 		if (adreno_isidle(device))
 			return 0;
+
+		/* Dont wait for timeout, detect hang faster.  */
+		if (time_after(jiffies, wait_time_part)) {
+			wait_time_part = jiffies +
+				msecs_to_jiffies(KGSL_TIMEOUT_PART);
+			if ((adreno_ft_detect(device, prev_reg_val)))
+				goto err;
+		}
+
 	}
 
+err:
+	KGSL_DRV_ERR(device, "spun too long waiting for RB to idle\n");
+	if (KGSL_STATE_DUMP_AND_FT != device->state &&
+		!adreno_dump_and_exec_ft(device)) {
+		wait_time = jiffies + ADRENO_IDLE_TIMEOUT;
+		goto retry;
+	}
 	return -ETIMEDOUT;
 }
 
 /**
- * adreno_drain() - Drain the dispatch queue
- * @device: Pointer to the KGSL device structure for the GPU
- *
- * Tell the dispatcher to pause - this has the effect of draining the inflight
- * command batches
+ * is_adreno_rbbm_status_idle - Check if GPU core is idle by probing
+ * rbbm_status register
+ * @device - Pointer to the GPU device whose idle status is to be
+ * checked
+ * @returns - Returns whether the core is idle (based on rbbm_status)
+ * false if the core is active, true if the core is idle
  */
-static int adreno_drain(struct kgsl_device *device)
+static bool is_adreno_rbbm_status_idle(struct kgsl_device *device)
 {
+	unsigned int reg_rbbm_status;
+	bool status = false;
 	struct adreno_device *adreno_dev = ADRENO_DEVICE(device);
 
-	adreno_dispatcher_pause(adreno_dev);
-	return 0;
+	/* Is the core idle? */
+	adreno_readreg(adreno_dev, ADRENO_REG_RBBM_STATUS,
+				&reg_rbbm_status);
+
+	if (adreno_is_a2xx(adreno_dev)) {
+		if (reg_rbbm_status == 0x110)
+			status = true;
+	} else {
+		if (!(reg_rbbm_status & 0x80000000))
+			status = true;
+	}
+	return status;
+}
+
+static unsigned int adreno_isidle(struct kgsl_device *device)
+{
+	int status = false;
+	struct adreno_device *adreno_dev = ADRENO_DEVICE(device);
+	struct adreno_ringbuffer *rb = &adreno_dev->ringbuffer;
+
+	/* If the device isn't active, don't force it on. */
+	if (kgsl_pwrctrl_isenabled(device)) {
+		/* Is the ring buffer is empty? */
+		unsigned int rptr = adreno_get_rptr(rb);
+		if (rptr == rb->wptr) {
+			/*
+			 * Are there interrupts pending? If so then pretend we
+			 * are not idle - this avoids the possiblity that we go
+			 * to a lower power state without handling interrupts
+			 * first.
+			 */
+
+			if (!adreno_dev->gpudev->irq_pending(adreno_dev)) {
+				/* Is the core idle? */
+				status = is_adreno_rbbm_status_idle(device);
+			}
+		}
+	} else {
+		status = true;
+	}
+	return status;
 }
 
 /* Caller must hold the device mutex. */
@@ -2498,6 +3338,9 @@
 	if (kgsl_gpuaddr_in_memdesc(&device->memstore, gpuaddr, size))
 		return &device->memstore;
 
+	if (kgsl_gpuaddr_in_memdesc(&adreno_dev->pwron_fixup, gpuaddr, size))
+		return &adreno_dev->pwron_fixup;
+
 	if (kgsl_gpuaddr_in_memdesc(&device->mmu.setstate_memory, gpuaddr,
 					size))
 		return &device->mmu.setstate_memory;
@@ -2595,6 +3438,324 @@
 	__raw_writel(value, reg);
 }
 
+static unsigned int _get_context_id(struct kgsl_context *k_ctxt)
+{
+	unsigned int context_id = KGSL_MEMSTORE_GLOBAL;
+
+	if (k_ctxt != NULL) {
+		struct adreno_context *a_ctxt = ADRENO_CONTEXT(k_ctxt);
+		if (kgsl_context_detached(k_ctxt))
+			context_id = KGSL_CONTEXT_INVALID;
+		else if (a_ctxt->flags & CTXT_FLAGS_PER_CONTEXT_TS)
+			context_id = k_ctxt->id;
+	}
+
+	return context_id;
+}
+
+static unsigned int adreno_check_hw_ts(struct kgsl_device *device,
+		struct kgsl_context *context, unsigned int timestamp)
+{
+	int status = 0;
+	unsigned int ref_ts, enableflag;
+	unsigned int context_id = _get_context_id(context);
+
+	/*
+	 * If the context ID is invalid, we are in a race with
+	 * the context being destroyed by userspace so bail.
+	 */
+	if (context_id == KGSL_CONTEXT_INVALID) {
+		KGSL_DRV_WARN(device, "context was detached");
+		return -EINVAL;
+	}
+
+	status = kgsl_check_timestamp(device, context, timestamp);
+	if (status)
+		return status;
+
+	kgsl_sharedmem_readl(&device->memstore, &enableflag,
+			KGSL_MEMSTORE_OFFSET(context_id, ts_cmp_enable));
+	/*
+	 * Barrier is needed here to make sure the read from memstore
+	 * has posted
+	 */
+
+	mb();
+
+	if (enableflag) {
+		kgsl_sharedmem_readl(&device->memstore, &ref_ts,
+				KGSL_MEMSTORE_OFFSET(context_id,
+					ref_wait_ts));
+
+		/* Make sure the memstore read has posted */
+		mb();
+		if (timestamp_cmp(ref_ts, timestamp) >= 0) {
+			kgsl_sharedmem_writel(device, &device->memstore,
+					KGSL_MEMSTORE_OFFSET(context_id,
+						ref_wait_ts), timestamp);
+			/* Make sure the memstore write is posted */
+			wmb();
+		}
+	} else {
+		kgsl_sharedmem_writel(device, &device->memstore,
+				KGSL_MEMSTORE_OFFSET(context_id,
+					ref_wait_ts), timestamp);
+		enableflag = 1;
+		kgsl_sharedmem_writel(device, &device->memstore,
+				KGSL_MEMSTORE_OFFSET(context_id,
+					ts_cmp_enable), enableflag);
+
+		/* Make sure the memstore write gets posted */
+		wmb();
+
+		/*
+		 * submit a dummy packet so that even if all
+		 * commands upto timestamp get executed we will still
+		 * get an interrupt
+		 */
+
+		if (context && device->state != KGSL_STATE_SLUMBER) {
+			adreno_ringbuffer_issuecmds(device,
+					ADRENO_CONTEXT(context),
+					KGSL_CMD_FLAGS_GET_INT, NULL, 0);
+		}
+	}
+
+	return 0;
+}
+
+/* Return 1 if the event timestmp has already passed, 0 if it was marked */
+static int adreno_next_event(struct kgsl_device *device,
+		struct kgsl_event *event)
+{
+	return adreno_check_hw_ts(device, event->context, event->timestamp);
+}
+
+static int adreno_check_interrupt_timestamp(struct kgsl_device *device,
+		struct kgsl_context *context, unsigned int timestamp)
+{
+	int status;
+
+	mutex_lock(&device->mutex);
+	status = adreno_check_hw_ts(device, context, timestamp);
+	mutex_unlock(&device->mutex);
+
+	return status;
+}
+
+/*
+ wait_event_interruptible_timeout checks for the exit condition before
+ placing a process in wait q. For conditional interrupts we expect the
+ process to already be in its wait q when its exit condition checking
+ function is called.
+*/
+#define kgsl_wait_event_interruptible_timeout(wq, condition, timeout, io)\
+({									\
+	long __ret = timeout;						\
+	if (io)						\
+		__wait_io_event_interruptible_timeout(wq, condition, __ret);\
+	else						\
+		__wait_event_interruptible_timeout(wq, condition, __ret);\
+	__ret;								\
+})
+
+
+
+unsigned int adreno_ft_detect(struct kgsl_device *device,
+						unsigned int *prev_reg_val)
+{
+	struct adreno_device *adreno_dev = ADRENO_DEVICE(device);
+	struct adreno_ringbuffer *rb = &adreno_dev->ringbuffer;
+	unsigned int curr_reg_val[FT_DETECT_REGS_COUNT];
+	unsigned int fast_hang_detected = 1;
+	unsigned int i;
+	static unsigned long next_hang_detect_time;
+	static unsigned int prev_global_ts;
+	unsigned int curr_global_ts = 0;
+	unsigned int curr_context_id = 0;
+	static struct adreno_context *curr_context;
+	static struct kgsl_context *context;
+	static char pid_name[TASK_COMM_LEN] = "unknown";
+
+	if (!adreno_dev->fast_hang_detect)
+		fast_hang_detected = 0;
+
+	if (!(adreno_dev->ringbuffer.flags & KGSL_FLAGS_STARTED))
+		return 0;
+
+	if (is_adreno_rbbm_status_idle(device) &&
+		(kgsl_readtimestamp(device, NULL, KGSL_TIMESTAMP_RETIRED)
+		 == rb->global_ts)) {
+
+		/*
+		 * On A2XX if the RPTR != WPTR and the device is idle, then
+		 * the last write to WPTR probably failed to latch so write it
+		 * again
+		 */
+
+		if (adreno_is_a2xx(adreno_dev)) {
+			unsigned int rptr;
+			adreno_readreg(adreno_dev, ADRENO_REG_CP_RB_RPTR,
+						&rptr);
+			if (rptr != adreno_dev->ringbuffer.wptr)
+				adreno_writereg(adreno_dev,
+					ADRENO_REG_CP_RB_WPTR,
+					adreno_dev->ringbuffer.wptr);
+		}
+
+		return 0;
+	}
+
+	/*
+	 * Time interval between hang detection should be KGSL_TIMEOUT_PART
+	 * or more, if next hang detection is requested < KGSL_TIMEOUT_PART
+	 * from the last time do nothing.
+	 */
+	if ((next_hang_detect_time) &&
+		(time_before(jiffies, next_hang_detect_time)))
+			return 0;
+	else
+		next_hang_detect_time = (jiffies +
+			msecs_to_jiffies(KGSL_TIMEOUT_PART-1));
+
+	/* Read the current Hang detect reg values here */
+	for (i = 0; i < FT_DETECT_REGS_COUNT; i++) {
+		if (ft_detect_regs[i] == 0)
+			continue;
+		kgsl_regread(device, ft_detect_regs[i],
+			&curr_reg_val[i]);
+	}
+
+	/* Read the current global timestamp here */
+	kgsl_sharedmem_readl(&device->memstore,
+			&curr_global_ts,
+			KGSL_MEMSTORE_OFFSET(KGSL_MEMSTORE_GLOBAL,
+			eoptimestamp));
+	/* Make sure the memstore read has posted */
+	mb();
+
+	if (curr_global_ts == prev_global_ts) {
+
+		/* If we don't already have a good context, get it. */
+		if (kgsl_context_detached(context)) {
+			kgsl_context_put(context);
+			context = NULL;
+			curr_context = NULL;
+			strlcpy(pid_name, "unknown", sizeof(pid_name));
+
+			kgsl_sharedmem_readl(&device->memstore,
+				&curr_context_id,
+				KGSL_MEMSTORE_OFFSET(KGSL_MEMSTORE_GLOBAL,
+				current_context));
+			/* Make sure the memstore read has posted */
+			mb();
+
+			context = kgsl_context_get(device, curr_context_id);
+			if (context != NULL) {
+				struct task_struct *task;
+				curr_context = ADRENO_CONTEXT(context);
+				curr_context->ib_gpu_time_used = 0;
+				task = find_task_by_vpid(context->pid);
+				if (task)
+					get_task_comm(pid_name, task);
+			} else {
+				KGSL_DRV_ERR(device,
+					"Fault tolerance no context found\n");
+			}
+		}
+		for (i = 0; i < FT_DETECT_REGS_COUNT; i++) {
+			if (curr_reg_val[i] != prev_reg_val[i])
+				fast_hang_detected = 0;
+		}
+
+		if (fast_hang_detected) {
+			KGSL_FT_ERR(device,
+				"Proc %s, ctxt_id %d ts %d triggered fault tolerance"
+				" on global ts %d\n",
+				pid_name, context ? context->id : 0,
+				(kgsl_readtimestamp(device, context,
+				KGSL_TIMESTAMP_RETIRED) + 1),
+				curr_global_ts + 1);
+			return 1;
+		}
+
+		if (curr_context != NULL) {
+
+			curr_context->ib_gpu_time_used += KGSL_TIMEOUT_PART;
+			KGSL_FT_INFO(device,
+			"Proc %s used GPU Time %d ms on timestamp 0x%X\n",
+			pid_name, curr_context->ib_gpu_time_used,
+			curr_global_ts+1);
+
+			if ((adreno_dev->long_ib_detect) &&
+				(!(curr_context->flags &
+				 CTXT_FLAGS_NO_FAULT_TOLERANCE)) &&
+				(curr_context->ib_gpu_time_used >
+					KGSL_TIMEOUT_LONG_IB_DETECTION) &&
+				(adreno_dev->long_ib_ts != curr_global_ts)) {
+						KGSL_FT_ERR(device,
+						"Proc %s, ctxt_id %d ts %d"
+						"used GPU for %d ms long ib "
+						"detected on global ts %d\n",
+						pid_name, context->id,
+						(kgsl_readtimestamp(device,
+						context,
+						KGSL_TIMESTAMP_RETIRED)+1),
+						curr_context->ib_gpu_time_used,
+						curr_global_ts+1);
+						adreno_dev->long_ib = 1;
+						adreno_dev->long_ib_ts =
+								curr_global_ts;
+						curr_context->ib_gpu_time_used =
+								0;
+						return 1;
+			}
+		}
+	} else {
+		/* GPU is moving forward */
+		prev_global_ts = curr_global_ts;
+		kgsl_context_put(context);
+		context = NULL;
+		curr_context = NULL;
+		strlcpy(pid_name, "unknown", sizeof(pid_name));
+		adreno_dev->long_ib = 0;
+		adreno_dev->long_ib_ts = 0;
+	}
+
+
+	/* If hangs are not detected copy the current reg values
+	 * to previous values and return no hang */
+	for (i = 0; i < FT_DETECT_REGS_COUNT; i++)
+			prev_reg_val[i] = curr_reg_val[i];
+	return 0;
+}
+
+static int _check_pending_timestamp(struct kgsl_device *device,
+		struct kgsl_context *context, unsigned int timestamp)
+{
+	struct adreno_device *adreno_dev = ADRENO_DEVICE(device);
+	unsigned int context_id = _get_context_id(context);
+	unsigned int ts_issued;
+
+	if (context_id == KGSL_CONTEXT_INVALID)
+		return -EINVAL;
+
+	ts_issued = adreno_context_timestamp(context, &adreno_dev->ringbuffer);
+
+	if (timestamp_cmp(timestamp, ts_issued) <= 0)
+		return 0;
+
+	if (context && !context->wait_on_invalid_ts) {
+		KGSL_DRV_ERR(device, "Cannot wait for invalid ts <%d:0x%x>, last issued ts <%d:0x%x>\n",
+			context_id, timestamp, context_id, ts_issued);
+
+			/* Only print this message once */
+			context->wait_on_invalid_ts = true;
+	}
+
+	return -EINVAL;
+}
+
 /**
  * adreno_waittimestamp - sleep while waiting for the specified timestamp
  * @device - pointer to a KGSL device structure
@@ -2602,35 +3763,147 @@
  * @timestamp - GPU timestamp to wait for
  * @msecs - amount of time to wait (in milliseconds)
  *
- * Wait up to 'msecs' milliseconds for the specified timestamp to expire.
+ * Wait 'msecs' milliseconds for the specified timestamp to expire. Wake up
+ * every KGSL_TIMEOUT_PART milliseconds to check for a device hang and process
+ * one if it happened.  Otherwise, spend most of our time in an interruptible
+ * wait for the timestamp interrupt to be processed.  This function must be
+ * called with the mutex already held.
  */
 static int adreno_waittimestamp(struct kgsl_device *device,
-		struct kgsl_context *context,
-		unsigned int timestamp,
-		unsigned int msecs)
+				struct kgsl_context *context,
+				unsigned int timestamp,
+				unsigned int msecs)
 {
-	int ret;
-	struct adreno_context *drawctxt;
+	static unsigned int io_cnt;
+	struct adreno_context *adreno_ctx = context ? ADRENO_CONTEXT(context) :
+		NULL;
+	struct kgsl_pwrctrl *pwr = &device->pwrctrl;
+	unsigned int context_id = _get_context_id(context);
+	unsigned int time_elapsed = 0;
+	unsigned int wait;
+	int ts_compare = 1;
+	int io, ret = -ETIMEDOUT;
 
-	if (context == NULL) {
-		/* If they are doing then complain once */
-		dev_WARN_ONCE(device->dev, 1,
-			"IOCTL_KGSL_DEVICE_WAITTIMESTAMP is deprecated\n");
+	if (context_id == KGSL_CONTEXT_INVALID) {
+		KGSL_DRV_WARN(device, "context was detached");
 		return -EINVAL;
 	}
 
-	/* Return -EINVAL if the context has been detached */
-	if (kgsl_context_detached(context))
-		return -EINVAL;
+	/*
+	 * Check to see if the requested timestamp is "newer" then the last
+	 * timestamp issued. If it is complain once and return error.  Only
+	 * print the message once per context so that badly behaving
+	 * applications don't spam the logs
+	 */
 
-	ret = adreno_drawctxt_wait(ADRENO_DEVICE(device), context,
-		timestamp, msecs_to_jiffies(msecs));
+	if (adreno_ctx && !(adreno_ctx->flags & CTXT_FLAGS_USER_GENERATED_TS)) {
+		if (_check_pending_timestamp(device, context, timestamp))
+			return -EINVAL;
 
-	/* If the context got invalidated then return a specific error */
-	drawctxt = ADRENO_CONTEXT(context);
+		/* Reset the invalid timestamp flag on a valid wait */
+		context->wait_on_invalid_ts = false;
+	}
 
-	if (drawctxt->state == ADRENO_CONTEXT_STATE_INVALID)
-		ret = -EDEADLK;
+	/*
+	 * On the first time through the loop only wait 100ms.
+	 * this gives enough time for the engine to start moving and oddly
+	 * provides better hang detection results than just going the full
+	 * KGSL_TIMEOUT_PART right off the bat. The exception to this rule
+	 * is if msecs happens to be < 100ms then just use 20ms or the msecs,
+	 * whichever is larger because anything less than 20 is unreliable
+	 */
+
+	if (msecs == 0 || msecs >= 100)
+		wait = 100;
+	else
+		wait = (msecs > 20) ? msecs : 20;
+
+	do {
+		long status;
+
+		/*
+		 * if the timestamp happens while we're not
+		 * waiting, there's a chance that an interrupt
+		 * will not be generated and thus the timestamp
+		 * work needs to be queued.
+		 */
+
+		if (kgsl_check_timestamp(device, context, timestamp)) {
+			queue_work(device->work_queue, &device->ts_expired_ws);
+			ret = 0;
+			break;
+		}
+
+		/*
+		 * For proper power accounting sometimes we need to call
+		 * io_wait_interruptible_timeout and sometimes we need to call
+		 * plain old wait_interruptible_timeout. We call the regular
+		 * timeout N times out of 100, where N is a number specified by
+		 * the current power level
+		 */
+
+		io_cnt = (io_cnt + 1) % 100;
+		io = (io_cnt < pwr->pwrlevels[pwr->active_pwrlevel].io_fraction)
+			? 0 : 1;
+
+		mutex_unlock(&device->mutex);
+
+		/* Wait for a timestamp event */
+		status = kgsl_wait_event_interruptible_timeout(
+			device->wait_queue,
+			adreno_check_interrupt_timestamp(device, context,
+				timestamp), msecs_to_jiffies(wait), io);
+
+		mutex_lock(&device->mutex);
+
+		/*
+		 * If status is non zero then either the condition was satisfied
+		 * or there was an error.  In either event, this is the end of
+		 * the line for us
+		 */
+
+		if (status != 0) {
+			ret = (status > 0) ? 0 : (int) status;
+			break;
+		}
+		time_elapsed += wait;
+
+		/* If user specified timestamps are being used, wait at least
+		 * KGSL_SYNCOBJ_SERVER_TIMEOUT msecs for the user driver to
+		 * issue a IB for a timestamp before checking to see if the
+		 * current timestamp we are waiting for is valid or not
+		 */
+
+		if (ts_compare && (adreno_ctx &&
+			(adreno_ctx->flags & CTXT_FLAGS_USER_GENERATED_TS))) {
+			if (time_elapsed > KGSL_SYNCOBJ_SERVER_TIMEOUT) {
+				ret = _check_pending_timestamp(device, context,
+					timestamp);
+				if (ret)
+					break;
+
+				/* Don't do this check again */
+				ts_compare = 0;
+
+				/*
+				 * Reset the invalid timestamp flag on a valid
+				 * wait
+				 */
+				context->wait_on_invalid_ts = false;
+			}
+		}
+
+		/*
+		 * We want to wait the floor of KGSL_TIMEOUT_PART
+		 * and (msecs - time_elapsed).
+		 */
+
+		if (KGSL_TIMEOUT_PART < (msecs - time_elapsed))
+			wait = KGSL_TIMEOUT_PART;
+		else
+			wait = (msecs - time_elapsed);
+
+	} while (!msecs || time_elapsed < msecs);
 
 	return ret;
 }
@@ -2639,13 +3912,13 @@
 		struct kgsl_context *context, enum kgsl_timestamp_type type)
 {
 	unsigned int timestamp = 0;
-	unsigned int id = context ? context->id : KGSL_MEMSTORE_GLOBAL;
+	unsigned int context_id = _get_context_id(context);
 
 	/*
-	 * If the context is detached we are in a race with
+	 * If the context ID is invalid, we are in a race with
 	 * the context being destroyed by userspace so bail.
 	 */
-	if (context && kgsl_context_detached(context)) {
+	if (context_id == KGSL_CONTEXT_INVALID) {
 		KGSL_DRV_WARN(device, "context was detached");
 		return timestamp;
 	}
@@ -2659,11 +3932,11 @@
 	}
 	case KGSL_TIMESTAMP_CONSUMED:
 		kgsl_sharedmem_readl(&device->memstore, &timestamp,
-			KGSL_MEMSTORE_OFFSET(id, soptimestamp));
+			KGSL_MEMSTORE_OFFSET(context_id, soptimestamp));
 		break;
 	case KGSL_TIMESTAMP_RETIRED:
 		kgsl_sharedmem_readl(&device->memstore, &timestamp,
-			KGSL_MEMSTORE_OFFSET(id, eoptimestamp));
+			KGSL_MEMSTORE_OFFSET(context_id, eoptimestamp));
 		break;
 	}
 
@@ -2823,7 +4096,6 @@
 	.gpuid = adreno_gpuid,
 	.snapshot = adreno_snapshot,
 	.irq_handler = adreno_irq_handler,
-	.drain = adreno_drain,
 	/* Optional functions */
 	.setstate = adreno_setstate,
 	.drawctxt_create = adreno_drawctxt_create,
@@ -2831,7 +4103,7 @@
 	.drawctxt_destroy = adreno_drawctxt_destroy,
 	.setproperty = adreno_setproperty,
 	.postmortem_dump = adreno_dump,
-	.drawctxt_sched = adreno_drawctxt_sched,
+	.next_event = adreno_next_event,
 };
 
 static struct platform_driver adreno_platform_driver = {
diff --git a/drivers/gpu/msm/adreno.h b/drivers/gpu/msm/adreno.h
index 0363739..6507852 100644
--- a/drivers/gpu/msm/adreno.h
+++ b/drivers/gpu/msm/adreno.h
@@ -35,11 +35,13 @@
 #define ADRENO_CHIPID_PATCH(_id) ((_id) & 0xFF)
 
 /* Flags to control command packet settings */
-#define KGSL_CMD_FLAGS_NONE             0
-#define KGSL_CMD_FLAGS_PMODE		BIT(0)
-#define KGSL_CMD_FLAGS_INTERNAL_ISSUE   BIT(1)
-#define KGSL_CMD_FLAGS_WFI              BIT(2)
-#define KGSL_CMD_FLAGS_PROFILE		BIT(3)
+#define KGSL_CMD_FLAGS_NONE             0x00000000
+#define KGSL_CMD_FLAGS_PMODE		0x00000001
+#define KGSL_CMD_FLAGS_INTERNAL_ISSUE	0x00000002
+#define KGSL_CMD_FLAGS_GET_INT		0x00000004
+#define KGSL_CMD_FLAGS_PROFILE		0x00000008
+#define KGSL_CMD_FLAGS_PWRON_FIXUP	0x00000010
+#define KGSL_CMD_FLAGS_EOF	        0x00000100
 
 /* Command identifiers */
 #define KGSL_CONTEXT_TO_MEM_IDENTIFIER	0x2EADBEEF
@@ -51,6 +53,7 @@
 #define KGSL_NOP_IB_IDENTIFIER	        0x20F20F20
 #define KGSL_START_OF_PROFILE_IDENTIFIER	0x2DEFADE1
 #define KGSL_END_OF_PROFILE_IDENTIFIER	0x2DEFADE2
+#define KGSL_PWRON_FIXUP_IDENTIFIER	0x2AFAFAFA
 
 #ifdef CONFIG_MSM_SCM
 #define ADRENO_DEFAULT_PWRSCALE_POLICY  (&kgsl_pwrscale_policy_tz)
@@ -95,55 +98,11 @@
 	TRACE_BUS_CTL,
 };
 
-#define ADRENO_SOFT_FAULT 1
-#define ADRENO_HARD_FAULT 2
-#define ADRENO_TIMEOUT_FAULT 3
-
-/*
- * Maximum size of the dispatcher ringbuffer - the actual inflight size will be
- * smaller then this but this size will allow for a larger range of inflight
- * sizes that can be chosen at runtime
- */
-
-#define ADRENO_DISPATCH_CMDQUEUE_SIZE 128
-
-/**
- * struct adreno_dispatcher - container for the adreno GPU dispatcher
- * @mutex: Mutex to protect the structure
- * @state: Current state of the dispatcher (active or paused)
- * @timer: Timer to monitor the progress of the command batches
- * @inflight: Number of command batch operations pending in the ringbuffer
- * @fault: Non-zero if a fault was detected.
- * @pending: Priority list of contexts waiting to submit command batches
- * @plist_lock: Spin lock to protect the pending queue
- * @cmdqueue: Queue of command batches currently flight
- * @head: pointer to the head of of the cmdqueue.  This is the oldest pending
- * operation
- * @tail: pointer to the tail of the cmdqueue.  This is the most recently
- * submitted operation
- * @work: work_struct to put the dispatcher in a work queue
- * @kobj: kobject for the dispatcher directory in the device sysfs node
- */
-struct adreno_dispatcher {
-	struct mutex mutex;
-	unsigned int state;
-	struct timer_list timer;
-	struct timer_list fault_timer;
-	unsigned int inflight;
-	atomic_t fault;
-	struct plist_head pending;
-	spinlock_t plist_lock;
-	struct kgsl_cmdbatch *cmdqueue[ADRENO_DISPATCH_CMDQUEUE_SIZE];
-	unsigned int head;
-	unsigned int tail;
-	struct work_struct work;
-	struct kobject kobj;
-};
-
 struct adreno_gpudev;
 
 struct adreno_device {
 	struct kgsl_device dev;    /* Must be first field in this struct */
+	unsigned long priv;
 	unsigned int chip_id;
 	enum adreno_gpurev gpurev;
 	unsigned long gmem_base;
@@ -180,7 +139,19 @@
 	unsigned int ocmem_base;
 	unsigned int gpu_cycles;
 	struct adreno_profile profile;
-	struct adreno_dispatcher dispatcher;
+	struct kgsl_memdesc pwron_fixup;
+	unsigned int pwron_fixup_dwords;
+};
+
+/**
+ * enum adreno_device_flags - Private flags for the adreno_device
+ * @ADRENO_DEVICE_PWRON - Set during init after a power collapse
+ * @ADRENO_DEVICE_PWRON_FIXUP - Set if the target requires the shader fixup
+ * after power collapse
+ */
+enum adreno_device_flags {
+	ADRENO_DEVICE_PWRON = 0,
+	ADRENO_DEVICE_PWRON_FIXUP = 1,
 };
 
 #define PERFCOUNTER_FLAG_NONE 0x0
@@ -311,9 +282,9 @@
 
 	/* GPU specific function hooks */
 	int (*ctxt_create)(struct adreno_device *, struct adreno_context *);
-	int (*ctxt_save)(struct adreno_device *, struct adreno_context *);
-	int (*ctxt_restore)(struct adreno_device *, struct adreno_context *);
-	int (*ctxt_draw_workaround)(struct adreno_device *,
+	void (*ctxt_save)(struct adreno_device *, struct adreno_context *);
+	void (*ctxt_restore)(struct adreno_device *, struct adreno_context *);
+	void (*ctxt_draw_workaround)(struct adreno_device *,
 					struct adreno_context *);
 	irqreturn_t (*irq_handler)(struct adreno_device *);
 	void (*irq_control)(struct adreno_device *, int);
@@ -336,6 +307,46 @@
 	void (*postmortem_dump)(struct adreno_device *adreno_dev);
 };
 
+/*
+ * struct adreno_ft_data - Structure that contains all information to
+ * perform gpu fault tolerance
+ * @ib1 - IB1 that the GPU was executing when hang happened
+ * @context_id - Context which caused the hang
+ * @global_eop - eoptimestamp at time of hang
+ * @rb_buffer - Buffer that holds the commands from good contexts
+ * @rb_size - Number of valid dwords in rb_buffer
+ * @bad_rb_buffer - Buffer that holds commands from the hanging context
+ * bad_rb_size - Number of valid dwords in bad_rb_buffer
+ * @good_rb_buffer - Buffer that holds commands from good contexts
+ * good_rb_size - Number of valid dwords in good_rb_buffer
+ * @last_valid_ctx_id - The last context from which commands were placed in
+ * ringbuffer before the GPU hung
+ * @step - Current fault tolerance step being executed
+ * @err_code - Fault tolerance error code
+ * @fault - Indicates whether the hang was caused due to a pagefault
+ * @start_of_replay_cmds - Offset in ringbuffer from where commands can be
+ * replayed during fault tolerance
+ * @replay_for_snapshot - Offset in ringbuffer where IB's can be saved for
+ * replaying with snapshot
+ */
+struct adreno_ft_data {
+	unsigned int ib1;
+	unsigned int context_id;
+	unsigned int global_eop;
+	unsigned int *rb_buffer;
+	unsigned int rb_size;
+	unsigned int *bad_rb_buffer;
+	unsigned int bad_rb_size;
+	unsigned int *good_rb_buffer;
+	unsigned int good_rb_size;
+	unsigned int last_valid_ctx_id;
+	unsigned int status;
+	unsigned int ft_policy;
+	unsigned int err_code;
+	unsigned int start_of_replay_cmds;
+	unsigned int replay_for_snapshot;
+};
+
 #define FT_DETECT_REGS_COUNT 12
 
 struct log_field {
@@ -344,16 +355,13 @@
 };
 
 /* Fault Tolerance policy flags */
-#define  KGSL_FT_OFF                      0
-#define  KGSL_FT_REPLAY                   1
-#define  KGSL_FT_SKIPIB                   2
-#define  KGSL_FT_SKIPFRAME                3
-#define  KGSL_FT_DISABLE                  4
-#define  KGSL_FT_TEMP_DISABLE             5
-#define  KGSL_FT_DEFAULT_POLICY (BIT(KGSL_FT_REPLAY) + BIT(KGSL_FT_SKIPIB))
-
-/* This internal bit is used to skip the PM dump on replayed command batches */
-#define  KGSL_FT_SKIP_PMDUMP              31
+#define  KGSL_FT_OFF                      BIT(0)
+#define  KGSL_FT_REPLAY                   BIT(1)
+#define  KGSL_FT_SKIPIB                   BIT(2)
+#define  KGSL_FT_SKIPFRAME                BIT(3)
+#define  KGSL_FT_DISABLE                  BIT(4)
+#define  KGSL_FT_TEMP_DISABLE             BIT(5)
+#define  KGSL_FT_DEFAULT_POLICY           (KGSL_FT_REPLAY + KGSL_FT_SKIPIB)
 
 /* Pagefault policy flags */
 #define KGSL_FT_PAGEFAULT_INT_ENABLE         BIT(0)
@@ -363,14 +371,6 @@
 #define KGSL_FT_PAGEFAULT_DEFAULT_POLICY     (KGSL_FT_PAGEFAULT_INT_ENABLE + \
 					KGSL_FT_PAGEFAULT_GPUHALT_ENABLE)
 
-#define ADRENO_FT_TYPES \
-	{ BIT(KGSL_FT_OFF), "off" }, \
-	{ BIT(KGSL_FT_REPLAY), "replay" }, \
-	{ BIT(KGSL_FT_SKIPIB), "skipib" }, \
-	{ BIT(KGSL_FT_SKIPFRAME), "skipframe" }, \
-	{ BIT(KGSL_FT_DISABLE), "disable" }, \
-	{ BIT(KGSL_FT_TEMP_DISABLE), "temp" }
-
 extern struct adreno_gpudev adreno_a2xx_gpudev;
 extern struct adreno_gpudev adreno_a3xx_gpudev;
 
@@ -426,23 +426,13 @@
 void *adreno_snapshot(struct kgsl_device *device, void *snapshot, int *remain,
 		int hang);
 
-void adreno_dispatcher_start(struct adreno_device *adreno_dev);
-int adreno_dispatcher_init(struct adreno_device *adreno_dev);
-void adreno_dispatcher_close(struct adreno_device *adreno_dev);
-int adreno_dispatcher_idle(struct adreno_device *adreno_dev,
-		unsigned int timeout);
-void adreno_dispatcher_irq_fault(struct kgsl_device *device);
-void adreno_dispatcher_stop(struct adreno_device *adreno_dev);
+int adreno_dump_and_exec_ft(struct kgsl_device *device);
 
-int adreno_dispatcher_queue_cmd(struct adreno_device *adreno_dev,
-		struct adreno_context *drawctxt, struct kgsl_cmdbatch *cmdbatch,
-		uint32_t *timestamp);
+void adreno_dump_rb(struct kgsl_device *device, const void *buf,
+			 size_t len, int start, int size);
 
-void adreno_dispatcher_schedule(struct kgsl_device *device);
-void adreno_dispatcher_pause(struct adreno_device *adreno_dev);
-void adreno_dispatcher_queue_context(struct kgsl_device *device,
-	struct adreno_context *drawctxt);
-int adreno_reset(struct kgsl_device *device);
+unsigned int adreno_ft_detect(struct kgsl_device *device,
+						unsigned int *prev_reg_val);
 
 int adreno_ft_init_sysfs(struct kgsl_device *device);
 void adreno_ft_uninit_sysfs(struct kgsl_device *device);
@@ -462,6 +452,7 @@
 
 int adreno_soft_reset(struct kgsl_device *device);
 
+int adreno_a3xx_pwron_fixup_init(struct adreno_device *adreno_dev);
 
 static inline int adreno_is_a200(struct adreno_device *adreno_dev)
 {
@@ -559,7 +550,9 @@
 {
 	if (k_ctxt) {
 		struct adreno_context *a_ctxt = ADRENO_CONTEXT(k_ctxt);
-		return a_ctxt->timestamp;
+
+		if (a_ctxt->flags & CTXT_FLAGS_PER_CONTEXT_TS)
+			return a_ctxt->timestamp;
 	}
 	return rb->global_ts;
 }
@@ -665,9 +658,7 @@
 	*cmds++ = cp_type3_packet(CP_WAIT_FOR_IDLE, 1);
 	*cmds++ = 0;
 
-	if ((adreno_dev->gpurev == ADRENO_REV_A305) ||
-		(adreno_dev->gpurev == ADRENO_REV_A305C) ||
-		(adreno_dev->gpurev == ADRENO_REV_A320)) {
+	if (adreno_is_a3xx(adreno_dev)) {
 		*cmds++ = cp_type3_packet(CP_WAIT_FOR_ME, 1);
 		*cmds++ = 0;
 	}
@@ -758,31 +749,4 @@
 		return ADRENO_REG_REGISTER_MAX;
 	return adreno_dev->gpudev->reg_offsets->offsets[offset_name];
 }
-
-/**
- * adreno_gpu_fault() - Return the current state of the GPU
- * @adreno_dev: A ponter to the adreno_device to query
- *
- * Return 0 if there is no fault or positive with the last type of fault that
- * occurred
- */
-static inline unsigned int adreno_gpu_fault(struct adreno_device *adreno_dev)
-{
-	smp_rmb();
-	return atomic_read(&adreno_dev->dispatcher.fault);
-}
-
-/**
- * adreno_set_gpu_fault() - Set the current fault status of the GPU
- * @adreno_dev: A pointer to the adreno_device to set
- * @state: fault state to set
- *
- */
-static inline void adreno_set_gpu_fault(struct adreno_device *adreno_dev,
-	int state)
-{
-	atomic_set(&adreno_dev->dispatcher.fault, state);
-	smp_wmb();
-}
-
 #endif /*__ADRENO_H */
diff --git a/drivers/gpu/msm/adreno_a2xx.c b/drivers/gpu/msm/adreno_a2xx.c
index cce4f91..3d72c5c 100644
--- a/drivers/gpu/msm/adreno_a2xx.c
+++ b/drivers/gpu/msm/adreno_a2xx.c
@@ -1451,7 +1451,7 @@
 	return ret;
 }
 
-static int a2xx_drawctxt_draw_workaround(struct adreno_device *adreno_dev,
+static void a2xx_drawctxt_draw_workaround(struct adreno_device *adreno_dev,
 					struct adreno_context *context)
 {
 	struct kgsl_device *device = &adreno_dev->dev;
@@ -1468,7 +1468,7 @@
 				ADRENO_NUM_CTX_SWITCH_ALLOWED_BEFORE_DRAW)
 			adreno_dev->gpudev->ctx_switches_since_last_draw = 0;
 		else
-			return 0;
+			return;
 		/*
 		 * Issue an empty draw call to avoid possible hangs due to
 		 * repeated idles without intervening draw calls.
@@ -1499,46 +1499,41 @@
 					| adreno_dev->pix_shader_start;
 	}
 
-	return adreno_ringbuffer_issuecmds(device, context,
-			KGSL_CMD_FLAGS_PMODE, &cmd[0], cmds - cmd);
+	adreno_ringbuffer_issuecmds(device, context, KGSL_CMD_FLAGS_PMODE,
+			&cmd[0], cmds - cmd);
 }
 
-static int a2xx_drawctxt_save(struct adreno_device *adreno_dev,
+static void a2xx_drawctxt_save(struct adreno_device *adreno_dev,
 			struct adreno_context *context)
 {
 	struct kgsl_device *device = &adreno_dev->dev;
-	int ret;
 
 	if (context == NULL || (context->flags & CTXT_FLAGS_BEING_DESTROYED))
-		return 0;
+		return;
 
-	if (context->state == ADRENO_CONTEXT_STATE_INVALID)
-		return 0;
+	if (context->flags & CTXT_FLAGS_GPU_HANG)
+		KGSL_CTXT_WARN(device,
+			"Current active context has caused gpu hang\n");
 
 	if (!(context->flags & CTXT_FLAGS_PREAMBLE)) {
 		kgsl_cffdump_syncmem(context->base.device, &context->gpustate,
 			context->reg_save[1],
 			context->reg_save[2] << 2, true);
 		/* save registers and constants. */
-		ret = adreno_ringbuffer_issuecmds(device, context,
+		adreno_ringbuffer_issuecmds(device, context,
 			KGSL_CMD_FLAGS_NONE,
 			context->reg_save, 3);
 
-		if (ret)
-			return ret;
-
 		if (context->flags & CTXT_FLAGS_SHADER_SAVE) {
 			kgsl_cffdump_syncmem(context->base.device,
 				&context->gpustate,
 				context->shader_save[1],
 				context->shader_save[2] << 2, true);
 			/* save shader partitioning and instructions. */
-			ret = adreno_ringbuffer_issuecmds(device, context,
+			adreno_ringbuffer_issuecmds(device, context,
 				KGSL_CMD_FLAGS_PMODE,
 				context->shader_save, 3);
 
-			if (ret)
-				return ret;
 			kgsl_cffdump_syncmem(context->base.device,
 				&context->gpustate,
 				context->shader_fixup[1],
@@ -1547,13 +1542,10 @@
 			 * fixup shader partitioning parameter for
 			 *  SET_SHADER_BASES.
 			 */
-			ret = adreno_ringbuffer_issuecmds(device, context,
+			adreno_ringbuffer_issuecmds(device, context,
 				KGSL_CMD_FLAGS_NONE,
 				context->shader_fixup, 3);
 
-			if (ret)
-				return ret;
-
 			context->flags |= CTXT_FLAGS_SHADER_RESTORE;
 		}
 	}
@@ -1566,41 +1558,32 @@
 		/* save gmem.
 		 * (note: changes shader. shader must already be saved.)
 		 */
-		ret = adreno_ringbuffer_issuecmds(device, context,
+		adreno_ringbuffer_issuecmds(device, context,
 			KGSL_CMD_FLAGS_PMODE,
 			context->context_gmem_shadow.gmem_save, 3);
 
-		if (ret)
-			return ret;
-
 		kgsl_cffdump_syncmem(context->base.device, &context->gpustate,
 			context->chicken_restore[1],
 			context->chicken_restore[2] << 2, true);
 
 		/* Restore TP0_CHICKEN */
 		if (!(context->flags & CTXT_FLAGS_PREAMBLE)) {
-			ret = adreno_ringbuffer_issuecmds(device, context,
+			adreno_ringbuffer_issuecmds(device, context,
 				KGSL_CMD_FLAGS_NONE,
 				context->chicken_restore, 3);
-
-			if (ret)
-				return ret;
 		}
 		adreno_dev->gpudev->ctx_switches_since_last_draw = 0;
 
 		context->flags |= CTXT_FLAGS_GMEM_RESTORE;
 	} else if (adreno_is_a2xx(adreno_dev))
-		return a2xx_drawctxt_draw_workaround(adreno_dev, context);
-
-	return 0;
+		a2xx_drawctxt_draw_workaround(adreno_dev, context);
 }
 
-static int a2xx_drawctxt_restore(struct adreno_device *adreno_dev,
+static void a2xx_drawctxt_restore(struct adreno_device *adreno_dev,
 			struct adreno_context *context)
 {
 	struct kgsl_device *device = &adreno_dev->dev;
 	unsigned int cmds[5];
-	int ret = 0;
 
 	if (context == NULL) {
 		/* No context - set the default pagetable and thats it */
@@ -1615,7 +1598,7 @@
 			: KGSL_CONTEXT_INVALID;
 		kgsl_mmu_setstate(&device->mmu, device->mmu.defaultpagetable,
 				  id);
-		return 0;
+		return;
 	}
 
 	cmds[0] = cp_nop_packet(1);
@@ -1624,11 +1607,8 @@
 	cmds[3] = device->memstore.gpuaddr +
 		KGSL_MEMSTORE_OFFSET(KGSL_MEMSTORE_GLOBAL, current_context);
 	cmds[4] = context->base.id;
-	ret = adreno_ringbuffer_issuecmds(device, context, KGSL_CMD_FLAGS_NONE,
+	adreno_ringbuffer_issuecmds(device, context, KGSL_CMD_FLAGS_NONE,
 					cmds, 5);
-	if (ret)
-		return ret;
-
 	kgsl_mmu_setstate(&device->mmu, context->base.pagetable,
 			context->base.id);
 
@@ -1641,11 +1621,9 @@
 			context->context_gmem_shadow.gmem_restore[2] << 2,
 			true);
 
-		ret = adreno_ringbuffer_issuecmds(device, context,
+		adreno_ringbuffer_issuecmds(device, context,
 			KGSL_CMD_FLAGS_PMODE,
 			context->context_gmem_shadow.gmem_restore, 3);
-		if (ret)
-			return ret;
 
 		if (!(context->flags & CTXT_FLAGS_PREAMBLE)) {
 			kgsl_cffdump_syncmem(context->base.device,
@@ -1654,11 +1632,9 @@
 				context->chicken_restore[2] << 2, true);
 
 			/* Restore TP0_CHICKEN */
-			ret = adreno_ringbuffer_issuecmds(device, context,
+			adreno_ringbuffer_issuecmds(device, context,
 				KGSL_CMD_FLAGS_NONE,
 				context->chicken_restore, 3);
-			if (ret)
-				return ret;
 		}
 
 		context->flags &= ~CTXT_FLAGS_GMEM_RESTORE;
@@ -1670,10 +1646,8 @@
 			context->reg_restore[2] << 2, true);
 
 		/* restore registers and constants. */
-		ret = adreno_ringbuffer_issuecmds(device, context,
+		adreno_ringbuffer_issuecmds(device, context,
 			KGSL_CMD_FLAGS_NONE, context->reg_restore, 3);
-		if (ret)
-			return ret;
 
 		/* restore shader instructions & partitioning. */
 		if (context->flags & CTXT_FLAGS_SHADER_RESTORE) {
@@ -1682,22 +1656,18 @@
 				context->shader_restore[1],
 				context->shader_restore[2] << 2, true);
 
-			ret = adreno_ringbuffer_issuecmds(device, context,
+			adreno_ringbuffer_issuecmds(device, context,
 				KGSL_CMD_FLAGS_NONE,
 				context->shader_restore, 3);
-			if (ret)
-				return ret;
 		}
 	}
 
 	if (adreno_is_a20x(adreno_dev)) {
 		cmds[0] = cp_type3_packet(CP_SET_BIN_BASE_OFFSET, 1);
 		cmds[1] = context->bin_base_offset;
-		ret = adreno_ringbuffer_issuecmds(device, context,
+		adreno_ringbuffer_issuecmds(device, context,
 			KGSL_CMD_FLAGS_NONE, cmds, 2);
 	}
-
-	return ret;
 }
 
 /*
@@ -1764,14 +1734,13 @@
 
 	if (!status) {
 		if (master_status & MASTER_INT_SIGNAL__CP_INT_STAT) {
-			/*
-			 * This indicates that we could not read CP_INT_STAT.
-			 * As a precaution schedule the dispatcher to check
-			 * things out. Since we did not ack any interrupts this
-			 * interrupt will be generated again
-			 */
+			/* This indicates that we could not read CP_INT_STAT.
+			 * As a precaution just wake up processes so
+			 * they can check their timestamps. Since, we
+			 * did not ack any interrupts this interrupt will
+			 * be generated again */
 			KGSL_DRV_WARN(device, "Unable to read CP_INT_STATUS\n");
-			adreno_dispatcher_schedule(device);
+			wake_up_interruptible_all(&device->wait_queue);
 		} else
 			KGSL_DRV_WARN(device, "Spurious interrput detected\n");
 		return;
@@ -1797,7 +1766,7 @@
 
 	if (status & (CP_INT_CNTL__IB1_INT_MASK | CP_INT_CNTL__RB_INT_MASK)) {
 		queue_work(device->work_queue, &device->ts_expired_ws);
-		adreno_dispatcher_schedule(device);
+		wake_up_interruptible_all(&device->wait_queue);
 	}
 }
 
diff --git a/drivers/gpu/msm/adreno_a3xx.c b/drivers/gpu/msm/adreno_a3xx.c
index c4f81fa..f9110ea 100644
--- a/drivers/gpu/msm/adreno_a3xx.c
+++ b/drivers/gpu/msm/adreno_a3xx.c
@@ -2382,38 +2382,32 @@
 	return ret;
 }
 
-static int a3xx_drawctxt_save(struct adreno_device *adreno_dev,
+static void a3xx_drawctxt_save(struct adreno_device *adreno_dev,
 			   struct adreno_context *context)
 {
 	struct kgsl_device *device = &adreno_dev->dev;
-	int ret;
 
 	if (context == NULL || (context->flags & CTXT_FLAGS_BEING_DESTROYED))
-		return 0;
+		return;
 
-	if (context->state == ADRENO_CONTEXT_STATE_INVALID)
-		return 0;
+	if (context->flags & CTXT_FLAGS_GPU_HANG)
+		KGSL_CTXT_WARN(device,
+			       "Current active context has caused gpu hang\n");
 
 	if (!(context->flags & CTXT_FLAGS_PREAMBLE)) {
 		/* Fixup self modifying IBs for save operations */
-		ret = adreno_ringbuffer_issuecmds(device, context,
+		adreno_ringbuffer_issuecmds(device, context,
 			KGSL_CMD_FLAGS_NONE, context->save_fixup, 3);
-		if (ret)
-			return ret;
 
 		/* save registers and constants. */
-		ret = adreno_ringbuffer_issuecmds(device, context,
+		adreno_ringbuffer_issuecmds(device, context,
 			KGSL_CMD_FLAGS_NONE,
 			context->regconstant_save, 3);
-		if (ret)
-			return ret;
 
 		if (context->flags & CTXT_FLAGS_SHADER_SAVE) {
 			/* Save shader instructions */
-			ret = adreno_ringbuffer_issuecmds(device, context,
+			adreno_ringbuffer_issuecmds(device, context,
 				KGSL_CMD_FLAGS_PMODE, context->shader_save, 3);
-			if (ret)
-				return ret;
 
 			context->flags |= CTXT_FLAGS_SHADER_RESTORE;
 		}
@@ -2431,25 +2425,19 @@
 			context->context_gmem_shadow.gmem_save[1],
 			context->context_gmem_shadow.gmem_save[2] << 2, true);
 
-		ret = adreno_ringbuffer_issuecmds(device, context,
+		adreno_ringbuffer_issuecmds(device, context,
 					KGSL_CMD_FLAGS_PMODE,
 					    context->context_gmem_shadow.
 					    gmem_save, 3);
-		if (ret)
-			return ret;
-
 		context->flags |= CTXT_FLAGS_GMEM_RESTORE;
 	}
-
-	return 0;
 }
 
-static int a3xx_drawctxt_restore(struct adreno_device *adreno_dev,
+static void a3xx_drawctxt_restore(struct adreno_device *adreno_dev,
 			      struct adreno_context *context)
 {
 	struct kgsl_device *device = &adreno_dev->dev;
 	unsigned int cmds[5];
-	int ret = 0;
 
 	if (context == NULL) {
 		/* No context - set the default pagetable and thats it */
@@ -2464,7 +2452,7 @@
 			: KGSL_CONTEXT_INVALID;
 		kgsl_mmu_setstate(&device->mmu, device->mmu.defaultpagetable,
 				  id);
-		return 0;
+		return;
 	}
 
 	cmds[0] = cp_nop_packet(1);
@@ -2473,11 +2461,8 @@
 	cmds[3] = device->memstore.gpuaddr +
 		KGSL_MEMSTORE_OFFSET(KGSL_MEMSTORE_GLOBAL, current_context);
 	cmds[4] = context->base.id;
-	ret = adreno_ringbuffer_issuecmds(device, context, KGSL_CMD_FLAGS_NONE,
+	adreno_ringbuffer_issuecmds(device, context, KGSL_CMD_FLAGS_NONE,
 					cmds, 5);
-	if (ret)
-		return ret;
-
 	kgsl_mmu_setstate(&device->mmu, context->base.pagetable,
 			context->base.id);
 
@@ -2493,47 +2478,508 @@
 			context->context_gmem_shadow.gmem_restore[2] << 2,
 			true);
 
-		ret = adreno_ringbuffer_issuecmds(device, context,
+		adreno_ringbuffer_issuecmds(device, context,
 					KGSL_CMD_FLAGS_PMODE,
 					    context->context_gmem_shadow.
 					    gmem_restore, 3);
-		if (ret)
-			return ret;
 		context->flags &= ~CTXT_FLAGS_GMEM_RESTORE;
 	}
 
 	if (!(context->flags & CTXT_FLAGS_PREAMBLE)) {
-		ret = adreno_ringbuffer_issuecmds(device, context,
+		adreno_ringbuffer_issuecmds(device, context,
 			KGSL_CMD_FLAGS_NONE, context->reg_restore, 3);
-		if (ret)
-			return ret;
 
 		/* Fixup self modifying IBs for restore operations */
-		ret = adreno_ringbuffer_issuecmds(device, context,
+		adreno_ringbuffer_issuecmds(device, context,
 			KGSL_CMD_FLAGS_NONE,
 			context->restore_fixup, 3);
-		if (ret)
-			return ret;
 
-		ret = adreno_ringbuffer_issuecmds(device, context,
+		adreno_ringbuffer_issuecmds(device, context,
 			KGSL_CMD_FLAGS_NONE,
 			context->constant_restore, 3);
-		if (ret)
-			return ret;
 
 		if (context->flags & CTXT_FLAGS_SHADER_RESTORE)
-			ret = adreno_ringbuffer_issuecmds(device, context,
+			adreno_ringbuffer_issuecmds(device, context,
 				KGSL_CMD_FLAGS_NONE,
 				context->shader_restore, 3);
-			if (ret)
-				return ret;
+
 		/* Restore HLSQ_CONTROL_0 register */
-		ret = adreno_ringbuffer_issuecmds(device, context,
+		adreno_ringbuffer_issuecmds(device, context,
 			KGSL_CMD_FLAGS_NONE,
 			context->hlsqcontrol_restore, 3);
 	}
+}
 
-	return ret;
+static const unsigned int _a3xx_pwron_fixup_fs_instructions[] = {
+	0x00000000, 0x302CC300, 0x00000000, 0x302CC304,
+	0x00000000, 0x302CC308, 0x00000000, 0x302CC30C,
+	0x00000000, 0x302CC310, 0x00000000, 0x302CC314,
+	0x00000000, 0x302CC318, 0x00000000, 0x302CC31C,
+	0x00000000, 0x302CC320, 0x00000000, 0x302CC324,
+	0x00000000, 0x302CC328, 0x00000000, 0x302CC32C,
+	0x00000000, 0x302CC330, 0x00000000, 0x302CC334,
+	0x00000000, 0x302CC338, 0x00000000, 0x302CC33C,
+	0x00000000, 0x00000400, 0x00020000, 0x63808003,
+	0x00060004, 0x63828007, 0x000A0008, 0x6384800B,
+	0x000E000C, 0x6386800F, 0x00120010, 0x63888013,
+	0x00160014, 0x638A8017, 0x001A0018, 0x638C801B,
+	0x001E001C, 0x638E801F, 0x00220020, 0x63908023,
+	0x00260024, 0x63928027, 0x002A0028, 0x6394802B,
+	0x002E002C, 0x6396802F, 0x00320030, 0x63988033,
+	0x00360034, 0x639A8037, 0x003A0038, 0x639C803B,
+	0x003E003C, 0x639E803F, 0x00000000, 0x00000400,
+	0x00000003, 0x80D60003, 0x00000007, 0x80D60007,
+	0x0000000B, 0x80D6000B, 0x0000000F, 0x80D6000F,
+	0x00000013, 0x80D60013, 0x00000017, 0x80D60017,
+	0x0000001B, 0x80D6001B, 0x0000001F, 0x80D6001F,
+	0x00000023, 0x80D60023, 0x00000027, 0x80D60027,
+	0x0000002B, 0x80D6002B, 0x0000002F, 0x80D6002F,
+	0x00000033, 0x80D60033, 0x00000037, 0x80D60037,
+	0x0000003B, 0x80D6003B, 0x0000003F, 0x80D6003F,
+	0x00000000, 0x03000000, 0x00000000, 0x00000000,
+};
+
+/**
+ * adreno_a3xx_pwron_fixup_init() - Initalize a special command buffer to run a
+ * post-power collapse shader workaround
+ * @adreno_dev: Pointer to a adreno_device struct
+ *
+ * Some targets require a special workaround shader to be executed after
+ * power-collapse.  Construct the IB once at init time and keep it
+ * handy
+ *
+ * Returns: 0 on success or negative on error
+ */
+int adreno_a3xx_pwron_fixup_init(struct adreno_device *adreno_dev)
+{
+	unsigned int *cmds;
+	int count = ARRAY_SIZE(_a3xx_pwron_fixup_fs_instructions);
+	int ret;
+
+	/* Return if the fixup is already in place */
+	if (test_bit(ADRENO_DEVICE_PWRON_FIXUP, &adreno_dev->priv))
+		return 0;
+
+	ret = kgsl_allocate_contiguous(&adreno_dev->pwron_fixup, PAGE_SIZE);
+
+	if (ret)
+		return ret;
+
+	adreno_dev->pwron_fixup.flags |= KGSL_MEMFLAGS_GPUREADONLY;
+
+	cmds = adreno_dev->pwron_fixup.hostptr;
+
+	*cmds++ = cp_type0_packet(A3XX_UCHE_CACHE_INVALIDATE0_REG, 2);
+	*cmds++ = 0x00000000;
+	*cmds++ = 0x90000000;
+	*cmds++ = cp_type3_packet(CP_WAIT_FOR_IDLE, 1);
+	*cmds++ = 0x00000000;
+	*cmds++ = cp_type3_packet(CP_REG_RMW, 3);
+	*cmds++ = A3XX_RBBM_CLOCK_CTL;
+	*cmds++ = 0xFFFCFFFF;
+	*cmds++ = 0x00010000;
+	*cmds++ = cp_type3_packet(CP_WAIT_FOR_IDLE, 1);
+	*cmds++ = 0x00000000;
+	*cmds++ = cp_type0_packet(A3XX_HLSQ_CONTROL_0_REG, 1);
+	*cmds++ = 0x1E000150;
+	*cmds++ = cp_type3_packet(CP_WAIT_FOR_IDLE, 1);
+	*cmds++ = 0x00000000;
+	*cmds++ = cp_type3_packet(CP_SET_CONSTANT, 2);
+	*cmds++ = CP_REG(A3XX_HLSQ_CONTROL_0_REG);
+	*cmds++ = 0x1E000150;
+	*cmds++ = cp_type3_packet(CP_WAIT_FOR_IDLE, 1);
+	*cmds++ = 0x00000000;
+	*cmds++ = cp_type0_packet(A3XX_HLSQ_CONTROL_0_REG, 1);
+	*cmds++ = 0x1E000150;
+	*cmds++ = cp_type0_packet(A3XX_HLSQ_CONTROL_1_REG, 1);
+	*cmds++ = 0x00000040;
+	*cmds++ = cp_type0_packet(A3XX_HLSQ_CONTROL_2_REG, 1);
+	*cmds++ = 0x80000000;
+	*cmds++ = cp_type0_packet(A3XX_HLSQ_CONTROL_3_REG, 1);
+	*cmds++ = 0x00000000;
+	*cmds++ = cp_type0_packet(A3XX_HLSQ_VS_CONTROL_REG, 1);
+	*cmds++ = 0x00000001;
+	*cmds++ = cp_type0_packet(A3XX_HLSQ_FS_CONTROL_REG, 1);
+	*cmds++ = 0x0D001002;
+	*cmds++ = cp_type0_packet(A3XX_HLSQ_CONST_VSPRESV_RANGE_REG, 1);
+	*cmds++ = 0x00000000;
+	*cmds++ = cp_type0_packet(A3XX_HLSQ_CONST_FSPRESV_RANGE_REG, 1);
+	*cmds++ = 0x00000000;
+	*cmds++ = cp_type0_packet(A3XX_HLSQ_CL_NDRANGE_0_REG, 1);
+	*cmds++ = 0x00401101;
+	*cmds++ = cp_type0_packet(A3XX_HLSQ_CL_NDRANGE_1_REG, 1);
+	*cmds++ = 0x00000400;
+	*cmds++ = cp_type0_packet(A3XX_HLSQ_CL_NDRANGE_2_REG, 1);
+	*cmds++ = 0x00000000;
+	*cmds++ = cp_type0_packet(A3XX_HLSQ_CL_NDRANGE_3_REG, 1);
+	*cmds++ = 0x00000001;
+	*cmds++ = cp_type0_packet(A3XX_HLSQ_CL_NDRANGE_4_REG, 1);
+	*cmds++ = 0x00000000;
+	*cmds++ = cp_type0_packet(A3XX_HLSQ_CL_NDRANGE_5_REG, 1);
+	*cmds++ = 0x00000001;
+	*cmds++ = cp_type0_packet(A3XX_HLSQ_CL_NDRANGE_6_REG, 1);
+	*cmds++ = 0x00000000;
+	*cmds++ = cp_type0_packet(A3XX_HLSQ_CL_CONTROL_0_REG, 1);
+	*cmds++ = 0x00000000;
+	*cmds++ = cp_type0_packet(A3XX_HLSQ_CL_CONTROL_1_REG, 1);
+	*cmds++ = 0x00000000;
+	*cmds++ = cp_type0_packet(A3XX_HLSQ_CL_KERNEL_CONST_REG, 1);
+	*cmds++ = 0x00000000;
+	*cmds++ = cp_type0_packet(A3XX_HLSQ_CL_KERNEL_GROUP_X_REG, 1);
+	*cmds++ = 0x00000010;
+	*cmds++ = cp_type0_packet(A3XX_HLSQ_CL_KERNEL_GROUP_Y_REG, 1);
+	*cmds++ = 0x00000001;
+	*cmds++ = cp_type0_packet(A3XX_HLSQ_CL_KERNEL_GROUP_Z_REG, 1);
+	*cmds++ = 0x00000001;
+	*cmds++ = cp_type0_packet(A3XX_HLSQ_CL_WG_OFFSET_REG, 1);
+	*cmds++ = 0x00000000;
+	*cmds++ = cp_type0_packet(A3XX_SP_SP_CTRL_REG, 1);
+	*cmds++ = 0x00040000;
+	*cmds++ = cp_type0_packet(A3XX_SP_VS_CTRL_REG0, 1);
+	*cmds++ = 0x0000000A;
+	*cmds++ = cp_type0_packet(A3XX_SP_VS_CTRL_REG1, 1);
+	*cmds++ = 0x00000001;
+	*cmds++ = cp_type0_packet(A3XX_SP_VS_PARAM_REG, 1);
+	*cmds++ = 0x00000000;
+	*cmds++ = cp_type0_packet(A3XX_SP_VS_OUT_REG_0, 1);
+	*cmds++ = 0x00000000;
+	*cmds++ = cp_type0_packet(A3XX_SP_VS_OUT_REG_1, 1);
+	*cmds++ = 0x00000000;
+	*cmds++ = cp_type0_packet(A3XX_SP_VS_OUT_REG_2, 1);
+	*cmds++ = 0x00000000;
+	*cmds++ = cp_type0_packet(A3XX_SP_VS_OUT_REG_3, 1);
+	*cmds++ = 0x00000000;
+	*cmds++ = cp_type0_packet(A3XX_SP_VS_OUT_REG_4, 1);
+	*cmds++ = 0x00000000;
+	*cmds++ = cp_type0_packet(A3XX_SP_VS_OUT_REG_5, 1);
+	*cmds++ = 0x00000000;
+	*cmds++ = cp_type0_packet(A3XX_SP_VS_OUT_REG_6, 1);
+	*cmds++ = 0x00000000;
+	*cmds++ = cp_type0_packet(A3XX_SP_VS_OUT_REG_7, 1);
+	*cmds++ = 0x00000000;
+	*cmds++ = cp_type0_packet(A3XX_SP_VS_VPC_DST_REG_0, 1);
+	*cmds++ = 0x00000000;
+	*cmds++ = cp_type0_packet(A3XX_SP_VS_VPC_DST_REG_1, 1);
+	*cmds++ = 0x00000000;
+	*cmds++ = cp_type0_packet(A3XX_SP_VS_VPC_DST_REG_2, 1);
+	*cmds++ = 0x00000000;
+	*cmds++ = cp_type0_packet(A3XX_SP_VS_VPC_DST_REG_3, 1);
+	*cmds++ = 0x00000000;
+	*cmds++ = cp_type0_packet(A3XX_SP_VS_OBJ_OFFSET_REG, 1);
+	*cmds++ = 0x00000000;
+	*cmds++ = cp_type0_packet(A3XX_SP_VS_OBJ_START_REG, 1);
+	*cmds++ = 0x00000004;
+	*cmds++ = cp_type0_packet(A3XX_SP_VS_PVT_MEM_PARAM_REG, 1);
+	*cmds++ = 0x04008001;
+	*cmds++ = cp_type0_packet(A3XX_SP_VS_PVT_MEM_ADDR_REG, 1);
+	*cmds++ = 0x00000000;
+	*cmds++ = cp_type0_packet(A3XX_SP_VS_PVT_MEM_SIZE_REG, 1);
+	*cmds++ = 0x00000000;
+	*cmds++ = cp_type0_packet(A3XX_SP_VS_LENGTH_REG, 1);
+	*cmds++ = 0x00000000;
+	*cmds++ = cp_type0_packet(A3XX_SP_FS_CTRL_REG0, 1);
+	*cmds++ = 0x0DB0400A;
+	*cmds++ = cp_type0_packet(A3XX_SP_FS_CTRL_REG1, 1);
+	*cmds++ = 0x00300402;
+	*cmds++ = cp_type0_packet(A3XX_SP_FS_OBJ_OFFSET_REG, 1);
+	*cmds++ = 0x00010000;
+	*cmds++ = cp_type0_packet(A3XX_SP_FS_OBJ_START_REG, 1);
+	*cmds++ = 0x00000000;
+	*cmds++ = cp_type0_packet(A3XX_SP_FS_PVT_MEM_PARAM_REG, 1);
+	*cmds++ = 0x04008001;
+	*cmds++ = cp_type0_packet(A3XX_SP_FS_PVT_MEM_ADDR_REG, 1);
+	*cmds++ = 0x00000000;
+	*cmds++ = cp_type0_packet(A3XX_SP_FS_PVT_MEM_SIZE_REG, 1);
+	*cmds++ = 0x00000000;
+	*cmds++ = cp_type0_packet(A3XX_SP_FS_FLAT_SHAD_MODE_REG_0, 1);
+	*cmds++ = 0x00000000;
+	*cmds++ = cp_type0_packet(A3XX_SP_FS_FLAT_SHAD_MODE_REG_1, 1);
+	*cmds++ = 0x00000000;
+	*cmds++ = cp_type0_packet(A3XX_SP_FS_OUTPUT_REG, 1);
+	*cmds++ = 0x00000000;
+	*cmds++ = cp_type0_packet(A3XX_SP_FS_MRT_REG_0, 1);
+	*cmds++ = 0x00000000;
+	*cmds++ = cp_type0_packet(A3XX_SP_FS_MRT_REG_1, 1);
+	*cmds++ = 0x00000000;
+	*cmds++ = cp_type0_packet(A3XX_SP_FS_MRT_REG_2, 1);
+	*cmds++ = 0x00000000;
+	*cmds++ = cp_type0_packet(A3XX_SP_FS_MRT_REG_3, 1);
+	*cmds++ = 0x00000000;
+	*cmds++ = cp_type0_packet(A3XX_SP_FS_IMAGE_OUTPUT_REG_0, 1);
+	*cmds++ = 0x00000000;
+	*cmds++ = cp_type0_packet(A3XX_SP_FS_IMAGE_OUTPUT_REG_1, 1);
+	*cmds++ = 0x00000000;
+	*cmds++ = cp_type0_packet(A3XX_SP_FS_IMAGE_OUTPUT_REG_2, 1);
+	*cmds++ = 0x00000000;
+	*cmds++ = cp_type0_packet(A3XX_SP_FS_IMAGE_OUTPUT_REG_3, 1);
+	*cmds++ = 0x00000000;
+	*cmds++ = cp_type0_packet(A3XX_SP_FS_LENGTH_REG, 1);
+	*cmds++ = 0x0000000D;
+	*cmds++ = cp_type0_packet(A3XX_GRAS_CL_CLIP_CNTL, 1);
+	*cmds++ = 0x00000000;
+	*cmds++ = cp_type0_packet(A3XX_GRAS_CL_GB_CLIP_ADJ, 1);
+	*cmds++ = 0x00000000;
+	*cmds++ = cp_type0_packet(A3XX_GRAS_CL_VPORT_XOFFSET, 1);
+	*cmds++ = 0x00000000;
+	*cmds++ = cp_type0_packet(A3XX_GRAS_CL_VPORT_XSCALE, 1);
+	*cmds++ = 0x00000000;
+	*cmds++ = cp_type0_packet(A3XX_GRAS_CL_VPORT_YOFFSET, 1);
+	*cmds++ = 0x00000000;
+	*cmds++ = cp_type0_packet(A3XX_GRAS_CL_VPORT_YSCALE, 1);
+	*cmds++ = 0x00000000;
+	*cmds++ = cp_type0_packet(A3XX_GRAS_CL_VPORT_ZOFFSET, 1);
+	*cmds++ = 0x00000000;
+	*cmds++ = cp_type0_packet(A3XX_GRAS_CL_VPORT_ZSCALE, 1);
+	*cmds++ = 0x00000000;
+	*cmds++ = cp_type0_packet(A3XX_GRAS_CL_USER_PLANE_X0, 1);
+	*cmds++ = 0x00000000;
+	*cmds++ = cp_type0_packet(A3XX_GRAS_CL_USER_PLANE_Y0, 1);
+	*cmds++ = 0x00000000;
+	*cmds++ = cp_type0_packet(A3XX_GRAS_CL_USER_PLANE_Z0, 1);
+	*cmds++ = 0x00000000;
+	*cmds++ = cp_type0_packet(A3XX_GRAS_CL_USER_PLANE_W0, 1);
+	*cmds++ = 0x00000000;
+	*cmds++ = cp_type0_packet(A3XX_GRAS_CL_USER_PLANE_X1, 1);
+	*cmds++ = 0x00000000;
+	*cmds++ = cp_type0_packet(A3XX_GRAS_CL_USER_PLANE_Y1, 1);
+	*cmds++ = 0x00000000;
+	*cmds++ = cp_type0_packet(A3XX_GRAS_CL_USER_PLANE_Z1, 1);
+	*cmds++ = 0x00000000;
+	*cmds++ = cp_type0_packet(A3XX_GRAS_CL_USER_PLANE_W1, 1);
+	*cmds++ = 0x00000000;
+	*cmds++ = cp_type0_packet(A3XX_GRAS_CL_USER_PLANE_X2, 1);
+	*cmds++ = 0x00000000;
+	*cmds++ = cp_type0_packet(A3XX_GRAS_CL_USER_PLANE_Y2, 1);
+	*cmds++ = 0x00000000;
+	*cmds++ = cp_type0_packet(A3XX_GRAS_CL_USER_PLANE_Z2, 1);
+	*cmds++ = 0x00000000;
+	*cmds++ = cp_type0_packet(A3XX_GRAS_CL_USER_PLANE_W2, 1);
+	*cmds++ = 0x00000000;
+	*cmds++ = cp_type0_packet(A3XX_GRAS_CL_USER_PLANE_X3, 1);
+	*cmds++ = 0x00000000;
+	*cmds++ = cp_type0_packet(A3XX_GRAS_CL_USER_PLANE_Y3, 1);
+	*cmds++ = 0x00000000;
+	*cmds++ = cp_type0_packet(A3XX_GRAS_CL_USER_PLANE_Z3, 1);
+	*cmds++ = 0x00000000;
+	*cmds++ = cp_type0_packet(A3XX_GRAS_CL_USER_PLANE_W3, 1);
+	*cmds++ = 0x00000000;
+	*cmds++ = cp_type0_packet(A3XX_GRAS_CL_USER_PLANE_X4, 1);
+	*cmds++ = 0x00000000;
+	*cmds++ = cp_type0_packet(A3XX_GRAS_CL_USER_PLANE_Y4, 1);
+	*cmds++ = 0x00000000;
+	*cmds++ = cp_type0_packet(A3XX_GRAS_CL_USER_PLANE_Z4, 1);
+	*cmds++ = 0x00000000;
+	*cmds++ = cp_type0_packet(A3XX_GRAS_CL_USER_PLANE_W4, 1);
+	*cmds++ = 0x00000000;
+	*cmds++ = cp_type0_packet(A3XX_GRAS_CL_USER_PLANE_X5, 1);
+	*cmds++ = 0x00000000;
+	*cmds++ = cp_type0_packet(A3XX_GRAS_CL_USER_PLANE_Y5, 1);
+	*cmds++ = 0x00000000;
+	*cmds++ = cp_type0_packet(A3XX_GRAS_CL_USER_PLANE_Z5, 1);
+	*cmds++ = 0x00000000;
+	*cmds++ = cp_type0_packet(A3XX_GRAS_CL_USER_PLANE_W5, 1);
+	*cmds++ = 0x00000000;
+	*cmds++ = cp_type0_packet(A3XX_GRAS_SU_POINT_MINMAX, 1);
+	*cmds++ = 0x00000000;
+	*cmds++ = cp_type0_packet(A3XX_GRAS_SU_POINT_SIZE, 1);
+	*cmds++ = 0x00000000;
+	*cmds++ = cp_type0_packet(A3XX_GRAS_SU_POLY_OFFSET_OFFSET, 1);
+	*cmds++ = 0x00000000;
+	*cmds++ = cp_type0_packet(A3XX_GRAS_SU_POLY_OFFSET_SCALE, 1);
+	*cmds++ = 0x00000000;
+	*cmds++ = cp_type0_packet(A3XX_GRAS_SU_MODE_CONTROL, 1);
+	*cmds++ = 0x00000000;
+	*cmds++ = cp_type0_packet(A3XX_GRAS_SC_CONTROL, 1);
+	*cmds++ = 0x00000000;
+	*cmds++ = cp_type0_packet(A3XX_GRAS_SC_SCREEN_SCISSOR_TL, 1);
+	*cmds++ = 0x00000000;
+	*cmds++ = cp_type0_packet(A3XX_GRAS_SC_SCREEN_SCISSOR_BR, 1);
+	*cmds++ = 0x00000000;
+	*cmds++ = cp_type0_packet(A3XX_GRAS_SC_WINDOW_SCISSOR_BR, 1);
+	*cmds++ = 0x00000000;
+	*cmds++ = cp_type0_packet(A3XX_GRAS_SC_WINDOW_SCISSOR_TL, 1);
+	*cmds++ = 0x00000000;
+	*cmds++ = cp_type0_packet(A3XX_GRAS_TSE_DEBUG_ECO, 1);
+	*cmds++ = 0x00000000;
+	*cmds++ = cp_type0_packet(A3XX_GRAS_PERFCOUNTER0_SELECT, 1);
+	*cmds++ = 0x00000000;
+	*cmds++ = cp_type0_packet(A3XX_GRAS_PERFCOUNTER1_SELECT, 1);
+	*cmds++ = 0x00000000;
+	*cmds++ = cp_type0_packet(A3XX_GRAS_PERFCOUNTER2_SELECT, 1);
+	*cmds++ = 0x00000000;
+	*cmds++ = cp_type0_packet(A3XX_GRAS_PERFCOUNTER3_SELECT, 1);
+	*cmds++ = 0x00000000;
+	*cmds++ = cp_type0_packet(A3XX_RB_MODE_CONTROL, 1);
+	*cmds++ = 0x00008000;
+	*cmds++ = cp_type0_packet(A3XX_RB_RENDER_CONTROL, 1);
+	*cmds++ = 0x00000000;
+	*cmds++ = cp_type0_packet(A3XX_RB_MSAA_CONTROL, 1);
+	*cmds++ = 0x00000000;
+	*cmds++ = cp_type0_packet(A3XX_RB_ALPHA_REFERENCE, 1);
+	*cmds++ = 0x00000000;
+	*cmds++ = cp_type0_packet(A3XX_RB_MRT_CONTROL0, 1);
+	*cmds++ = 0x00000000;
+	*cmds++ = cp_type0_packet(A3XX_RB_MRT_CONTROL1, 1);
+	*cmds++ = 0x00000000;
+	*cmds++ = cp_type0_packet(A3XX_RB_MRT_CONTROL2, 1);
+	*cmds++ = 0x00000000;
+	*cmds++ = cp_type0_packet(A3XX_RB_MRT_CONTROL3, 1);
+	*cmds++ = 0x00000000;
+	*cmds++ = cp_type0_packet(A3XX_RB_MRT_BUF_INFO0, 1);
+	*cmds++ = 0x00000000;
+	*cmds++ = cp_type0_packet(A3XX_RB_MRT_BUF_INFO1, 1);
+	*cmds++ = 0x00000000;
+	*cmds++ = cp_type0_packet(A3XX_RB_MRT_BUF_INFO2, 1);
+	*cmds++ = 0x00000000;
+	*cmds++ = cp_type0_packet(A3XX_RB_MRT_BUF_INFO3, 1);
+	*cmds++ = 0x00000000;
+	*cmds++ = cp_type0_packet(A3XX_RB_MRT_BUF_BASE0, 1);
+	*cmds++ = 0x00000000;
+	*cmds++ = cp_type0_packet(A3XX_RB_MRT_BUF_BASE1, 1);
+	*cmds++ = 0x00000000;
+	*cmds++ = cp_type0_packet(A3XX_RB_MRT_BUF_BASE2, 1);
+	*cmds++ = 0x00000000;
+	*cmds++ = cp_type0_packet(A3XX_RB_MRT_BUF_BASE3, 1);
+	*cmds++ = 0x00000000;
+	*cmds++ = cp_type0_packet(A3XX_RB_MRT_BLEND_CONTROL0, 1);
+	*cmds++ = 0x00000000;
+	*cmds++ = cp_type0_packet(A3XX_RB_MRT_BLEND_CONTROL1, 1);
+	*cmds++ = 0x00000000;
+	*cmds++ = cp_type0_packet(A3XX_RB_MRT_BLEND_CONTROL2, 1);
+	*cmds++ = 0x00000000;
+	*cmds++ = cp_type0_packet(A3XX_RB_MRT_BLEND_CONTROL3, 1);
+	*cmds++ = 0x00000000;
+	*cmds++ = cp_type0_packet(A3XX_RB_BLEND_RED, 1);
+	*cmds++ = 0x00000000;
+	*cmds++ = cp_type0_packet(A3XX_RB_BLEND_GREEN, 1);
+	*cmds++ = 0x00000000;
+	*cmds++ = cp_type0_packet(A3XX_RB_BLEND_BLUE, 1);
+	*cmds++ = 0x00000000;
+	*cmds++ = cp_type0_packet(A3XX_RB_BLEND_ALPHA, 1);
+	*cmds++ = 0x00000000;
+	*cmds++ = cp_type0_packet(A3XX_RB_CLEAR_COLOR_DW0, 1);
+	*cmds++ = 0x00000000;
+	*cmds++ = cp_type0_packet(A3XX_RB_CLEAR_COLOR_DW1, 1);
+	*cmds++ = 0x00000000;
+	*cmds++ = cp_type0_packet(A3XX_RB_CLEAR_COLOR_DW2, 1);
+	*cmds++ = 0x00000000;
+	*cmds++ = cp_type0_packet(A3XX_RB_CLEAR_COLOR_DW3, 1);
+	*cmds++ = 0x00000000;
+	*cmds++ = cp_type0_packet(A3XX_RB_COPY_CONTROL, 1);
+	*cmds++ = 0x00000000;
+	*cmds++ = cp_type0_packet(A3XX_RB_COPY_DEST_BASE, 1);
+	*cmds++ = 0x00000000;
+	*cmds++ = cp_type0_packet(A3XX_RB_COPY_DEST_PITCH, 1);
+	*cmds++ = 0x00000000;
+	*cmds++ = cp_type0_packet(A3XX_RB_COPY_DEST_INFO, 1);
+	*cmds++ = 0x00000000;
+	*cmds++ = cp_type0_packet(A3XX_RB_DEPTH_CONTROL, 1);
+	*cmds++ = 0x00000000;
+	*cmds++ = cp_type0_packet(A3XX_RB_DEPTH_CLEAR, 1);
+	*cmds++ = 0x00000000;
+	*cmds++ = cp_type0_packet(A3XX_RB_DEPTH_BUF_INFO, 1);
+	*cmds++ = 0x00000000;
+	*cmds++ = cp_type0_packet(A3XX_RB_DEPTH_BUF_PITCH, 1);
+	*cmds++ = 0x00000000;
+	*cmds++ = cp_type0_packet(A3XX_RB_STENCIL_CONTROL, 1);
+	*cmds++ = 0x00000000;
+	*cmds++ = cp_type0_packet(A3XX_RB_STENCIL_CLEAR, 1);
+	*cmds++ = 0x00000000;
+	*cmds++ = cp_type0_packet(A3XX_RB_STENCIL_BUF_INFO, 1);
+	*cmds++ = 0x00000000;
+	*cmds++ = cp_type0_packet(A3XX_RB_STENCIL_BUF_PITCH, 1);
+	*cmds++ = 0x00000000;
+	*cmds++ = cp_type0_packet(A3XX_RB_STENCIL_REF_MASK, 1);
+	*cmds++ = 0x00000000;
+	*cmds++ = cp_type0_packet(A3XX_RB_STENCIL_REF_MASK_BF, 1);
+	*cmds++ = 0x00000000;
+	*cmds++ = cp_type0_packet(A3XX_RB_LRZ_VSC_CONTROL, 1);
+	*cmds++ = 0x00000000;
+	*cmds++ = cp_type0_packet(A3XX_RB_WINDOW_OFFSET, 1);
+	*cmds++ = 0x00000000;
+	*cmds++ = cp_type0_packet(A3XX_RB_SAMPLE_COUNT_CONTROL, 1);
+	*cmds++ = 0x00000000;
+	*cmds++ = cp_type0_packet(A3XX_RB_SAMPLE_COUNT_ADDR, 1);
+	*cmds++ = 0x00000000;
+	*cmds++ = cp_type0_packet(A3XX_RB_Z_CLAMP_MIN, 1);
+	*cmds++ = 0x00000000;
+	*cmds++ = cp_type0_packet(A3XX_RB_Z_CLAMP_MAX, 1);
+	*cmds++ = 0x00000000;
+	*cmds++ = cp_type0_packet(A3XX_RB_GMEM_BASE_ADDR, 1);
+	*cmds++ = 0x00000000;
+	*cmds++ = cp_type0_packet(A3XX_RB_DEBUG_ECO_CONTROLS_ADDR, 1);
+	*cmds++ = 0x00000000;
+	*cmds++ = cp_type0_packet(A3XX_RB_PERFCOUNTER0_SELECT, 1);
+	*cmds++ = 0x00000000;
+	*cmds++ = cp_type0_packet(A3XX_RB_PERFCOUNTER1_SELECT, 1);
+	*cmds++ = 0x00000000;
+	*cmds++ = cp_type0_packet(A3XX_RB_FRAME_BUFFER_DIMENSION, 1);
+	*cmds++ = 0x00000000;
+	*cmds++ = cp_type3_packet(CP_LOAD_STATE, 4);
+	*cmds++ = (1 << CP_LOADSTATE_DSTOFFSET_SHIFT) |
+		(0 << CP_LOADSTATE_STATESRC_SHIFT) |
+		(6 << CP_LOADSTATE_STATEBLOCKID_SHIFT) |
+		(1 << CP_LOADSTATE_NUMOFUNITS_SHIFT);
+	*cmds++ = (1 << CP_LOADSTATE_STATETYPE_SHIFT) |
+		(0 << CP_LOADSTATE_EXTSRCADDR_SHIFT);
+	*cmds++ = 0x00400000;
+	*cmds++ = 0x00000000;
+	*cmds++ = cp_type3_packet(CP_LOAD_STATE, 4);
+	*cmds++ = (2 << CP_LOADSTATE_DSTOFFSET_SHIFT) |
+		(6 << CP_LOADSTATE_STATEBLOCKID_SHIFT) |
+		(1 << CP_LOADSTATE_NUMOFUNITS_SHIFT);
+	*cmds++ = (1 << CP_LOADSTATE_STATETYPE_SHIFT);
+	*cmds++ = 0x00400220;
+	*cmds++ = 0x00000000;
+	*cmds++ = cp_type3_packet(CP_LOAD_STATE, 4);
+	*cmds++ = (6 << CP_LOADSTATE_STATEBLOCKID_SHIFT) |
+		(1 << CP_LOADSTATE_NUMOFUNITS_SHIFT);
+	*cmds++ = (1 << CP_LOADSTATE_STATETYPE_SHIFT);
+	*cmds++ = 0x00000000;
+	*cmds++ = 0x00000000;
+	*cmds++ = cp_type3_packet(CP_LOAD_STATE, 2 + count);
+	*cmds++ = (6 << CP_LOADSTATE_STATEBLOCKID_SHIFT) |
+		(13 << CP_LOADSTATE_NUMOFUNITS_SHIFT);
+	*cmds++ = 0x00000000;
+
+	memcpy(cmds, _a3xx_pwron_fixup_fs_instructions, count << 2);
+
+	cmds += count;
+
+	*cmds++ = cp_type3_packet(CP_EXEC_CL, 1);
+	*cmds++ = 0x00000000;
+	*cmds++ = cp_type3_packet(CP_WAIT_FOR_IDLE, 1);
+	*cmds++ = 0x00000000;
+	*cmds++ = cp_type0_packet(A3XX_HLSQ_CL_CONTROL_0_REG, 1);
+	*cmds++ = 0x00000000;
+	*cmds++ = cp_type3_packet(CP_WAIT_FOR_IDLE, 1);
+	*cmds++ = 0x00000000;
+	*cmds++ = cp_type0_packet(A3XX_HLSQ_CONTROL_0_REG, 1);
+	*cmds++ = 0x1E000150;
+	*cmds++ = cp_type3_packet(CP_WAIT_FOR_IDLE, 1);
+	*cmds++ = 0x00000000;
+	*cmds++ = cp_type3_packet(CP_SET_CONSTANT, 2);
+	*cmds++ = CP_REG(A3XX_HLSQ_CONTROL_0_REG);
+	*cmds++ = 0x1E000050;
+	*cmds++ = cp_type3_packet(CP_WAIT_FOR_IDLE, 1);
+	*cmds++ = 0x00000000;
+	*cmds++ = cp_type3_packet(CP_REG_RMW, 3);
+	*cmds++ = A3XX_RBBM_CLOCK_CTL;
+	*cmds++ = 0xFFFCFFFF;
+	*cmds++ = 0x00000000;
+	*cmds++ = cp_type3_packet(CP_WAIT_FOR_IDLE, 1);
+	*cmds++ = 0x00000000;
+
+	/*
+	 * Remember the number of dwords in the command buffer for when we
+	 * program the indirect buffer call in the ringbuffer
+	 */
+	adreno_dev->pwron_fixup_dwords =
+		(cmds - (unsigned int *) adreno_dev->pwron_fixup.hostptr);
+
+	/* Mark the flag in ->priv to show that we have the fix */
+	set_bit(ADRENO_DEVICE_PWRON_FIXUP, &adreno_dev->priv);
+	return 0;
 }
 
 static int a3xx_rb_init(struct adreno_device *adreno_dev,
@@ -2596,7 +3042,7 @@
 
 		/* Clear the error */
 		kgsl_regwrite(device, A3XX_RBBM_AHB_CMD, (1 << 3));
-		goto done;
+		return;
 	}
 	case A3XX_INT_RBBM_REG_TIMEOUT:
 		err = "RBBM: AHB register timeout";
@@ -2637,23 +3083,21 @@
 	case A3XX_INT_UCHE_OOB_ACCESS:
 		err = "UCHE:  Out of bounds access";
 		break;
-	default:
-		return;
 	}
+
 	KGSL_DRV_CRIT(device, "%s\n", err);
 	kgsl_pwrctrl_irq(device, KGSL_PWRFLAGS_OFF);
-
-done:
-	/* Trigger a fault in the dispatcher - this will effect a restart */
-	adreno_dispatcher_irq_fault(device);
 }
 
 static void a3xx_cp_callback(struct adreno_device *adreno_dev, int irq)
 {
 	struct kgsl_device *device = &adreno_dev->dev;
 
+	/* Wake up everybody waiting for the interrupt */
+	wake_up_interruptible_all(&device->wait_queue);
+
+	/* Schedule work to free mem and issue ibs */
 	queue_work(device->work_queue, &device->ts_expired_ws);
-	adreno_dispatcher_schedule(device);
 }
 
 /**
diff --git a/drivers/gpu/msm/adreno_dispatch.c b/drivers/gpu/msm/adreno_dispatch.c
deleted file mode 100644
index 13b4ba3..0000000
--- a/drivers/gpu/msm/adreno_dispatch.c
+++ /dev/null
@@ -1,1611 +0,0 @@
-/* Copyright (c) 2013, The Linux Foundation. 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 and
- * only 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/wait.h>
-#include <linux/delay.h>
-#include <linux/sched.h>
-#include <linux/jiffies.h>
-#include <linux/err.h>
-
-#include "kgsl.h"
-#include "adreno.h"
-#include "adreno_ringbuffer.h"
-#include "adreno_trace.h"
-
-#define ADRENO_DISPATCHER_ACTIVE 0
-#define ADRENO_DISPATCHER_PAUSE 1
-
-#define CMDQUEUE_NEXT(_i, _s) (((_i) + 1) % (_s))
-
-/* Number of commands that can be queued in a context before it sleeps */
-static unsigned int _context_cmdqueue_size = 50;
-
-/* Number of milliseconds to wait for the context queue to clear */
-static unsigned int _context_queue_wait = 10000;
-
-/* Number of command batches sent at a time from a single context */
-static unsigned int _context_cmdbatch_burst = 5;
-
-/* Number of command batches inflight in the ringbuffer at any time */
-static unsigned int _dispatcher_inflight = 15;
-
-/* Command batch timeout (in milliseconds) */
-static unsigned int _cmdbatch_timeout = 2000;
-
-/* Interval for reading and comparing fault detection registers */
-static unsigned int _fault_timer_interval = 50;
-
-/* Local array for the current set of fault detect registers */
-static unsigned int fault_detect_regs[FT_DETECT_REGS_COUNT];
-
-/* The last retired global timestamp read during fault detect */
-static unsigned int fault_detect_ts;
-
-/**
- * fault_detect_read() - Read the set of fault detect registers
- * @device: Pointer to the KGSL device struct
- *
- * Read the set of fault detect registers and store them in the local array.
- * This is for the initial values that are compared later with
- * fault_detect_read_compare
- */
-static void fault_detect_read(struct kgsl_device *device)
-{
-	int i;
-
-	fault_detect_ts = kgsl_readtimestamp(device, NULL,
-		KGSL_TIMESTAMP_RETIRED);
-
-	for (i = 0; i < FT_DETECT_REGS_COUNT; i++) {
-		if (ft_detect_regs[i] == 0)
-			continue;
-		kgsl_regread(device, ft_detect_regs[i],
-			&fault_detect_regs[i]);
-	}
-}
-
-/**
- * fault_detect_read_compare() - Read the fault detect registers and compare
- * them to the current value
- * @device: Pointer to the KGSL device struct
- *
- * Read the set of fault detect registers and compare them to the current set
- * of registers.  Return 1 if any of the register values changed
- */
-static int fault_detect_read_compare(struct kgsl_device *device)
-{
-	int i, ret = 0;
-	unsigned int ts;
-
-	for (i = 0; i < FT_DETECT_REGS_COUNT; i++) {
-		unsigned int val;
-
-		if (ft_detect_regs[i] == 0)
-			continue;
-		kgsl_regread(device, ft_detect_regs[i], &val);
-		if (val != fault_detect_regs[i])
-			ret = 1;
-		fault_detect_regs[i] = val;
-	}
-
-	ts = kgsl_readtimestamp(device, NULL, KGSL_TIMESTAMP_RETIRED);
-	if (ts != fault_detect_ts)
-		ret = 1;
-
-	fault_detect_ts = ts;
-
-	return ret;
-}
-
-/**
- * adreno_dispatcher_get_cmdbatch() - Get a new command from a context queue
- * @drawctxt: Pointer to the adreno draw context
- *
- * Dequeue a new command batch from the context list
- */
-static inline struct kgsl_cmdbatch *adreno_dispatcher_get_cmdbatch(
-		struct adreno_context *drawctxt)
-{
-	struct kgsl_cmdbatch *cmdbatch = NULL;
-
-	mutex_lock(&drawctxt->mutex);
-	if (drawctxt->cmdqueue_head != drawctxt->cmdqueue_tail) {
-		cmdbatch = drawctxt->cmdqueue[drawctxt->cmdqueue_head];
-
-		/*
-		 * Don't dequeue a cmdbatch that is still waiting for other
-		 * events
-		 */
-		if (kgsl_cmdbatch_sync_pending(cmdbatch)) {
-			cmdbatch = ERR_PTR(-EAGAIN);
-			goto done;
-		}
-
-		drawctxt->cmdqueue_head =
-			CMDQUEUE_NEXT(drawctxt->cmdqueue_head,
-			ADRENO_CONTEXT_CMDQUEUE_SIZE);
-		drawctxt->queued--;
-	}
-
-done:
-	mutex_unlock(&drawctxt->mutex);
-
-	return cmdbatch;
-}
-
-/**
- * adreno_dispatcher_requeue_cmdbatch() - Put a command back on the context
- * queue
- * @drawctxt: Pointer to the adreno draw context
- * @cmdbatch: Pointer to the KGSL cmdbatch to requeue
- *
- * Failure to submit a command to the ringbuffer isn't the fault of the command
- * being submitted so if a failure happens, push it back on the head of the the
- * context queue to be reconsidered again
- */
-static inline void adreno_dispatcher_requeue_cmdbatch(
-		struct adreno_context *drawctxt, struct kgsl_cmdbatch *cmdbatch)
-{
-	unsigned int prev;
-	mutex_lock(&drawctxt->mutex);
-
-	if (kgsl_context_detached(&drawctxt->base) ||
-		drawctxt->state == ADRENO_CONTEXT_STATE_INVALID) {
-		mutex_unlock(&drawctxt->mutex);
-		return;
-	}
-
-	prev = drawctxt->cmdqueue_head - 1;
-
-	if (prev < 0)
-		prev = ADRENO_CONTEXT_CMDQUEUE_SIZE - 1;
-
-	/*
-	 * The maximum queue size always needs to be one less then the size of
-	 * the ringbuffer queue so there is "room" to put the cmdbatch back in
-	 */
-
-	BUG_ON(prev == drawctxt->cmdqueue_tail);
-
-	drawctxt->cmdqueue[prev] = cmdbatch;
-	drawctxt->queued++;
-
-	/* Reset the command queue head to reflect the newly requeued change */
-	drawctxt->cmdqueue_head = prev;
-	mutex_unlock(&drawctxt->mutex);
-}
-
-/**
- * dispatcher_queue_context() - Queue a context in the dispatcher pending list
- * @dispatcher: Pointer to the adreno dispatcher struct
- * @drawctxt: Pointer to the adreno draw context
- *
- * Add a context to the dispatcher pending list.
- */
-static void  dispatcher_queue_context(struct adreno_device *adreno_dev,
-		struct adreno_context *drawctxt)
-{
-	struct adreno_dispatcher *dispatcher = &adreno_dev->dispatcher;
-
-	spin_lock(&dispatcher->plist_lock);
-
-	if (plist_node_empty(&drawctxt->pending)) {
-		/* Get a reference to the context while it sits on the list */
-		_kgsl_context_get(&drawctxt->base);
-		trace_dispatch_queue_context(drawctxt);
-		plist_add(&drawctxt->pending, &dispatcher->pending);
-	}
-
-	spin_unlock(&dispatcher->plist_lock);
-}
-
-/**
- * sendcmd() - Send a command batch to the GPU hardware
- * @dispatcher: Pointer to the adreno dispatcher struct
- * @cmdbatch: Pointer to the KGSL cmdbatch being sent
- *
- * Send a KGSL command batch to the GPU hardware
- */
-static int sendcmd(struct adreno_device *adreno_dev,
-	struct kgsl_cmdbatch *cmdbatch)
-{
-	struct kgsl_device *device = &adreno_dev->dev;
-	struct adreno_dispatcher *dispatcher = &adreno_dev->dispatcher;
-	int ret;
-
-	dispatcher->inflight++;
-
-	mutex_lock(&device->mutex);
-
-	if (dispatcher->inflight == 1) {
-		/* Time to make the donuts.  Turn on the GPU */
-		ret = kgsl_active_count_get(device);
-		if (ret) {
-			dispatcher->inflight--;
-			mutex_unlock(&device->mutex);
-			return ret;
-		}
-	}
-
-	ret = adreno_ringbuffer_submitcmd(adreno_dev, cmdbatch);
-
-	/*
-	 * On the first command, if the submission was successful, then read the
-	 * fault registers.  If it failed then turn off the GPU. Sad face.
-	 */
-
-	if (dispatcher->inflight == 1) {
-		if (ret == 0)
-			fault_detect_read(device);
-		else
-			kgsl_active_count_put(device);
-	}
-
-	mutex_unlock(&device->mutex);
-
-	if (ret) {
-		dispatcher->inflight--;
-		KGSL_DRV_ERR(device,
-			"Unable to submit command to the ringbuffer\n");
-		return ret;
-	}
-
-	trace_adreno_cmdbatch_submitted(cmdbatch, dispatcher->inflight);
-
-	dispatcher->cmdqueue[dispatcher->tail] = cmdbatch;
-	dispatcher->tail = (dispatcher->tail + 1) %
-		ADRENO_DISPATCH_CMDQUEUE_SIZE;
-
-	/*
-	 * If this is the first command in the pipe then the GPU will
-	 * immediately start executing it so we can start the expiry timeout on
-	 * the command batch here.  Subsequent command batches will have their
-	 * timer started when the previous command batch is retired
-	 */
-	if (dispatcher->inflight == 1) {
-		cmdbatch->expires = jiffies +
-			msecs_to_jiffies(_cmdbatch_timeout);
-		mod_timer(&dispatcher->timer, cmdbatch->expires);
-
-		/* Start the fault detection timer */
-		if (adreno_dev->fast_hang_detect)
-			mod_timer(&dispatcher->fault_timer,
-				jiffies +
-				msecs_to_jiffies(_fault_timer_interval));
-	}
-
-	return 0;
-}
-
-/**
- * dispatcher_context_sendcmds() - Send commands from a context to the GPU
- * @adreno_dev: Pointer to the adreno device struct
- * @drawctxt: Pointer to the adreno context to dispatch commands from
- *
- * Dequeue and send a burst of commands from the specified context to the GPU
- */
-static int dispatcher_context_sendcmds(struct adreno_device *adreno_dev,
-		struct adreno_context *drawctxt)
-{
-	struct adreno_dispatcher *dispatcher = &adreno_dev->dispatcher;
-	int count = 0;
-	int requeued = 0;
-
-	/*
-	 * Each context can send a specific number of command batches per cycle
-	 */
-	while ((count < _context_cmdbatch_burst) &&
-		(dispatcher->inflight < _dispatcher_inflight)) {
-		int ret;
-		struct kgsl_cmdbatch *cmdbatch;
-
-		if (dispatcher->state != ADRENO_DISPATCHER_ACTIVE)
-			break;
-
-		if (adreno_gpu_fault(adreno_dev) != 0)
-			break;
-
-		cmdbatch = adreno_dispatcher_get_cmdbatch(drawctxt);
-
-		if (cmdbatch == NULL)
-			break;
-
-		/*
-		 * adreno_context_get_cmdbatch returns -EAGAIN if the current
-		 * cmdbatch has pending sync points so no more to do here.
-		 * When the sync points are satisfied then the context will get
-		 * reqeueued
-		 */
-
-		if (IS_ERR(cmdbatch) && PTR_ERR(cmdbatch) == -EAGAIN) {
-			requeued = 1;
-			break;
-		}
-
-		/*
-		 * If this is a synchronization submission then there are no
-		 * commands to submit.  Discard it and get the next item from
-		 * the queue.  Decrement count so this packet doesn't count
-		 * against the burst for the context
-		 */
-
-		if (cmdbatch->flags & KGSL_CONTEXT_SYNC) {
-			kgsl_cmdbatch_destroy(cmdbatch);
-			continue;
-		}
-
-		ret = sendcmd(adreno_dev, cmdbatch);
-
-		/*
-		 * There are various reasons why we can't submit a command (no
-		 * memory for the commands, full ringbuffer, etc) but none of
-		 * these are actually the current command's fault.  Requeue it
-		 * back on the context and let it come back around again if
-		 * conditions improve
-		 */
-		if (ret) {
-			adreno_dispatcher_requeue_cmdbatch(drawctxt, cmdbatch);
-			requeued = 1;
-			break;
-		}
-		count++;
-	}
-
-	/*
-	 * If the context successfully submitted commands, then
-	 * unconditionally put it back on the queue to be considered the
-	 * next time around. This might seem a little wasteful but it is
-	 * reasonable to think that a busy context will stay busy.
-	 */
-
-	if (count || requeued) {
-		dispatcher_queue_context(adreno_dev, drawctxt);
-
-		/*
-		 * If we submitted something there will be room in the
-		 * context queue so ping the context wait queue on the
-		 * chance that the context is snoozing
-		 */
-
-		wake_up_interruptible_all(&drawctxt->wq);
-	}
-
-	/* Return the number of command batches processed */
-	if (count > 0)
-		return count;
-
-	/*
-	 * If we didn't process anything because of a stall or an error
-	 * return -1 so the issuecmds loop knows that we shouldn't
-	 * keep trying to process it
-	 */
-
-	return requeued ? -1 : 0;
-}
-
-/**
- * _adreno_dispatcher_issuecmds() - Issue commmands from pending contexts
- * @adreno_dev: Pointer to the adreno device struct
- *
- * Issue as many commands as possible (up to inflight) from the pending contexts
- * This function assumes the dispatcher mutex has been locked.
- */
-static int _adreno_dispatcher_issuecmds(struct adreno_device *adreno_dev)
-{
-	struct adreno_dispatcher *dispatcher = &adreno_dev->dispatcher;
-	int last_id = 0;
-
-	while (dispatcher->inflight < _dispatcher_inflight) {
-		struct adreno_context *drawctxt = NULL;
-
-		/* Don't do anything if the dispatcher is paused */
-		if (dispatcher->state != ADRENO_DISPATCHER_ACTIVE)
-			break;
-
-		if (adreno_gpu_fault(adreno_dev) != 0)
-			break;
-
-		spin_lock(&dispatcher->plist_lock);
-
-		if (!plist_head_empty(&dispatcher->pending)) {
-			drawctxt = plist_first_entry(&dispatcher->pending,
-				struct adreno_context, pending);
-
-			plist_del(&drawctxt->pending, &dispatcher->pending);
-		}
-
-		spin_unlock(&dispatcher->plist_lock);
-
-		if (drawctxt == NULL)
-			break;
-
-		if (kgsl_context_detached(&drawctxt->base) ||
-			drawctxt->state == ADRENO_CONTEXT_STATE_INVALID) {
-			kgsl_context_put(&drawctxt->base);
-			continue;
-		}
-
-		/*
-		 * Don't loop endlessly on the same stalled context - if we see
-		 * the same context twice in a row then assume that there is
-		 * nothing else to do and bail.  But don't forget to put the
-		 * stalled context back on the queue otherwise it will get
-		 * forgotten
-		 */
-
-		if (last_id == drawctxt->base.id) {
-			dispatcher_queue_context(adreno_dev, drawctxt);
-			kgsl_context_put(&drawctxt->base);
-			break;
-		}
-
-		last_id = drawctxt->base.id;
-		dispatcher_context_sendcmds(adreno_dev, drawctxt);
-		kgsl_context_put(&drawctxt->base);
-	}
-
-	return 0;
-}
-
-/**
- * adreno_dispatcher_issuecmds() - Issue commmands from pending contexts
- * @adreno_dev: Pointer to the adreno device struct
- *
- * Lock the dispatcher and call _adreno_dispatcher_issueibcmds
- */
-int adreno_dispatcher_issuecmds(struct adreno_device *adreno_dev)
-{
-	struct adreno_dispatcher *dispatcher = &adreno_dev->dispatcher;
-	int ret;
-
-	mutex_lock(&dispatcher->mutex);
-	ret = _adreno_dispatcher_issuecmds(adreno_dev);
-	mutex_unlock(&dispatcher->mutex);
-
-	return ret;
-}
-
-static int _check_context_queue(struct adreno_context *drawctxt)
-{
-	int ret;
-
-	mutex_lock(&drawctxt->mutex);
-
-	/*
-	 * Wake up if there is room in the context or if the whole thing got
-	 * invalidated while we were asleep
-	 */
-
-	if (drawctxt->state == ADRENO_CONTEXT_STATE_INVALID)
-		ret = 1;
-	else
-		ret = drawctxt->queued < _context_cmdqueue_size ? 1 : 0;
-
-	mutex_unlock(&drawctxt->mutex);
-
-	return ret;
-}
-
-/**
- * get_timestamp() - Return the next timestamp for the context
- * @drawctxt - Pointer to an adreno draw context struct
- * @cmdbatch - Pointer to a command batch
- * @timestamp - Pointer to a timestamp value possibly passed from the user
- *
- * Assign a timestamp based on the settings of the draw context and the command
- * batch.
- */
-static int get_timestamp(struct adreno_context *drawctxt,
-		struct kgsl_cmdbatch *cmdbatch, unsigned int *timestamp)
-{
-	/* Synchronization commands don't get a timestamp */
-	if (cmdbatch->flags & KGSL_CONTEXT_SYNC) {
-		*timestamp = 0;
-		return 0;
-	}
-
-	if (drawctxt->flags & CTXT_FLAGS_USER_GENERATED_TS) {
-		/*
-		 * User specified timestamps need to be greater than the last
-		 * issued timestamp in the context
-		 */
-		if (timestamp_cmp(drawctxt->timestamp, *timestamp) >= 0)
-			return -ERANGE;
-
-		drawctxt->timestamp = *timestamp;
-	} else
-		drawctxt->timestamp++;
-
-	*timestamp = drawctxt->timestamp;
-	return 0;
-}
-
-/**
- * adreno_dispactcher_queue_cmd() - Queue a new command in the context
- * @adreno_dev: Pointer to the adreno device struct
- * @drawctxt: Pointer to the adreno draw context
- * @cmdbatch: Pointer to the command batch being submitted
- * @timestamp: Pointer to the requested timestamp
- *
- * Queue a command in the context - if there isn't any room in the queue, then
- * block until there is
- */
-int adreno_dispatcher_queue_cmd(struct adreno_device *adreno_dev,
-		struct adreno_context *drawctxt, struct kgsl_cmdbatch *cmdbatch,
-		uint32_t *timestamp)
-{
-	int ret;
-
-	mutex_lock(&drawctxt->mutex);
-
-	if (drawctxt->flags & CTXT_FLAGS_BEING_DESTROYED) {
-		mutex_unlock(&drawctxt->mutex);
-		return -EINVAL;
-	}
-
-	/*
-	 * After skipping to the end of the frame we need to force the preamble
-	 * to run (if it exists) regardless of the context state.
-	 */
-
-	if (drawctxt->flags & CTXT_FLAGS_FORCE_PREAMBLE) {
-		set_bit(CMDBATCH_FLAG_FORCE_PREAMBLE, &cmdbatch->priv);
-		drawctxt->flags &= ~CTXT_FLAGS_FORCE_PREAMBLE;
-	}
-
-	/*
-	 * If we are waiting for the end of frame and it hasn't appeared yet,
-	 * then mark the command batch as skipped.  It will still progress
-	 * through the pipeline but it won't actually send any commands
-	 */
-
-	if (drawctxt->flags & CTXT_FLAGS_SKIP_EOF) {
-		set_bit(CMDBATCH_FLAG_SKIP, &cmdbatch->priv);
-
-		/*
-		 * If this command batch represents the EOF then clear the way
-		 * for the dispatcher to continue submitting
-		 */
-
-		if (cmdbatch->flags & KGSL_CONTEXT_END_OF_FRAME) {
-			drawctxt->flags &= ~CTXT_FLAGS_SKIP_EOF;
-
-			/*
-			 * Force the preamble on the next command to ensure that
-			 * the state is correct
-			 */
-
-			drawctxt->flags |= CTXT_FLAGS_FORCE_PREAMBLE;
-		}
-	}
-
-	/* Wait for room in the context queue */
-
-	while (drawctxt->queued >= _context_cmdqueue_size) {
-		trace_adreno_drawctxt_sleep(drawctxt);
-		mutex_unlock(&drawctxt->mutex);
-
-		ret = wait_event_interruptible_timeout(drawctxt->wq,
-			_check_context_queue(drawctxt),
-			msecs_to_jiffies(_context_queue_wait));
-
-		mutex_lock(&drawctxt->mutex);
-		trace_adreno_drawctxt_wake(drawctxt);
-
-		if (ret <= 0) {
-			mutex_unlock(&drawctxt->mutex);
-			return (ret == 0) ? -ETIMEDOUT : (int) ret;
-		}
-
-		/*
-		 * Account for the possiblity that the context got invalidated
-		 * while we were sleeping
-		 */
-
-		if (drawctxt->state == ADRENO_CONTEXT_STATE_INVALID) {
-			mutex_unlock(&drawctxt->mutex);
-			return -EDEADLK;
-		}
-	}
-
-	ret = get_timestamp(drawctxt, cmdbatch, timestamp);
-	if (ret) {
-		mutex_unlock(&drawctxt->mutex);
-		return ret;
-	}
-
-	cmdbatch->timestamp = *timestamp;
-
-	/*
-	 * Set the fault tolerance policy for the command batch - assuming the
-	 * context hsn't disabled FT use the current device policy
-	 */
-
-	if (drawctxt->flags & CTXT_FLAGS_NO_FAULT_TOLERANCE)
-		set_bit(KGSL_FT_DISABLE, &cmdbatch->fault_policy);
-	else
-		cmdbatch->fault_policy = adreno_dev->ft_policy;
-
-	/* Put the command into the queue */
-	drawctxt->cmdqueue[drawctxt->cmdqueue_tail] = cmdbatch;
-	drawctxt->cmdqueue_tail = (drawctxt->cmdqueue_tail + 1) %
-		ADRENO_CONTEXT_CMDQUEUE_SIZE;
-
-	drawctxt->queued++;
-	trace_adreno_cmdbatch_queued(cmdbatch, drawctxt->queued);
-
-
-	mutex_unlock(&drawctxt->mutex);
-
-	/* Add the context to the dispatcher pending list */
-	dispatcher_queue_context(adreno_dev, drawctxt);
-
-	/*
-	 * Only issue commands if inflight is less than burst -this prevents us
-	 * from sitting around waiting for the mutex on a busy system - the work
-	 * loop will schedule it for us. Inflight is mutex protected but the
-	 * worse that can happen is that it will go to 0 after we check and if
-	 * it goes to 0 it is because the work loop decremented it and the work
-	 * queue will try to schedule new commands anyway.
-	 */
-
-	if (adreno_dev->dispatcher.inflight < _context_cmdbatch_burst)
-		adreno_dispatcher_issuecmds(adreno_dev);
-
-	return 0;
-}
-
-/*
- * If an IB inside of the command batch has a gpuaddr that matches the base
- * passed in then zero the size which effectively skips it when it is submitted
- * in the ringbuffer.
- */
-static void cmdbatch_skip_ib(struct kgsl_cmdbatch *cmdbatch, unsigned int base)
-{
-	int i;
-
-	for (i = 0; i < cmdbatch->ibcount; i++) {
-		if (cmdbatch->ibdesc[i].gpuaddr == base) {
-			cmdbatch->ibdesc[i].sizedwords = 0;
-			return;
-		}
-	}
-}
-
-static void cmdbatch_skip_frame(struct kgsl_cmdbatch *cmdbatch,
-	struct kgsl_cmdbatch **replay, int count)
-{
-	struct adreno_context *drawctxt = ADRENO_CONTEXT(cmdbatch->context);
-	int skip = 1;
-	int i;
-
-	for (i = 0; i < count; i++) {
-
-		/*
-		 * Only operate on command batches that belong to the
-		 * faulting context
-		 */
-
-		if (replay[i]->context->id != cmdbatch->context->id)
-			continue;
-
-		/*
-		 * Skip all the command batches in this context until
-		 * the EOF flag is seen.  If the EOF flag is seen then
-		 * force the preamble for the next command.
-		 */
-
-		if (skip) {
-			set_bit(CMDBATCH_FLAG_SKIP, &replay[i]->priv);
-
-			if (replay[i]->flags & KGSL_CONTEXT_END_OF_FRAME)
-				skip = 0;
-		} else {
-			set_bit(CMDBATCH_FLAG_FORCE_PREAMBLE, &replay[i]->priv);
-			return;
-		}
-	}
-
-	/*
-	 * If the EOF flag hasn't been seen yet then set the flag in the
-	 * drawctxt to keep looking for it
-	 */
-
-	if (skip && drawctxt)
-		drawctxt->flags |= CTXT_FLAGS_SKIP_EOF;
-
-	/*
-	 * If we did see the EOF flag then force the preamble on for the
-	 * next command issued on this context
-	 */
-
-	if (!skip && drawctxt)
-		drawctxt->flags |= CTXT_FLAGS_FORCE_PREAMBLE;
-}
-
-static void remove_invalidated_cmdbatches(struct kgsl_device *device,
-		struct kgsl_cmdbatch **replay, int count)
-{
-	int i;
-
-	for (i = 0; i < count; i++) {
-		struct kgsl_cmdbatch *cmd = replay[i];
-		struct adreno_context *drawctxt;
-
-		if (cmd == NULL)
-			continue;
-
-		drawctxt = ADRENO_CONTEXT(cmd->context);
-
-		if (kgsl_context_detached(cmd->context) ||
-			drawctxt->state == ADRENO_CONTEXT_STATE_INVALID) {
-			replay[i] = NULL;
-
-			mutex_lock(&device->mutex);
-			kgsl_cancel_events_timestamp(device, cmd->context,
-				cmd->timestamp);
-			mutex_unlock(&device->mutex);
-
-			kgsl_cmdbatch_destroy(cmd);
-		}
-	}
-}
-
-static char _pidname[TASK_COMM_LEN];
-
-static inline const char *_kgsl_context_comm(struct kgsl_context *context)
-{
-	struct task_struct *task = NULL;
-
-	if (context)
-		task = find_task_by_vpid(context->pid);
-
-	if (task)
-		get_task_comm(_pidname, task);
-	else
-		snprintf(_pidname, TASK_COMM_LEN, "unknown");
-
-	return _pidname;
-}
-
-#define pr_fault(_d, _c, fmt, args...) \
-		dev_err((_d)->dev, "%s[%d]: " fmt, \
-		_kgsl_context_comm((_c)->context), \
-		(_c)->context->pid, ##args)
-
-
-static void adreno_fault_header(struct kgsl_device *device,
-	struct kgsl_cmdbatch *cmdbatch)
-{
-	struct adreno_device *adreno_dev = ADRENO_DEVICE(device);
-	unsigned int status, base, rptr, wptr, ib1base, ib2base, ib1sz, ib2sz;
-
-	kgsl_regread(device,
-			adreno_getreg(adreno_dev, ADRENO_REG_RBBM_STATUS),
-			&status);
-	kgsl_regread(device,
-		adreno_getreg(adreno_dev, ADRENO_REG_CP_RB_BASE),
-		&base);
-	kgsl_regread(device,
-		adreno_getreg(adreno_dev, ADRENO_REG_CP_RB_RPTR),
-		&rptr);
-	kgsl_regread(device,
-		adreno_getreg(adreno_dev, ADRENO_REG_CP_RB_WPTR),
-		&wptr);
-	kgsl_regread(device,
-		adreno_getreg(adreno_dev, ADRENO_REG_CP_IB1_BASE),
-		&ib1base);
-	kgsl_regread(device,
-		adreno_getreg(adreno_dev, ADRENO_REG_CP_IB1_BUFSZ),
-		&ib1sz);
-	kgsl_regread(device,
-		adreno_getreg(adreno_dev, ADRENO_REG_CP_IB2_BASE),
-		&ib2base);
-	kgsl_regread(device,
-		adreno_getreg(adreno_dev, ADRENO_REG_CP_IB2_BUFSZ),
-		&ib2sz);
-
-	trace_adreno_gpu_fault(cmdbatch->context->id, cmdbatch->timestamp,
-		status, rptr, wptr, ib1base, ib1sz, ib2base, ib2sz);
-
-	pr_fault(device, cmdbatch,
-		"gpu fault ctx %d ts %d status %8.8X rb %4.4x/%4.4x ib1 %8.8x/%4.4x ib2 %8.8x/%4.4x\n",
-		cmdbatch->context->id, cmdbatch->timestamp, status,
-		rptr, wptr, ib1base, ib1sz, ib2base, ib2sz);
-}
-
-static int dispatcher_do_fault(struct kgsl_device *device)
-{
-	struct adreno_device *adreno_dev = ADRENO_DEVICE(device);
-	struct adreno_dispatcher *dispatcher = &adreno_dev->dispatcher;
-	unsigned int ptr;
-	unsigned int reg, base;
-	struct kgsl_cmdbatch **replay = NULL;
-	struct kgsl_cmdbatch *cmdbatch;
-	int ret, i, count = 0;
-	int fault, first = 0;
-	bool pagefault = false;
-	BUG_ON(dispatcher->inflight == 0);
-
-	fault = atomic_xchg(&dispatcher->fault, 0);
-	if (fault == 0)
-		return 0;
-
-	/* Turn off all the timers */
-	del_timer_sync(&dispatcher->timer);
-	del_timer_sync(&dispatcher->fault_timer);
-
-	mutex_lock(&device->mutex);
-
-	cmdbatch = dispatcher->cmdqueue[dispatcher->head];
-
-	trace_adreno_cmdbatch_fault(cmdbatch, fault);
-
-	/*
-	 * If the fault was due to a timeout then stop the CP to ensure we don't
-	 * get activity while we are trying to dump the state of the system
-	 */
-
-	if (fault == ADRENO_TIMEOUT_FAULT) {
-		adreno_readreg(adreno_dev, ADRENO_REG_CP_ME_CNTL, &reg);
-		reg |= (1 << 27) | (1 << 28);
-		adreno_writereg(adreno_dev, ADRENO_REG_CP_ME_CNTL, reg);
-
-		/* Skip the PM dump for a timeout because it confuses people */
-		set_bit(KGSL_FT_SKIP_PMDUMP, &cmdbatch->fault_policy);
-	}
-
-	adreno_readreg(adreno_dev, ADRENO_REG_CP_IB1_BASE, &base);
-
-	/*
-	 * Dump the postmortem and snapshot information if this is the first
-	 * detected fault for the oldest active command batch
-	 */
-
-	if (!test_bit(KGSL_FT_SKIP_PMDUMP, &cmdbatch->fault_policy)) {
-		adreno_fault_header(device, cmdbatch);
-
-		if (device->pm_dump_enable)
-			kgsl_postmortem_dump(device, 0);
-
-		kgsl_device_snapshot(device, 1);
-	}
-
-	mutex_unlock(&device->mutex);
-
-	/* Allocate memory to store the inflight commands */
-	replay = kzalloc(sizeof(*replay) * dispatcher->inflight, GFP_KERNEL);
-
-	if (replay == NULL) {
-		unsigned int ptr = dispatcher->head;
-
-		while (ptr != dispatcher->tail) {
-			struct kgsl_context *context =
-				dispatcher->cmdqueue[ptr]->context;
-
-			adreno_drawctxt_invalidate(device, context);
-			kgsl_cmdbatch_destroy(dispatcher->cmdqueue[ptr]);
-
-			ptr = CMDQUEUE_NEXT(ptr, ADRENO_DISPATCH_CMDQUEUE_SIZE);
-		}
-
-		/*
-		 * Set the replay count to zero - this will ensure that the
-		 * hardware gets reset but nothing else goes played
-		 */
-
-		count = 0;
-		goto replay;
-	}
-
-	/* Copy the inflight command batches into the temporary storage */
-	ptr = dispatcher->head;
-
-	while (ptr != dispatcher->tail) {
-		replay[count++] = dispatcher->cmdqueue[ptr];
-		ptr = CMDQUEUE_NEXT(ptr, ADRENO_DISPATCH_CMDQUEUE_SIZE);
-	}
-
-	/*
-	 * For the purposes of replay, we assume that the oldest command batch
-	 * that hasn't retired a timestamp is "hung".
-	 */
-
-	cmdbatch = replay[0];
-
-	/*
-	 * If FT is disabled for this cmdbatch invalidate immediately
-	 */
-
-	if (test_bit(KGSL_FT_DISABLE, &cmdbatch->fault_policy) ||
-		test_bit(KGSL_FT_TEMP_DISABLE, &cmdbatch->fault_policy)) {
-		pr_fault(device, cmdbatch, "gpu skipped ctx %d ts %d\n",
-			cmdbatch->context->id, cmdbatch->timestamp);
-
-		adreno_drawctxt_invalidate(device, cmdbatch->context);
-	}
-
-	/*
-	 * Set a flag so we don't print another PM dump if the cmdbatch fails
-	 * again on replay
-	 */
-
-	set_bit(KGSL_FT_SKIP_PMDUMP, &cmdbatch->fault_policy);
-
-	/*
-	 * A hardware fault generally means something was deterministically
-	 * wrong with the command batch - no point in trying to replay it
-	 * Clear the replay bit and move on to the next policy level
-	 */
-
-	if (fault == ADRENO_HARD_FAULT)
-		clear_bit(KGSL_FT_REPLAY, &(cmdbatch->fault_policy));
-
-	/*
-	 * A timeout fault means the IB timed out - clear the policy and
-	 * invalidate - this will clear the FT_SKIP_PMDUMP bit but that is okay
-	 * because we won't see this cmdbatch again
-	 */
-
-	if (fault == ADRENO_TIMEOUT_FAULT)
-		bitmap_zero(&cmdbatch->fault_policy, BITS_PER_LONG);
-
-	/*
-	 * If the context had a GPU page fault then it is likely it would fault
-	 * again if replayed
-	 */
-
-	if (test_bit(KGSL_CONTEXT_PAGEFAULT, &cmdbatch->context->priv)) {
-		/* we'll need to resume the mmu later... */
-		pagefault = true;
-		clear_bit(KGSL_FT_REPLAY, &cmdbatch->fault_policy);
-		clear_bit(KGSL_CONTEXT_PAGEFAULT, &cmdbatch->context->priv);
-	}
-
-	/*
-	 * Execute the fault tolerance policy. Each command batch stores the
-	 * current fault policy that was set when it was queued.
-	 * As the options are tried in descending priority
-	 * (REPLAY -> SKIPIBS -> SKIPFRAME -> NOTHING) the bits are cleared
-	 * from the cmdbatch policy so the next thing can be tried if the
-	 * change comes around again
-	 */
-
-	/* Replay the hanging command batch again */
-	if (test_and_clear_bit(KGSL_FT_REPLAY, &cmdbatch->fault_policy)) {
-		trace_adreno_cmdbatch_recovery(cmdbatch, BIT(KGSL_FT_REPLAY));
-		set_bit(KGSL_FT_REPLAY, &cmdbatch->fault_recovery);
-		goto replay;
-	}
-
-	/*
-	 * Skip the last IB1 that was played but replay everything else.
-	 * Note that the last IB1 might not be in the "hung" command batch
-	 * because the CP may have caused a page-fault while it was prefetching
-	 * the next IB1/IB2. walk all outstanding commands and zap the
-	 * supposedly bad IB1 where ever it lurks.
-	 */
-
-	if (test_and_clear_bit(KGSL_FT_SKIPIB, &cmdbatch->fault_policy)) {
-		trace_adreno_cmdbatch_recovery(cmdbatch, BIT(KGSL_FT_SKIPIB));
-		set_bit(KGSL_FT_SKIPIB, &cmdbatch->fault_recovery);
-
-		for (i = 0; i < count; i++) {
-			if (replay[i] != NULL)
-				cmdbatch_skip_ib(replay[i], base);
-		}
-
-		goto replay;
-	}
-
-	if (test_and_clear_bit(KGSL_FT_SKIPFRAME, &cmdbatch->fault_policy)) {
-		trace_adreno_cmdbatch_recovery(cmdbatch,
-			BIT(KGSL_FT_SKIPFRAME));
-		set_bit(KGSL_FT_SKIPFRAME, &cmdbatch->fault_recovery);
-
-		/*
-		 * Skip all the pending command batches for this context until
-		 * the EOF frame is seen
-		 */
-		cmdbatch_skip_frame(cmdbatch, replay, count);
-		goto replay;
-	}
-
-	/* If we get here then all the policies failed */
-
-	pr_fault(device, cmdbatch, "gpu failed ctx %d ts %d\n",
-		cmdbatch->context->id, cmdbatch->timestamp);
-
-	/* Invalidate the context */
-	adreno_drawctxt_invalidate(device, cmdbatch->context);
-
-
-replay:
-	/* Reset the dispatcher queue */
-	dispatcher->inflight = 0;
-	dispatcher->head = dispatcher->tail = 0;
-
-	/* Reset the GPU */
-	mutex_lock(&device->mutex);
-
-	/* resume the MMU if it is stalled */
-	if (pagefault && device->mmu.mmu_ops->mmu_pagefault_resume != NULL)
-		device->mmu.mmu_ops->mmu_pagefault_resume(&device->mmu);
-
-	ret = adreno_reset(device);
-	mutex_unlock(&device->mutex);
-
-	/* If adreno_reset() fails then what hope do we have for the future? */
-	BUG_ON(ret);
-
-	/* Remove any pending command batches that have been invalidated */
-	remove_invalidated_cmdbatches(device, replay, count);
-
-	/* Replay the pending command buffers */
-	for (i = 0; i < count; i++) {
-
-		int ret;
-
-		if (replay[i] == NULL)
-			continue;
-
-		/*
-		 * Force the preamble on the first command (if applicable) to
-		 * avoid any strange stage issues
-		 */
-
-		if (first == 0) {
-			set_bit(CMDBATCH_FLAG_FORCE_PREAMBLE, &replay[i]->priv);
-			first = 1;
-		}
-
-		/*
-		 * Force each command batch to wait for idle - this avoids weird
-		 * CP parse issues
-		 */
-
-		set_bit(CMDBATCH_FLAG_WFI, &replay[i]->priv);
-
-		ret = sendcmd(adreno_dev, replay[i]);
-
-		/*
-		 * If sending the command fails, then try to recover by
-		 * invalidating the context
-		 */
-
-		if (ret) {
-			pr_fault(device, replay[i],
-				"gpu reset failed ctx %d ts %d\n",
-				replay[i]->context->id, replay[i]->timestamp);
-
-			adreno_drawctxt_invalidate(device, replay[i]->context);
-			remove_invalidated_cmdbatches(device, &replay[i],
-				count - i);
-		}
-	}
-
-	mutex_lock(&device->mutex);
-	kgsl_active_count_put(device);
-	mutex_unlock(&device->mutex);
-
-	kfree(replay);
-
-	return 1;
-}
-
-static inline int cmdbatch_consumed(struct kgsl_cmdbatch *cmdbatch,
-		unsigned int consumed, unsigned int retired)
-{
-	return ((timestamp_cmp(cmdbatch->timestamp, consumed) >= 0) &&
-		(timestamp_cmp(retired, cmdbatch->timestamp) < 0));
-}
-
-static void _print_recovery(struct kgsl_device *device,
-		struct kgsl_cmdbatch *cmdbatch)
-{
-	static struct {
-		unsigned int mask;
-		const char *str;
-	} flags[] = { ADRENO_FT_TYPES };
-
-	int i, nr = find_first_bit(&cmdbatch->fault_recovery, BITS_PER_LONG);
-	char *result = "unknown";
-
-	for (i = 0; i < ARRAY_SIZE(flags); i++) {
-		if (flags[i].mask == BIT(nr)) {
-			result = (char *) flags[i].str;
-			break;
-		}
-	}
-
-	pr_fault(device, cmdbatch,
-		"gpu %s ctx %d ts %d policy %lX\n",
-		result, cmdbatch->context->id, cmdbatch->timestamp,
-		cmdbatch->fault_recovery);
-}
-
-/**
- * adreno_dispatcher_work() - Master work handler for the dispatcher
- * @work: Pointer to the work struct for the current work queue
- *
- * Process expired commands and send new ones.
- */
-static void adreno_dispatcher_work(struct work_struct *work)
-{
-	struct adreno_dispatcher *dispatcher =
-		container_of(work, struct adreno_dispatcher, work);
-	struct adreno_device *adreno_dev =
-		container_of(dispatcher, struct adreno_device, dispatcher);
-	struct kgsl_device *device = &adreno_dev->dev;
-	int count = 0;
-
-	mutex_lock(&dispatcher->mutex);
-
-	while (dispatcher->head != dispatcher->tail) {
-		uint32_t consumed, retired = 0;
-		struct kgsl_cmdbatch *cmdbatch =
-			dispatcher->cmdqueue[dispatcher->head];
-		struct adreno_context *drawctxt;
-		BUG_ON(cmdbatch == NULL);
-
-		drawctxt = ADRENO_CONTEXT(cmdbatch->context);
-
-		/*
-		 * First try to expire the timestamp. This happens if the
-		 * context is valid and the timestamp expired normally or if the
-		 * context was destroyed before the command batch was finished
-		 * in the GPU.  Either way retire the command batch advance the
-		 * pointers and continue processing the queue
-		 */
-
-		if (!kgsl_context_detached(cmdbatch->context))
-			retired = kgsl_readtimestamp(device, cmdbatch->context,
-				KGSL_TIMESTAMP_RETIRED);
-
-		if (kgsl_context_detached(cmdbatch->context) ||
-			(timestamp_cmp(cmdbatch->timestamp, retired) <= 0)) {
-
-			/*
-			 * If the cmdbatch in question had faulted announce its
-			 * successful completion to the world
-			 */
-
-			if (cmdbatch->fault_recovery != 0)
-				_print_recovery(device, cmdbatch);
-
-			trace_adreno_cmdbatch_retired(cmdbatch,
-				dispatcher->inflight - 1);
-
-			/* Reduce the number of inflight command batches */
-			dispatcher->inflight--;
-
-			/* Zero the old entry*/
-			dispatcher->cmdqueue[dispatcher->head] = NULL;
-
-			/* Advance the buffer head */
-			dispatcher->head = CMDQUEUE_NEXT(dispatcher->head,
-				ADRENO_DISPATCH_CMDQUEUE_SIZE);
-
-			/* Destroy the retired command batch */
-			kgsl_cmdbatch_destroy(cmdbatch);
-
-			/* Update the expire time for the next command batch */
-
-			if (dispatcher->inflight > 0) {
-				cmdbatch =
-					dispatcher->cmdqueue[dispatcher->head];
-				cmdbatch->expires = jiffies +
-					msecs_to_jiffies(_cmdbatch_timeout);
-			}
-
-			count++;
-			continue;
-		}
-
-		/*
-		 * If we got a fault from the interrupt handler, this command
-		 * is to blame.  Invalidate it, reset and replay
-		 */
-
-		if (dispatcher_do_fault(device))
-			goto done;
-
-		/* Get the last consumed timestamp */
-		consumed = kgsl_readtimestamp(device, cmdbatch->context,
-			KGSL_TIMESTAMP_CONSUMED);
-
-		/*
-		 * Break here if fault detection is disabled for the context or
-		 * if the long running IB detection is disaled device wide
-		 * Long running command buffers will be allowed to run to
-		 * completion - but badly behaving command buffers (infinite
-		 * shaders etc) can end up running forever.
-		 */
-
-		if (!adreno_dev->long_ib_detect ||
-			drawctxt->flags & CTXT_FLAGS_NO_FAULT_TOLERANCE)
-			break;
-
-		/*
-		 * The last line of defense is to check if the command batch has
-		 * timed out. If we get this far but the timeout hasn't expired
-		 * yet then the GPU is still ticking away
-		 */
-
-		if (time_is_after_jiffies(cmdbatch->expires))
-			break;
-
-		/* Boom goes the dynamite */
-
-		pr_fault(device, cmdbatch,
-			"gpu timeout ctx %d ts %d\n",
-			cmdbatch->context->id, cmdbatch->timestamp);
-
-		adreno_set_gpu_fault(adreno_dev, ADRENO_TIMEOUT_FAULT);
-
-		dispatcher_do_fault(device);
-		break;
-	}
-
-	/*
-	 * Decrement the active count to 0 - this will allow the system to go
-	 * into suspend even if there are queued command batches
-	 */
-
-	if (count && dispatcher->inflight == 0) {
-		mutex_lock(&device->mutex);
-		kgsl_active_count_put(device);
-		mutex_unlock(&device->mutex);
-	}
-
-	/* Dispatch new commands if we have the room */
-	if (dispatcher->inflight < _dispatcher_inflight)
-		_adreno_dispatcher_issuecmds(adreno_dev);
-
-done:
-	/* Either update the timer for the next command batch or disable it */
-	if (dispatcher->inflight) {
-		struct kgsl_cmdbatch *cmdbatch
-			= dispatcher->cmdqueue[dispatcher->head];
-
-		/* Update the timeout timer for the next command batch */
-		mod_timer(&dispatcher->timer, cmdbatch->expires);
-	} else {
-		del_timer_sync(&dispatcher->timer);
-		del_timer_sync(&dispatcher->fault_timer);
-	}
-
-	/* Before leaving update the pwrscale information */
-	mutex_lock(&device->mutex);
-	kgsl_pwrscale_idle(device);
-	mutex_unlock(&device->mutex);
-
-	mutex_unlock(&dispatcher->mutex);
-}
-
-void adreno_dispatcher_schedule(struct kgsl_device *device)
-{
-	struct adreno_device *adreno_dev = ADRENO_DEVICE(device);
-	struct adreno_dispatcher *dispatcher = &adreno_dev->dispatcher;
-
-	queue_work(device->work_queue, &dispatcher->work);
-}
-
-/**
- * adreno_dispatcher_queue_context() - schedule a drawctxt in the dispatcher
- * device: pointer to the KGSL device
- * drawctxt: pointer to the drawctxt to schedule
- *
- * Put a draw context on the dispatcher pending queue and schedule the
- * dispatcher. This is used to reschedule changes that might have been blocked
- * for sync points or other concerns
- */
-void adreno_dispatcher_queue_context(struct kgsl_device *device,
-	struct adreno_context *drawctxt)
-{
-	struct adreno_device *adreno_dev = ADRENO_DEVICE(device);
-
-	dispatcher_queue_context(adreno_dev, drawctxt);
-	adreno_dispatcher_schedule(device);
-}
-
-/*
- * This is called on a regular basis while command batches are inflight.  Fault
- * detection registers are read and compared to the existing values - if they
- * changed then the GPU is still running.  If they are the same between
- * subsequent calls then the GPU may have faulted
- */
-
-void adreno_dispatcher_fault_timer(unsigned long data)
-{
-	struct adreno_device *adreno_dev = (struct adreno_device *) data;
-	struct kgsl_device *device = &adreno_dev->dev;
-	struct adreno_dispatcher *dispatcher = &adreno_dev->dispatcher;
-
-	/* Leave if the user decided to turn off fast hang detection */
-	if (adreno_dev->fast_hang_detect == 0)
-		return;
-
-	if (adreno_gpu_fault(adreno_dev)) {
-		adreno_dispatcher_schedule(device);
-		return;
-	}
-
-	/*
-	 * Read the fault registers - if it returns 0 then they haven't changed
-	 * so mark the dispatcher as faulted and schedule the work loop.
-	 */
-
-	if (!fault_detect_read_compare(device)) {
-		adreno_set_gpu_fault(adreno_dev, ADRENO_SOFT_FAULT);
-		adreno_dispatcher_schedule(device);
-	} else {
-		mod_timer(&dispatcher->fault_timer,
-			jiffies + msecs_to_jiffies(_fault_timer_interval));
-	}
-}
-
-/*
- * This is called when the timer expires - it either means the GPU is hung or
- * the IB is taking too long to execute
- */
-void adreno_dispatcher_timer(unsigned long data)
-{
-	struct adreno_device *adreno_dev = (struct adreno_device *) data;
-	struct kgsl_device *device = &adreno_dev->dev;
-
-	adreno_dispatcher_schedule(device);
-}
-/**
- * adreno_dispatcher_irq_fault() - Trigger a fault in the dispatcher
- * @device: Pointer to the KGSL device
- *
- * Called from an interrupt context this will trigger a fault in the
- * dispatcher for the oldest pending command batch
- */
-void adreno_dispatcher_irq_fault(struct kgsl_device *device)
-{
-	adreno_set_gpu_fault(ADRENO_DEVICE(device), ADRENO_HARD_FAULT);
-	adreno_dispatcher_schedule(device);
-}
-
-/**
- * adreno_dispatcher_pause() - stop the dispatcher
- * @adreno_dev: pointer to the adreno device structure
- *
- * Pause the dispather so it doesn't accept any new commands
- */
-void adreno_dispatcher_pause(struct adreno_device *adreno_dev)
-{
-	struct adreno_dispatcher *dispatcher = &adreno_dev->dispatcher;
-
-	/*
-	 * This will probably get called while holding other mutexes so don't
-	 * take the dispatcher mutex.  The biggest penalty is that another
-	 * command might be submitted while we are in here but thats okay
-	 * because whoever is waiting for the drain will just have another
-	 * command batch to wait for
-	 */
-
-	dispatcher->state = ADRENO_DISPATCHER_PAUSE;
-}
-
-/**
- * adreno_dispatcher_start() - activate the dispatcher
- * @adreno_dev: pointer to the adreno device structure
- *
- * Set the disaptcher active and start the loop once to get things going
- */
-void adreno_dispatcher_start(struct adreno_device *adreno_dev)
-{
-	struct adreno_dispatcher *dispatcher = &adreno_dev->dispatcher;
-
-	dispatcher->state = ADRENO_DISPATCHER_ACTIVE;
-
-	/* Schedule the work loop to get things going */
-	adreno_dispatcher_schedule(&adreno_dev->dev);
-}
-
-/**
- * adreno_dispatcher_stop() - stop the dispatcher
- * @adreno_dev: pointer to the adreno device structure
- *
- * Stop the dispatcher and close all the timers
- */
-void adreno_dispatcher_stop(struct adreno_device *adreno_dev)
-{
-	struct adreno_dispatcher *dispatcher = &adreno_dev->dispatcher;
-
-	del_timer_sync(&dispatcher->timer);
-	del_timer_sync(&dispatcher->fault_timer);
-
-	dispatcher->state = ADRENO_DISPATCHER_PAUSE;
-}
-
-/**
- * adreno_dispatcher_close() - close the dispatcher
- * @adreno_dev: pointer to the adreno device structure
- *
- * Close the dispatcher and free all the oustanding commands and memory
- */
-void adreno_dispatcher_close(struct adreno_device *adreno_dev)
-{
-	struct adreno_dispatcher *dispatcher = &adreno_dev->dispatcher;
-
-	mutex_lock(&dispatcher->mutex);
-	del_timer_sync(&dispatcher->timer);
-	del_timer_sync(&dispatcher->fault_timer);
-
-	while (dispatcher->head != dispatcher->tail) {
-		kgsl_cmdbatch_destroy(dispatcher->cmdqueue[dispatcher->head]);
-		dispatcher->head = (dispatcher->head + 1)
-			% ADRENO_DISPATCH_CMDQUEUE_SIZE;
-	}
-
-	mutex_unlock(&dispatcher->mutex);
-
-	kobject_put(&dispatcher->kobj);
-}
-
-struct dispatcher_attribute {
-	struct attribute attr;
-	ssize_t (*show)(struct adreno_dispatcher *,
-			struct dispatcher_attribute *, char *);
-	ssize_t (*store)(struct adreno_dispatcher *,
-			struct dispatcher_attribute *, const char *buf,
-			size_t count);
-	unsigned int max;
-	unsigned int *value;
-};
-
-#define DISPATCHER_UINT_ATTR(_name, _mode, _max, _value) \
-	struct dispatcher_attribute dispatcher_attr_##_name =  { \
-		.attr = { .name = __stringify(_name), .mode = _mode }, \
-		.show = _show_uint, \
-		.store = _store_uint, \
-		.max = _max, \
-		.value = &(_value), \
-	}
-
-#define to_dispatcher_attr(_a) \
-	container_of((_a), struct dispatcher_attribute, attr)
-#define to_dispatcher(k) container_of(k, struct adreno_dispatcher, kobj)
-
-static ssize_t _store_uint(struct adreno_dispatcher *dispatcher,
-		struct dispatcher_attribute *attr,
-		const char *buf, size_t size)
-{
-	unsigned long val;
-	int ret = kstrtoul(buf, 0, &val);
-
-	if (ret)
-		return ret;
-
-	if (!val || (attr->max && (val > attr->max)))
-		return -EINVAL;
-
-	*((unsigned int *) attr->value) = val;
-	return size;
-}
-
-static ssize_t _show_uint(struct adreno_dispatcher *dispatcher,
-		struct dispatcher_attribute *attr,
-		char *buf)
-{
-	return snprintf(buf, PAGE_SIZE, "%d\n",
-		*((unsigned int *) attr->value));
-}
-
-static DISPATCHER_UINT_ATTR(inflight, 0644, ADRENO_DISPATCH_CMDQUEUE_SIZE,
-	_dispatcher_inflight);
-/*
- * Our code that "puts back" a command from the context is much cleaner
- * if we are sure that there will always be enough room in the
- * ringbuffer so restrict the maximum size of the context queue to
- * ADRENO_CONTEXT_CMDQUEUE_SIZE - 1
- */
-static DISPATCHER_UINT_ATTR(context_cmdqueue_size, 0644,
-	ADRENO_CONTEXT_CMDQUEUE_SIZE - 1, _context_cmdqueue_size);
-static DISPATCHER_UINT_ATTR(context_burst_count, 0644, 0,
-	_context_cmdbatch_burst);
-static DISPATCHER_UINT_ATTR(cmdbatch_timeout, 0644, 0, _cmdbatch_timeout);
-static DISPATCHER_UINT_ATTR(context_queue_wait, 0644, 0, _context_queue_wait);
-static DISPATCHER_UINT_ATTR(fault_detect_interval, 0644, 0,
-	_fault_timer_interval);
-
-static struct attribute *dispatcher_attrs[] = {
-	&dispatcher_attr_inflight.attr,
-	&dispatcher_attr_context_cmdqueue_size.attr,
-	&dispatcher_attr_context_burst_count.attr,
-	&dispatcher_attr_cmdbatch_timeout.attr,
-	&dispatcher_attr_context_queue_wait.attr,
-	&dispatcher_attr_fault_detect_interval.attr,
-	NULL,
-};
-
-static ssize_t dispatcher_sysfs_show(struct kobject *kobj,
-				   struct attribute *attr, char *buf)
-{
-	struct adreno_dispatcher *dispatcher = to_dispatcher(kobj);
-	struct dispatcher_attribute *pattr = to_dispatcher_attr(attr);
-	ssize_t ret = -EIO;
-
-	if (pattr->show)
-		ret = pattr->show(dispatcher, pattr, buf);
-
-	return ret;
-}
-
-static ssize_t dispatcher_sysfs_store(struct kobject *kobj,
-				    struct attribute *attr,
-				    const char *buf, size_t count)
-{
-	struct adreno_dispatcher *dispatcher = to_dispatcher(kobj);
-	struct dispatcher_attribute *pattr = to_dispatcher_attr(attr);
-	ssize_t ret = -EIO;
-
-	if (pattr->store)
-		ret = pattr->store(dispatcher, pattr, buf, count);
-
-	return ret;
-}
-
-static void dispatcher_sysfs_release(struct kobject *kobj)
-{
-}
-
-static const struct sysfs_ops dispatcher_sysfs_ops = {
-	.show = dispatcher_sysfs_show,
-	.store = dispatcher_sysfs_store
-};
-
-static struct kobj_type ktype_dispatcher = {
-	.sysfs_ops = &dispatcher_sysfs_ops,
-	.default_attrs = dispatcher_attrs,
-	.release = dispatcher_sysfs_release
-};
-
-/**
- * adreno_dispatcher_init() - Initialize the dispatcher
- * @adreno_dev: pointer to the adreno device structure
- *
- * Initialize the dispatcher
- */
-int adreno_dispatcher_init(struct adreno_device *adreno_dev)
-{
-	struct kgsl_device *device = &adreno_dev->dev;
-	struct adreno_dispatcher *dispatcher = &adreno_dev->dispatcher;
-	int ret;
-
-	memset(dispatcher, 0, sizeof(*dispatcher));
-
-	mutex_init(&dispatcher->mutex);
-
-	setup_timer(&dispatcher->timer, adreno_dispatcher_timer,
-		(unsigned long) adreno_dev);
-
-	setup_timer(&dispatcher->fault_timer, adreno_dispatcher_fault_timer,
-		(unsigned long) adreno_dev);
-
-	INIT_WORK(&dispatcher->work, adreno_dispatcher_work);
-
-	plist_head_init(&dispatcher->pending);
-	spin_lock_init(&dispatcher->plist_lock);
-
-	dispatcher->state = ADRENO_DISPATCHER_ACTIVE;
-
-	ret = kobject_init_and_add(&dispatcher->kobj, &ktype_dispatcher,
-		&device->dev->kobj, "dispatch");
-
-	return ret;
-}
diff --git a/drivers/gpu/msm/adreno_drawctxt.c b/drivers/gpu/msm/adreno_drawctxt.c
index 907d41f..0af4c12e 100644
--- a/drivers/gpu/msm/adreno_drawctxt.c
+++ b/drivers/gpu/msm/adreno_drawctxt.c
@@ -13,12 +13,10 @@
 
 #include <linux/slab.h>
 #include <linux/msm_kgsl.h>
-#include <linux/sched.h>
 
 #include "kgsl.h"
 #include "kgsl_sharedmem.h"
 #include "adreno.h"
-#include "adreno_trace.h"
 
 #define KGSL_INIT_REFTIMESTAMP		0x7FFFFFFF
 
@@ -134,247 +132,6 @@
 	*incmd = cmd;
 }
 
-static void wait_callback(struct kgsl_device *device, void *priv, u32 id,
-		u32 timestamp, u32 type)
-{
-	struct adreno_context *drawctxt = priv;
-	wake_up_interruptible_all(&drawctxt->waiting);
-}
-
-#define adreno_wait_event_interruptible_timeout(wq, condition, timeout, io)   \
-({                                                                            \
-	long __ret = timeout;                                                 \
-	if (io)                                                               \
-		__wait_io_event_interruptible_timeout(wq, condition, __ret);  \
-	else                                                                  \
-		__wait_event_interruptible_timeout(wq, condition, __ret);     \
-	__ret;                                                                \
-})
-
-#define adreno_wait_event_interruptible(wq, condition, io)                    \
-({                                                                            \
-	long __ret;                                                           \
-	if (io)                                                               \
-		__wait_io_event_interruptible(wq, condition, __ret);          \
-	else                                                                  \
-		__wait_event_interruptible(wq, condition, __ret);             \
-	__ret;                                                                \
-})
-
-static int _check_context_timestamp(struct kgsl_device *device,
-		struct adreno_context *drawctxt, unsigned int timestamp)
-{
-	int ret = 0;
-
-	/* Bail if the drawctxt has been invalidated or destroyed */
-	if (kgsl_context_detached(&drawctxt->base) ||
-		drawctxt->state != ADRENO_CONTEXT_STATE_ACTIVE)
-		return 1;
-
-	mutex_lock(&device->mutex);
-	ret = kgsl_check_timestamp(device, &drawctxt->base, timestamp);
-	mutex_unlock(&device->mutex);
-
-	return ret;
-}
-
-/**
- * adreno_drawctxt_wait() - sleep until a timestamp expires
- * @adreno_dev: pointer to the adreno_device struct
- * @drawctxt: Pointer to the draw context to sleep for
- * @timetamp: Timestamp to wait on
- * @timeout: Number of jiffies to wait (0 for infinite)
- *
- * Register an event to wait for a timestamp on a context and sleep until it
- * has past.  Returns < 0 on error, -ETIMEDOUT if the timeout expires or 0
- * on success
- */
-int adreno_drawctxt_wait(struct adreno_device *adreno_dev,
-		struct kgsl_context *context,
-		uint32_t timestamp, unsigned int timeout)
-{
-	static unsigned int io_cnt;
-	struct kgsl_device *device = &adreno_dev->dev;
-	struct kgsl_pwrctrl *pwr = &device->pwrctrl;
-	struct adreno_context *drawctxt = ADRENO_CONTEXT(context);
-	int ret, io;
-
-	if (kgsl_context_detached(context))
-		return -EINVAL;
-
-	if (drawctxt->state == ADRENO_CONTEXT_STATE_INVALID)
-		return -EDEADLK;
-
-	/* Needs to hold the device mutex */
-	BUG_ON(!mutex_is_locked(&device->mutex));
-
-	trace_adreno_drawctxt_wait_start(context->id, timestamp);
-
-	ret = kgsl_add_event(device, context->id, timestamp,
-		wait_callback, drawctxt, NULL);
-	if (ret)
-		goto done;
-
-	/*
-	 * For proper power accounting sometimes we need to call
-	 * io_wait_interruptible_timeout and sometimes we need to call
-	 * plain old wait_interruptible_timeout. We call the regular
-	 * timeout N times out of 100, where N is a number specified by
-	 * the current power level
-	 */
-
-	io_cnt = (io_cnt + 1) % 100;
-	io = (io_cnt < pwr->pwrlevels[pwr->active_pwrlevel].io_fraction)
-		? 0 : 1;
-
-	mutex_unlock(&device->mutex);
-
-	if (timeout) {
-		ret = (int) adreno_wait_event_interruptible_timeout(
-			drawctxt->waiting,
-			_check_context_timestamp(device, drawctxt, timestamp),
-			msecs_to_jiffies(timeout), io);
-
-		if (ret == 0)
-			ret = -ETIMEDOUT;
-		else if (ret > 0)
-			ret = 0;
-	} else {
-		ret = (int) adreno_wait_event_interruptible(drawctxt->waiting,
-			_check_context_timestamp(device, drawctxt, timestamp),
-				io);
-	}
-
-	mutex_lock(&device->mutex);
-
-	/* -EDEADLK if the context was invalidated while we were waiting */
-	if (drawctxt->state == ADRENO_CONTEXT_STATE_INVALID)
-		ret = -EDEADLK;
-
-
-	/* Return -EINVAL if the context was detached while we were waiting */
-	if (kgsl_context_detached(context))
-		ret = -EINVAL;
-
-done:
-	trace_adreno_drawctxt_wait_done(context->id, timestamp, ret);
-	return ret;
-}
-
-static void global_wait_callback(struct kgsl_device *device, void *priv, u32 id,
-		u32 timestamp, u32 type)
-{
-	struct adreno_context *drawctxt = priv;
-
-	wake_up_interruptible_all(&drawctxt->waiting);
-	kgsl_context_put(&drawctxt->base);
-}
-
-static int _check_global_timestamp(struct kgsl_device *device,
-		unsigned int timestamp)
-{
-	int ret;
-
-	mutex_lock(&device->mutex);
-	ret = kgsl_check_timestamp(device, NULL, timestamp);
-	mutex_unlock(&device->mutex);
-
-	return ret;
-}
-
-int adreno_drawctxt_wait_global(struct adreno_device *adreno_dev,
-		struct kgsl_context *context,
-		uint32_t timestamp, unsigned int timeout)
-{
-	struct kgsl_device *device = &adreno_dev->dev;
-	struct adreno_context *drawctxt = ADRENO_CONTEXT(context);
-	int ret;
-
-	/* Needs to hold the device mutex */
-	BUG_ON(!mutex_is_locked(&device->mutex));
-
-	_kgsl_context_get(context);
-
-	trace_adreno_drawctxt_wait_start(KGSL_MEMSTORE_GLOBAL, timestamp);
-
-	ret = kgsl_add_event(device, KGSL_MEMSTORE_GLOBAL, timestamp,
-		global_wait_callback, drawctxt, NULL);
-	if (ret) {
-		kgsl_context_put(context);
-		goto done;
-	}
-
-	mutex_unlock(&device->mutex);
-
-	if (timeout) {
-		ret = (int) wait_event_interruptible_timeout(drawctxt->waiting,
-			_check_global_timestamp(device, timestamp),
-			msecs_to_jiffies(timeout));
-
-		if (ret == 0)
-			ret = -ETIMEDOUT;
-		else if (ret > 0)
-			ret = 0;
-	} else {
-		ret = (int) wait_event_interruptible(drawctxt->waiting,
-			_check_global_timestamp(device, timestamp));
-	}
-
-	mutex_lock(&device->mutex);
-
-	if (ret)
-		kgsl_cancel_events_timestamp(device, NULL, timestamp);
-
-done:
-	trace_adreno_drawctxt_wait_done(KGSL_MEMSTORE_GLOBAL, timestamp, ret);
-	return ret;
-}
-
-/**
- * adreno_drawctxt_invalidate() - Invalidate an adreno draw context
- * @device: Pointer to the KGSL device structure for the GPU
- * @context: Pointer to the KGSL context structure
- *
- * Invalidate the context and remove all queued commands and cancel any pending
- * waiters
- */
-void adreno_drawctxt_invalidate(struct kgsl_device *device,
-		struct kgsl_context *context)
-{
-	struct adreno_context *drawctxt = ADRENO_CONTEXT(context);
-
-	trace_adreno_drawctxt_invalidate(drawctxt);
-
-	drawctxt->state = ADRENO_CONTEXT_STATE_INVALID;
-
-	/* Clear the pending queue */
-	mutex_lock(&drawctxt->mutex);
-
-	while (drawctxt->cmdqueue_head != drawctxt->cmdqueue_tail) {
-		struct kgsl_cmdbatch *cmdbatch =
-			drawctxt->cmdqueue[drawctxt->cmdqueue_head];
-
-		drawctxt->cmdqueue_head = (drawctxt->cmdqueue_head + 1) %
-			ADRENO_CONTEXT_CMDQUEUE_SIZE;
-
-		mutex_unlock(&drawctxt->mutex);
-
-		mutex_lock(&device->mutex);
-		kgsl_cancel_events_timestamp(device, context,
-			cmdbatch->timestamp);
-		mutex_unlock(&device->mutex);
-
-		kgsl_cmdbatch_destroy(cmdbatch);
-		mutex_lock(&drawctxt->mutex);
-	}
-
-	mutex_unlock(&drawctxt->mutex);
-
-	/* Give the bad news to everybody waiting around */
-	wake_up_interruptible_all(&drawctxt->waiting);
-	wake_up_interruptible_all(&drawctxt->wq);
-}
-
 /**
  * adreno_drawctxt_create - create a new adreno draw context
  * @dev_priv: the owner of the context
@@ -392,7 +149,6 @@
 	int ret;
 
 	drawctxt = kzalloc(sizeof(struct adreno_context), GFP_KERNEL);
-
 	if (drawctxt == NULL)
 		return ERR_PTR(-ENOMEM);
 
@@ -412,30 +168,22 @@
 		KGSL_CONTEXT_NO_FAULT_TOLERANCE |
 		KGSL_CONTEXT_TYPE_MASK);
 
-	/* Always enable per-context timestamps */
-	*flags |= KGSL_CONTEXT_PER_CONTEXT_TS;
-	drawctxt->flags |= CTXT_FLAGS_PER_CONTEXT_TS;
-
 	if (*flags & KGSL_CONTEXT_PREAMBLE)
 		drawctxt->flags |= CTXT_FLAGS_PREAMBLE;
 
 	if (*flags & KGSL_CONTEXT_NO_GMEM_ALLOC)
 		drawctxt->flags |= CTXT_FLAGS_NOGMEMALLOC;
 
-	if (*flags & KGSL_CONTEXT_USER_GENERATED_TS)
+	if (*flags & KGSL_CONTEXT_PER_CONTEXT_TS)
+		drawctxt->flags |= CTXT_FLAGS_PER_CONTEXT_TS;
+
+	if (*flags & KGSL_CONTEXT_USER_GENERATED_TS) {
+		if (!(*flags & KGSL_CONTEXT_PER_CONTEXT_TS)) {
+			ret = -EINVAL;
+			goto err;
+		}
 		drawctxt->flags |= CTXT_FLAGS_USER_GENERATED_TS;
-
-	mutex_init(&drawctxt->mutex);
-	init_waitqueue_head(&drawctxt->wq);
-	init_waitqueue_head(&drawctxt->waiting);
-
-	/*
-	 * Set up the plist node for the dispatcher.  For now all contexts have
-	 * the same priority, but later the priority will be set at create time
-	 * by the user
-	 */
-
-	plist_node_init(&drawctxt->pending, ADRENO_CONTEXT_DEFAULT_PRIORITY);
+	}
 
 	if (*flags & KGSL_CONTEXT_NO_FAULT_TOLERANCE)
 		drawctxt->flags |= CTXT_FLAGS_NO_FAULT_TOLERANCE;
@@ -448,6 +196,12 @@
 		goto err;
 
 	kgsl_sharedmem_writel(device, &device->memstore,
+			KGSL_MEMSTORE_OFFSET(drawctxt->base.id, ref_wait_ts),
+			KGSL_INIT_REFTIMESTAMP);
+	kgsl_sharedmem_writel(device, &device->memstore,
+			KGSL_MEMSTORE_OFFSET(drawctxt->base.id, ts_cmp_enable),
+			0);
+	kgsl_sharedmem_writel(device, &device->memstore,
 			KGSL_MEMSTORE_OFFSET(drawctxt->base.id, soptimestamp),
 			0);
 	kgsl_sharedmem_writel(device, &device->memstore,
@@ -461,39 +215,22 @@
 }
 
 /**
- * adreno_drawctxt_sched() - Schedule a previously blocked context
- * @device: pointer to a KGSL device
- * @drawctxt: drawctxt to rechedule
- *
- * This function is called by the core when it knows that a previously blocked
- * context has been unblocked.  The default adreno response is to reschedule the
- * context on the dispatcher
- */
-void adreno_drawctxt_sched(struct kgsl_device *device,
-		struct kgsl_context *context)
-{
-	adreno_dispatcher_queue_context(device, ADRENO_CONTEXT(context));
-}
-
-/**
  * adreno_drawctxt_detach(): detach a context from the GPU
  * @context: Generic KGSL context container for the context
  *
  */
-int adreno_drawctxt_detach(struct kgsl_context *context)
+void adreno_drawctxt_detach(struct kgsl_context *context)
 {
 	struct kgsl_device *device;
 	struct adreno_device *adreno_dev;
 	struct adreno_context *drawctxt;
-	int ret;
 
 	if (context == NULL)
-		return 0;
+		return;
 
 	device = context->device;
 	adreno_dev = ADRENO_DEVICE(device);
 	drawctxt = ADRENO_CONTEXT(context);
-
 	/* deactivate context */
 	if (adreno_dev->drawctxt_active == drawctxt) {
 		/* no need to save GMEM or shader, the context is
@@ -509,39 +246,13 @@
 		adreno_drawctxt_switch(adreno_dev, NULL, 0);
 	}
 
-	mutex_lock(&drawctxt->mutex);
-
-	while (drawctxt->cmdqueue_head != drawctxt->cmdqueue_tail) {
-		struct kgsl_cmdbatch *cmdbatch =
-			drawctxt->cmdqueue[drawctxt->cmdqueue_head];
-
-		drawctxt->cmdqueue_head = (drawctxt->cmdqueue_head + 1) %
-			ADRENO_CONTEXT_CMDQUEUE_SIZE;
-
-		mutex_unlock(&drawctxt->mutex);
-
-		/*
-		 * Don't hold the drawctxt mutex while the cmdbatch is being
-		 * destroyed because the cmdbatch destroy takes the device
-		 * mutex and the world falls in on itself
-		 */
-
-		kgsl_cmdbatch_destroy(cmdbatch);
-		mutex_lock(&drawctxt->mutex);
-	}
-
-	mutex_unlock(&drawctxt->mutex);
-
-	/* Wait for the last global timestamp to pass before continuing */
-	ret = adreno_drawctxt_wait_global(adreno_dev, context,
-		drawctxt->internal_timestamp, 10 * 1000);
+	if (device->state != KGSL_STATE_HUNG)
+		adreno_idle(device);
 
 	adreno_profile_process_results(device);
 
 	kgsl_sharedmem_free(&drawctxt->gpustate);
 	kgsl_sharedmem_free(&drawctxt->context_gmem_shadow.gmemshadow);
-
-	return ret;
 }
 
 
@@ -585,12 +296,11 @@
  * Switch the current draw context
  */
 
-int adreno_drawctxt_switch(struct adreno_device *adreno_dev,
+void adreno_drawctxt_switch(struct adreno_device *adreno_dev,
 				struct adreno_context *drawctxt,
 				unsigned int flags)
 {
 	struct kgsl_device *device = &adreno_dev->dev;
-	int ret = 0;
 
 	if (drawctxt) {
 		if (flags & KGSL_CONTEXT_SAVE_GMEM)
@@ -606,24 +316,18 @@
 	if (adreno_dev->drawctxt_active == drawctxt) {
 		if (adreno_dev->gpudev->ctxt_draw_workaround &&
 			adreno_is_a225(adreno_dev))
-				ret = adreno_dev->gpudev->ctxt_draw_workaround(
+				adreno_dev->gpudev->ctxt_draw_workaround(
 					adreno_dev, drawctxt);
-		return ret;
+		return;
 	}
 
-	trace_adreno_drawctxt_switch(adreno_dev->drawctxt_active,
-		drawctxt, flags);
+	KGSL_CTXT_INFO(device, "from %d to %d flags %d\n",
+		adreno_dev->drawctxt_active ?
+		adreno_dev->drawctxt_active->base.id : 0,
+		drawctxt ? drawctxt->base.id : 0, flags);
 
 	/* Save the old context */
-	ret = adreno_dev->gpudev->ctxt_save(adreno_dev,
-		adreno_dev->drawctxt_active);
-
-	if (ret) {
-		KGSL_DRV_ERR(device,
-			"Error in GPU context %d save: %d\n",
-			adreno_dev->drawctxt_active->base.id, ret);
-		return ret;
-	}
+	adreno_dev->gpudev->ctxt_save(adreno_dev, adreno_dev->drawctxt_active);
 
 	/* Put the old instance of the active drawctxt */
 	if (adreno_dev->drawctxt_active) {
@@ -636,14 +340,6 @@
 		_kgsl_context_get(&drawctxt->base);
 
 	/* Set the new context */
-	ret = adreno_dev->gpudev->ctxt_restore(adreno_dev, drawctxt);
-	if (ret) {
-		KGSL_DRV_ERR(device,
-			"Error in GPU context %d restore: %d\n",
-			drawctxt->base.id, ret);
-		return ret;
-	}
-
+	adreno_dev->gpudev->ctxt_restore(adreno_dev, drawctxt);
 	adreno_dev->drawctxt_active = drawctxt;
-	return 0;
 }
diff --git a/drivers/gpu/msm/adreno_drawctxt.h b/drivers/gpu/msm/adreno_drawctxt.h
index 5c12676..3088099 100644
--- a/drivers/gpu/msm/adreno_drawctxt.h
+++ b/drivers/gpu/msm/adreno_drawctxt.h
@@ -54,8 +54,6 @@
 #define CTXT_FLAGS_SKIP_EOF             BIT(15)
 /* Context no fault tolerance */
 #define CTXT_FLAGS_NO_FAULT_TOLERANCE  BIT(16)
-/* Force the preamble for the next submission */
-#define CTXT_FLAGS_FORCE_PREAMBLE      BIT(17)
 
 /* Symbolic table for the adreno draw context type */
 #define ADRENO_DRAWCTXT_TYPES \
@@ -71,13 +69,6 @@
 	const char *str;
 };
 
-#define ADRENO_CONTEXT_CMDQUEUE_SIZE 128
-
-#define ADRENO_CONTEXT_DEFAULT_PRIORITY 1
-
-#define ADRENO_CONTEXT_STATE_ACTIVE 0
-#define ADRENO_CONTEXT_STATE_INVALID 1
-
 struct kgsl_device;
 struct adreno_device;
 struct kgsl_device_private;
@@ -108,58 +99,18 @@
 	struct kgsl_memdesc quad_vertices_restore;
 };
 
-/**
- * struct adreno_context - Adreno GPU draw context
- * @id: Unique integer ID of the context
- * @timestamp: Last issued context-specific timestamp
- * @internal_timestamp: Global timestamp of the last issued command
- * @state: Current state of the context
- * @flags: Bitfield controlling behavior of the context
- * @type: Context type (GL, CL, RS)
- * @mutex: Mutex to protect the cmdqueue
- * @pagetable: Pointer to the GPU pagetable for the context
- * @gpustate: Pointer to the GPU scratch memory for context save/restore
- * @reg_restore: Command buffer for restoring context registers
- * @shader_save: Command buffer for saving shaders
- * @shader_restore: Command buffer to restore shaders
- * @context_gmem_shadow: GMEM shadow structure for save/restore
- * @reg_save: A2XX command buffer to save context registers
- * @shader_fixup: A2XX command buffer to "fix" shaders on restore
- * @chicken_restore: A2XX command buffer to "fix" register restore
- * @bin_base_offset: Saved value of the A2XX BIN_BASE_OFFSET register
- * @regconstant_save: A3XX command buffer to save some registers
- * @constant_retore: A3XX command buffer to restore some registers
- * @hslqcontrol_restore: A3XX command buffer to restore HSLSQ registers
- * @save_fixup: A3XX command buffer to "fix" register save
- * @restore_fixup: A3XX cmmand buffer to restore register save fixes
- * @shader_load_commands: A3XX GPU memory descriptor for shader load IB
- * @shader_save_commands: A3XX GPU memory descriptor for shader save IB
- * @constantr_save_commands: A3XX GPU memory descriptor for constant save IB
- * @constant_load_commands: A3XX GPU memory descriptor for constant load IB
- * @cond_execs: A3XX GPU memory descriptor for conditional exec IB
- * @hlsq_restore_commands: A3XX GPU memory descriptor for HLSQ restore IB
- * @cmdqueue: Queue of command batches waiting to be dispatched for this context
- * @cmdqueue_head: Head of the cmdqueue queue
- * @cmdqueue_tail: Tail of the cmdqueue queue
- * @pending: Priority list node for the dispatcher list of pending contexts
- * @wq: Workqueue structure for contexts to sleep pending room in the queue
- * @waiting: Workqueue structure for contexts waiting for a timestamp or event
- * @queued: Number of commands queued in the cmdqueue
- */
 struct adreno_context {
 	struct kgsl_context base;
 	unsigned int ib_gpu_time_used;
 	unsigned int timestamp;
-	unsigned int internal_timestamp;
-	int state;
 	uint32_t flags;
 	unsigned int type;
-	struct mutex mutex;
 	struct kgsl_memdesc gpustate;
 	unsigned int reg_restore[3];
 	unsigned int shader_save[3];
 	unsigned int shader_restore[3];
 
+	/* Information of the GMEM shadow that is created in context create */
 	struct gmem_shadow_t context_gmem_shadow;
 
 	/* A2XX specific items */
@@ -180,44 +131,23 @@
 	struct kgsl_memdesc constant_load_commands[3];
 	struct kgsl_memdesc cond_execs[4];
 	struct kgsl_memdesc hlsqcontrol_restore_commands[1];
-
-	/* Dispatcher */
-	struct kgsl_cmdbatch *cmdqueue[ADRENO_CONTEXT_CMDQUEUE_SIZE];
-	int cmdqueue_head;
-	int cmdqueue_tail;
-
-	struct plist_node pending;
-	wait_queue_head_t wq;
-	wait_queue_head_t waiting;
-
-	int queued;
 };
 
 
 struct kgsl_context *adreno_drawctxt_create(struct kgsl_device_private *,
 			uint32_t *flags);
 
-int adreno_drawctxt_detach(struct kgsl_context *context);
+void adreno_drawctxt_detach(struct kgsl_context *context);
 
 void adreno_drawctxt_destroy(struct kgsl_context *context);
 
-void adreno_drawctxt_sched(struct kgsl_device *device,
-		struct kgsl_context *context);
-
-int adreno_drawctxt_switch(struct adreno_device *adreno_dev,
+void adreno_drawctxt_switch(struct adreno_device *adreno_dev,
 				struct adreno_context *drawctxt,
 				unsigned int flags);
 void adreno_drawctxt_set_bin_base_offset(struct kgsl_device *device,
 					struct kgsl_context *context,
 					unsigned int offset);
 
-int adreno_drawctxt_wait(struct adreno_device *adreno_dev,
-		struct kgsl_context *context,
-		uint32_t timestamp, unsigned int timeout);
-
-void adreno_drawctxt_invalidate(struct kgsl_device *device,
-		struct kgsl_context *context);
-
 /* GPU context switch helper functions */
 
 void build_quad_vtxbuff(struct adreno_context *drawctxt,
diff --git a/drivers/gpu/msm/adreno_pm4types.h b/drivers/gpu/msm/adreno_pm4types.h
index f449870..d1e2b43 100644
--- a/drivers/gpu/msm/adreno_pm4types.h
+++ b/drivers/gpu/msm/adreno_pm4types.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2002,2007-2012, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2002,2007-2013, The Linux Foundation. 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 and
@@ -177,6 +177,8 @@
 /* Load a buffer with pre-fetch enabled */
 #define CP_INDIRECT_BUFFER_PFE 0x3F
 
+#define CP_EXEC_CL 0x31
+
 #define CP_LOADSTATE_DSTOFFSET_SHIFT 0x00000000
 #define CP_LOADSTATE_STATESRC_SHIFT 0x00000010
 #define CP_LOADSTATE_STATEBLOCKID_SHIFT 0x00000013
diff --git a/drivers/gpu/msm/adreno_postmortem.c b/drivers/gpu/msm/adreno_postmortem.c
index 8fb2830..32dbd51 100644
--- a/drivers/gpu/msm/adreno_postmortem.c
+++ b/drivers/gpu/msm/adreno_postmortem.c
@@ -22,7 +22,6 @@
 #include "adreno_ringbuffer.h"
 #include "kgsl_cffdump.h"
 #include "kgsl_pwrctrl.h"
-#include "adreno_trace.h"
 
 #include "a2xx_reg.h"
 #include "a3xx_reg.h"
@@ -396,8 +395,8 @@
 
 int adreno_dump(struct kgsl_device *device, int manual)
 {
-	unsigned int cp_ib1_base;
-	unsigned int cp_ib2_base;
+	unsigned int cp_ib1_base, cp_ib1_bufsz;
+	unsigned int cp_ib2_base, cp_ib2_bufsz;
 	phys_addr_t pt_base, cur_pt_base;
 	unsigned int cp_rb_base, cp_rb_ctrl, rb_count;
 	unsigned int cp_rb_wptr, cp_rb_rptr;
@@ -410,6 +409,7 @@
 	unsigned int ts_processed = 0xdeaddead;
 	struct kgsl_context *context;
 	unsigned int context_id;
+	unsigned int rbbm_status;
 
 	static struct ib_list ib_list;
 
@@ -419,10 +419,16 @@
 
 	mb();
 
-	msm_clk_dump_debug_info();
+	if (device->pm_dump_enable) {
+		msm_clk_dump_debug_info();
 
-	if (adreno_dev->gpudev->postmortem_dump)
-		adreno_dev->gpudev->postmortem_dump(adreno_dev);
+		if (adreno_dev->gpudev->postmortem_dump)
+			adreno_dev->gpudev->postmortem_dump(adreno_dev);
+	}
+
+	kgsl_regread(device,
+			adreno_getreg(adreno_dev, ADRENO_REG_RBBM_STATUS),
+			&rbbm_status);
 
 	pt_base = kgsl_mmu_get_current_ptbase(&device->mmu);
 	cur_pt_base = pt_base;
@@ -444,8 +450,26 @@
 		adreno_getreg(adreno_dev, ADRENO_REG_CP_IB1_BASE),
 		&cp_ib1_base);
 	kgsl_regread(device,
+		adreno_getreg(adreno_dev, ADRENO_REG_CP_IB1_BUFSZ),
+		&cp_ib1_bufsz);
+	kgsl_regread(device,
 		adreno_getreg(adreno_dev, ADRENO_REG_CP_IB2_BASE),
 		&cp_ib2_base);
+	kgsl_regread(device,
+		adreno_getreg(adreno_dev, ADRENO_REG_CP_IB2_BUFSZ),
+		&cp_ib2_bufsz);
+
+	/* If postmortem dump is not enabled, dump minimal set and return */
+	if (!device->pm_dump_enable) {
+
+		KGSL_LOG_DUMP(device,
+			"STATUS %08X | IB1:%08X/%08X | IB2: %08X/%08X"
+			" | RPTR: %04X | WPTR: %04X\n",
+			rbbm_status,  cp_ib1_base, cp_ib1_bufsz, cp_ib2_base,
+			cp_ib2_bufsz, cp_rb_rptr, cp_rb_wptr);
+
+		return 0;
+	}
 
 	kgsl_sharedmem_readl(&device->memstore,
 			(unsigned int *) &context_id,
@@ -620,9 +644,5 @@
 error_vfree:
 	vfree(rb_copy);
 end:
-	/* Restart the dispatcher after a manually triggered dump */
-	if (manual)
-		adreno_dispatcher_start(adreno_dev);
-
 	return result;
 }
diff --git a/drivers/gpu/msm/adreno_ringbuffer.c b/drivers/gpu/msm/adreno_ringbuffer.c
index 1ad90fd..ceff923 100644
--- a/drivers/gpu/msm/adreno_ringbuffer.c
+++ b/drivers/gpu/msm/adreno_ringbuffer.c
@@ -67,8 +67,11 @@
 	unsigned long wait_time;
 	unsigned long wait_timeout = msecs_to_jiffies(ADRENO_IDLE_TIMEOUT);
 	unsigned long wait_time_part;
+	unsigned int prev_reg_val[FT_DETECT_REGS_COUNT];
 	unsigned int rptr;
 
+	memset(prev_reg_val, 0, sizeof(prev_reg_val));
+
 	/* if wptr ahead, fill the remaining with NOPs */
 	if (wptr_ahead) {
 		/* -1 for header */
@@ -102,13 +105,43 @@
 		if (freecmds == 0 || freecmds > numcmds)
 			break;
 
+		/* Dont wait for timeout, detect hang faster.
+		 */
+		if (time_after(jiffies, wait_time_part)) {
+			wait_time_part = jiffies +
+				msecs_to_jiffies(KGSL_TIMEOUT_PART);
+			if ((adreno_ft_detect(rb->device,
+						prev_reg_val))){
+				KGSL_DRV_ERR(rb->device,
+				"Hang detected while waiting for freespace in"
+				"ringbuffer rptr: 0x%x, wptr: 0x%x\n",
+				rptr, rb->wptr);
+				goto err;
+			}
+		}
+
 		if (time_after(jiffies, wait_time)) {
 			KGSL_DRV_ERR(rb->device,
 			"Timed out while waiting for freespace in ringbuffer "
 			"rptr: 0x%x, wptr: 0x%x\n", rptr, rb->wptr);
-			return -ETIMEDOUT;
+			goto err;
 		}
 
+		continue;
+
+err:
+		if (!adreno_dump_and_exec_ft(rb->device)) {
+			if (context && context->flags & CTXT_FLAGS_GPU_HANG) {
+				KGSL_CTXT_WARN(rb->device,
+				"Context %p caused a gpu hang. Will not accept commands for context %d\n",
+				context, context->base.id);
+				return -EDEADLK;
+			}
+			wait_time = jiffies + wait_timeout;
+		} else {
+			/* GPU is hung and fault tolerance failed */
+			BUG();
+		}
 	}
 	return 0;
 }
@@ -147,8 +180,7 @@
 	if (!ret) {
 		ptr = (unsigned int *)rb->buffer_desc.hostptr + rb->wptr;
 		rb->wptr += numcmds;
-	} else
-		ptr = ERR_PTR(ret);
+	}
 
 	return ptr;
 }
@@ -315,6 +347,7 @@
 int _ringbuffer_start_common(struct adreno_ringbuffer *rb)
 {
 	int status;
+	/*cp_rb_cntl_u cp_rb_cntl; */
 	union reg_cp_rb_cntl cp_rb_cntl;
 	unsigned int rb_cntl;
 	struct kgsl_device *device = rb->device;
@@ -535,17 +568,18 @@
 
 static int
 adreno_ringbuffer_addcmds(struct adreno_ringbuffer *rb,
-				struct adreno_context *drawctxt,
+				struct adreno_context *context,
 				unsigned int flags, unsigned int *cmds,
-				int sizedwords, uint32_t timestamp)
+				int sizedwords)
 {
 	struct adreno_device *adreno_dev = ADRENO_DEVICE(rb->device);
 	unsigned int *ringcmds;
 	unsigned int total_sizedwords = sizedwords;
 	unsigned int i;
 	unsigned int rcmd_gpu;
-	unsigned int context_id;
+	unsigned int context_id = KGSL_MEMSTORE_GLOBAL;
 	unsigned int gpuaddr = rb->device->memstore.gpuaddr;
+	unsigned int timestamp;
 	bool profile_ready;
 
 	/*
@@ -556,23 +590,19 @@
 	 * the _addcmds call since it is allocating additional ringbuffer
 	 * command space.
 	 */
-	profile_ready = !adreno_is_a2xx(adreno_dev) &&
+	profile_ready = !adreno_is_a2xx(adreno_dev) && context &&
 		adreno_profile_assignments_ready(&adreno_dev->profile) &&
 		!(flags & KGSL_CMD_FLAGS_INTERNAL_ISSUE);
 
-	/* The global timestamp always needs to be incremented */
-	rb->global_ts++;
-
-	/* If this is a internal IB, use the global timestamp for it */
-	if (!drawctxt || (flags & KGSL_CMD_FLAGS_INTERNAL_ISSUE)) {
-		timestamp = rb->global_ts;
-		context_id = KGSL_MEMSTORE_GLOBAL;
-	} else {
-		context_id = drawctxt->base.id;
-	}
-
-	if (drawctxt)
-		drawctxt->internal_timestamp = rb->global_ts;
+	/*
+	 * if the context was not created with per context timestamp
+	 * support, we must use the global timestamp since issueibcmds
+	 * will be returning that one, or if an internal issue then
+	 * use global timestamp.
+	 */
+	if ((context && (context->flags & CTXT_FLAGS_PER_CONTEXT_TS)) &&
+		!(flags & KGSL_CMD_FLAGS_INTERNAL_ISSUE))
+		context_id = context->base.id;
 
 	/* reserve space to temporarily turn off protected mode
 	*  error checking if needed
@@ -583,8 +613,13 @@
 	/* internal ib command identifier for the ringbuffer */
 	total_sizedwords += (flags & KGSL_CMD_FLAGS_INTERNAL_ISSUE) ? 2 : 0;
 
-	/* Add two dwords for the CP_INTERRUPT */
-	total_sizedwords += drawctxt ? 2 : 0;
+	/* Add CP_COND_EXEC commands to generate CP_INTERRUPT */
+	total_sizedwords += context ? 13 : 0;
+
+	if ((context) && (context->flags & CTXT_FLAGS_PER_CONTEXT_TS) &&
+		(flags & (KGSL_CMD_FLAGS_INTERNAL_ISSUE |
+		KGSL_CMD_FLAGS_GET_INT)))
+			total_sizedwords += 2;
 
 	if (adreno_is_a3xx(adreno_dev))
 		total_sizedwords += 7;
@@ -592,31 +627,29 @@
 	if (adreno_is_a2xx(adreno_dev))
 		total_sizedwords += 2; /* CP_WAIT_FOR_IDLE */
 
+	total_sizedwords += 2; /* scratchpad ts for fault tolerance */
 	total_sizedwords += 3; /* sop timestamp */
 	total_sizedwords += 4; /* eop timestamp */
 
-	if (adreno_is_a20x(adreno_dev))
-		total_sizedwords += 2; /* CACHE_FLUSH */
-
-	if (drawctxt) {
+	if (KGSL_MEMSTORE_GLOBAL != context_id)
 		total_sizedwords += 3; /* global timestamp without cache
 					* flush for non-zero context */
-	}
 
 	if (adreno_is_a20x(adreno_dev))
 		total_sizedwords += 2; /* CACHE_FLUSH */
 
-	if (flags & KGSL_CMD_FLAGS_WFI)
-		total_sizedwords += 2; /* WFI */
+	if (flags & KGSL_CMD_FLAGS_EOF)
+		total_sizedwords += 2;
 
 	if (profile_ready)
 		total_sizedwords += 6;   /* space for pre_ib and post_ib */
 
-	ringcmds = adreno_ringbuffer_allocspace(rb, drawctxt, total_sizedwords);
+	/* Add space for the power on shader fixup if we need it */
+	if (flags & KGSL_CMD_FLAGS_PWRON_FIXUP)
+		total_sizedwords += 5;
 
-	if (IS_ERR(ringcmds))
-		return PTR_ERR(ringcmds);
-	if (ringcmds == NULL)
+	ringcmds = adreno_ringbuffer_allocspace(rb, context, total_sizedwords);
+	if (!ringcmds)
 		return -ENOSPC;
 
 	rcmd_gpu = rb->buffer_desc.gpuaddr
@@ -631,11 +664,38 @@
 				KGSL_CMD_INTERNAL_IDENTIFIER);
 	}
 
+	if (flags & KGSL_CMD_FLAGS_PWRON_FIXUP) {
+		GSL_RB_WRITE(rb->device, ringcmds, rcmd_gpu, cp_nop_packet(1));
+		GSL_RB_WRITE(rb->device, ringcmds, rcmd_gpu,
+				KGSL_PWRON_FIXUP_IDENTIFIER);
+		GSL_RB_WRITE(rb->device, ringcmds, rcmd_gpu,
+			CP_HDR_INDIRECT_BUFFER_PFD);
+		GSL_RB_WRITE(rb->device, ringcmds, rcmd_gpu,
+			adreno_dev->pwron_fixup.gpuaddr);
+		GSL_RB_WRITE(rb->device, ringcmds, rcmd_gpu,
+			adreno_dev->pwron_fixup_dwords);
+	}
+
 	/* Add any IB required for profiling if it is enabled */
 	if (profile_ready)
-		adreno_profile_preib_processing(rb->device, drawctxt->base.id,
+		adreno_profile_preib_processing(rb->device, context->base.id,
 				&flags, &ringcmds, &rcmd_gpu);
 
+	/* always increment the global timestamp. once. */
+	rb->global_ts++;
+
+	if (KGSL_MEMSTORE_GLOBAL != context_id)
+		timestamp = context->timestamp;
+	else
+		timestamp = rb->global_ts;
+
+	/* scratchpad ts for fault tolerance */
+	GSL_RB_WRITE(rb->device, ringcmds, rcmd_gpu,
+		cp_type0_packet(adreno_getreg(adreno_dev,
+			ADRENO_REG_CP_TIMESTAMP), 1));
+	GSL_RB_WRITE(rb->device, ringcmds, rcmd_gpu,
+			rb->global_ts);
+
 	/* start-of-pipeline timestamp */
 	GSL_RB_WRITE(rb->device, ringcmds, rcmd_gpu,
 			cp_type3_packet(CP_MEM_WRITE, 2));
@@ -705,7 +765,7 @@
 		KGSL_MEMSTORE_OFFSET(context_id, eoptimestamp)));
 	GSL_RB_WRITE(rb->device, ringcmds, rcmd_gpu, timestamp);
 
-	if (drawctxt) {
+	if (KGSL_MEMSTORE_GLOBAL != context_id) {
 		GSL_RB_WRITE(rb->device, ringcmds, rcmd_gpu,
 			cp_type3_packet(CP_MEM_WRITE, 2));
 		GSL_RB_WRITE(rb->device, ringcmds, rcmd_gpu, (gpuaddr +
@@ -721,13 +781,56 @@
 		GSL_RB_WRITE(rb->device, ringcmds, rcmd_gpu, CACHE_FLUSH);
 	}
 
-	if (drawctxt || (flags & KGSL_CMD_FLAGS_INTERNAL_ISSUE)) {
+	if (context) {
+		/* Conditional execution based on memory values */
+		GSL_RB_WRITE(rb->device, ringcmds, rcmd_gpu,
+			cp_type3_packet(CP_COND_EXEC, 4));
+		GSL_RB_WRITE(rb->device, ringcmds, rcmd_gpu, (gpuaddr +
+			KGSL_MEMSTORE_OFFSET(
+				context_id, ts_cmp_enable)) >> 2);
+		GSL_RB_WRITE(rb->device, ringcmds, rcmd_gpu, (gpuaddr +
+			KGSL_MEMSTORE_OFFSET(
+				context_id, ref_wait_ts)) >> 2);
+		GSL_RB_WRITE(rb->device, ringcmds, rcmd_gpu, timestamp);
+		/* # of conditional command DWORDs */
+		GSL_RB_WRITE(rb->device, ringcmds, rcmd_gpu, 8);
+
+		/* Clear the ts_cmp_enable for the context */
+		GSL_RB_WRITE(rb->device, ringcmds, rcmd_gpu,
+			cp_type3_packet(CP_MEM_WRITE, 2));
+		GSL_RB_WRITE(rb->device, ringcmds, rcmd_gpu, gpuaddr +
+			KGSL_MEMSTORE_OFFSET(
+				context_id, ts_cmp_enable));
+		GSL_RB_WRITE(rb->device, ringcmds, rcmd_gpu, 0x0);
+
+		/* Clear the ts_cmp_enable for the global timestamp */
+		GSL_RB_WRITE(rb->device, ringcmds, rcmd_gpu,
+			cp_type3_packet(CP_MEM_WRITE, 2));
+		GSL_RB_WRITE(rb->device, ringcmds, rcmd_gpu, gpuaddr +
+			KGSL_MEMSTORE_OFFSET(
+				KGSL_MEMSTORE_GLOBAL, ts_cmp_enable));
+		GSL_RB_WRITE(rb->device, ringcmds, rcmd_gpu, 0x0);
+
+		/* Trigger the interrupt */
 		GSL_RB_WRITE(rb->device, ringcmds, rcmd_gpu,
 			cp_type3_packet(CP_INTERRUPT, 1));
 		GSL_RB_WRITE(rb->device, ringcmds, rcmd_gpu,
 				CP_INT_CNTL__RB_INT_MASK);
 	}
 
+	/*
+	 * If per context timestamps are enabled and any of the kgsl
+	 * internal commands want INT to be generated trigger the INT
+	*/
+	if ((context) && (context->flags & CTXT_FLAGS_PER_CONTEXT_TS) &&
+		(flags & (KGSL_CMD_FLAGS_INTERNAL_ISSUE |
+		KGSL_CMD_FLAGS_GET_INT))) {
+			GSL_RB_WRITE(rb->device, ringcmds, rcmd_gpu,
+				cp_type3_packet(CP_INTERRUPT, 1));
+			GSL_RB_WRITE(rb->device, ringcmds, rcmd_gpu,
+				CP_INT_CNTL__RB_INT_MASK);
+	}
+
 	if (adreno_is_a3xx(adreno_dev)) {
 		/* Dummy set-constant to trigger context rollover */
 		GSL_RB_WRITE(rb->device, ringcmds, rcmd_gpu,
@@ -737,10 +840,10 @@
 		GSL_RB_WRITE(rb->device, ringcmds, rcmd_gpu, 0);
 	}
 
-	if (flags & KGSL_CMD_FLAGS_WFI) {
+	if (flags & KGSL_CMD_FLAGS_EOF) {
+		GSL_RB_WRITE(rb->device, ringcmds, rcmd_gpu, cp_nop_packet(1));
 		GSL_RB_WRITE(rb->device, ringcmds, rcmd_gpu,
-			cp_type3_packet(CP_WAIT_FOR_IDLE, 1));
-		GSL_RB_WRITE(rb->device, ringcmds, rcmd_gpu, 0x00000000);
+				KGSL_END_OF_FRAME_IDENTIFIER);
 	}
 
 	adreno_ringbuffer_submit(rb);
@@ -758,10 +861,14 @@
 	struct adreno_device *adreno_dev = ADRENO_DEVICE(device);
 	struct adreno_ringbuffer *rb = &adreno_dev->ringbuffer;
 
+	if (device->state & KGSL_STATE_HUNG)
+		return kgsl_readtimestamp(device, KGSL_MEMSTORE_GLOBAL,
+					KGSL_TIMESTAMP_RETIRED);
+
 	flags |= KGSL_CMD_FLAGS_INTERNAL_ISSUE;
 
 	return adreno_ringbuffer_addcmds(rb, drawctxt, flags, cmds,
-		sizedwords, 0);
+							sizedwords);
 }
 
 static bool _parse_ibs(struct kgsl_device_private *dev_priv, uint gpuaddr,
@@ -954,90 +1061,39 @@
 	return ret;
 }
 
-/**
- * _ringbuffer_verify_ib() - parse an IB and verify that it is correct
- * @dev_priv: Pointer to the process struct
- * @ibdesc: Pointer to the IB descriptor
- *
- * This function only gets called if debugging is enabled  - it walks the IB and
- * does additional level parsing and verification above and beyond what KGSL
- * core does
- */
-static inline bool _ringbuffer_verify_ib(struct kgsl_device_private *dev_priv,
-		struct kgsl_ibdesc *ibdesc)
-{
-	struct kgsl_device *device = dev_priv->device;
-	struct adreno_device *adreno_dev = ADRENO_DEVICE(device);
-
-	/* Check that the size of the IBs is under the allowable limit */
-	if (ibdesc->sizedwords == 0 || ibdesc->sizedwords > 0xFFFFF) {
-		KGSL_DRV_ERR(device, "Invalid IB size 0x%X\n",
-				ibdesc->sizedwords);
-		return false;
-	}
-
-	if (unlikely(adreno_dev->ib_check_level >= 1) &&
-		!_parse_ibs(dev_priv, ibdesc->gpuaddr, ibdesc->sizedwords)) {
-		KGSL_DRV_ERR(device, "Could not verify the IBs\n");
-		return false;
-	}
-
-	return true;
-}
-
 int
 adreno_ringbuffer_issueibcmds(struct kgsl_device_private *dev_priv,
 				struct kgsl_context *context,
-				struct kgsl_cmdbatch *cmdbatch,
-				uint32_t *timestamp)
+				struct kgsl_ibdesc *ibdesc,
+				unsigned int numibs,
+				uint32_t *timestamp,
+				unsigned int flags)
 {
 	struct kgsl_device *device = dev_priv->device;
 	struct adreno_device *adreno_dev = ADRENO_DEVICE(device);
-	struct adreno_context *drawctxt = ADRENO_CONTEXT(context);
-	int i, ret;
-
-	if (drawctxt->state == ADRENO_CONTEXT_STATE_INVALID)
-		return -EDEADLK;
-
-	/* Verify the IBs before they get queued */
-
-	for (i = 0; i < cmdbatch->ibcount; i++) {
-		if (!_ringbuffer_verify_ib(dev_priv, &cmdbatch->ibdesc[i]))
-			return -EINVAL;
-	}
-
-	/* Queue the command in the ringbuffer */
-	ret = adreno_dispatcher_queue_cmd(adreno_dev, drawctxt, cmdbatch,
-		timestamp);
-
-	if (ret)
-		KGSL_DRV_ERR(device,
-			"adreno_dispatcher_queue_cmd returned %d\n", ret);
-
-	return ret;
-}
-
-/* adreno_rindbuffer_submitcmd - submit userspace IBs to the GPU */
-int adreno_ringbuffer_submitcmd(struct adreno_device *adreno_dev,
-		struct kgsl_cmdbatch *cmdbatch)
-{
-	struct kgsl_device *device = &adreno_dev->dev;
-	struct kgsl_ibdesc *ibdesc;
-	unsigned int numibs;
-	unsigned int *link;
+	unsigned int *link = 0;
 	unsigned int *cmds;
 	unsigned int i;
-	struct kgsl_context *context;
-	struct adreno_context *drawctxt;
+	struct adreno_context *drawctxt = NULL;
 	unsigned int start_index = 0;
-	int flags = KGSL_CMD_FLAGS_NONE;
 	int ret;
 
-	context = cmdbatch->context;
+	if (device->state & KGSL_STATE_HUNG) {
+		ret = -EBUSY;
+		goto done;
+	}
+
+	if (!(adreno_dev->ringbuffer.flags & KGSL_FLAGS_STARTED) ||
+	      context == NULL || ibdesc == 0 || numibs == 0) {
+		ret = -EINVAL;
+		goto done;
+	}
 	drawctxt = ADRENO_CONTEXT(context);
 
-	ibdesc = cmdbatch->ibdesc;
-	numibs = cmdbatch->ibcount;
+	if (drawctxt->flags & CTXT_FLAGS_GPU_HANG) {
+		ret = -EDEADLK;
+		goto done;
+	}
 
 	/* process any profiling results that are available into the log_buf */
 	adreno_profile_process_results(device);
@@ -1046,21 +1102,17 @@
 	commands are stored in the first node of the IB chain. We can skip that
 	if a context switch hasn't occured */
 
-	if ((drawctxt->flags & CTXT_FLAGS_PREAMBLE) &&
-		!test_bit(CMDBATCH_FLAG_FORCE_PREAMBLE, &cmdbatch->priv) &&
-		(adreno_dev->drawctxt_active == drawctxt))
+	if (drawctxt->flags & CTXT_FLAGS_PREAMBLE &&
+		adreno_dev->drawctxt_active == drawctxt)
 		start_index = 1;
 
-	/*
-	 * In skip mode don't issue the draw IBs but keep all the other
-	 * accoutrements of a submision (including the interrupt) to keep
-	 * the accounting sane. Set start_index and numibs to 0 to just
-	 * generate the start and end markers and skip everything else
-	 */
-
-	if (test_bit(CMDBATCH_FLAG_SKIP, &cmdbatch->priv)) {
-		start_index = 0;
-		numibs = 0;
+	if (drawctxt->flags & CTXT_FLAGS_SKIP_EOF) {
+		if (flags & KGSL_CMD_FLAGS_EOF)
+			drawctxt->flags &= ~CTXT_FLAGS_SKIP_EOF;
+		if (start_index)
+			numibs = 1;
+		else
+			numibs = 0;
 	}
 
 	cmds = link = kzalloc(sizeof(unsigned int) * (numibs * 3 + 4),
@@ -1081,17 +1133,19 @@
 		*cmds++ = ibdesc[0].sizedwords;
 	}
 	for (i = start_index; i < numibs; i++) {
+		if (unlikely(adreno_dev->ib_check_level >= 1 &&
+		    !_parse_ibs(dev_priv, ibdesc[i].gpuaddr,
+				ibdesc[i].sizedwords))) {
+			ret = -EINVAL;
+			goto done;
+		}
 
-		/*
-		 * Skip 0 sized IBs - these are presumed to have been removed
-		 * from consideration by the FT policy
-		 */
+		if (ibdesc[i].sizedwords == 0) {
+			ret = -EINVAL;
+			goto done;
+		}
 
-		if (ibdesc[i].sizedwords == 0)
-			*cmds++ = cp_nop_packet(2);
-		else
-			*cmds++ = CP_HDR_INDIRECT_BUFFER_PFD;
-
+		*cmds++ = CP_HDR_INDIRECT_BUFFER_PFD;
 		*cmds++ = ibdesc[i].gpuaddr;
 		*cmds++ = ibdesc[i].sizedwords;
 	}
@@ -1099,47 +1153,257 @@
 	*cmds++ = cp_nop_packet(1);
 	*cmds++ = KGSL_END_OF_IB_IDENTIFIER;
 
-	ret = kgsl_setstate(&device->mmu, context->id,
+	kgsl_setstate(&device->mmu, context->id,
 		      kgsl_mmu_pt_get_flags(device->mmu.hwpagetable,
 					device->id));
 
-	if (ret)
-		goto done;
+	adreno_drawctxt_switch(adreno_dev, drawctxt, flags);
 
-	ret = adreno_drawctxt_switch(adreno_dev, drawctxt, cmdbatch->flags);
+	if (test_and_clear_bit(ADRENO_DEVICE_PWRON, &adreno_dev->priv) &&
+		test_bit(ADRENO_DEVICE_PWRON_FIXUP, &adreno_dev->priv))
+			flags |= KGSL_CMD_FLAGS_PWRON_FIXUP;
 
-	/*
-	 * In the unlikely event of an error in the drawctxt switch,
-	 * treat it like a hang
-	 */
-	if (ret)
-		goto done;
-
-	if (test_bit(CMDBATCH_FLAG_WFI, &cmdbatch->priv))
-		flags = KGSL_CMD_FLAGS_WFI;
+	if (drawctxt->flags & CTXT_FLAGS_USER_GENERATED_TS) {
+		if (timestamp_cmp(drawctxt->timestamp, *timestamp) >= 0) {
+			KGSL_DRV_ERR(device,
+				"Invalid user generated ts <%d:0x%x>, "
+				"less than last issued ts <%d:0x%x>\n",
+				context->id, *timestamp, context->id,
+				drawctxt->timestamp);
+			return -ERANGE;
+		}
+		drawctxt->timestamp = *timestamp;
+	} else
+		drawctxt->timestamp++;
 
 	ret = adreno_ringbuffer_addcmds(&adreno_dev->ringbuffer,
 					drawctxt,
 					flags,
-					&link[0], (cmds - link),
-					cmdbatch->timestamp);
-
-#ifdef CONFIG_MSM_KGSL_CFF_DUMP
+					&link[0], (cmds - link));
 	if (ret)
 		goto done;
+
+	if (drawctxt->flags & CTXT_FLAGS_PER_CONTEXT_TS)
+		*timestamp = drawctxt->timestamp;
+	else
+		*timestamp = adreno_dev->ringbuffer.global_ts;
+
+#ifdef CONFIG_MSM_KGSL_CFF_DUMP
 	/*
 	 * insert wait for idle after every IB1
 	 * this is conservative but works reliably and is ok
 	 * even for performance simulations
 	 */
-	ret = adreno_idle(device);
+	adreno_idle(device);
 #endif
 
+	/*
+	 * If context hung and recovered then return error so that the
+	 * application may handle it
+	 */
+	if (drawctxt->flags & CTXT_FLAGS_GPU_HANG_FT) {
+		drawctxt->flags &= ~CTXT_FLAGS_GPU_HANG_FT;
+		ret = -EPROTO;
+	} else
+		ret = 0;
+
 done:
-	kgsl_trace_issueibcmds(device, context->id, cmdbatch,
-		cmdbatch->timestamp, cmdbatch->flags, ret,
-		drawctxt->type);
+	device->pwrctrl.irq_last = 0;
+	kgsl_trace_issueibcmds(device, context ? context->id : 0, ibdesc,
+		numibs, *timestamp, flags, ret,
+		drawctxt ? drawctxt->type : 0);
 
 	kfree(link);
 	return ret;
 }
+
+static void _turn_preamble_on_for_ib_seq(struct adreno_ringbuffer *rb,
+				unsigned int rb_rptr)
+{
+	unsigned int temp_rb_rptr = rb_rptr;
+	unsigned int size = rb->buffer_desc.size;
+	unsigned int val[2];
+	int i = 0;
+	bool check = false;
+	bool cmd_start = false;
+
+	/* Go till the start of the ib sequence and turn on preamble */
+	while (temp_rb_rptr / sizeof(unsigned int) != rb->wptr) {
+		kgsl_sharedmem_readl(&rb->buffer_desc, &val[i], temp_rb_rptr);
+		if (check && KGSL_START_OF_IB_IDENTIFIER == val[i]) {
+			/* decrement i */
+			i = (i + 1) % 2;
+			if (val[i] == cp_nop_packet(4)) {
+				temp_rb_rptr = adreno_ringbuffer_dec_wrapped(
+						temp_rb_rptr, size);
+				kgsl_sharedmem_writel(rb->device,
+					&rb->buffer_desc,
+					temp_rb_rptr, cp_nop_packet(1));
+			}
+			KGSL_FT_INFO(rb->device,
+			"Turned preamble on at offset 0x%x\n",
+			temp_rb_rptr / 4);
+			break;
+		}
+		/* If you reach beginning of next command sequence then exit
+		 * First command encountered is the current one so don't break
+		 * on that. */
+		if (KGSL_CMD_IDENTIFIER == val[i]) {
+			if (cmd_start)
+				break;
+			cmd_start = true;
+		}
+
+		i = (i + 1) % 2;
+		if (1 == i)
+			check = true;
+		temp_rb_rptr = adreno_ringbuffer_inc_wrapped(temp_rb_rptr,
+								size);
+	}
+}
+
+void adreno_ringbuffer_extract(struct adreno_ringbuffer *rb,
+				struct adreno_ft_data *ft_data)
+{
+	struct kgsl_device *device = rb->device;
+	unsigned int rb_rptr = ft_data->start_of_replay_cmds;
+	unsigned int good_rb_idx = 0, bad_rb_idx = 0, temp_rb_idx = 0;
+	unsigned int last_good_cmd_end_idx = 0, last_bad_cmd_end_idx = 0;
+	unsigned int cmd_start_idx = 0;
+	unsigned int val1 = 0;
+	int copy_rb_contents = 0;
+	unsigned int temp_rb_rptr;
+	struct kgsl_context *k_ctxt;
+	struct adreno_context *a_ctxt;
+	unsigned int size = rb->buffer_desc.size;
+	unsigned int *temp_rb_buffer = ft_data->rb_buffer;
+	int *rb_size = &ft_data->rb_size;
+	unsigned int *bad_rb_buffer = ft_data->bad_rb_buffer;
+	int *bad_rb_size = &ft_data->bad_rb_size;
+	unsigned int *good_rb_buffer = ft_data->good_rb_buffer;
+	int *good_rb_size = &ft_data->good_rb_size;
+
+	/*
+	 * If the start index from where commands need to be copied is invalid
+	 * then no need to save off any commands
+	 */
+	if (0xFFFFFFFF == ft_data->start_of_replay_cmds)
+		return;
+
+	k_ctxt = kgsl_context_get(device, ft_data->context_id);
+
+	if (k_ctxt) {
+		a_ctxt = ADRENO_CONTEXT(k_ctxt);
+		if (a_ctxt->flags & CTXT_FLAGS_PREAMBLE)
+			_turn_preamble_on_for_ib_seq(rb, rb_rptr);
+		kgsl_context_put(k_ctxt);
+	}
+	k_ctxt = NULL;
+
+	/* Walk the rb from the context switch. Omit any commands
+	 * for an invalid context. */
+	while ((rb_rptr / sizeof(unsigned int)) != rb->wptr) {
+		kgsl_sharedmem_readl(&rb->buffer_desc, &val1, rb_rptr);
+
+		if (KGSL_CMD_IDENTIFIER == val1) {
+			/* Start is the NOP dword that comes before
+			 * KGSL_CMD_IDENTIFIER */
+			cmd_start_idx = temp_rb_idx - 1;
+			if ((copy_rb_contents) && (good_rb_idx))
+				last_good_cmd_end_idx = good_rb_idx - 1;
+			if ((!copy_rb_contents) && (bad_rb_idx))
+				last_bad_cmd_end_idx = bad_rb_idx - 1;
+		}
+
+		/* check for context switch indicator */
+		if (val1 == KGSL_CONTEXT_TO_MEM_IDENTIFIER) {
+			unsigned int temp_idx, val2;
+			/* increment by 3 to get to the context_id */
+			temp_rb_rptr = rb_rptr + (3 * sizeof(unsigned int)) %
+					size;
+			kgsl_sharedmem_readl(&rb->buffer_desc, &val2,
+						temp_rb_rptr);
+
+			/* if context switches to a context that did not cause
+			 * hang then start saving the rb contents as those
+			 * commands can be executed */
+			k_ctxt = kgsl_context_get(rb->device, val2);
+
+			if (k_ctxt) {
+				a_ctxt = ADRENO_CONTEXT(k_ctxt);
+
+			/* If we are changing to a good context and were not
+			 * copying commands then copy over commands to the good
+			 * context */
+			if (!copy_rb_contents && ((k_ctxt &&
+				!(a_ctxt->flags & CTXT_FLAGS_GPU_HANG)) ||
+				!k_ctxt)) {
+				for (temp_idx = cmd_start_idx;
+					temp_idx < temp_rb_idx;
+					temp_idx++)
+					good_rb_buffer[good_rb_idx++] =
+						temp_rb_buffer[temp_idx];
+				ft_data->last_valid_ctx_id = val2;
+				copy_rb_contents = 1;
+				/* remove the good commands from bad buffer */
+				bad_rb_idx = last_bad_cmd_end_idx;
+			} else if (copy_rb_contents && k_ctxt &&
+				(a_ctxt->flags & CTXT_FLAGS_GPU_HANG)) {
+
+				/* If we are changing back to a bad context
+				 * from good ctxt and were not copying commands
+				 * to bad ctxt then copy over commands to
+				 * the bad context */
+				for (temp_idx = cmd_start_idx;
+					temp_idx < temp_rb_idx;
+					temp_idx++)
+					bad_rb_buffer[bad_rb_idx++] =
+						temp_rb_buffer[temp_idx];
+				/* If we are changing to bad context then
+				 * remove the dwords we copied for this
+				 * sequence from the good buffer */
+				good_rb_idx = last_good_cmd_end_idx;
+				copy_rb_contents = 0;
+			}
+			}
+			kgsl_context_put(k_ctxt);
+		}
+
+		if (copy_rb_contents)
+			good_rb_buffer[good_rb_idx++] = val1;
+		else
+			bad_rb_buffer[bad_rb_idx++] = val1;
+
+		/* Copy both good and bad commands to temp buffer */
+		temp_rb_buffer[temp_rb_idx++] = val1;
+
+		rb_rptr = adreno_ringbuffer_inc_wrapped(rb_rptr, size);
+	}
+	*good_rb_size = good_rb_idx;
+	*bad_rb_size = bad_rb_idx;
+	*rb_size = temp_rb_idx;
+}
+
+void
+adreno_ringbuffer_restore(struct adreno_ringbuffer *rb, unsigned int *rb_buff,
+			int num_rb_contents)
+{
+	int i;
+	unsigned int *ringcmds;
+	unsigned int rcmd_gpu;
+	struct adreno_device *adreno_dev = ADRENO_DEVICE(rb->device);
+
+	if (!num_rb_contents)
+		return;
+
+	if (num_rb_contents > (rb->buffer_desc.size - rb->wptr)) {
+		adreno_writereg(adreno_dev, ADRENO_REG_CP_RB_RPTR, 0);
+		BUG_ON(num_rb_contents > rb->buffer_desc.size);
+	}
+	ringcmds = (unsigned int *)rb->buffer_desc.hostptr + rb->wptr;
+	rcmd_gpu = rb->buffer_desc.gpuaddr + sizeof(unsigned int) * rb->wptr;
+	for (i = 0; i < num_rb_contents; i++)
+		GSL_RB_WRITE(rb->device, ringcmds, rcmd_gpu, rb_buff[i]);
+	rb->wptr += num_rb_contents;
+	adreno_ringbuffer_submit(rb);
+}
diff --git a/drivers/gpu/msm/adreno_ringbuffer.h b/drivers/gpu/msm/adreno_ringbuffer.h
index 3aa0101..9634e32 100644
--- a/drivers/gpu/msm/adreno_ringbuffer.h
+++ b/drivers/gpu/msm/adreno_ringbuffer.h
@@ -27,6 +27,7 @@
 
 struct kgsl_device;
 struct kgsl_device_private;
+struct adreno_ft_data;
 
 #define GSL_RB_MEMPTRS_SCRATCH_COUNT	 8
 struct kgsl_rbmemptrs {
@@ -98,11 +99,10 @@
 
 int adreno_ringbuffer_issueibcmds(struct kgsl_device_private *dev_priv,
 				struct kgsl_context *context,
-				struct kgsl_cmdbatch *cmdbatch,
-				uint32_t *timestamp);
-
-int adreno_ringbuffer_submitcmd(struct adreno_device *adreno_dev,
-		struct kgsl_cmdbatch *cmdbatch);
+				struct kgsl_ibdesc *ibdesc,
+				unsigned int numibs,
+				uint32_t *timestamp,
+				unsigned int flags);
 
 int adreno_ringbuffer_init(struct kgsl_device *device);
 
@@ -124,6 +124,13 @@
 
 void kgsl_cp_intrcallback(struct kgsl_device *device);
 
+void adreno_ringbuffer_extract(struct adreno_ringbuffer *rb,
+				struct adreno_ft_data *ft_data);
+
+void
+adreno_ringbuffer_restore(struct adreno_ringbuffer *rb, unsigned int *rb_buff,
+			int num_rb_contents);
+
 unsigned int *adreno_ringbuffer_allocspace(struct adreno_ringbuffer *rb,
 						struct adreno_context *context,
 						unsigned int numcmds);
diff --git a/drivers/gpu/msm/adreno_trace.h b/drivers/gpu/msm/adreno_trace.h
deleted file mode 100644
index 6079b61..0000000
--- a/drivers/gpu/msm/adreno_trace.h
+++ /dev/null
@@ -1,270 +0,0 @@
-/* Copyright (c) 2013, The Linux Foundation. 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 and
- * only 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.
- *
- */
-
-#if !defined(_ADRENO_TRACE_H) || defined(TRACE_HEADER_MULTI_READ)
-#define _ADRENO_TRACE_H
-
-#undef TRACE_SYSTEM
-#define TRACE_SYSTEM kgsl
-#undef TRACE_INCLUDE_PATH
-#define TRACE_INCLUDE_PATH .
-#define TRACE_INCLUDE_FILE adreno_trace
-
-#include <linux/tracepoint.h>
-
-TRACE_EVENT(adreno_cmdbatch_queued,
-	TP_PROTO(struct kgsl_cmdbatch *cmdbatch, unsigned int queued),
-	TP_ARGS(cmdbatch, queued),
-	TP_STRUCT__entry(
-		__field(unsigned int, id)
-		__field(unsigned int, timestamp)
-		__field(unsigned int, queued)
-		__field(unsigned int, flags)
-	),
-	TP_fast_assign(
-		__entry->id = cmdbatch->context->id;
-		__entry->timestamp = cmdbatch->timestamp;
-		__entry->queued = queued;
-		__entry->flags = cmdbatch->flags;
-	),
-	TP_printk(
-		"ctx=%u ts=%u queued=%u flags=%s",
-			__entry->id, __entry->timestamp, __entry->queued,
-			__entry->flags ? __print_flags(__entry->flags, "|",
-				{ KGSL_CONTEXT_SYNC, "SYNC" },
-				{ KGSL_CONTEXT_END_OF_FRAME, "EOF" })
-				: "none"
-	)
-);
-
-DECLARE_EVENT_CLASS(adreno_cmdbatch_template,
-	TP_PROTO(struct kgsl_cmdbatch *cmdbatch, int inflight),
-	TP_ARGS(cmdbatch, inflight),
-	TP_STRUCT__entry(
-		__field(unsigned int, id)
-		__field(unsigned int, timestamp)
-		__field(unsigned int, inflight)
-	),
-	TP_fast_assign(
-		__entry->id = cmdbatch->context->id;
-		__entry->timestamp = cmdbatch->timestamp;
-		__entry->inflight = inflight;
-	),
-	TP_printk(
-		"ctx=%u ts=%u inflight=%u",
-			__entry->id, __entry->timestamp,
-			__entry->inflight
-	)
-);
-
-DEFINE_EVENT(adreno_cmdbatch_template, adreno_cmdbatch_submitted,
-	TP_PROTO(struct kgsl_cmdbatch *cmdbatch, int inflight),
-	TP_ARGS(cmdbatch, inflight)
-);
-
-TRACE_EVENT(adreno_cmdbatch_retired,
-	TP_PROTO(struct kgsl_cmdbatch *cmdbatch, int inflight),
-	TP_ARGS(cmdbatch, inflight),
-	TP_STRUCT__entry(
-		__field(unsigned int, id)
-		__field(unsigned int, timestamp)
-		__field(unsigned int, inflight)
-		__field(unsigned int, recovery)
-	),
-	TP_fast_assign(
-		__entry->id = cmdbatch->context->id;
-		__entry->timestamp = cmdbatch->timestamp;
-		__entry->inflight = inflight;
-		__entry->recovery = cmdbatch->fault_recovery;
-	),
-	TP_printk(
-		"ctx=%u ts=%u inflight=%u recovery=%s",
-			__entry->id, __entry->timestamp,
-			__entry->inflight,
-			__entry->recovery ?
-				__print_flags(__entry->recovery, "|",
-				ADRENO_FT_TYPES) : "none"
-	)
-);
-
-TRACE_EVENT(adreno_cmdbatch_fault,
-	TP_PROTO(struct kgsl_cmdbatch *cmdbatch, unsigned int fault),
-	TP_ARGS(cmdbatch, fault),
-	TP_STRUCT__entry(
-		__field(unsigned int, id)
-		__field(unsigned int, timestamp)
-		__field(unsigned int, fault)
-	),
-	TP_fast_assign(
-		__entry->id = cmdbatch->context->id;
-		__entry->timestamp = cmdbatch->timestamp;
-		__entry->fault = fault;
-	),
-	TP_printk(
-		"ctx=%u ts=%u type=%s",
-			__entry->id, __entry->timestamp,
-			__print_symbolic(__entry->fault,
-				{ 0, "none" },
-				{ ADRENO_SOFT_FAULT, "soft" },
-				{ ADRENO_HARD_FAULT, "hard" },
-				{ ADRENO_TIMEOUT_FAULT, "timeout" })
-	)
-);
-
-TRACE_EVENT(adreno_cmdbatch_recovery,
-	TP_PROTO(struct kgsl_cmdbatch *cmdbatch, unsigned int action),
-	TP_ARGS(cmdbatch, action),
-	TP_STRUCT__entry(
-		__field(unsigned int, id)
-		__field(unsigned int, timestamp)
-		__field(unsigned int, action)
-	),
-	TP_fast_assign(
-		__entry->id = cmdbatch->context->id;
-		__entry->timestamp = cmdbatch->timestamp;
-		__entry->action = action;
-	),
-	TP_printk(
-		"ctx=%u ts=%u action=%s",
-			__entry->id, __entry->timestamp,
-			__print_symbolic(__entry->action, ADRENO_FT_TYPES)
-	)
-);
-
-DECLARE_EVENT_CLASS(adreno_drawctxt_template,
-	TP_PROTO(struct adreno_context *drawctxt),
-	TP_ARGS(drawctxt),
-	TP_STRUCT__entry(
-		__field(unsigned int, id)
-	),
-	TP_fast_assign(
-		__entry->id = drawctxt->base.id;
-	),
-	TP_printk("ctx=%u", __entry->id)
-);
-
-DEFINE_EVENT(adreno_drawctxt_template, adreno_drawctxt_sleep,
-	TP_PROTO(struct adreno_context *drawctxt),
-	TP_ARGS(drawctxt)
-);
-
-DEFINE_EVENT(adreno_drawctxt_template, adreno_drawctxt_wake,
-	TP_PROTO(struct adreno_context *drawctxt),
-	TP_ARGS(drawctxt)
-);
-
-DEFINE_EVENT(adreno_drawctxt_template, dispatch_queue_context,
-	TP_PROTO(struct adreno_context *drawctxt),
-	TP_ARGS(drawctxt)
-);
-
-DEFINE_EVENT(adreno_drawctxt_template, adreno_drawctxt_invalidate,
-	TP_PROTO(struct adreno_context *drawctxt),
-	TP_ARGS(drawctxt)
-);
-
-TRACE_EVENT(adreno_drawctxt_wait_start,
-	TP_PROTO(unsigned int id, unsigned int ts),
-	TP_ARGS(id, ts),
-	TP_STRUCT__entry(
-		__field(unsigned int, id)
-		__field(unsigned int, ts)
-	),
-	TP_fast_assign(
-		__entry->id = id;
-		__entry->ts = ts;
-	),
-	TP_printk(
-		"ctx=%u ts=%u",
-			__entry->id, __entry->ts
-	)
-);
-
-TRACE_EVENT(adreno_drawctxt_wait_done,
-	TP_PROTO(unsigned int id, unsigned int ts, int status),
-	TP_ARGS(id, ts, status),
-	TP_STRUCT__entry(
-		__field(unsigned int, id)
-		__field(unsigned int, ts)
-		__field(int, status)
-	),
-	TP_fast_assign(
-		__entry->id = id;
-		__entry->ts = ts;
-		__entry->status = status;
-	),
-	TP_printk(
-		"ctx=%u ts=%u status=%d",
-			__entry->id, __entry->ts, __entry->status
-	)
-);
-
-TRACE_EVENT(adreno_drawctxt_switch,
-	TP_PROTO(struct adreno_context *oldctx,
-		struct adreno_context *newctx,
-		unsigned int flags),
-	TP_ARGS(oldctx, newctx, flags),
-	TP_STRUCT__entry(
-		__field(unsigned int, oldctx)
-		__field(unsigned int, newctx)
-		__field(unsigned int, flags)
-	),
-	TP_fast_assign(
-		__entry->oldctx = oldctx ? oldctx->base.id : 0;
-		__entry->newctx = newctx ? newctx->base.id : 0;
-	),
-	TP_printk(
-		"oldctx=%u newctx=%u flags=%X",
-			__entry->oldctx, __entry->newctx, flags
-	)
-);
-
-TRACE_EVENT(adreno_gpu_fault,
-	TP_PROTO(unsigned int ctx, unsigned int ts,
-		unsigned int status, unsigned int rptr, unsigned int wptr,
-		unsigned int ib1base, unsigned int ib1size,
-		unsigned int ib2base, unsigned int ib2size),
-	TP_ARGS(ctx, ts, status, rptr, wptr, ib1base, ib1size, ib2base,
-		ib2size),
-	TP_STRUCT__entry(
-		__field(unsigned int, ctx)
-		__field(unsigned int, ts)
-		__field(unsigned int, status)
-		__field(unsigned int, rptr)
-		__field(unsigned int, wptr)
-		__field(unsigned int, ib1base)
-		__field(unsigned int, ib1size)
-		__field(unsigned int, ib2base)
-		__field(unsigned int, ib2size)
-	),
-	TP_fast_assign(
-		__entry->ctx = ctx;
-		__entry->ts = ts;
-		__entry->status = status;
-		__entry->rptr = rptr;
-		__entry->wptr = wptr;
-		__entry->ib1base = ib1base;
-		__entry->ib1size = ib1size;
-		__entry->ib2base = ib2base;
-		__entry->ib2size = ib2size;
-	),
-	TP_printk("ctx=%d ts=%d status=%X RB=%X/%X IB1=%X/%X IB2=%X/%X",
-		__entry->ctx, __entry->ts, __entry->status, __entry->wptr,
-		__entry->rptr, __entry->ib1base, __entry->ib1size,
-		__entry->ib2base, __entry->ib2size)
-);
-
-#endif /* _ADRENO_TRACE_H */
-
-/* This part must be outside protection */
-#include <trace/define_trace.h>
diff --git a/drivers/gpu/msm/kgsl.c b/drivers/gpu/msm/kgsl.c
index 35a03de..7da0811 100644
--- a/drivers/gpu/msm/kgsl.c
+++ b/drivers/gpu/msm/kgsl.c
@@ -14,7 +14,6 @@
 #include <linux/fb.h>
 #include <linux/file.h>
 #include <linux/fs.h>
-#include <linux/list.h>
 #include <linux/debugfs.h>
 #include <linux/uaccess.h>
 #include <linux/interrupt.h>
@@ -63,10 +62,59 @@
 static void kgsl_mem_entry_detach_process(struct kgsl_mem_entry *entry);
 
 /**
+ * kgsl_hang_check() - Check for GPU hang
+ * data: KGSL device structure
+ *
+ * This function is called every KGSL_TIMEOUT_PART time when
+ * GPU is active to check for hang. If a hang is detected we
+ * trigger fault tolerance.
+ */
+void kgsl_hang_check(struct work_struct *work)
+{
+	struct kgsl_device *device = container_of(work, struct kgsl_device,
+							hang_check_ws);
+	static unsigned int prev_reg_val[FT_DETECT_REGS_COUNT];
+
+	mutex_lock(&device->mutex);
+
+	if (device->state == KGSL_STATE_ACTIVE) {
+
+		/* Check to see if the GPU is hung */
+		if (adreno_ft_detect(device, prev_reg_val))
+			adreno_dump_and_exec_ft(device);
+
+		mod_timer(&device->hang_timer,
+			(jiffies + msecs_to_jiffies(KGSL_TIMEOUT_PART)));
+	}
+
+	mutex_unlock(&device->mutex);
+}
+
+/**
+ * hang_timer() - Hang timer function
+ * data: KGSL device structure
+ *
+ * This function is called when hang timer expires, in this
+ * function we check if GPU is in active state and queue the
+ * work on device workqueue to check for the hang. We restart
+ * the timer after KGSL_TIMEOUT_PART time.
+ */
+void hang_timer(unsigned long data)
+{
+	struct kgsl_device *device = (struct kgsl_device *) data;
+
+	if (device->state == KGSL_STATE_ACTIVE) {
+		/* Have work run in a non-interrupt context. */
+		queue_work(device->work_queue, &device->hang_check_ws);
+	}
+}
+
+/**
  * kgsl_trace_issueibcmds() - Call trace_issueibcmds by proxy
  * device: KGSL device
  * id: ID of the context submitting the command
- * cmdbatch: Pointer to kgsl_cmdbatch describing these commands
+ * ibdesc: Pointer to the list of IB descriptors
+ * numib: Number of IBs in the list
  * timestamp: Timestamp assigned to the command batch
  * flags: Flags sent by the user
  * result: Result of the submission attempt
@@ -76,11 +124,11 @@
  * GPU specific modules.
  */
 void kgsl_trace_issueibcmds(struct kgsl_device *device, int id,
-		struct kgsl_cmdbatch *cmdbatch,
+		struct kgsl_ibdesc *ibdesc, int numibs,
 		unsigned int timestamp, unsigned int flags,
 		int result, unsigned int type)
 {
-	trace_kgsl_issueibcmds(device, id, cmdbatch,
+	trace_kgsl_issueibcmds(device, id, ibdesc, numibs,
 		timestamp, flags, result, type);
 }
 EXPORT_SYMBOL(kgsl_trace_issueibcmds);
@@ -482,8 +530,8 @@
 EXPORT_SYMBOL(kgsl_context_init);
 
 /**
- * kgsl_context_detach() - Release the "master" context reference
- * @context: The context that will be detached
+ * kgsl_context_detach - Release the "master" context reference
+ * @context - The context that will be detached
  *
  * This is called when a context becomes unusable, because userspace
  * has requested for it to be destroyed. The context itself may
@@ -492,12 +540,14 @@
  * detached by checking the KGSL_CONTEXT_DETACHED bit in
  * context->priv.
  */
-int kgsl_context_detach(struct kgsl_context *context)
+void
+kgsl_context_detach(struct kgsl_context *context)
 {
-	int ret;
-
+	struct kgsl_device *device;
 	if (context == NULL)
-		return -EINVAL;
+		return;
+
+	device = context->device;
 
 	/*
 	 * Mark the context as detached to keep others from using
@@ -505,22 +555,19 @@
 	 * we don't try to detach twice.
 	 */
 	if (test_and_set_bit(KGSL_CONTEXT_DETACHED, &context->priv))
-		return -EINVAL;
+		return;
 
-	trace_kgsl_context_detach(context->device, context);
+	trace_kgsl_context_detach(device, context);
 
-	ret = context->device->ftbl->drawctxt_detach(context);
-
+	device->ftbl->drawctxt_detach(context);
 	/*
 	 * Cancel events after the device-specific context is
 	 * detached, to avoid possibly freeing memory while
 	 * it is still in use by the GPU.
 	 */
-	kgsl_context_cancel_events(context->device, context);
+	kgsl_context_cancel_events(device, context);
 
 	kgsl_context_put(context);
-
-	return ret;
 }
 
 void
@@ -532,8 +579,6 @@
 
 	trace_kgsl_context_destroy(device, context);
 
-	BUG_ON(!kgsl_context_detached(context));
-
 	write_lock(&device->context_lock);
 	if (context->id != KGSL_CONTEXT_INVALID) {
 		idr_remove(&device->context_idr, context->id);
@@ -604,11 +649,10 @@
 	policy_saved = device->pwrscale.policy;
 	device->pwrscale.policy = NULL;
 	kgsl_pwrctrl_request_state(device, KGSL_STATE_SUSPEND);
-
-	/* Tell the device to drain the submission queue */
-	device->ftbl->drain(device);
-
-	/* Wait for the active count to hit zero */
+	/*
+	 * Make sure no user process is waiting for a timestamp
+	 * before supending.
+	 */
 	kgsl_active_count_wait(device, 0);
 
 	/*
@@ -619,10 +663,13 @@
 
 	/* Don't let the timer wake us during suspended sleep. */
 	del_timer_sync(&device->idle_timer);
+	del_timer_sync(&device->hang_timer);
 	switch (device->state) {
 		case KGSL_STATE_INIT:
 			break;
 		case KGSL_STATE_ACTIVE:
+			/* Wait for the device to become idle */
+			device->ftbl->idle(device);
 		case KGSL_STATE_NAP:
 		case KGSL_STATE_SLEEP:
 			/* make sure power is on to stop the device */
@@ -864,11 +911,7 @@
 
 	mutex_lock(&private->process_private_mutex);
 
-	/*
-	 * If debug root initialized then it means the rest of the fields
-	 * are also initialized
-	 */
-	if (private->debug_root)
+	if (test_bit(KGSL_PROCESS_INIT, &private->priv))
 		goto done;
 
 	private->mem_rb = RB_ROOT;
@@ -889,6 +932,8 @@
 	if (kgsl_process_init_debugfs(private))
 		goto error;
 
+	set_bit(KGSL_PROCESS_INIT, &private->priv);
+
 done:
 	mutex_unlock(&private->process_private_mutex);
 	return private;
@@ -948,16 +993,8 @@
 		if (context == NULL)
 			break;
 
-		if (context->dev_priv == dev_priv) {
-			/*
-			 * Hold a reference to the context in case somebody
-			 * tries to put it while we are detaching
-			 */
-
-			_kgsl_context_get(context);
+		if (context->dev_priv == dev_priv)
 			kgsl_context_detach(context);
-			kgsl_context_put(context);
-		}
 
 		next = next + 1;
 	}
@@ -971,7 +1008,6 @@
 
 	result = kgsl_close_device(device);
 	mutex_unlock(&device->mutex);
-
 	kfree(dev_priv);
 
 	kgsl_put_process_private(device, private);
@@ -1004,6 +1040,7 @@
 		 * Make sure the gates are open, so they don't block until
 		 * we start suspend or FT.
 		 */
+		complete_all(&device->ft_gate);
 		complete_all(&device->hwaccess_gate);
 		kgsl_pwrctrl_set_state(device, KGSL_STATE_ACTIVE);
 		kgsl_active_count_put(device);
@@ -1399,610 +1436,93 @@
 	return result;
 }
 
-/*
- * KGSL command batch management
- * A command batch is a single submission from userland.  The cmdbatch
- * encapsulates everything about the submission : command buffers, flags and
- * sync points.
- *
- * Sync points are events that need to expire before the
- * cmdbatch can be queued to the hardware. For each sync point a
- * kgsl_cmdbatch_sync_event struct is created and added to a list in the
- * cmdbatch. There can be multiple types of events both internal ones (GPU
- * events) and external triggers. As the events expire the struct is deleted
- * from the list. The GPU will submit the command batch as soon as the list
- * goes empty indicating that all the sync points have been met.
- */
-
-/**
- * struct kgsl_cmdbatch_sync_event
- * @type: Syncpoint type
- * @node: Local list node for the cmdbatch sync point list
- * @cmdbatch: Pointer to the cmdbatch that owns the sync event
- * @context: Pointer to the KGSL context that owns the cmdbatch
- * @timestamp: Pending timestamp for the event
- * @handle: Pointer to a sync fence handle
- * @device: Pointer to the KGSL device
- * @lock: Spin lock to protect the sync event list
- */
-struct kgsl_cmdbatch_sync_event {
-	int type;
-	struct list_head node;
-	struct kgsl_cmdbatch *cmdbatch;
-	struct kgsl_context *context;
-	unsigned int timestamp;
-	struct kgsl_sync_fence_waiter *handle;
-	struct kgsl_device *device;
-	spinlock_t lock;
-};
-
-/**
- * kgsl_cmdbatch_destroy_object() - Destroy a cmdbatch object
- * @kref: Pointer to the kref structure for this object
- *
- * Actually destroy a command batch object.  Called from kgsl_cmdbatch_put
- */
-void kgsl_cmdbatch_destroy_object(struct kref *kref)
-{
-	struct kgsl_cmdbatch *cmdbatch = container_of(kref,
-		struct kgsl_cmdbatch, refcount);
-
-	kgsl_context_put(cmdbatch->context);
-	kfree(cmdbatch->ibdesc);
-
-	kfree(cmdbatch);
-}
-EXPORT_SYMBOL(kgsl_cmdbatch_destroy_object);
-
-/*
- * a generic function to retire a pending sync event and (possibly)
- * kick the dispatcher
- */
-static void kgsl_cmdbatch_sync_expire(struct kgsl_device *device,
-	struct kgsl_cmdbatch_sync_event *event)
-{
-	int sched = 0;
-
-	spin_lock(&event->cmdbatch->lock);
-	list_del(&event->node);
-	sched = list_empty(&event->cmdbatch->synclist) ? 1 : 0;
-	spin_unlock(&event->cmdbatch->lock);
-
-	/*
-	 * if this is the last event in the list then tell
-	 * the GPU device that the cmdbatch can be submitted
-	 */
-
-	if (sched && device->ftbl->drawctxt_sched)
-		device->ftbl->drawctxt_sched(device, event->cmdbatch->context);
-}
-
-
-/*
- * This function is called by the GPU event when the sync event timestamp
- * expires
- */
-static void kgsl_cmdbatch_sync_func(struct kgsl_device *device, void *priv,
-		u32 id, u32 timestamp, u32 type)
-{
-	struct kgsl_cmdbatch_sync_event *event = priv;
-
-	kgsl_cmdbatch_sync_expire(device, event);
-
-	kgsl_context_put(event->context);
-	kgsl_cmdbatch_put(event->cmdbatch);
-
-	kfree(event);
-}
-
-/**
- * kgsl_cmdbatch_destroy() - Destroy a cmdbatch structure
- * @cmdbatch: Pointer to the command batch object to destroy
- *
- * Start the process of destroying a command batch.  Cancel any pending events
- * and decrement the refcount.
- */
-void kgsl_cmdbatch_destroy(struct kgsl_cmdbatch *cmdbatch)
-{
-	struct kgsl_cmdbatch_sync_event *event, *tmp;
-
-	spin_lock(&cmdbatch->lock);
-
-	/* Delete any pending sync points for this command batch */
-	list_for_each_entry_safe(event, tmp, &cmdbatch->synclist, node) {
-
-		if (event->type == KGSL_CMD_SYNCPOINT_TYPE_TIMESTAMP) {
-			/* Cancel the event if it still exists */
-			kgsl_cancel_event(cmdbatch->device, event->context,
-				event->timestamp, kgsl_cmdbatch_sync_func,
-				event);
-		} else if (event->type == KGSL_CMD_SYNCPOINT_TYPE_FENCE) {
-			if (kgsl_sync_fence_async_cancel(event->handle)) {
-				list_del(&event->node);
-				kfree(event);
-				kgsl_cmdbatch_put(cmdbatch);
-			}
-		}
-	}
-
-	spin_unlock(&cmdbatch->lock);
-	kgsl_cmdbatch_put(cmdbatch);
-}
-EXPORT_SYMBOL(kgsl_cmdbatch_destroy);
-
-/*
- * A callback that gets registered with kgsl_sync_fence_async_wait and is fired
- * when a fence is expired
- */
-static void kgsl_cmdbatch_sync_fence_func(void *priv)
-{
-	struct kgsl_cmdbatch_sync_event *event = priv;
-
-	spin_lock(&event->lock);
-	kgsl_cmdbatch_sync_expire(event->device, event);
-	kgsl_cmdbatch_put(event->cmdbatch);
-	spin_unlock(&event->lock);
-	kfree(event);
-}
-
-/* kgsl_cmdbatch_add_sync_fence() - Add a new sync fence syncpoint
- * @device: KGSL device
- * @cmdbatch: KGSL cmdbatch to add the sync point to
- * @priv: Private sructure passed by the user
- *
- * Add a new fence sync syncpoint to the cmdbatch.
- */
-static int kgsl_cmdbatch_add_sync_fence(struct kgsl_device *device,
-		struct kgsl_cmdbatch *cmdbatch, void *priv)
-{
-	struct kgsl_cmd_syncpoint_fence *sync = priv;
-	struct kgsl_cmdbatch_sync_event *event;
-
-	event = kzalloc(sizeof(*event), GFP_KERNEL);
-
-	if (event == NULL)
-		return -ENOMEM;
-
-	kref_get(&cmdbatch->refcount);
-
-	event->type = KGSL_CMD_SYNCPOINT_TYPE_FENCE;
-	event->cmdbatch = cmdbatch;
-	event->device = device;
-	spin_lock_init(&event->lock);
-
-	/*
-	 * Add it to the list first to account for the possiblity that the
-	 * callback will happen immediately after the call to
-	 * kgsl_sync_fence_async_wait
-	 */
-
-	spin_lock(&cmdbatch->lock);
-	list_add(&event->node, &cmdbatch->synclist);
-	spin_unlock(&cmdbatch->lock);
-
-	/*
-	 * There is a distinct race condition that can occur if the fence
-	 * callback is fired before the function has a chance to return.  The
-	 * event struct would be freed before we could write event->handle and
-	 * hilarity ensued.  Protect against this by protecting the call to
-	 * kgsl_sync_fence_async_wait and the kfree in the callback with a lock.
-	 */
-
-	spin_lock(&event->lock);
-
-	event->handle = kgsl_sync_fence_async_wait(sync->fd,
-		kgsl_cmdbatch_sync_fence_func, event);
-
-
-	if (IS_ERR_OR_NULL(event->handle)) {
-		int ret = PTR_ERR(event->handle);
-
-		spin_lock(&cmdbatch->lock);
-		list_del(&event->node);
-		spin_unlock(&cmdbatch->lock);
-
-		kgsl_cmdbatch_put(cmdbatch);
-		spin_unlock(&event->lock);
-		kfree(event);
-
-		return ret;
-	}
-
-	spin_unlock(&event->lock);
-	return 0;
-}
-
-/* kgsl_cmdbatch_add_sync_timestamp() - Add a new sync point for a cmdbatch
- * @device: KGSL device
- * @cmdbatch: KGSL cmdbatch to add the sync point to
- * @priv: Private sructure passed by the user
- *
- * Add a new sync point timestamp event to the cmdbatch.
- */
-static int kgsl_cmdbatch_add_sync_timestamp(struct kgsl_device *device,
-		struct kgsl_cmdbatch *cmdbatch, void *priv)
-{
-	struct kgsl_cmd_syncpoint_timestamp *sync = priv;
-	struct kgsl_context *context = kgsl_context_get(cmdbatch->device,
-		sync->context_id);
-	struct kgsl_cmdbatch_sync_event *event;
-	int ret = -EINVAL;
-
-	if (context == NULL)
-		return -EINVAL;
-
-	/* Sanity check - you can't create a sync point on your own context */
-	if (context == cmdbatch->context) {
-		KGSL_DRV_ERR(device,
-			"Cannot create a sync point on your own context %d\n",
-			context->id);
-		goto done;
-	}
-
-	event = kzalloc(sizeof(*event), GFP_KERNEL);
-	if (event == NULL) {
-		ret = -ENOMEM;
-		goto done;
-	}
-
-	kref_get(&cmdbatch->refcount);
-
-	event->type = KGSL_CMD_SYNCPOINT_TYPE_TIMESTAMP;
-	event->cmdbatch = cmdbatch;
-	event->context = context;
-	event->timestamp = sync->timestamp;
-
-	spin_lock(&cmdbatch->lock);
-	list_add(&event->node, &cmdbatch->synclist);
-	spin_unlock(&cmdbatch->lock);
-
-	mutex_lock(&device->mutex);
-	kgsl_active_count_get(device);
-	ret = kgsl_add_event(device, context->id, sync->timestamp,
-		kgsl_cmdbatch_sync_func, event, NULL);
-	kgsl_active_count_put(device);
-	mutex_unlock(&device->mutex);
-
-	if (ret) {
-		spin_lock(&cmdbatch->lock);
-		list_del(&event->node);
-		spin_unlock(&cmdbatch->lock);
-
-		kgsl_cmdbatch_put(cmdbatch);
-		kfree(event);
-	}
-
-done:
-	if (ret)
-		kgsl_context_put(context);
-
-	return ret;
-}
-
-/**
- * kgsl_cmdbatch_add_sync() - Add a sync point to a command batch
- * @device: Pointer to the KGSL device struct for the GPU
- * @cmdbatch: Pointer to the cmdbatch
- * @sync: Pointer to the user-specified struct defining the syncpoint
- *
- * Create a new sync point in the cmdbatch based on the user specified
- * parameters
- */
-static int kgsl_cmdbatch_add_sync(struct kgsl_device *device,
-	struct kgsl_cmdbatch *cmdbatch,
-	struct kgsl_cmd_syncpoint *sync)
-{
-	void *priv;
-	int ret, psize;
-	int (*func)(struct kgsl_device *device, struct kgsl_cmdbatch *cmdbatch,
-			void *priv);
-
-	switch (sync->type) {
-	case KGSL_CMD_SYNCPOINT_TYPE_TIMESTAMP:
-		psize = sizeof(struct kgsl_cmd_syncpoint_timestamp);
-		func = kgsl_cmdbatch_add_sync_timestamp;
-		break;
-	case KGSL_CMD_SYNCPOINT_TYPE_FENCE:
-		psize = sizeof(struct kgsl_cmd_syncpoint_fence);
-		func = kgsl_cmdbatch_add_sync_fence;
-		break;
-	default:
-		KGSL_DRV_ERR(device, "Invalid sync type 0x%x\n", sync->type);
-		return -EINVAL;
-	}
-
-	if (sync->size != psize) {
-		KGSL_DRV_ERR(device, "Invalid sync size %d\n", sync->size);
-		return -EINVAL;
-	}
-
-	priv = kzalloc(sync->size, GFP_KERNEL);
-	if (priv == NULL)
-		return -ENOMEM;
-
-	if (copy_from_user(priv, sync->priv, sync->size)) {
-		kfree(priv);
-		return -EFAULT;
-	}
-
-	ret = func(device, cmdbatch, priv);
-	kfree(priv);
-
-	return ret;
-}
-
-/**
- * kgsl_cmdbatch_create() - Create a new cmdbatch structure
- * @device: Pointer to a KGSL device struct
- * @context: Pointer to a KGSL context struct
- * @numibs: Number of indirect buffers to make room for in the cmdbatch
- *
- * Allocate an new cmdbatch structure and add enough room to store the list of
- * indirect buffers
- */
-static struct kgsl_cmdbatch *kgsl_cmdbatch_create(struct kgsl_device *device,
-		struct kgsl_context *context, unsigned int flags,
-		unsigned int numibs)
-{
-	struct kgsl_cmdbatch *cmdbatch = kzalloc(sizeof(*cmdbatch), GFP_KERNEL);
-	if (cmdbatch == NULL)
-		return ERR_PTR(-ENOMEM);
-
-	if (!(flags & KGSL_CONTEXT_SYNC)) {
-		cmdbatch->ibdesc = kzalloc(sizeof(*cmdbatch->ibdesc) * numibs,
-			GFP_KERNEL);
-		if (cmdbatch->ibdesc == NULL) {
-			kfree(cmdbatch);
-			return ERR_PTR(-ENOMEM);
-		}
-	}
-
-	kref_init(&cmdbatch->refcount);
-	INIT_LIST_HEAD(&cmdbatch->synclist);
-	spin_lock_init(&cmdbatch->lock);
-
-	cmdbatch->device = device;
-	cmdbatch->ibcount = (flags & KGSL_CONTEXT_SYNC) ? 0 : numibs;
-	cmdbatch->context = context;
-	cmdbatch->flags = flags & ~KGSL_CONTEXT_SUBMIT_IB_LIST;
-
-	/*
-	 * Increase the reference count on the context so it doesn't disappear
-	 * during the lifetime of this command batch
-	 */
-	_kgsl_context_get(context);
-
-	return cmdbatch;
-}
-
-/**
- * _kgsl_cmdbatch_verify() - Perform a quick sanity check on a command batch
- * @device: Pointer to a KGSL instance that owns the command batch
- * @pagetable: Pointer to the pagetable for the current process
- * @cmdbatch: Number of indirect buffers to make room for in the cmdbatch
- *
- * Do a quick sanity test on the list of indirect buffers in a command batch
- * verifying that the size and GPU address
- */
-static bool _kgsl_cmdbatch_verify(struct kgsl_device_private *dev_priv,
-	struct kgsl_cmdbatch *cmdbatch)
-{
-	int i;
-	struct kgsl_process_private *private = dev_priv->process_priv;
-
-	for (i = 0; i < cmdbatch->ibcount; i++) {
-		if (cmdbatch->ibdesc[i].sizedwords == 0) {
-			KGSL_DRV_ERR(dev_priv->device,
-				"invalid size ctx %d ib(%d) %X/%X\n",
-				cmdbatch->context->id, i,
-				cmdbatch->ibdesc[i].gpuaddr,
-				cmdbatch->ibdesc[i].sizedwords);
-
-			return false;
-		}
-
-		if (!kgsl_mmu_gpuaddr_in_range(private->pagetable,
-			cmdbatch->ibdesc[i].gpuaddr)) {
-			KGSL_DRV_ERR(dev_priv->device,
-				"Invalid address ctx %d ib(%d) %X/%X\n",
-				cmdbatch->context->id, i,
-				cmdbatch->ibdesc[i].gpuaddr,
-				cmdbatch->ibdesc[i].sizedwords);
-
-			return false;
-		}
-	}
-
-	return true;
-}
-
-/**
- * _kgsl_cmdbatch_create_legacy() - Create a cmdbatch from a legacy ioctl struct
- * @device: Pointer to the KGSL device struct for the GPU
- * @context: Pointer to the KGSL context that issued the command batch
- * @param: Pointer to the kgsl_ringbuffer_issueibcmds struct that the user sent
- *
- * Create a command batch from the legacy issueibcmds format.
- */
-static struct kgsl_cmdbatch *_kgsl_cmdbatch_create_legacy(
-		struct kgsl_device *device,
-		struct kgsl_context *context,
-		struct kgsl_ringbuffer_issueibcmds *param)
-{
-	struct kgsl_cmdbatch *cmdbatch =
-		kgsl_cmdbatch_create(device, context, param->flags, 1);
-
-	if (IS_ERR(cmdbatch))
-		return cmdbatch;
-
-	cmdbatch->ibdesc[0].gpuaddr = param->ibdesc_addr;
-	cmdbatch->ibdesc[0].sizedwords = param->numibs;
-	cmdbatch->ibcount = 1;
-	cmdbatch->flags = param->flags;
-
-	return cmdbatch;
-}
-
-/**
- * _kgsl_cmdbatch_create() - Create a cmdbatch from a ioctl struct
- * @device: Pointer to the KGSL device struct for the GPU
- * @context: Pointer to the KGSL context that issued the command batch
- * @flags: Flags passed in from the user command
- * @cmdlist: Pointer to the list of commands from the user
- * @numcmds: Number of commands in the list
- * @synclist: Pointer to the list of syncpoints from the user
- * @numsyncs: Number of syncpoints in the list
- *
- * Create a command batch from the standard issueibcmds format sent by the user.
- */
-static struct kgsl_cmdbatch *_kgsl_cmdbatch_create(struct kgsl_device *device,
-		struct kgsl_context *context,
-		unsigned int flags,
-		unsigned int cmdlist, unsigned int numcmds,
-		unsigned int synclist, unsigned int numsyncs)
-{
-	struct kgsl_cmdbatch *cmdbatch =
-		kgsl_cmdbatch_create(device, context, flags, numcmds);
-	int ret = 0;
-
-	if (IS_ERR(cmdbatch))
-		return cmdbatch;
-
-	if (!(flags & KGSL_CONTEXT_SYNC)) {
-		if (copy_from_user(cmdbatch->ibdesc, (void __user *) cmdlist,
-			sizeof(struct kgsl_ibdesc) * numcmds)) {
-			ret = -EFAULT;
-			goto done;
-		}
-	}
-
-	if (synclist && numsyncs) {
-		struct kgsl_cmd_syncpoint sync;
-		void  __user *uptr = (void __user *) synclist;
-		int i;
-
-		for (i = 0; i < numsyncs; i++) {
-			memset(&sync, 0, sizeof(sync));
-
-			if (copy_from_user(&sync, uptr, sizeof(sync))) {
-				ret = -EFAULT;
-				break;
-			}
-
-			ret = kgsl_cmdbatch_add_sync(device, cmdbatch, &sync);
-
-			if (ret)
-				break;
-
-			uptr += sizeof(sync);
-		}
-	}
-
-done:
-	if (ret) {
-		kgsl_cmdbatch_destroy(cmdbatch);
-		return ERR_PTR(ret);
-	}
-
-	return cmdbatch;
-}
-
 static long kgsl_ioctl_rb_issueibcmds(struct kgsl_device_private *dev_priv,
 				      unsigned int cmd, void *data)
 {
+	int result = 0;
+	int i = 0;
 	struct kgsl_ringbuffer_issueibcmds *param = data;
-	struct kgsl_device *device = dev_priv->device;
+	struct kgsl_ibdesc *ibdesc;
 	struct kgsl_context *context;
-	struct kgsl_cmdbatch *cmdbatch;
-	long result = -EINVAL;
 
-	/* The legacy functions don't support synchronization commands */
-	if (param->flags & KGSL_CONTEXT_SYNC)
-		return -EINVAL;
-
-	/* Get the context */
 	context = kgsl_context_get_owner(dev_priv, param->drawctxt_id);
-	if (context == NULL)
+	if (context == NULL) {
+		result = -EINVAL;
 		goto done;
+	}
 
 	if (param->flags & KGSL_CONTEXT_SUBMIT_IB_LIST) {
+		if (!param->numibs) {
+			result = -EINVAL;
+			goto done;
+		}
+
 		/*
-		 * Do a quick sanity check on the number of IBs in the
-		 * submission
+		 * Put a reasonable upper limit on the number of IBs that can be
+		 * submitted
 		 */
 
-		if (param->numibs == 0 || param->numibs > KGSL_MAX_NUMIBS)
+		if (param->numibs > 10000) {
+			result = -EINVAL;
 			goto done;
+		}
 
-		cmdbatch = _kgsl_cmdbatch_create(device, context, param->flags,
-				param->ibdesc_addr, param->numibs, 0, 0);
-	} else
-		cmdbatch = _kgsl_cmdbatch_create_legacy(device, context, param);
+		ibdesc = kzalloc(sizeof(struct kgsl_ibdesc) * param->numibs,
+					GFP_KERNEL);
+		if (!ibdesc) {
+			KGSL_MEM_ERR(dev_priv->device,
+				"kzalloc(%d) failed\n",
+				sizeof(struct kgsl_ibdesc) * param->numibs);
+			result = -ENOMEM;
+			goto done;
+		}
 
-	if (IS_ERR(cmdbatch)) {
-		result = PTR_ERR(cmdbatch);
-		goto done;
+		if (copy_from_user(ibdesc, (void *)param->ibdesc_addr,
+				sizeof(struct kgsl_ibdesc) * param->numibs)) {
+			result = -EFAULT;
+			KGSL_DRV_ERR(dev_priv->device,
+				"copy_from_user failed\n");
+			goto free_ibdesc;
+		}
+	} else {
+		KGSL_DRV_INFO(dev_priv->device,
+			"Using single IB submission mode for ib submission\n");
+		/* If user space driver is still using the old mode of
+		 * submitting single ib then we need to support that as well */
+		ibdesc = kzalloc(sizeof(struct kgsl_ibdesc), GFP_KERNEL);
+		if (!ibdesc) {
+			KGSL_MEM_ERR(dev_priv->device,
+				"kzalloc(%d) failed\n",
+				sizeof(struct kgsl_ibdesc));
+			result = -ENOMEM;
+			goto done;
+		}
+		ibdesc[0].gpuaddr = param->ibdesc_addr;
+		ibdesc[0].sizedwords = param->numibs;
+		param->numibs = 1;
 	}
 
-	/* Run basic sanity checking on the command */
-	if (!_kgsl_cmdbatch_verify(dev_priv, cmdbatch))
-		goto free_cmdbatch;
+	for (i = 0; i < param->numibs; i++) {
+		struct kgsl_pagetable *pt = dev_priv->process_priv->pagetable;
 
-	result = dev_priv->device->ftbl->issueibcmds(dev_priv, context,
-		cmdbatch, &param->timestamp);
-
-free_cmdbatch:
-	if (result)
-		kgsl_cmdbatch_destroy(cmdbatch);
-
-done:
-	kgsl_context_put(context);
-	return result;
-}
-
-static long kgsl_ioctl_submit_commands(struct kgsl_device_private *dev_priv,
-				      unsigned int cmd, void *data)
-{
-	struct kgsl_submit_commands *param = data;
-	struct kgsl_device *device = dev_priv->device;
-	struct kgsl_context *context;
-	struct kgsl_cmdbatch *cmdbatch;
-
-	long result = -EINVAL;
-
-	/* The number of IBs are completely ignored for sync commands */
-	if (!(param->flags & KGSL_CONTEXT_SYNC)) {
-		if (param->numcmds == 0 || param->numcmds > KGSL_MAX_NUMIBS)
-			return -EINVAL;
-	} else if (param->numcmds != 0) {
-		KGSL_DEV_ERR_ONCE(device,
-			"Commands specified with the SYNC flag.  They will be ignored\n");
+		if (!kgsl_mmu_gpuaddr_in_range(pt, ibdesc[i].gpuaddr)) {
+			result = -ERANGE;
+			KGSL_DRV_ERR(dev_priv->device,
+				     "invalid ib base GPU virtual addr %x\n",
+				     ibdesc[i].gpuaddr);
+			goto free_ibdesc;
+		}
 	}
 
-	context = kgsl_context_get_owner(dev_priv, param->context_id);
-	if (context == NULL)
-		return -EINVAL;
+	result = dev_priv->device->ftbl->issueibcmds(dev_priv,
+					     context,
+					     ibdesc,
+					     param->numibs,
+					     &param->timestamp,
+					     param->flags);
 
-	cmdbatch = _kgsl_cmdbatch_create(device, context, param->flags,
-		(unsigned int) param->cmdlist, param->numcmds,
-		(unsigned int) param->synclist, param->numsyncs);
-
-	if (IS_ERR(cmdbatch)) {
-		result = PTR_ERR(cmdbatch);
-		goto done;
-	}
-
-	/* Run basic sanity checking on the command */
-	if (!_kgsl_cmdbatch_verify(dev_priv, cmdbatch))
-		goto free_cmdbatch;
-
-	result = dev_priv->device->ftbl->issueibcmds(dev_priv, context,
-		cmdbatch, &param->timestamp);
-
-free_cmdbatch:
-	if (result)
-		kgsl_cmdbatch_destroy(cmdbatch);
-
+free_ibdesc:
+	kfree(ibdesc);
 done:
 	kgsl_context_put(context);
 	return result;
@@ -2143,11 +1663,14 @@
 {
 	struct kgsl_drawctxt_destroy *param = data;
 	struct kgsl_context *context;
-	long result;
+	long result = -EINVAL;
 
 	context = kgsl_context_get_owner(dev_priv, param->drawctxt_id);
 
-	result = kgsl_context_detach(context);
+	if (context) {
+		kgsl_context_detach(context);
+		result = 0;
+	}
 
 	kgsl_context_put(context);
 	return result;
@@ -3246,7 +2769,7 @@
 } kgsl_ioctl_funcs[] = {
 	KGSL_IOCTL_FUNC(IOCTL_KGSL_DEVICE_GETPROPERTY,
 			kgsl_ioctl_device_getproperty,
-			KGSL_IOCTL_LOCK | KGSL_IOCTL_WAKE),
+			KGSL_IOCTL_LOCK),
 	KGSL_IOCTL_FUNC(IOCTL_KGSL_DEVICE_WAITTIMESTAMP,
 			kgsl_ioctl_device_waittimestamp,
 			KGSL_IOCTL_LOCK | KGSL_IOCTL_WAKE),
@@ -3254,9 +2777,8 @@
 			kgsl_ioctl_device_waittimestamp_ctxtid,
 			KGSL_IOCTL_LOCK | KGSL_IOCTL_WAKE),
 	KGSL_IOCTL_FUNC(IOCTL_KGSL_RINGBUFFER_ISSUEIBCMDS,
-			kgsl_ioctl_rb_issueibcmds, 0),
-	KGSL_IOCTL_FUNC(IOCTL_KGSL_SUBMIT_COMMANDS,
-			kgsl_ioctl_submit_commands, 0),
+			kgsl_ioctl_rb_issueibcmds,
+			KGSL_IOCTL_LOCK | KGSL_IOCTL_WAKE),
 	KGSL_IOCTL_FUNC(IOCTL_KGSL_CMDSTREAM_READTIMESTAMP,
 			kgsl_ioctl_cmdstream_readtimestamp,
 			KGSL_IOCTL_LOCK),
@@ -3265,13 +2787,13 @@
 			KGSL_IOCTL_LOCK),
 	KGSL_IOCTL_FUNC(IOCTL_KGSL_CMDSTREAM_FREEMEMONTIMESTAMP,
 			kgsl_ioctl_cmdstream_freememontimestamp,
-			KGSL_IOCTL_LOCK | KGSL_IOCTL_WAKE),
+			KGSL_IOCTL_LOCK),
 	KGSL_IOCTL_FUNC(IOCTL_KGSL_CMDSTREAM_FREEMEMONTIMESTAMP_CTXTID,
 			kgsl_ioctl_cmdstream_freememontimestamp_ctxtid,
-			KGSL_IOCTL_LOCK | KGSL_IOCTL_WAKE),
+			KGSL_IOCTL_LOCK),
 	KGSL_IOCTL_FUNC(IOCTL_KGSL_DRAWCTXT_CREATE,
 			kgsl_ioctl_drawctxt_create,
-			KGSL_IOCTL_LOCK | KGSL_IOCTL_WAKE),
+			KGSL_IOCTL_LOCK),
 	KGSL_IOCTL_FUNC(IOCTL_KGSL_DRAWCTXT_DESTROY,
 			kgsl_ioctl_drawctxt_destroy,
 			KGSL_IOCTL_LOCK | KGSL_IOCTL_WAKE),
@@ -3291,10 +2813,10 @@
 			kgsl_ioctl_cff_user_event, 0),
 	KGSL_IOCTL_FUNC(IOCTL_KGSL_TIMESTAMP_EVENT,
 			kgsl_ioctl_timestamp_event,
-			KGSL_IOCTL_LOCK | KGSL_IOCTL_WAKE),
+			KGSL_IOCTL_LOCK),
 	KGSL_IOCTL_FUNC(IOCTL_KGSL_SETPROPERTY,
 			kgsl_ioctl_device_setproperty,
-			KGSL_IOCTL_LOCK | KGSL_IOCTL_WAKE),
+			KGSL_IOCTL_LOCK),
 	KGSL_IOCTL_FUNC(IOCTL_KGSL_GPUMEM_ALLOC_ID,
 			kgsl_ioctl_gpumem_alloc_id, 0),
 	KGSL_IOCTL_FUNC(IOCTL_KGSL_GPUMEM_FREE_ID,
@@ -3938,6 +3460,7 @@
 
 
 	setup_timer(&device->idle_timer, kgsl_timer, (unsigned long) device);
+	setup_timer(&device->hang_timer, hang_timer, (unsigned long) device);
 	status = kgsl_create_device_workqueue(device);
 	if (status)
 		goto error_pwrctrl_close;
@@ -3997,6 +3520,7 @@
 
 		if (device->state == KGSL_STATE_ACTIVE)
 			kgsl_idle(device);
+
 	}
 
 	if (device->pm_dump_enable) {
@@ -4010,12 +3534,13 @@
 			pwr->power_flags, pwr->active_pwrlevel);
 
 		KGSL_LOG_DUMP(device, "POWER: INTERVAL TIMEOUT = %08X ",
-				pwr->interval_timeout);
+			pwr->interval_timeout);
 
 	}
 
 	/* Disable the idle timer so we don't get interrupted */
 	del_timer_sync(&device->idle_timer);
+	del_timer_sync(&device->hang_timer);
 
 	/* Force on the clocks */
 	kgsl_pwrctrl_wake(device);
diff --git a/drivers/gpu/msm/kgsl.h b/drivers/gpu/msm/kgsl.h
index 2e9d52e..8d390a9 100644
--- a/drivers/gpu/msm/kgsl.h
+++ b/drivers/gpu/msm/kgsl.h
@@ -78,8 +78,6 @@
 
 #define KGSL_MEMFREE_HIST_SIZE	((int)(PAGE_SIZE * 2))
 
-#define KGSL_MAX_NUMIBS 100000
-
 struct kgsl_memfree_hist_elem {
 	unsigned int pid;
 	unsigned int gpuaddr;
@@ -143,7 +141,6 @@
 
 struct kgsl_pagetable;
 struct kgsl_memdesc;
-struct kgsl_cmdbatch;
 
 struct kgsl_memdesc_ops {
 	int (*vmflags)(struct kgsl_memdesc *);
@@ -208,6 +205,7 @@
 #define MMU_CONFIG 1
 #endif
 
+void kgsl_hang_check(struct work_struct *work);
 void kgsl_mem_entry_destroy(struct kref *kref);
 int kgsl_postmortem_dump(struct kgsl_device *device, int manual);
 
@@ -239,7 +237,7 @@
 		unsigned int value);
 
 void kgsl_trace_issueibcmds(struct kgsl_device *device, int id,
-		struct kgsl_cmdbatch *cmdbatch,
+		struct kgsl_ibdesc *ibdesc, int numibs,
 		unsigned int timestamp, unsigned int flags,
 		int result, unsigned int type);
 
diff --git a/drivers/gpu/msm/kgsl_debugfs.c b/drivers/gpu/msm/kgsl_debugfs.c
index 110264b..e623515 100644
--- a/drivers/gpu/msm/kgsl_debugfs.c
+++ b/drivers/gpu/msm/kgsl_debugfs.c
@@ -19,7 +19,6 @@
 #include "kgsl_sharedmem.h"
 
 /*default log levels is error for everything*/
-#define KGSL_LOG_LEVEL_DEFAULT 3
 #define KGSL_LOG_LEVEL_MAX     7
 
 struct dentry *kgsl_debugfs_dir;
@@ -123,6 +122,7 @@
 KGSL_DEBUGFS_LOG(ctxt_log);
 KGSL_DEBUGFS_LOG(mem_log);
 KGSL_DEBUGFS_LOG(pwr_log);
+KGSL_DEBUGFS_LOG(ft_log);
 
 static int memfree_hist_print(struct seq_file *s, void *unused)
 {
@@ -179,12 +179,6 @@
 	if (!device->d_debugfs || IS_ERR(device->d_debugfs))
 		return;
 
-	device->cmd_log = KGSL_LOG_LEVEL_DEFAULT;
-	device->ctxt_log = KGSL_LOG_LEVEL_DEFAULT;
-	device->drv_log = KGSL_LOG_LEVEL_DEFAULT;
-	device->mem_log = KGSL_LOG_LEVEL_DEFAULT;
-	device->pwr_log = KGSL_LOG_LEVEL_DEFAULT;
-
 	debugfs_create_file("log_level_cmd", 0644, device->d_debugfs, device,
 			    &cmd_log_fops);
 	debugfs_create_file("log_level_ctxt", 0644, device->d_debugfs, device,
@@ -197,6 +191,8 @@
 				&pwr_log_fops);
 	debugfs_create_file("memfree_history", 0444, device->d_debugfs, device,
 				&memfree_hist_fops);
+	debugfs_create_file("log_level_ft", 0644, device->d_debugfs, device,
+				&ft_log_fops);
 
 	/* Create postmortem dump control files */
 
@@ -211,7 +207,6 @@
 			    &pm_regs_enabled_fops);
 	debugfs_create_file("ib_enabled", 0644, pm_d_debugfs, device,
 				    &pm_ib_enabled_fops);
-	device->pm_dump_enable = 0;
 	debugfs_create_file("enable", 0644, pm_d_debugfs, device,
 				    &pm_enabled_fops);
 
diff --git a/drivers/gpu/msm/kgsl_debugfs.h b/drivers/gpu/msm/kgsl_debugfs.h
index b2f137c..fe9bc76 100644
--- a/drivers/gpu/msm/kgsl_debugfs.h
+++ b/drivers/gpu/msm/kgsl_debugfs.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2002,2008-2011, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2002,2008-2011,2013, The Linux Foundation. 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 and
@@ -35,7 +35,7 @@
 static inline void kgsl_device_debugfs_init(struct kgsl_device *device) { }
 static inline void kgsl_core_debugfs_close(void) { }
 static inline struct dentry *kgsl_get_debugfs_dir(void) { return NULL; }
-static inline int kgsl_process_init_debugfs(struct kgsl_process_private *)
+static inline int kgsl_process_init_debugfs(struct kgsl_process_private *priv)
 {
 	return 0;
 }
diff --git a/drivers/gpu/msm/kgsl_device.h b/drivers/gpu/msm/kgsl_device.h
index cd9c4f7..0b5fe52 100644
--- a/drivers/gpu/msm/kgsl_device.h
+++ b/drivers/gpu/msm/kgsl_device.h
@@ -13,7 +13,6 @@
 #ifndef __KGSL_DEVICE_H
 #define __KGSL_DEVICE_H
 
-#include <linux/slab.h>
 #include <linux/idr.h>
 #include <linux/pm_qos.h>
 #include <linux/sched.h>
@@ -77,7 +76,6 @@
 struct kgsl_context;
 struct kgsl_power_stats;
 struct kgsl_event;
-struct kgsl_cmdbatch;
 
 struct kgsl_functable {
 	/* Mandatory functions - these functions must be implemented
@@ -89,7 +87,7 @@
 	void (*regwrite) (struct kgsl_device *device,
 		unsigned int offsetwords, unsigned int value);
 	int (*idle) (struct kgsl_device *device);
-	bool (*isidle) (struct kgsl_device *device);
+	unsigned int (*isidle) (struct kgsl_device *device);
 	int (*suspend_context) (struct kgsl_device *device);
 	int (*init) (struct kgsl_device *device);
 	int (*start) (struct kgsl_device *device);
@@ -103,8 +101,9 @@
 	unsigned int (*readtimestamp) (struct kgsl_device *device,
 		struct kgsl_context *context, enum kgsl_timestamp_type type);
 	int (*issueibcmds) (struct kgsl_device_private *dev_priv,
-		struct kgsl_context *context, struct kgsl_cmdbatch *cmdbatch,
-		uint32_t *timestamps);
+		struct kgsl_context *context, struct kgsl_ibdesc *ibdesc,
+		unsigned int sizedwords, uint32_t *timestamp,
+		unsigned int flags);
 	int (*setup_pt)(struct kgsl_device *device,
 		struct kgsl_pagetable *pagetable);
 	void (*cleanup_pt)(struct kgsl_device *device,
@@ -116,15 +115,14 @@
 	void * (*snapshot)(struct kgsl_device *device, void *snapshot,
 		int *remain, int hang);
 	irqreturn_t (*irq_handler)(struct kgsl_device *device);
-	int (*drain)(struct kgsl_device *device);
 	/* Optional functions - these functions are not mandatory.  The
 	   driver will check that the function pointer is not NULL before
 	   calling the hook */
-	int (*setstate) (struct kgsl_device *device, unsigned int context_id,
+	void (*setstate) (struct kgsl_device *device, unsigned int context_id,
 			uint32_t flags);
 	struct kgsl_context *(*drawctxt_create) (struct kgsl_device_private *,
 						uint32_t *flags);
-	int (*drawctxt_detach) (struct kgsl_context *context);
+	void (*drawctxt_detach) (struct kgsl_context *context);
 	void (*drawctxt_destroy) (struct kgsl_context *context);
 	long (*ioctl) (struct kgsl_device_private *dev_priv,
 		unsigned int cmd, void *data);
@@ -134,8 +132,6 @@
 	int (*postmortem_dump) (struct kgsl_device *device, int manual);
 	int (*next_event)(struct kgsl_device *device,
 		struct kgsl_event *event);
-	void (*drawctxt_sched)(struct kgsl_device *device,
-		struct kgsl_context *context);
 };
 
 /* MH register values */
@@ -159,56 +155,6 @@
 	unsigned int created;
 };
 
-/**
- * struct kgsl_cmdbatch - KGSl command descriptor
- * @device: KGSL GPU device that the command was created for
- * @context: KGSL context that created the command
- * @timestamp: Timestamp assigned to the command
- * @flags: flags
- * @priv: Internal flags
- * @fault_policy: Internal policy describing how to handle this command in case
- * of a fault
- * @fault_recovery: recovery actions actually tried for this batch
- * @ibcount: Number of IBs in the command list
- * @ibdesc: Pointer to the list of IBs
- * @expires: Point in time when the cmdbatch is considered to be hung
- * @invalid:  non-zero if the dispatcher determines the command and the owning
- * context should be invalidated
- * @refcount: kref structure to maintain the reference count
- * @synclist: List of context/timestamp tuples to wait for before issuing
- *
- * This struture defines an atomic batch of command buffers issued from
- * userspace.
- */
-struct kgsl_cmdbatch {
-	struct kgsl_device *device;
-	struct kgsl_context *context;
-	spinlock_t lock;
-	uint32_t timestamp;
-	uint32_t flags;
-	unsigned long priv;
-	unsigned long fault_policy;
-	unsigned long fault_recovery;
-	uint32_t ibcount;
-	struct kgsl_ibdesc *ibdesc;
-	unsigned long expires;
-	int invalid;
-	struct kref refcount;
-	struct list_head synclist;
-};
-
-/**
- * enum kgsl_cmdbatch_priv - Internal cmdbatch flags
- * @CMDBATCH_FLAG_SKIP - skip the entire command batch
- * @CMDBATCH_FLAG_FORCE_PREAMBLE - Force the preamble on for the cmdbatch
- * @CMDBATCH_FLAG_WFI - Force wait-for-idle for the submission
- */
-
-enum kgsl_cmdbatch_priv {
-	CMDBATCH_FLAG_SKIP = 0,
-	CMDBATCH_FLAG_FORCE_PREAMBLE,
-	CMDBATCH_FLAG_WFI,
-};
 
 struct kgsl_device {
 	struct device *dev;
@@ -244,7 +190,9 @@
 	struct completion hwaccess_gate;
 	const struct kgsl_functable *ftbl;
 	struct work_struct idle_check_ws;
+	struct work_struct hang_check_ws;
 	struct timer_list idle_timer;
+	struct timer_list hang_timer;
 	struct kgsl_pwrctrl pwrctrl;
 	int open_count;
 
@@ -258,6 +206,7 @@
 	wait_queue_head_t active_cnt_wq;
 	struct workqueue_struct *work_queue;
 	struct device *parentdev;
+	struct completion ft_gate;
 	struct dentry *d_debugfs;
 	struct idr context_idr;
 	rwlock_t context_lock;
@@ -284,13 +233,13 @@
 	int drv_log;
 	int mem_log;
 	int pwr_log;
+	int ft_log;
 	int pm_dump_enable;
 	struct kgsl_pwrscale pwrscale;
 	struct kobject pwrscale_kobj;
 	struct work_struct ts_expired_ws;
 	struct list_head events;
 	struct list_head events_pending_list;
-	unsigned int events_last_timestamp;
 	s64 on_time;
 
 	/* Postmortem Control switches */
@@ -305,8 +254,11 @@
 
 #define KGSL_DEVICE_COMMON_INIT(_dev) \
 	.hwaccess_gate = COMPLETION_INITIALIZER((_dev).hwaccess_gate),\
+	.ft_gate = COMPLETION_INITIALIZER((_dev).ft_gate),\
 	.idle_check_ws = __WORK_INITIALIZER((_dev).idle_check_ws,\
 			kgsl_idle_check),\
+	.hang_check_ws = __WORK_INITIALIZER((_dev).hang_check_ws,\
+			kgsl_hang_check),\
 	.ts_expired_ws  = __WORK_INITIALIZER((_dev).ts_expired_ws,\
 			kgsl_process_events),\
 	.context_idr = IDR_INIT((_dev).context_idr),\
@@ -363,8 +315,23 @@
 	unsigned int pagefault_ts;
 };
 
+/**
+ * struct kgsl_process_private -  Private structure for a KGSL process (across
+ * all devices)
+ * @priv: Internal flags, use KGSL_PROCESS_* values
+ * @pid: ID for the task owner of the process
+ * @mem_lock: Spinlock to protect the process memory lists
+ * @refcount: kref object for reference counting the process
+ * @process_private_mutex: Mutex to synchronize access to the process struct
+ * @mem_rb: RB tree node for the memory owned by this process
+ * @idr: Iterator for assigning IDs to memory allocations
+ * @pagetable: Pointer to the pagetable owned by this process
+ * @kobj: Pointer to a kobj for the sysfs directory for this process
+ * @debug_root: Pointer to the debugfs root for this process
+ * @stats: Memory allocation statistics for this process
+ */
 struct kgsl_process_private {
-	unsigned int refcnt;
+	unsigned long priv;
 	pid_t pid;
 	spinlock_t mem_lock;
 
@@ -386,6 +353,14 @@
 	} stats[KGSL_MEM_ENTRY_MAX];
 };
 
+/**
+ * enum kgsl_process_priv_flags - Private flags for kgsl_process_private
+ * @KGSL_PROCESS_INIT: Set if the process structure has been set up
+ */
+enum kgsl_process_priv_flags {
+	KGSL_PROCESS_INIT = 0,
+};
+
 struct kgsl_device_private {
 	struct kgsl_device *device;
 	struct kgsl_process_private *process_priv;
@@ -401,9 +376,6 @@
 int kgsl_add_event(struct kgsl_device *device, u32 id, u32 ts,
 	kgsl_event_func func, void *priv, void *owner);
 
-void kgsl_cancel_event(struct kgsl_device *device, struct kgsl_context *context,
-		unsigned int timestamp, kgsl_event_func func, void *priv);
-
 static inline void kgsl_process_add_stats(struct kgsl_process_private *priv,
 	unsigned int type, size_t size)
 {
@@ -491,6 +463,8 @@
 	return 0;
 }
 
+
+
 int kgsl_check_timestamp(struct kgsl_device *device,
 		struct kgsl_context *context, unsigned int timestamp);
 
@@ -646,40 +620,4 @@
 {
 	kgsl_signal_event(device, context, timestamp, KGSL_EVENT_CANCELLED);
 }
-
-void kgsl_cmdbatch_destroy(struct kgsl_cmdbatch *cmdbatch);
-
-void kgsl_cmdbatch_destroy_object(struct kref *kref);
-
-/**
- * kgsl_cmdbatch_put() - Decrement the refcount for a command batch object
- * @cmdbatch: Pointer to the command batch object
- */
-static inline void kgsl_cmdbatch_put(struct kgsl_cmdbatch *cmdbatch)
-{
-	if (cmdbatch)
-		kref_put(&cmdbatch->refcount, kgsl_cmdbatch_destroy_object);
-}
-
-/**
- * kgsl_cmdbatch_sync_pending() - return true if the cmdbatch is waiting
- * @cmdbatch: Pointer to the command batch object to check
- *
- * Return non-zero if the specified command batch is still waiting for sync
- * point dependencies to be satisfied
- */
-static inline int kgsl_cmdbatch_sync_pending(struct kgsl_cmdbatch *cmdbatch)
-{
-	int ret;
-
-	if (cmdbatch == NULL)
-		return 0;
-
-	spin_lock(&cmdbatch->lock);
-	ret = list_empty(&cmdbatch->synclist) ? 0 : 1;
-	spin_unlock(&cmdbatch->lock);
-
-	return ret;
-}
-
 #endif  /* __KGSL_DEVICE_H */
diff --git a/drivers/gpu/msm/kgsl_events.c b/drivers/gpu/msm/kgsl_events.c
index c7ac0ad..9e8f6d0 100644
--- a/drivers/gpu/msm/kgsl_events.c
+++ b/drivers/gpu/msm/kgsl_events.c
@@ -48,8 +48,7 @@
 {
 	int id = event->context ? event->context->id : KGSL_MEMSTORE_GLOBAL;
 
-	trace_kgsl_fire_event(id, timestamp, type, jiffies - event->created,
-		event->func);
+	trace_kgsl_fire_event(id, timestamp, type, jiffies - event->created);
 
 	if (event->func)
 		event->func(device, event->priv, id, timestamp, type);
@@ -236,7 +235,7 @@
 	 */
 
 	if (timestamp_cmp(cur_ts, ts) >= 0) {
-		trace_kgsl_fire_event(id, cur_ts, ts, 0, func);
+		trace_kgsl_fire_event(id, cur_ts, ts, 0);
 
 		func(device, priv, id, ts, KGSL_EVENT_TIMESTAMP_RETIRED);
 		kgsl_context_put(context);
@@ -253,7 +252,7 @@
 	 * Increase the active count on the device to avoid going into power
 	 * saving modes while events are pending
 	 */
-	ret = kgsl_active_count_get_light(device);
+	ret = kgsl_active_count_get(device);
 	if (ret < 0) {
 		kgsl_context_put(context);
 		kfree(event);
@@ -267,7 +266,7 @@
 	event->owner = owner;
 	event->created = jiffies;
 
-	trace_kgsl_register_event(id, ts, func);
+	trace_kgsl_register_event(id, ts);
 
 	/* Add the event to either the owning context or the global list */
 
@@ -334,11 +333,7 @@
 		void *priv)
 {
 	struct kgsl_event *event;
-	struct list_head *head;
-
-	BUG_ON(!mutex_is_locked(&device->mutex));
-
-	head = _get_list_head(device, context);
+	struct list_head *head = _get_list_head(device, context);
 
 	event = _find_event(device, head, timestamp, func, priv);
 
@@ -405,19 +400,10 @@
 	struct kgsl_context *context, *tmp;
 	uint32_t timestamp;
 
-	/*
-	 * Bail unless the global timestamp has advanced.  We can safely do this
-	 * outside of the mutex for speed
-	 */
-
-	timestamp = kgsl_readtimestamp(device, NULL, KGSL_TIMESTAMP_RETIRED);
-	if (timestamp == device->events_last_timestamp)
-		return;
-
 	mutex_lock(&device->mutex);
 
-	device->events_last_timestamp = timestamp;
-
+	/* Process expired global events */
+	timestamp = kgsl_readtimestamp(device, NULL, KGSL_TIMESTAMP_RETIRED);
 	_retire_events(device, &device->events, timestamp);
 	_mark_next_event(device, &device->events);
 
diff --git a/drivers/gpu/msm/kgsl_gpummu.c b/drivers/gpu/msm/kgsl_gpummu.c
index 2634e4f..68052b1 100644
--- a/drivers/gpu/msm/kgsl_gpummu.c
+++ b/drivers/gpu/msm/kgsl_gpummu.c
@@ -482,17 +482,15 @@
 	return NULL;
 }
 
-static int kgsl_gpummu_default_setstate(struct kgsl_mmu *mmu,
+static void kgsl_gpummu_default_setstate(struct kgsl_mmu *mmu,
 					uint32_t flags)
 {
 	struct kgsl_gpummu_pt *gpummu_pt;
 	if (!kgsl_mmu_enabled())
-		return 0;
+		return;
 
 	if (flags & KGSL_MMUFLAGS_PTUPDATE) {
-		int ret = kgsl_idle(mmu->device);
-		if (ret)
-			return ret;
+		kgsl_idle(mmu->device);
 		gpummu_pt = mmu->hwpagetable->priv;
 		kgsl_regwrite(mmu->device, MH_MMU_PT_BASE,
 			gpummu_pt->base.gpuaddr);
@@ -502,16 +500,12 @@
 		/* Invalidate all and tc */
 		kgsl_regwrite(mmu->device, MH_MMU_INVALIDATE,  0x00000003);
 	}
-
-	return 0;
 }
 
-static int kgsl_gpummu_setstate(struct kgsl_mmu *mmu,
+static void kgsl_gpummu_setstate(struct kgsl_mmu *mmu,
 				struct kgsl_pagetable *pagetable,
 				unsigned int context_id)
 {
-	int ret = 0;
-
 	if (mmu->flags & KGSL_FLAGS_STARTED) {
 		/* page table not current, then setup mmu to use new
 		 *  specified page table
@@ -524,13 +518,10 @@
 			kgsl_mmu_pt_get_flags(pagetable, mmu->device->id);
 
 			/* call device specific set page table */
-			ret = kgsl_setstate(mmu, context_id,
-				KGSL_MMUFLAGS_TLBFLUSH |
+			kgsl_setstate(mmu, context_id, KGSL_MMUFLAGS_TLBFLUSH |
 				KGSL_MMUFLAGS_PTUPDATE);
 		}
 	}
-
-	return ret;
 }
 
 static int kgsl_gpummu_init(struct kgsl_mmu *mmu)
@@ -572,7 +563,6 @@
 
 	struct kgsl_device *device = mmu->device;
 	struct kgsl_gpummu_pt *gpummu_pt;
-	int ret;
 
 	if (mmu->flags & KGSL_FLAGS_STARTED)
 		return 0;
@@ -584,6 +574,9 @@
 	/* setup MMU and sub-client behavior */
 	kgsl_regwrite(device, MH_MMU_CONFIG, mmu->config);
 
+	/* idle device */
+	kgsl_idle(device);
+
 	/* enable axi interrupts */
 	kgsl_regwrite(device, MH_INTERRUPT_MASK,
 			GSL_MMU_INT_MASK | MH_INTERRUPT_MASK__MMU_PAGE_FAULT);
@@ -614,12 +607,10 @@
 	kgsl_regwrite(mmu->device, MH_MMU_VA_RANGE,
 		      (KGSL_PAGETABLE_BASE |
 		      (CONFIG_MSM_KGSL_PAGE_TABLE_SIZE >> 16)));
+	kgsl_setstate(mmu, KGSL_MEMSTORE_GLOBAL, KGSL_MMUFLAGS_TLBFLUSH);
+	mmu->flags |= KGSL_FLAGS_STARTED;
 
-	ret = kgsl_setstate(mmu, KGSL_MEMSTORE_GLOBAL, KGSL_MMUFLAGS_TLBFLUSH);
-	if (!ret)
-		mmu->flags |= KGSL_FLAGS_STARTED;
-
-	return ret;
+	return 0;
 }
 
 static int
diff --git a/drivers/gpu/msm/kgsl_iommu.c b/drivers/gpu/msm/kgsl_iommu.c
index e296784..ecda5a7 100644
--- a/drivers/gpu/msm/kgsl_iommu.c
+++ b/drivers/gpu/msm/kgsl_iommu.c
@@ -423,12 +423,8 @@
 	 * the GPU and trigger a snapshot. To stall the transaction return
 	 * EBUSY error.
 	 */
-	if (adreno_dev->ft_pf_policy & KGSL_FT_PAGEFAULT_GPUHALT_ENABLE) {
-		/* turn off GPU IRQ so we don't get faults from it too */
-		kgsl_pwrctrl_irq(device, KGSL_PWRFLAGS_OFF);
-		adreno_dispatcher_irq_fault(device);
+	if (adreno_dev->ft_pf_policy & KGSL_FT_PAGEFAULT_GPUHALT_ENABLE)
 		ret = -EBUSY;
-	}
 done:
 	return ret;
 }
@@ -1209,12 +1205,10 @@
 	return 0;
 }
 
-static int kgsl_iommu_setstate(struct kgsl_mmu *mmu,
+static void kgsl_iommu_setstate(struct kgsl_mmu *mmu,
 				struct kgsl_pagetable *pagetable,
 				unsigned int context_id)
 {
-	int ret = 0;
-
 	if (mmu->flags & KGSL_FLAGS_STARTED) {
 		/* page table not current, then setup mmu to use new
 		 *  specified page table
@@ -1225,12 +1219,10 @@
 			flags |= kgsl_mmu_pt_get_flags(mmu->hwpagetable,
 							mmu->device->id) |
 							KGSL_MMUFLAGS_TLBFLUSH;
-			ret = kgsl_setstate(mmu, context_id,
+			kgsl_setstate(mmu, context_id,
 				KGSL_MMUFLAGS_PTUPDATE | flags);
 		}
 	}
-
-	return ret;
 }
 
 /*
@@ -1900,40 +1892,31 @@
  * cpu
  * Return - void
  */
-static int kgsl_iommu_default_setstate(struct kgsl_mmu *mmu,
+static void kgsl_iommu_default_setstate(struct kgsl_mmu *mmu,
 					uint32_t flags)
 {
 	struct kgsl_iommu *iommu = mmu->priv;
 	int temp;
 	int i;
-	int ret = 0;
 	phys_addr_t pt_base = kgsl_iommu_get_pt_base_addr(mmu,
 						mmu->hwpagetable);
 	phys_addr_t pt_val;
 
-	ret = kgsl_iommu_enable_clk(mmu, KGSL_IOMMU_CONTEXT_USER);
-
-	if (ret) {
+	if (kgsl_iommu_enable_clk(mmu, KGSL_IOMMU_CONTEXT_USER)) {
 		KGSL_DRV_ERR(mmu->device, "Failed to enable iommu clocks\n");
-		return ret;
+		return;
 	}
 
 	/* For v0 SMMU GPU needs to be idle for tlb invalidate as well */
-	if (msm_soc_version_supports_iommu_v0()) {
-		ret = kgsl_idle(mmu->device);
-		if (ret)
-			return ret;
-	}
+	if (msm_soc_version_supports_iommu_v0())
+		kgsl_idle(mmu->device);
 
 	/* Acquire GPU-CPU sync Lock here */
 	_iommu_lock();
 
 	if (flags & KGSL_MMUFLAGS_PTUPDATE) {
-		if (!msm_soc_version_supports_iommu_v0()) {
-			ret = kgsl_idle(mmu->device);
-			if (ret)
-				goto unlock;
-		}
+		if (!msm_soc_version_supports_iommu_v0())
+			kgsl_idle(mmu->device);
 		for (i = 0; i < iommu->unit_count; i++) {
 			/* get the lsb value which should not change when
 			 * changing ttbr0 */
@@ -1994,13 +1977,12 @@
 			}
 		}
 	}
-unlock:
+
 	/* Release GPU-CPU sync Lock here */
 	_iommu_unlock();
 
 	/* Disable smmu clock */
 	kgsl_iommu_disable_clk_on_ts(mmu, 0, false);
-	return ret;
 }
 
 /*
@@ -2057,7 +2039,6 @@
 	.mmu_pagefault_resume = kgsl_iommu_pagefault_resume,
 	.mmu_get_current_ptbase = kgsl_iommu_get_current_ptbase,
 	.mmu_enable_clk = kgsl_iommu_enable_clk,
-	.mmu_disable_clk = kgsl_iommu_disable_clk,
 	.mmu_disable_clk_on_ts = kgsl_iommu_disable_clk_on_ts,
 	.mmu_get_default_ttbr0 = kgsl_iommu_get_default_ttbr0,
 	.mmu_get_reg_gpuaddr = kgsl_iommu_get_reg_gpuaddr,
diff --git a/drivers/gpu/msm/kgsl_log.h b/drivers/gpu/msm/kgsl_log.h
index 3a32953..a7832e4 100644
--- a/drivers/gpu/msm/kgsl_log.h
+++ b/drivers/gpu/msm/kgsl_log.h
@@ -103,6 +103,15 @@
 #define KGSL_PWR_CRIT(_dev, fmt, args...) \
 KGSL_LOG_CRIT(_dev->dev, _dev->pwr_log, fmt, ##args)
 
+#define KGSL_FT_INFO(_dev, fmt, args...) \
+KGSL_LOG_INFO(_dev->dev, _dev->ft_log, fmt, ##args)
+#define KGSL_FT_WARN(_dev, fmt, args...) \
+KGSL_LOG_WARN(_dev->dev, _dev->ft_log, fmt, ##args)
+#define KGSL_FT_ERR(_dev, fmt, args...) \
+KGSL_LOG_ERR(_dev->dev, _dev->ft_log, fmt, ##args)
+#define KGSL_FT_CRIT(_dev, fmt, args...) \
+KGSL_LOG_CRIT(_dev->dev, _dev->ft_log, fmt, ##args)
+
 /* Core error messages - these are for core KGSL functions that have
    no device associated with them (such as memory) */
 
diff --git a/drivers/gpu/msm/kgsl_mmu.c b/drivers/gpu/msm/kgsl_mmu.c
index 6635a7c..952019f 100644
--- a/drivers/gpu/msm/kgsl_mmu.c
+++ b/drivers/gpu/msm/kgsl_mmu.c
@@ -566,7 +566,7 @@
 }
 EXPORT_SYMBOL(kgsl_mmu_putpagetable);
 
-int kgsl_setstate(struct kgsl_mmu *mmu, unsigned int context_id,
+void kgsl_setstate(struct kgsl_mmu *mmu, unsigned int context_id,
 			uint32_t flags)
 {
 	struct kgsl_device *device = mmu->device;
@@ -574,16 +574,14 @@
 
 	if (!(flags & (KGSL_MMUFLAGS_TLBFLUSH | KGSL_MMUFLAGS_PTUPDATE))
 		&& !adreno_is_a2xx(adreno_dev))
-		return 0;
+		return;
 
 	if (KGSL_MMU_TYPE_NONE == kgsl_mmu_type)
-		return 0;
+		return;
 	else if (device->ftbl->setstate)
-		return device->ftbl->setstate(device, context_id, flags);
+		device->ftbl->setstate(device, context_id, flags);
 	else if (mmu->mmu_ops->mmu_device_setstate)
-		return mmu->mmu_ops->mmu_device_setstate(mmu, flags);
-
-	return 0;
+		mmu->mmu_ops->mmu_device_setstate(mmu, flags);
 }
 EXPORT_SYMBOL(kgsl_setstate);
 
@@ -592,6 +590,7 @@
 	struct kgsl_mh *mh = &device->mh;
 	/* force mmu off to for now*/
 	kgsl_regwrite(device, MH_MMU_CONFIG, 0);
+	kgsl_idle(device);
 
 	/* define physical memory range accessible by the core */
 	kgsl_regwrite(device, MH_MMU_MPU_BASE, mh->mpu_base);
diff --git a/drivers/gpu/msm/kgsl_mmu.h b/drivers/gpu/msm/kgsl_mmu.h
index a30ee3f..faba81e 100644
--- a/drivers/gpu/msm/kgsl_mmu.h
+++ b/drivers/gpu/msm/kgsl_mmu.h
@@ -133,10 +133,10 @@
 	int (*mmu_close) (struct kgsl_mmu *mmu);
 	int (*mmu_start) (struct kgsl_mmu *mmu);
 	void (*mmu_stop) (struct kgsl_mmu *mmu);
-	int (*mmu_setstate) (struct kgsl_mmu *mmu,
+	void (*mmu_setstate) (struct kgsl_mmu *mmu,
 		struct kgsl_pagetable *pagetable,
 		unsigned int context_id);
-	int (*mmu_device_setstate) (struct kgsl_mmu *mmu,
+	void (*mmu_device_setstate) (struct kgsl_mmu *mmu,
 					uint32_t flags);
 	void (*mmu_pagefault) (struct kgsl_mmu *mmu);
 	phys_addr_t (*mmu_get_current_ptbase)
@@ -147,8 +147,6 @@
 		(struct kgsl_mmu *mmu, uint32_t ts, bool ts_valid);
 	int (*mmu_enable_clk)
 		(struct kgsl_mmu *mmu, int ctx_id);
-	void (*mmu_disable_clk)
-		(struct kgsl_mmu *mmu);
 	phys_addr_t (*mmu_get_default_ttbr0)(struct kgsl_mmu *mmu,
 				unsigned int unit_id,
 				enum kgsl_iommu_context_id ctx_id);
@@ -233,7 +231,7 @@
 int kgsl_mmu_put_gpuaddr(struct kgsl_pagetable *pagetable,
 		 struct kgsl_memdesc *memdesc);
 unsigned int kgsl_virtaddr_to_physaddr(void *virtaddr);
-int kgsl_setstate(struct kgsl_mmu *mmu, unsigned int context_id,
+void kgsl_setstate(struct kgsl_mmu *mmu, unsigned int context_id,
 			uint32_t flags);
 int kgsl_mmu_get_ptname_from_ptbase(struct kgsl_mmu *mmu,
 					phys_addr_t pt_base);
@@ -262,23 +260,19 @@
 		return 0;
 }
 
-static inline int kgsl_mmu_setstate(struct kgsl_mmu *mmu,
+static inline void kgsl_mmu_setstate(struct kgsl_mmu *mmu,
 			struct kgsl_pagetable *pagetable,
 			unsigned int context_id)
 {
 	if (mmu->mmu_ops && mmu->mmu_ops->mmu_setstate)
-		return mmu->mmu_ops->mmu_setstate(mmu, pagetable, context_id);
-
-	return 0;
+		mmu->mmu_ops->mmu_setstate(mmu, pagetable, context_id);
 }
 
-static inline int kgsl_mmu_device_setstate(struct kgsl_mmu *mmu,
+static inline void kgsl_mmu_device_setstate(struct kgsl_mmu *mmu,
 						uint32_t flags)
 {
 	if (mmu->mmu_ops && mmu->mmu_ops->mmu_device_setstate)
-		return mmu->mmu_ops->mmu_device_setstate(mmu, flags);
-
-	return 0;
+		mmu->mmu_ops->mmu_device_setstate(mmu, flags);
 }
 
 static inline void kgsl_mmu_stop(struct kgsl_mmu *mmu)
@@ -326,12 +320,6 @@
 		return 0;
 }
 
-static inline void kgsl_mmu_disable_clk(struct kgsl_mmu *mmu)
-{
-	if (mmu->mmu_ops && mmu->mmu_ops->mmu_disable_clk)
-		mmu->mmu_ops->mmu_disable_clk(mmu);
-}
-
 static inline void kgsl_mmu_disable_clk_on_ts(struct kgsl_mmu *mmu,
 						unsigned int ts, bool ts_valid)
 {
diff --git a/drivers/gpu/msm/kgsl_pwrctrl.c b/drivers/gpu/msm/kgsl_pwrctrl.c
index 07131f7..6faf0bf 100644
--- a/drivers/gpu/msm/kgsl_pwrctrl.c
+++ b/drivers/gpu/msm/kgsl_pwrctrl.c
@@ -1215,6 +1215,9 @@
 		} else {
 			device->pwrctrl.irq_last = 0;
 		}
+	} else if (device->state & (KGSL_STATE_HUNG |
+					KGSL_STATE_DUMP_AND_FT)) {
+		kgsl_pwrctrl_request_state(device, KGSL_STATE_NONE);
 	}
 
 	mutex_unlock(&device->mutex);
@@ -1270,6 +1273,7 @@
 			kgsl_pwrctrl_request_state(device, KGSL_STATE_NONE);
 			return -EBUSY;
 		}
+		del_timer_sync(&device->hang_timer);
 		kgsl_pwrctrl_irq(device, KGSL_PWRFLAGS_OFF);
 		kgsl_pwrctrl_clk(device, KGSL_PWRFLAGS_OFF, KGSL_STATE_NAP);
 		kgsl_pwrctrl_set_state(device, KGSL_STATE_NAP);
@@ -1339,6 +1343,7 @@
 	case KGSL_STATE_NAP:
 	case KGSL_STATE_SLEEP:
 		del_timer_sync(&device->idle_timer);
+		del_timer_sync(&device->hang_timer);
 		/* make sure power is on to stop the device*/
 		kgsl_pwrctrl_enable(device);
 		device->ftbl->suspend_context(device);
@@ -1430,11 +1435,15 @@
 		kgsl_pwrctrl_set_state(device, KGSL_STATE_ACTIVE);
 		kgsl_pwrctrl_irq(device, KGSL_PWRFLAGS_ON);
 
+		mod_timer(&device->hang_timer,
+			(jiffies + msecs_to_jiffies(KGSL_TIMEOUT_PART)));
 		pm_qos_update_request(&device->pwrctrl.pm_qos_req_dma,
 				device->pwrctrl.pm_qos_latency);
 	case KGSL_STATE_ACTIVE:
 		kgsl_pwrctrl_request_state(device, KGSL_STATE_NONE);
 		break;
+	case KGSL_STATE_INIT:
+		break;
 	default:
 		KGSL_PWR_WARN(device, "unhandled state %s\n",
 				kgsl_pwrstate_to_str(device->state));
@@ -1497,6 +1506,10 @@
 		return "SLEEP";
 	case KGSL_STATE_SUSPEND:
 		return "SUSPEND";
+	case KGSL_STATE_HUNG:
+		return "HUNG";
+	case KGSL_STATE_DUMP_AND_FT:
+		return "DNR";
 	case KGSL_STATE_SLUMBER:
 		return "SLUMBER";
 	default:
@@ -1526,9 +1539,13 @@
 
 	if ((atomic_read(&device->active_cnt) == 0) &&
 		(device->state != KGSL_STATE_ACTIVE)) {
-		mutex_unlock(&device->mutex);
-		wait_for_completion(&device->hwaccess_gate);
-		mutex_lock(&device->mutex);
+
+		if (device->state != KGSL_STATE_DUMP_AND_FT) {
+			mutex_unlock(&device->mutex);
+			wait_for_completion(&device->hwaccess_gate);
+			wait_for_completion(&device->ft_gate);
+			mutex_lock(&device->mutex);
+		}
 
 		/* Stop the idle timer */
 		del_timer_sync(&device->idle_timer);
diff --git a/drivers/gpu/msm/kgsl_pwrscale_trustzone.c b/drivers/gpu/msm/kgsl_pwrscale_trustzone.c
index 8fc1753..7f8a6b1 100644
--- a/drivers/gpu/msm/kgsl_pwrscale_trustzone.c
+++ b/drivers/gpu/msm/kgsl_pwrscale_trustzone.c
@@ -159,11 +159,13 @@
 		(priv->bin.total_time < FLOOR))
 		return;
 
-	/* If there is an extended block of busy processing,
-	 * increase frequency.  Otherwise run the normal algorithm.
+	/* If there is an extended block of busy processing, set
+	 * frequency to turbo.  Otherwise run the normal algorithm.
 	 */
 	if (priv->bin.busy_time > CEILING) {
-		val = -1;
+		val = 0;
+		kgsl_pwrctrl_pwrlevel_change(device,
+				KGSL_PWRLEVEL_TURBO);
 	} else if (priv->idle_dcvs) {
 		idle = priv->bin.total_time - priv->bin.busy_time;
 		idle = (idle > 0) ? idle : 0;
diff --git a/drivers/gpu/msm/kgsl_sync.c b/drivers/gpu/msm/kgsl_sync.c
index dc3ad21..b7d7235 100644
--- a/drivers/gpu/msm/kgsl_sync.c
+++ b/drivers/gpu/msm/kgsl_sync.c
@@ -11,7 +11,6 @@
  *
  */
 
-#include <linux/err.h>
 #include <linux/file.h>
 #include <linux/sched.h>
 #include <linux/slab.h>
@@ -282,65 +281,3 @@
 {
 	sync_timeline_destroy(context->timeline);
 }
-
-static void kgsl_sync_callback(struct sync_fence *fence,
-	struct sync_fence_waiter *waiter)
-{
-	struct kgsl_sync_fence_waiter *kwaiter =
-		(struct kgsl_sync_fence_waiter *) waiter;
-	kwaiter->func(kwaiter->priv);
-	sync_fence_put(kwaiter->fence);
-	kfree(kwaiter);
-}
-
-struct kgsl_sync_fence_waiter *kgsl_sync_fence_async_wait(int fd,
-	void (*func)(void *priv), void *priv)
-{
-	struct kgsl_sync_fence_waiter *kwaiter;
-	struct sync_fence *fence;
-	int status;
-
-	fence = sync_fence_fdget(fd);
-	if (fence == NULL)
-		return ERR_PTR(-EINVAL);
-
-	/* create the waiter */
-	kwaiter = kzalloc(sizeof(*kwaiter), GFP_ATOMIC);
-	if (kwaiter == NULL) {
-		sync_fence_put(fence);
-		return ERR_PTR(-ENOMEM);
-	}
-	kwaiter->fence = fence;
-	kwaiter->priv = priv;
-	kwaiter->func = func;
-	sync_fence_waiter_init((struct sync_fence_waiter *) kwaiter,
-		kgsl_sync_callback);
-
-	/* if status then error or signaled */
-	status = sync_fence_wait_async(fence,
-		(struct sync_fence_waiter *) kwaiter);
-	if (status) {
-		kfree(kwaiter);
-		sync_fence_put(fence);
-		if (status < 0)
-			kwaiter = ERR_PTR(status);
-		else
-			kwaiter = NULL;
-	}
-
-	return kwaiter;
-}
-
-int kgsl_sync_fence_async_cancel(struct kgsl_sync_fence_waiter *kwaiter)
-{
-	if (kwaiter == NULL)
-		return 0;
-
-	if (sync_fence_cancel_async(kwaiter->fence,
-		(struct sync_fence_waiter *) kwaiter) == 0) {
-		sync_fence_put(kwaiter->fence);
-		kfree(kwaiter);
-		return 1;
-	}
-	return 0;
-}
diff --git a/drivers/gpu/msm/kgsl_sync.h b/drivers/gpu/msm/kgsl_sync.h
index 275eaf0..63adf06 100644
--- a/drivers/gpu/msm/kgsl_sync.h
+++ b/drivers/gpu/msm/kgsl_sync.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2012-2013, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2012, The Linux Foundation. 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 and
@@ -28,13 +28,6 @@
 	unsigned int timestamp;
 };
 
-struct kgsl_sync_fence_waiter {
-	struct sync_fence_waiter waiter;
-	struct sync_fence *fence;
-	void (*func)(void *priv);
-	void *priv;
-};
-
 #if defined(CONFIG_SYNC)
 struct sync_pt *kgsl_sync_pt_create(struct sync_timeline *timeline,
 	unsigned int timestamp);
@@ -46,9 +39,6 @@
 void kgsl_sync_timeline_signal(struct sync_timeline *timeline,
 	unsigned int timestamp);
 void kgsl_sync_timeline_destroy(struct kgsl_context *context);
-struct kgsl_sync_fence_waiter *kgsl_sync_fence_async_wait(int fd,
-	void (*func)(void *priv), void *priv);
-int kgsl_sync_fence_async_cancel(struct kgsl_sync_fence_waiter *waiter);
 #else
 static inline struct sync_pt
 *kgsl_sync_pt_create(struct sync_timeline *timeline, unsigned int timestamp)
@@ -82,20 +72,6 @@
 static inline void kgsl_sync_timeline_destroy(struct kgsl_context *context)
 {
 }
-
-static inline struct
-kgsl_sync_fence_waiter *kgsl_sync_fence_async_wait(int fd,
-	void (*func)(void *priv), void *priv)
-{
-	return NULL;
-}
-
-static inline int
-kgsl_sync_fence_async_cancel(struct kgsl_sync_fence_waiter *waiter)
-{
-	return 1;
-}
-
 #endif
 
 #endif /* __KGSL_SYNC_H */
diff --git a/drivers/gpu/msm/kgsl_trace.h b/drivers/gpu/msm/kgsl_trace.h
index 5f39b8b..f16f2b4 100644
--- a/drivers/gpu/msm/kgsl_trace.h
+++ b/drivers/gpu/msm/kgsl_trace.h
@@ -37,13 +37,14 @@
 
 	TP_PROTO(struct kgsl_device *device,
 			int drawctxt_id,
-			struct kgsl_cmdbatch *cmdbatch,
+			struct kgsl_ibdesc *ibdesc,
+			int numibs,
 			int timestamp,
 			int flags,
 			int result,
 			unsigned int type),
 
-	TP_ARGS(device, drawctxt_id, cmdbatch, timestamp, flags,
+	TP_ARGS(device, drawctxt_id, ibdesc, numibs, timestamp, flags,
 		result, type),
 
 	TP_STRUCT__entry(
@@ -60,8 +61,8 @@
 	TP_fast_assign(
 		__assign_str(device_name, device->name);
 		__entry->drawctxt_id = drawctxt_id;
-		__entry->ibdesc_addr = cmdbatch->ibdesc[0].gpuaddr;
-		__entry->numibs = cmdbatch->ibcount;
+		__entry->ibdesc_addr = ibdesc[0].gpuaddr;
+		__entry->numibs = numibs;
 		__entry->timestamp = timestamp;
 		__entry->flags = flags;
 		__entry->result = result;
@@ -730,46 +731,42 @@
 );
 
 TRACE_EVENT(kgsl_register_event,
-		TP_PROTO(unsigned int id, unsigned int timestamp, void *func),
-		TP_ARGS(id, timestamp, func),
+		TP_PROTO(unsigned int id, unsigned int timestamp),
+		TP_ARGS(id, timestamp),
 		TP_STRUCT__entry(
 			__field(unsigned int, id)
 			__field(unsigned int, timestamp)
-			__field(void *, func)
 		),
 		TP_fast_assign(
 			__entry->id = id;
 			__entry->timestamp = timestamp;
-			__entry->func = func;
 		),
 		TP_printk(
-			"ctx=%u ts=%u cb=%pF",
-			__entry->id, __entry->timestamp, __entry->func)
+			"ctx=%u ts=%u",
+			__entry->id, __entry->timestamp)
 );
 
 TRACE_EVENT(kgsl_fire_event,
 		TP_PROTO(unsigned int id, unsigned int ts,
-			unsigned int type, unsigned int age, void *func),
-		TP_ARGS(id, ts, type, age, func),
+			unsigned int type, unsigned int age),
+		TP_ARGS(id, ts, type, age),
 		TP_STRUCT__entry(
 			__field(unsigned int, id)
 			__field(unsigned int, ts)
 			__field(unsigned int, type)
 			__field(unsigned int, age)
-			__field(void *, func)
 		),
 		TP_fast_assign(
 			__entry->id = id;
 			__entry->ts = ts;
 			__entry->type = type;
 			__entry->age = age;
-			__entry->func = func;
 		),
 		TP_printk(
-			"ctx=%u ts=%u type=%s age=%u cb=%pF",
+			"ctx=%u ts=%u type=%s age=%u",
 			__entry->id, __entry->ts,
 			__print_symbolic(__entry->type, KGSL_EVENT_TYPES),
-			__entry->age, __entry->func)
+			__entry->age)
 );
 
 TRACE_EVENT(kgsl_active_count,
diff --git a/drivers/gpu/msm/z180.c b/drivers/gpu/msm/z180.c
index 0af57aa..103a751 100644
--- a/drivers/gpu/msm/z180.c
+++ b/drivers/gpu/msm/z180.c
@@ -124,6 +124,8 @@
 	| (MMU_CONFIG << MH_MMU_CONFIG__TC_R_CLNT_BEHAVIOR__SHIFT)   \
 	| (MMU_CONFIG << MH_MMU_CONFIG__PA_W_CLNT_BEHAVIOR__SHIFT))
 
+#define KGSL_LOG_LEVEL_DEFAULT 3
+
 static const struct kgsl_functable z180_functable;
 
 static struct z180_device device_2d0 = {
@@ -149,6 +151,13 @@
 		},
 		.iomemname = KGSL_2D0_REG_MEMORY,
 		.ftbl = &z180_functable,
+		.cmd_log = KGSL_LOG_LEVEL_DEFAULT,
+		.ctxt_log = KGSL_LOG_LEVEL_DEFAULT,
+		.drv_log = KGSL_LOG_LEVEL_DEFAULT,
+		.mem_log = KGSL_LOG_LEVEL_DEFAULT,
+		.pwr_log = KGSL_LOG_LEVEL_DEFAULT,
+		.ft_log = KGSL_LOG_LEVEL_DEFAULT,
+		.pm_dump_enable = 0,
 	},
 	.cmdwin_lock = __SPIN_LOCK_INITIALIZER(device_2d1.cmdwin_lock),
 };
@@ -353,13 +362,7 @@
 	return ts_diff < Z180_PACKET_COUNT;
 }
 
-/**
- * z180_idle() - Idle the 2D device
- * @device: Pointer to the KGSL device struct for the Z180
- *
- * wait until the z180 submission queue is idle
- */
-int z180_idle(struct kgsl_device *device)
+static int z180_idle(struct kgsl_device *device)
 {
 	int status = 0;
 	struct z180_device *z180_dev = Z180_DEVICE(device);
@@ -379,8 +382,10 @@
 int
 z180_cmdstream_issueibcmds(struct kgsl_device_private *dev_priv,
 			struct kgsl_context *context,
-			struct kgsl_cmdbatch *cmdbatch,
-			uint32_t *timestamp)
+			struct kgsl_ibdesc *ibdesc,
+			unsigned int numibs,
+			uint32_t *timestamp,
+			unsigned int ctrl)
 {
 	long result = 0;
 	unsigned int ofs        = PACKETSIZE_STATESTREAM * sizeof(unsigned int);
@@ -393,20 +398,6 @@
 	struct kgsl_pagetable *pagetable = dev_priv->process_priv->pagetable;
 	struct z180_device *z180_dev = Z180_DEVICE(device);
 	unsigned int sizedwords;
-	unsigned int numibs;
-	struct kgsl_ibdesc *ibdesc;
-
-	mutex_lock(&device->mutex);
-
-	kgsl_active_count_get(device);
-
-	if (cmdbatch == NULL) {
-		result = EINVAL;
-		goto error;
-	}
-
-	ibdesc = cmdbatch->ibdesc;
-	numibs = cmdbatch->ibcount;
 
 	if (device->state & KGSL_STATE_HUNG) {
 		result = -EINVAL;
@@ -448,7 +439,7 @@
 		context->id, cmd, sizedwords);
 	/* context switch */
 	if ((context->id != (int)z180_dev->ringbuffer.prevctx) ||
-	    (cmdbatch->flags & KGSL_CONTEXT_CTX_SWITCH)) {
+	    (ctrl & KGSL_CONTEXT_CTX_SWITCH)) {
 		KGSL_CMD_INFO(device, "context switch %d -> %d\n",
 			context->id, z180_dev->ringbuffer.prevctx);
 		kgsl_mmu_setstate(&device->mmu, pagetable,
@@ -456,13 +447,10 @@
 		cnt = PACKETSIZE_STATESTREAM;
 		ofs = 0;
 	}
-
-	result = kgsl_setstate(&device->mmu,
+	kgsl_setstate(&device->mmu,
 			KGSL_MEMSTORE_GLOBAL,
 			kgsl_mmu_pt_get_flags(device->mmu.hwpagetable,
 			device->id));
-	if (result < 0)
-		goto error;
 
 	result = wait_event_interruptible_timeout(device->wait_queue,
 				  room_in_rb(z180_dev),
@@ -503,12 +491,9 @@
 	z180_cmdwindow_write(device, ADDR_VGV3_CONTROL, cmd);
 	z180_cmdwindow_write(device, ADDR_VGV3_CONTROL, 0);
 error:
-	kgsl_trace_issueibcmds(device, context->id, cmdbatch,
-		*timestamp, cmdbatch->flags, result, 0);
 
-	kgsl_active_count_put(device);
-
-	mutex_unlock(&device->mutex);
+	kgsl_trace_issueibcmds(device, context->id, ibdesc, numibs,
+		*timestamp, ctrl, result, 0);
 
 	return (int)result;
 }
@@ -619,12 +604,8 @@
 
 static int z180_stop(struct kgsl_device *device)
 {
-	int ret;
-
 	device->ftbl->irqctrl(device, 0);
-	ret = z180_idle(device);
-	if (ret)
-		return ret;
+	z180_idle(device);
 
 	del_timer_sync(&device->idle_timer);
 
@@ -690,7 +671,7 @@
 	return status;
 }
 
-static bool z180_isidle(struct kgsl_device *device)
+static unsigned int z180_isidle(struct kgsl_device *device)
 {
 	struct z180_device *z180_dev = Z180_DEVICE(device);
 
@@ -903,7 +884,7 @@
 	return context;
 }
 
-static int
+static void
 z180_drawctxt_detach(struct kgsl_context *context)
 {
 	struct kgsl_device *device;
@@ -917,13 +898,9 @@
 	if (z180_dev->ringbuffer.prevctx == context->id) {
 		z180_dev->ringbuffer.prevctx = Z180_INVALID_CONTEXT;
 		device->mmu.hwpagetable = device->mmu.defaultpagetable;
-
-		/* Ignore the result - we are going down anyway */
 		kgsl_setstate(&device->mmu, KGSL_MEMSTORE_GLOBAL,
 				KGSL_MMUFLAGS_PTUPDATE);
 	}
-
-	return 0;
 }
 
 static void
@@ -997,7 +974,6 @@
 	.irqctrl = z180_irqctrl,
 	.gpuid = z180_gpuid,
 	.irq_handler = z180_irq_handler,
-	.drain = z180_idle, /* drain == idle for the z180 */
 	/* Optional functions */
 	.drawctxt_create = z180_drawctxt_create,
 	.drawctxt_detach = z180_drawctxt_detach,
diff --git a/drivers/gpu/msm/z180.h b/drivers/gpu/msm/z180.h
index a36e92d..1be0870 100644
--- a/drivers/gpu/msm/z180.h
+++ b/drivers/gpu/msm/z180.h
@@ -45,6 +45,5 @@
 };
 
 int z180_dump(struct kgsl_device *, int);
-int z180_idle(struct kgsl_device *);
 
 #endif /* __Z180_H */
diff --git a/drivers/gpu/msm/z180_postmortem.c b/drivers/gpu/msm/z180_postmortem.c
index bc53c0e..5d929cf 100644
--- a/drivers/gpu/msm/z180_postmortem.c
+++ b/drivers/gpu/msm/z180_postmortem.c
@@ -58,8 +58,6 @@
 	unsigned int i;
 	unsigned int reg_val;
 
-	z180_idle(device);
-
 	KGSL_LOG_DUMP(device, "Z180 Register Dump\n");
 	for (i = 0; i < ARRAY_SIZE(regs_to_dump); i++) {
 		kgsl_regread(device,
diff --git a/drivers/hwmon/qpnp-adc-common.c b/drivers/hwmon/qpnp-adc-common.c
index 8b0fcf4..9e0be59 100644
--- a/drivers/hwmon/qpnp-adc-common.c
+++ b/drivers/hwmon/qpnp-adc-common.c
@@ -131,57 +131,111 @@
 };
 
 static const struct qpnp_vadc_map_pt adcmap_qrd_btm_threshold[] = {
-	{-200,	1672},
-	{-180,	1656},
-	{-160,	1639},
-	{-140,	1620},
-	{-120,	1599},
-	{-100,	1577},
-	{-80,	1553},
-	{-60,	1527},
-	{-40,	1550},
-	{-20,	1471},
-	{0,	1440},
-	{20,	1408},
-	{40,	1374},
-	{60,	1339},
-	{80,	1303},
-	{100,	1266},
-	{120,	1228},
-	{140,	1190},
-	{160,	1150},
-	{180,	1111},
-	{200,	1071},
-	{220,	1032},
-	{240,	992},
-	{260,	953},
-	{280,	915},
-	{300,	877},
-	{320,	841},
-	{340,	805},
-	{360,	770},
-	{380,	736},
-	{400,	704},
-	{420,	673},
-	{440,	643},
-	{460,	614},
-	{480,	587},
-	{500,	561},
-	{520,	536},
-	{540,	513},
-	{560,	491},
-	{580,	470},
-	{600,	450},
-	{620,	431},
-	{640,	414},
-	{660,	397},
-	{680,	382},
-	{700,	367},
-	{720,	353},
-	{740,	340},
-	{760,	328},
-	{780,	317},
-	{800,	306},
+	{-200,	1540},
+	{-180,	1517},
+	{-160,	1492},
+	{-140,	1467},
+	{-120,	1440},
+	{-100,	1412},
+	{-80,	1383},
+	{-60,	1353},
+	{-40,	1323},
+	{-20,	1292},
+	{0,	1260},
+	{20,	1228},
+	{40,	1196},
+	{60,	1163},
+	{80,	1131},
+	{100,	1098},
+	{120,	1066},
+	{140,	1034},
+	{160,	1002},
+	{180,	971},
+	{200,	941},
+	{220,	911},
+	{240,	882},
+	{260,	854},
+	{280,	826},
+	{300,	800},
+	{320,	774},
+	{340,	749},
+	{360,	726},
+	{380,	703},
+	{400,	681},
+	{420,	660},
+	{440,	640},
+	{460,	621},
+	{480,	602},
+	{500,	585},
+	{520,	568},
+	{540,	552},
+	{560,	537},
+	{580,	523},
+	{600,	510},
+	{620,	497},
+	{640,	485},
+	{660,	473},
+	{680,	462},
+	{700,	452},
+	{720,	442},
+	{740,	433},
+	{760,	424},
+	{780,	416},
+	{800,	408},
+};
+
+static const struct qpnp_vadc_map_pt adcmap_qrd_skuaa_btm_threshold[] = {
+	{-200,	1476},
+	{-180,	1450},
+	{-160,	1422},
+	{-140,	1394},
+	{-120,	1365},
+	{-100,	1336},
+	{-80,	1306},
+	{-60,	1276},
+	{-40,	1246},
+	{-20,	1216},
+	{0,	1185},
+	{20,	1155},
+	{40,	1126},
+	{60,	1096},
+	{80,	1068},
+	{100,	1040},
+	{120,	1012},
+	{140,	986},
+	{160,	960},
+	{180,	935},
+	{200,	911},
+	{220,	888},
+	{240,	866},
+	{260,	844},
+	{280,	824},
+	{300,	805},
+	{320,	786},
+	{340,	769},
+	{360,	752},
+	{380,	737},
+	{400,	722},
+	{420,	707},
+	{440,	694},
+	{460,	681},
+	{480,	669},
+	{500,	658},
+	{520,	648},
+	{540,	637},
+	{560,	628},
+	{580,	619},
+	{600,	611},
+	{620,	603},
+	{640,	595},
+	{660,	588},
+	{680,	582},
+	{700,	575},
+	{720,	569},
+	{740,	564},
+	{760,	559},
+	{780,	554},
+	{800,	549},
 };
 
 /* Voltage to temperature */
@@ -539,6 +593,25 @@
 }
 EXPORT_SYMBOL(qpnp_adc_scale_qrd_batt_therm);
 
+int32_t qpnp_adc_scale_qrd_skuaa_batt_therm(struct qpnp_vadc_chip *chip,
+		int32_t adc_code,
+		const struct qpnp_adc_properties *adc_properties,
+		const struct qpnp_vadc_chan_properties *chan_properties,
+		struct qpnp_vadc_result *adc_chan_result)
+{
+	int64_t bat_voltage = 0;
+
+	bat_voltage = qpnp_adc_scale_ratiometric_calib(adc_code,
+			adc_properties, chan_properties);
+
+	return qpnp_adc_map_temp_voltage(
+			adcmap_qrd_skuaa_btm_threshold,
+			ARRAY_SIZE(adcmap_qrd_skuaa_btm_threshold),
+			bat_voltage,
+			&adc_chan_result->physical);
+}
+EXPORT_SYMBOL(qpnp_adc_scale_qrd_skuaa_batt_therm);
+
 int32_t qpnp_adc_scale_therm_pu1(struct qpnp_vadc_chip *chip,
 		int32_t adc_code,
 		const struct qpnp_adc_properties *adc_properties,
diff --git a/drivers/hwmon/qpnp-adc-current.c b/drivers/hwmon/qpnp-adc-current.c
index 606d8dd..adaff41 100644
--- a/drivers/hwmon/qpnp-adc-current.c
+++ b/drivers/hwmon/qpnp-adc-current.c
@@ -31,6 +31,7 @@
 #include <linux/hwmon-sysfs.h>
 #include <linux/qpnp/qpnp-adc.h>
 #include <linux/platform_device.h>
+#include <linux/wakelock.h>
 
 /* QPNP IADC register definition */
 #define QPNP_IADC_REVISION1				0x0
@@ -48,6 +49,7 @@
 #define QPNP_STATUS1_MEAS_INTERVAL_EN_STS		BIT(2)
 #define QPNP_STATUS1_REQ_STS				BIT(1)
 #define QPNP_STATUS1_EOC				BIT(0)
+#define QPNP_STATUS1_REQ_STS_EOC_MASK			0x3
 #define QPNP_STATUS2					0x9
 #define QPNP_STATUS2_CONV_SEQ_STATE_SHIFT		4
 #define QPNP_STATUS2_FIFO_NOT_EMPTY_FLAG		BIT(1)
@@ -110,8 +112,9 @@
 #define QPNP_IADC_DATA0					0x60
 #define QPNP_IADC_DATA1					0x61
 
-#define QPNP_ADC_CONV_TIME_MIN				8000
-#define QPNP_ADC_CONV_TIME_MAX				8200
+#define QPNP_ADC_CONV_TIME_MIN				2000
+#define QPNP_ADC_CONV_TIME_MAX				2100
+#define QPNP_ADC_ERR_COUNT				20
 
 #define QPNP_ADC_GAIN_NV				17857
 #define QPNP_OFFSET_CALIBRATION_SHORT_CADC_LEADS_IDEAL	0
@@ -131,30 +134,34 @@
 	bool	ext_rsense;
 	u8	id;
 	u8	sys_gain;
-	u8	revision;
+	u8	revision_dig_major;
+	u8	revision_ana_minor;
 };
 
-struct qpnp_iadc_drv {
+struct qpnp_iadc_chip {
+	struct device				*dev;
 	struct qpnp_adc_drv			*adc;
 	int32_t					rsense;
 	bool					external_rsense;
 	struct device				*iadc_hwmon;
-	bool					iadc_initialized;
+	struct list_head			list;
 	int64_t					die_temp;
 	struct delayed_work			iadc_work;
 	struct mutex				iadc_vadc_lock;
 	bool					iadc_mode_sel;
 	struct qpnp_iadc_comp			iadc_comp;
 	struct qpnp_vadc_chip			*vadc_dev;
-	struct sensor_device_attribute		sens_attr[0];
+	struct work_struct			trigger_completion_work;
 	bool					skip_auto_calibrations;
+	bool					iadc_poll_eoc;
+	struct sensor_device_attribute		sens_attr[0];
 };
 
-static struct qpnp_iadc_drv	*qpnp_iadc;
+LIST_HEAD(qpnp_iadc_device_list);
 
-static int32_t qpnp_iadc_read_reg(uint32_t reg, u8 *data)
+static int32_t qpnp_iadc_read_reg(struct qpnp_iadc_chip *iadc,
+						uint32_t reg, u8 *data)
 {
-	struct qpnp_iadc_drv *iadc = qpnp_iadc;
 	int rc;
 
 	rc = spmi_ext_register_readl(iadc->adc->spmi->ctrl, iadc->adc->slave,
@@ -167,9 +174,9 @@
 	return 0;
 }
 
-static int32_t qpnp_iadc_write_reg(uint32_t reg, u8 data)
+static int32_t qpnp_iadc_write_reg(struct qpnp_iadc_chip *iadc,
+						uint32_t reg, u8 data)
 {
-	struct qpnp_iadc_drv *iadc = qpnp_iadc;
 	int rc;
 	u8 *buf;
 
@@ -184,41 +191,54 @@
 	return 0;
 }
 
-static void trigger_iadc_completion(struct work_struct *work)
+static int qpnp_iadc_is_valid(struct qpnp_iadc_chip *iadc)
 {
-	struct qpnp_iadc_drv *iadc = qpnp_iadc;
+	struct qpnp_iadc_chip *iadc_chip = NULL;
 
-	if (!iadc || !iadc->iadc_initialized)
+	list_for_each_entry(iadc_chip, &qpnp_iadc_device_list, list)
+		if (iadc == iadc_chip)
+			return 0;
+
+	return -EINVAL;
+}
+
+static void qpnp_iadc_trigger_completion(struct work_struct *work)
+{
+	struct qpnp_iadc_chip *iadc = container_of(work,
+			struct qpnp_iadc_chip, trigger_completion_work);
+
+	if (qpnp_iadc_is_valid(iadc) < 0)
 		return;
 
 	complete(&iadc->adc->adc_rslt_completion);
 
 	return;
 }
-DECLARE_WORK(trigger_iadc_completion_work, trigger_iadc_completion);
 
 static irqreturn_t qpnp_iadc_isr(int irq, void *dev_id)
 {
-	schedule_work(&trigger_iadc_completion_work);
+	struct qpnp_iadc_chip *iadc = dev_id;
+
+	schedule_work(&iadc->trigger_completion_work);
 
 	return IRQ_HANDLED;
 }
 
-static int32_t qpnp_iadc_enable(bool state)
+static int32_t qpnp_iadc_enable(struct qpnp_iadc_chip *dev, bool state)
 {
 	int rc = 0;
 	u8 data = 0;
 
 	data = QPNP_IADC_ADC_EN;
 	if (state) {
-		rc = qpnp_iadc_write_reg(QPNP_IADC_EN_CTL1,
+		rc = qpnp_iadc_write_reg(dev, QPNP_IADC_EN_CTL1,
 					data);
 		if (rc < 0) {
 			pr_err("IADC enable failed\n");
 			return rc;
 		}
 	} else {
-		rc = qpnp_iadc_write_reg(QPNP_IADC_EN_CTL1,
+		rc = qpnp_iadc_write_reg(dev, QPNP_IADC_EN_CTL1,
 					(~data & QPNP_IADC_ADC_EN));
 		if (rc < 0) {
 			pr_err("IADC disable failed\n");
@@ -229,36 +249,36 @@
 	return 0;
 }
 
-static int32_t qpnp_iadc_status_debug(void)
+static int32_t qpnp_iadc_status_debug(struct qpnp_iadc_chip *dev)
 {
 	int rc = 0;
 	u8 mode = 0, status1 = 0, chan = 0, dig = 0, en = 0;
 
-	rc = qpnp_iadc_read_reg(QPNP_IADC_MODE_CTL, &mode);
+	rc = qpnp_iadc_read_reg(dev, QPNP_IADC_MODE_CTL, &mode);
 	if (rc < 0) {
 		pr_err("mode ctl register read failed with %d\n", rc);
 		return rc;
 	}
 
-	rc = qpnp_iadc_read_reg(QPNP_ADC_DIG_PARAM, &dig);
+	rc = qpnp_iadc_read_reg(dev, QPNP_ADC_DIG_PARAM, &dig);
 	if (rc < 0) {
 		pr_err("digital param read failed with %d\n", rc);
 		return rc;
 	}
 
-	rc = qpnp_iadc_read_reg(QPNP_IADC_ADC_CH_SEL_CTL, &chan);
+	rc = qpnp_iadc_read_reg(dev, QPNP_IADC_ADC_CH_SEL_CTL, &chan);
 	if (rc < 0) {
 		pr_err("channel read failed with %d\n", rc);
 		return rc;
 	}
 
-	rc = qpnp_iadc_read_reg(QPNP_STATUS1, &status1);
+	rc = qpnp_iadc_read_reg(dev, QPNP_STATUS1, &status1);
 	if (rc < 0) {
 		pr_err("status1 read failed with %d\n", rc);
 		return rc;
 	}
 
-	rc = qpnp_iadc_read_reg(QPNP_IADC_EN_CTL1, &en);
+	rc = qpnp_iadc_read_reg(dev, QPNP_IADC_EN_CTL1, &en);
 	if (rc < 0) {
 		pr_err("en read failed with %d\n", rc);
 		return rc;
@@ -267,7 +287,7 @@
 	pr_debug("EOC not set with status:%x, dig:%x, ch:%x, mode:%x, en:%x\n",
 			status1, dig, chan, mode, en);
 
-	rc = qpnp_iadc_enable(false);
+	rc = qpnp_iadc_enable(dev, false);
 	if (rc < 0) {
 		pr_err("IADC disable failed with %d\n", rc);
 		return rc;
@@ -276,19 +296,20 @@
 	return 0;
 }
 
-static int32_t qpnp_iadc_read_conversion_result(uint16_t *data)
+static int32_t qpnp_iadc_read_conversion_result(struct qpnp_iadc_chip *iadc,
+								int16_t *data)
 {
 	uint8_t rslt_lsb, rslt_msb;
 	uint16_t rslt;
 	int32_t rc;
 
-	rc = qpnp_iadc_read_reg(QPNP_IADC_DATA0, &rslt_lsb);
+	rc = qpnp_iadc_read_reg(iadc, QPNP_IADC_DATA0, &rslt_lsb);
 	if (rc < 0) {
 		pr_err("qpnp adc result read failed with %d\n", rc);
 		return rc;
 	}
 
-	rc = qpnp_iadc_read_reg(QPNP_IADC_DATA1, &rslt_msb);
+	rc = qpnp_iadc_read_reg(iadc, QPNP_IADC_DATA1, &rslt_msb);
 	if (rc < 0) {
 		pr_err("qpnp adc result read failed with %d\n", rc);
 		return rc;
@@ -297,99 +318,287 @@
 	rslt = (rslt_msb << 8) | rslt_lsb;
 	*data = rslt;
 
-	rc = qpnp_iadc_enable(false);
+	rc = qpnp_iadc_enable(iadc, false);
 	if (rc)
 		return rc;
 
 	return 0;
 }
 
-static int32_t qpnp_iadc_comp(int64_t *result, struct qpnp_iadc_comp comp,
+#define QPNP_IADC_PM8941_3_1_REV2	3
+#define QPNP_IADC_PM8941_3_1_REV3	2
+#define QPNP_IADC_PM8026_1_REV2		1
+#define QPNP_IADC_PM8026_1_REV3		2
+#define QPNP_IADC_PM8026_2_REV2		4
+#define QPNP_IADC_PM8026_2_REV3		2
+#define QPNP_IADC_PM8110_1_REV2		2
+#define QPNP_IADC_PM8110_1_REV3		2
+
+#define QPNP_IADC_REV_ID_8941_3_1	1
+#define QPNP_IADC_REV_ID_8026_1_0	2
+#define QPNP_IADC_REV_ID_8026_2_0	3
+#define QPNP_IADC_REV_ID_8110_1_0	4
+
+static void qpnp_temp_comp_version_check(struct qpnp_iadc_chip *iadc,
+						int32_t *version)
+{
+	if ((iadc->iadc_comp.revision_dig_major ==
+			QPNP_IADC_PM8941_3_1_REV2) &&
+			(iadc->iadc_comp.revision_ana_minor ==
+			QPNP_IADC_PM8941_3_1_REV3))
+		*version = QPNP_IADC_REV_ID_8941_3_1;
+	else if ((iadc->iadc_comp.revision_dig_major ==
+			QPNP_IADC_PM8026_1_REV2) &&
+			(iadc->iadc_comp.revision_ana_minor ==
+			QPNP_IADC_PM8026_1_REV3))
+		*version = QPNP_IADC_REV_ID_8026_1_0;
+	else if ((iadc->iadc_comp.revision_dig_major ==
+			QPNP_IADC_PM8026_2_REV2) &&
+			(iadc->iadc_comp.revision_ana_minor ==
+			QPNP_IADC_PM8026_2_REV3))
+		*version = QPNP_IADC_REV_ID_8026_2_0;
+	else if ((iadc->iadc_comp.revision_dig_major ==
+			QPNP_IADC_PM8110_1_REV2) &&
+			(iadc->iadc_comp.revision_ana_minor ==
+			QPNP_IADC_PM8110_1_REV3))
+		*version = QPNP_IADC_REV_ID_8110_1_0;
+	else
+		*version = -EINVAL;
+
+	return;
+}
+
+#define QPNP_COEFF_1					969000
+#define QPNP_COEFF_2					32
+#define QPNP_COEFF_3_TYPEA				1700000
+#define QPNP_COEFF_3_TYPEB				1000000
+#define QPNP_COEFF_4					100
+#define QPNP_COEFF_5					15
+#define QPNP_COEFF_6					100000
+#define QPNP_COEFF_7					21
+#define QPNP_COEFF_8					100000000
+#define QPNP_COEFF_9					38
+#define QPNP_COEFF_10					40
+#define QPNP_COEFF_11					7
+#define QPNP_COEFF_12					11
+#define QPNP_COEFF_13					37
+#define QPNP_COEFF_14					39
+#define QPNP_COEFF_15					9
+#define QPNP_COEFF_16					11
+#define QPNP_COEFF_17					851200
+#define QPNP_COEFF_18					296500
+#define QPNP_COEFF_19					222400
+#define QPNP_COEFF_20					813800
+#define QPNP_COEFF_21					1059100
+#define QPNP_COEFF_22					5000000
+#define QPNP_COEFF_23					3722500
+#define QPNP_COEFF_24					84
+
+static int32_t qpnp_iadc_comp(int64_t *result, struct qpnp_iadc_chip *iadc,
 							int64_t die_temp)
 {
-	int64_t temp_var = 0, sign_coeff = 0, sys_gain_coeff = 0, old;
+	int64_t temp_var = 0, sys_gain_coeff = 0, old;
+	int32_t coeff_a = 0, coeff_b = 0;
+	int32_t version;
+
+	qpnp_temp_comp_version_check(iadc, &version);
+	if (version == -EINVAL)
+		return 0;
 
 	old = *result;
 	*result = *result * 1000000;
 
-	if (comp.revision == QPNP_IADC_VER_3_1) {
-		/* revision 3.1 */
-		if (comp.sys_gain > 127)
-			sys_gain_coeff = -QPNP_COEFF_6 * (comp.sys_gain - 128);
-		else
-			sys_gain_coeff = QPNP_COEFF_6 * comp.sys_gain;
-	} else if (comp.revision != QPNP_IADC_VER_3_0) {
-		/* unsupported revision, do not compensate */
-		*result = old;
-		return 0;
-	}
+	if (iadc->iadc_comp.sys_gain > 127)
+		sys_gain_coeff = -QPNP_COEFF_6 *
+				(iadc->iadc_comp.sys_gain - 128);
+	else
+		sys_gain_coeff = QPNP_COEFF_6 *
+				iadc->iadc_comp.sys_gain;
 
-	if (!comp.ext_rsense) {
-		/* internal rsense */
-		switch (comp.id) {
-		case COMP_ID_TSMC:
-			temp_var = ((QPNP_COEFF_2 * die_temp) -
-						QPNP_COEFF_3_TYPEB);
-		break;
+	switch (version) {
+	case QPNP_IADC_REV_ID_8941_3_1:
+		switch (iadc->iadc_comp.id) {
 		case COMP_ID_GF:
+			if (!iadc->iadc_comp.ext_rsense) {
+				/* internal rsense */
+				coeff_a = QPNP_COEFF_2;
+				coeff_b = -QPNP_COEFF_3_TYPEA;
+			} else {
+				if (*result < 0) {
+					/* charge */
+					coeff_a = QPNP_COEFF_5;
+					coeff_b = QPNP_COEFF_6;
+				} else {
+					/* discharge */
+					coeff_a = -QPNP_COEFF_7;
+					coeff_b = QPNP_COEFF_6;
+				}
+			}
+			break;
+		case COMP_ID_TSMC:
 		default:
-			temp_var = ((QPNP_COEFF_2 * die_temp) -
-						QPNP_COEFF_3_TYPEA);
-		break;
+			if (!iadc->iadc_comp.ext_rsense) {
+				/* internal rsense */
+				coeff_a = QPNP_COEFF_2;
+				coeff_b = -QPNP_COEFF_3_TYPEB;
+			} else {
+				if (*result < 0) {
+					/* charge */
+					coeff_a = QPNP_COEFF_5;
+					coeff_b = QPNP_COEFF_6;
+				} else {
+					/* discharge */
+					coeff_a = -QPNP_COEFF_7;
+					coeff_b = QPNP_COEFF_6;
+				}
+			}
+			break;
 		}
-		temp_var = div64_s64(temp_var, QPNP_COEFF_4);
-		if (comp.revision == QPNP_IADC_VER_3_0)
-			temp_var = QPNP_COEFF_1 * (1000000 - temp_var);
-		else if (comp.revision == QPNP_IADC_VER_3_1)
-			temp_var = 1000000 * (1000000 - temp_var);
-		*result = div64_s64(*result * 1000000, temp_var);
+		break;
+	case QPNP_IADC_REV_ID_8026_1_0:
+		/* pm8026 rev 1.0 */
+		switch (iadc->iadc_comp.id) {
+		case COMP_ID_GF:
+			if (!iadc->iadc_comp.ext_rsense) {
+				/* internal rsense */
+				if (*result < 0) {
+					/* charge */
+					coeff_a = QPNP_COEFF_9;
+					coeff_b = -QPNP_COEFF_17;
+				} else {
+					coeff_a = QPNP_COEFF_10;
+					coeff_b = QPNP_COEFF_18;
+				}
+			} else {
+				if (*result < 0) {
+					/* charge */
+					coeff_a = -QPNP_COEFF_11;
+					coeff_b = 0;
+				} else {
+					/* discharge */
+					coeff_a = -QPNP_COEFF_17;
+					coeff_b = -QPNP_COEFF_19;
+				}
+			}
+			break;
+		case COMP_ID_TSMC:
+		default:
+			if (!iadc->iadc_comp.ext_rsense) {
+				/* internal rsense */
+				if (*result < 0) {
+					/* charge */
+					coeff_a = QPNP_COEFF_13;
+					coeff_b = -QPNP_COEFF_20;
+				} else {
+					coeff_a = QPNP_COEFF_14;
+					coeff_b = QPNP_COEFF_21;
+				}
+			} else {
+				if (*result < 0) {
+					/* charge */
+					coeff_a = -QPNP_COEFF_15;
+					coeff_b = 0;
+				} else {
+					/* discharge */
+					coeff_a = -QPNP_COEFF_12;
+					coeff_b = -QPNP_COEFF_19;
+				}
+			}
+			break;
+		}
+		break;
+	case QPNP_IADC_REV_ID_8110_1_0:
+		/* pm8110 rev 1.0 */
+		switch (iadc->iadc_comp.id) {
+		case COMP_ID_GF:
+			if (!iadc->iadc_comp.ext_rsense) {
+				/* internal rsense */
+				if (*result < 0) {
+					/* charge */
+					coeff_a = QPNP_COEFF_24;
+					coeff_b = -QPNP_COEFF_22;
+				} else {
+					coeff_a = QPNP_COEFF_24;
+					coeff_b = -QPNP_COEFF_23;
+				}
+			}
+			break;
+		case COMP_ID_SMIC:
+		default:
+			if (!iadc->iadc_comp.ext_rsense) {
+				/* internal rsense */
+				if (*result < 0) {
+					/* charge */
+					coeff_a = QPNP_COEFF_24;
+					coeff_b = -QPNP_COEFF_22;
+				} else {
+					coeff_a = QPNP_COEFF_24;
+					coeff_b = -QPNP_COEFF_23;
+				}
+			}
+			break;
+		}
+		break;
+	default:
+	case QPNP_IADC_REV_ID_8026_2_0:
+		/* pm8026 rev 1.0 */
+		coeff_a = 0;
+		coeff_b = 0;
+		break;
 	}
 
-	sign_coeff = *result < 0 ? QPNP_COEFF_7 : QPNP_COEFF_5;
-	if (comp.ext_rsense) {
-		/* external rsense and current charging */
-		temp_var = div64_s64((-sign_coeff * die_temp) + QPNP_COEFF_8,
-						QPNP_COEFF_4);
-		temp_var = 1000000000 - temp_var;
-		if (comp.revision == QPNP_IADC_VER_3_1) {
-			sys_gain_coeff = (1000000 +
-				div64_s64(sys_gain_coeff, QPNP_COEFF_4));
-			temp_var = div64_s64(temp_var * sys_gain_coeff,
-				1000000000);
-		}
-		*result = div64_s64(*result, temp_var);
+	temp_var = (coeff_a * die_temp) + coeff_b;
+	temp_var = div64_s64(temp_var, QPNP_COEFF_4);
+	temp_var = 1000 * (1000000 - temp_var);
+
+	if (!iadc->iadc_comp.ext_rsense) {
+		/* internal rsense */
+		*result = div64_s64(*result * 1000, temp_var);
+	}
+
+	if (iadc->iadc_comp.ext_rsense) {
+		/* external rsense */
+		sys_gain_coeff = (1000000 +
+			div64_s64(sys_gain_coeff, QPNP_COEFF_4));
+		temp_var = div64_s64(temp_var * sys_gain_coeff, 1000000);
+		*result = div64_s64(*result * 1000, temp_var);
 	}
 	pr_debug("%lld compensated into %lld\n", old, *result);
 
 	return 0;
 }
 
-int32_t qpnp_iadc_comp_result(int64_t *result)
+int32_t qpnp_iadc_comp_result(struct qpnp_iadc_chip *iadc, int64_t *result)
 {
-	struct qpnp_iadc_drv *iadc = qpnp_iadc;
-
-	return qpnp_iadc_comp(result, iadc->iadc_comp, iadc->die_temp);
+	return qpnp_iadc_comp(result, iadc, iadc->die_temp);
 }
 EXPORT_SYMBOL(qpnp_iadc_comp_result);
 
-static int32_t qpnp_iadc_comp_info(void)
+static int32_t qpnp_iadc_comp_info(struct qpnp_iadc_chip *iadc)
 {
-	struct qpnp_iadc_drv *iadc = qpnp_iadc;
 	int rc = 0;
 
-	rc = qpnp_iadc_read_reg(QPNP_INT_TEST_VAL, &iadc->iadc_comp.id);
+	rc = qpnp_iadc_read_reg(iadc, QPNP_INT_TEST_VAL, &iadc->iadc_comp.id);
 	if (rc < 0) {
 		pr_err("qpnp adc comp id failed with %d\n", rc);
 		return rc;
 	}
 
-	rc = qpnp_iadc_read_reg(QPNP_IADC_REVISION2, &iadc->iadc_comp.revision);
+	rc = qpnp_iadc_read_reg(iadc, QPNP_IADC_REVISION2,
+					&iadc->iadc_comp.revision_dig_major);
 	if (rc < 0) {
-		pr_err("qpnp adc revision read failed with %d\n", rc);
+		pr_err("qpnp adc revision2 read failed with %d\n", rc);
 		return rc;
 	}
 
-	rc = qpnp_iadc_read_reg(QPNP_IADC_ATE_GAIN_CALIB_OFFSET,
+	rc = qpnp_iadc_read_reg(iadc, QPNP_IADC_REVISION3,
+					&iadc->iadc_comp.revision_ana_minor);
+	if (rc < 0) {
+		pr_err("qpnp adc revision3 read failed with %d\n", rc);
+		return rc;
+	}
+
+	rc = qpnp_iadc_read_reg(iadc, QPNP_IADC_ATE_GAIN_CALIB_OFFSET,
 						&iadc->iadc_comp.sys_gain);
 	if (rc < 0) {
 		pr_err("full scale read failed with %d\n", rc);
@@ -399,20 +608,23 @@
 	if (iadc->external_rsense)
 		iadc->iadc_comp.ext_rsense = true;
 
-	pr_debug("fab id = %u, revision = %u, sys gain = %u, external_rsense = %d\n",
+	pr_debug("fab id = %u, revision_dig_major = %u, revision_ana_minor = %u sys gain = %u, external_rsense = %d\n",
 			iadc->iadc_comp.id,
-			iadc->iadc_comp.revision,
+			iadc->iadc_comp.revision_dig_major,
+			iadc->iadc_comp.revision_ana_minor,
 			iadc->iadc_comp.sys_gain,
 			iadc->iadc_comp.ext_rsense);
 	return rc;
 }
 
-static int32_t qpnp_iadc_configure(enum qpnp_iadc_channels channel,
+static int32_t qpnp_iadc_configure(struct qpnp_iadc_chip *iadc,
+					enum qpnp_iadc_channels channel,
 					uint16_t *raw_code, uint32_t mode_sel)
 {
-	struct qpnp_iadc_drv *iadc = qpnp_iadc;
 	u8 qpnp_iadc_mode_reg = 0, qpnp_iadc_ch_sel_reg = 0;
 	u8 qpnp_iadc_conv_req = 0, qpnp_iadc_dig_param_reg = 0;
+	u8 status1 = 0;
+	uint32_t count = 0;
 	int32_t rc = 0;
 
 	qpnp_iadc_ch_sel_reg = channel;
@@ -426,73 +638,94 @@
 
 	qpnp_iadc_conv_req = QPNP_IADC_CONV_REQ;
 
-	rc = qpnp_iadc_write_reg(QPNP_IADC_MODE_CTL, qpnp_iadc_mode_reg);
+	rc = qpnp_iadc_write_reg(iadc, QPNP_IADC_MODE_CTL, qpnp_iadc_mode_reg);
 	if (rc) {
 		pr_err("qpnp adc read adc failed with %d\n", rc);
 		return rc;
 	}
 
-	rc = qpnp_iadc_write_reg(QPNP_IADC_ADC_CH_SEL_CTL,
+	rc = qpnp_iadc_write_reg(iadc, QPNP_IADC_ADC_CH_SEL_CTL,
 						qpnp_iadc_ch_sel_reg);
 	if (rc) {
 		pr_err("qpnp adc read adc failed with %d\n", rc);
 		return rc;
 	}
 
-	rc = qpnp_iadc_write_reg(QPNP_ADC_DIG_PARAM,
+	rc = qpnp_iadc_write_reg(iadc, QPNP_ADC_DIG_PARAM,
 						qpnp_iadc_dig_param_reg);
 	if (rc) {
 		pr_err("qpnp adc read adc failed with %d\n", rc);
 		return rc;
 	}
 
-	rc = qpnp_iadc_write_reg(QPNP_HW_SETTLE_DELAY,
+	rc = qpnp_iadc_write_reg(iadc, QPNP_HW_SETTLE_DELAY,
 				iadc->adc->amux_prop->hw_settle_time);
 	if (rc < 0) {
 		pr_err("qpnp adc configure error for hw settling time setup\n");
 		return rc;
 	}
 
-	rc = qpnp_iadc_write_reg(QPNP_FAST_AVG_CTL,
+	rc = qpnp_iadc_write_reg(iadc, QPNP_FAST_AVG_CTL,
 					iadc->adc->amux_prop->fast_avg_setup);
 	if (rc < 0) {
 		pr_err("qpnp adc fast averaging configure error\n");
 		return rc;
 	}
 
-	INIT_COMPLETION(iadc->adc->adc_rslt_completion);
+	if (!iadc->iadc_poll_eoc)
+		INIT_COMPLETION(iadc->adc->adc_rslt_completion);
 
-	rc = qpnp_iadc_enable(true);
+	rc = qpnp_iadc_enable(iadc, true);
 	if (rc)
 		return rc;
 
-	rc = qpnp_iadc_write_reg(QPNP_CONV_REQ, qpnp_iadc_conv_req);
+	rc = qpnp_iadc_write_reg(iadc, QPNP_CONV_REQ, qpnp_iadc_conv_req);
 	if (rc) {
 		pr_err("qpnp adc read adc failed with %d\n", rc);
 		return rc;
 	}
 
-	rc = wait_for_completion_timeout(&iadc->adc->adc_rslt_completion,
-				QPNP_ADC_COMPLETION_TIMEOUT);
-	if (!rc) {
-		u8 status1 = 0;
-		rc = qpnp_iadc_read_reg(QPNP_STATUS1, &status1);
-		if (rc < 0)
-			return rc;
-		status1 &= (QPNP_STATUS1_REQ_STS | QPNP_STATUS1_EOC);
-		if (status1 == QPNP_STATUS1_EOC)
-			pr_debug("End of conversion status set\n");
-		else {
-			rc = qpnp_iadc_status_debug();
-			if (rc < 0) {
-				pr_err("status1 read failed with %d\n", rc);
+	if (iadc->iadc_poll_eoc) {
+		while (status1 != QPNP_STATUS1_EOC) {
+			rc = qpnp_iadc_read_reg(iadc, QPNP_STATUS1, &status1);
+			if (rc < 0)
+				return rc;
+			status1 &= QPNP_STATUS1_REQ_STS_EOC_MASK;
+			usleep_range(QPNP_ADC_CONV_TIME_MIN,
+					QPNP_ADC_CONV_TIME_MAX);
+			count++;
+			if (count > QPNP_ADC_ERR_COUNT) {
+				pr_err("retry error exceeded\n");
+				rc = qpnp_iadc_status_debug(iadc);
+				if (rc < 0)
+					pr_err("IADC status debug failed\n");
+				rc = -EINVAL;
 				return rc;
 			}
-			return -EINVAL;
+		}
+	} else {
+		rc = wait_for_completion_timeout(
+				&iadc->adc->adc_rslt_completion,
+				QPNP_ADC_COMPLETION_TIMEOUT);
+		if (!rc) {
+			rc = qpnp_iadc_read_reg(iadc, QPNP_STATUS1, &status1);
+			if (rc < 0)
+				return rc;
+			status1 &= QPNP_STATUS1_REQ_STS_EOC_MASK;
+			if (status1 == QPNP_STATUS1_EOC)
+				pr_debug("End of conversion status set\n");
+			else {
+				rc = qpnp_iadc_status_debug(iadc);
+				if (rc < 0) {
+					pr_err("status debug failed %d\n", rc);
+					return rc;
+				}
+				return -EINVAL;
+			}
 		}
 	}
 
-	rc = qpnp_iadc_read_conversion_result(raw_code);
+	rc = qpnp_iadc_read_conversion_result(iadc, raw_code);
 	if (rc) {
 		pr_err("qpnp adc read adc failed with %d\n", rc);
 		return rc;
@@ -504,9 +737,8 @@
 #define IADC_CENTER	0xC000
 #define IADC_READING_RESOLUTION_N	542535
 #define IADC_READING_RESOLUTION_D	100000
-static int32_t qpnp_convert_raw_offset_voltage(void)
+static int32_t qpnp_convert_raw_offset_voltage(struct qpnp_iadc_chip *iadc)
 {
-	struct qpnp_iadc_drv *iadc = qpnp_iadc;
 	s64 numerator;
 
 	if ((iadc->adc->calib.gain_raw - iadc->adc->calib.offset_raw) == 0) {
@@ -531,20 +763,26 @@
 	return 0;
 }
 
-int32_t qpnp_iadc_calibrate_for_trim(bool batfet_closed)
+#define IADC_IDEAL_RAW_GAIN	3291
+int32_t qpnp_iadc_calibrate_for_trim(struct qpnp_iadc_chip *iadc,
+							bool batfet_closed)
 {
-	struct qpnp_iadc_drv *iadc = qpnp_iadc;
 	uint8_t rslt_lsb, rslt_msb;
 	int32_t rc = 0;
 	uint16_t raw_data;
 	uint32_t mode_sel = 0;
 
-	if (!iadc || !iadc->iadc_initialized)
+	if (qpnp_iadc_is_valid(iadc) < 0)
 		return -EPROBE_DEFER;
 
 	mutex_lock(&iadc->adc->adc_lock);
 
-	rc = qpnp_iadc_configure(GAIN_CALIBRATION_17P857MV,
+	if (iadc->iadc_poll_eoc) {
+		pr_debug("acquiring iadc eoc wakelock\n");
+		pm_stay_awake(iadc->dev);
+	}
+
+	rc = qpnp_iadc_configure(iadc, GAIN_CALIBRATION_17P857MV,
 						&raw_data, mode_sel);
 	if (rc < 0) {
 		pr_err("qpnp adc result read failed with %d\n", rc);
@@ -562,7 +800,7 @@
 	 */
 	if (!batfet_closed || iadc->external_rsense) {
 		/* external offset calculation */
-		rc = qpnp_iadc_configure(OFFSET_CALIBRATION_CSP_CSN,
+		rc = qpnp_iadc_configure(iadc, OFFSET_CALIBRATION_CSP_CSN,
 						&raw_data, mode_sel);
 		if (rc < 0) {
 			pr_err("qpnp adc result read failed with %d\n", rc);
@@ -570,7 +808,7 @@
 		}
 	} else {
 		/* internal offset calculation */
-		rc = qpnp_iadc_configure(OFFSET_CALIBRATION_CSP2_CSN2,
+		rc = qpnp_iadc_configure(iadc, OFFSET_CALIBRATION_CSP2_CSN2,
 						&raw_data, mode_sel);
 		if (rc < 0) {
 			pr_err("qpnp adc result read failed with %d\n", rc);
@@ -584,10 +822,16 @@
 		goto fail;
 	}
 
+	if (iadc->iadc_comp.revision_dig_major == QPNP_IADC_PM8026_2_REV2
+		&& iadc->iadc_comp.revision_ana_minor ==
+						QPNP_IADC_PM8026_2_REV3)
+		iadc->adc->calib.gain_raw =
+			iadc->adc->calib.offset_raw + IADC_IDEAL_RAW_GAIN;
+
 	pr_debug("raw gain:0x%x, raw offset:0x%x\n",
 		iadc->adc->calib.gain_raw, iadc->adc->calib.offset_raw);
 
-	rc = qpnp_convert_raw_offset_voltage();
+	rc = qpnp_convert_raw_offset_voltage(iadc);
 	if (rc < 0) {
 		pr_err("qpnp raw_voltage conversion failed\n");
 		goto fail;
@@ -599,34 +843,38 @@
 
 	pr_debug("trim values:lsb:0x%x and msb:0x%x\n", rslt_lsb, rslt_msb);
 
-	rc = qpnp_iadc_write_reg(QPNP_IADC_SEC_ACCESS,
+	rc = qpnp_iadc_write_reg(iadc, QPNP_IADC_SEC_ACCESS,
 					QPNP_IADC_SEC_ACCESS_DATA);
 	if (rc < 0) {
 		pr_err("qpnp iadc configure error for sec access\n");
 		goto fail;
 	}
 
-	rc = qpnp_iadc_write_reg(QPNP_IADC_MSB_OFFSET,
+	rc = qpnp_iadc_write_reg(iadc, QPNP_IADC_MSB_OFFSET,
 						rslt_msb);
 	if (rc < 0) {
 		pr_err("qpnp iadc configure error for MSB write\n");
 		goto fail;
 	}
 
-	rc = qpnp_iadc_write_reg(QPNP_IADC_SEC_ACCESS,
+	rc = qpnp_iadc_write_reg(iadc, QPNP_IADC_SEC_ACCESS,
 					QPNP_IADC_SEC_ACCESS_DATA);
 	if (rc < 0) {
 		pr_err("qpnp iadc configure error for sec access\n");
 		goto fail;
 	}
 
-	rc = qpnp_iadc_write_reg(QPNP_IADC_LSB_OFFSET,
+	rc = qpnp_iadc_write_reg(iadc, QPNP_IADC_LSB_OFFSET,
 						rslt_lsb);
 	if (rc < 0) {
 		pr_err("qpnp iadc configure error for LSB write\n");
 		goto fail;
 	}
 fail:
+	if (iadc->iadc_poll_eoc) {
+		pr_debug("releasing iadc eoc wakelock\n");
+		pm_relax(iadc->dev);
+	}
 	mutex_unlock(&iadc->adc->adc_lock);
 	return rc;
 }
@@ -634,11 +882,12 @@
 
 static void qpnp_iadc_work(struct work_struct *work)
 {
-	struct qpnp_iadc_drv *iadc = qpnp_iadc;
+	struct qpnp_iadc_chip *iadc = container_of(work,
+			struct qpnp_iadc_chip, iadc_work.work);
 	int rc = 0;
 
 	if (!iadc->skip_auto_calibrations) {
-		rc = qpnp_iadc_calibrate_for_trim(true);
+		rc = qpnp_iadc_calibrate_for_trim(iadc, true);
 		if (rc)
 			pr_debug("periodic IADC calibration failed\n");
 	}
@@ -649,12 +898,12 @@
 	return;
 }
 
-static int32_t qpnp_iadc_version_check(void)
+static int32_t qpnp_iadc_version_check(struct qpnp_iadc_chip *iadc)
 {
 	uint8_t revision;
 	int rc;
 
-	rc = qpnp_iadc_read_reg(QPNP_IADC_REVISION2, &revision);
+	rc = qpnp_iadc_read_reg(iadc, QPNP_IADC_REVISION2, &revision);
 	if (rc < 0) {
 		pr_err("qpnp adc result read failed with %d\n", rc);
 		return rc;
@@ -668,24 +917,31 @@
 	return 0;
 }
 
-int32_t qpnp_iadc_is_ready(void)
+struct qpnp_iadc_chip *qpnp_get_iadc(struct device *dev, const char *name)
 {
-	struct qpnp_iadc_drv *iadc = qpnp_iadc;
+	struct qpnp_iadc_chip *iadc;
+	struct device_node *node = NULL;
+	char prop_name[QPNP_MAX_PROP_NAME_LEN];
 
-	if (!iadc || !iadc->iadc_initialized)
-		return -EPROBE_DEFER;
-	else
-		return 0;
+	snprintf(prop_name, QPNP_MAX_PROP_NAME_LEN, "qcom,%s-iadc", name);
+
+	node = of_parse_phandle(dev->of_node, prop_name, 0);
+	if (node == NULL)
+		return ERR_PTR(-ENODEV);
+
+	list_for_each_entry(iadc, &qpnp_iadc_device_list, list)
+		if (iadc->adc->spmi->dev.of_node == node)
+			return iadc;
+	return ERR_PTR(-EPROBE_DEFER);
 }
-EXPORT_SYMBOL(qpnp_iadc_is_ready);
+EXPORT_SYMBOL(qpnp_get_iadc);
 
-int32_t qpnp_iadc_get_rsense(int32_t *rsense)
+int32_t qpnp_iadc_get_rsense(struct qpnp_iadc_chip *iadc, int32_t *rsense)
 {
-	struct qpnp_iadc_drv *iadc = qpnp_iadc;
 	uint8_t	rslt_rsense;
 	int32_t	rc = 0, sign_bit = 0;
 
-	if (!iadc || !iadc->iadc_initialized)
+	if (qpnp_iadc_is_valid(iadc) < 0)
 		return -EPROBE_DEFER;
 
 	if (iadc->external_rsense) {
@@ -693,7 +949,7 @@
 		return rc;
 	}
 
-	rc = qpnp_iadc_read_reg(QPNP_IADC_NOMINAL_RSENSE, &rslt_rsense);
+	rc = qpnp_iadc_read_reg(iadc, QPNP_IADC_NOMINAL_RSENSE, &rslt_rsense);
 	if (rc < 0) {
 		pr_err("qpnp adc rsense read failed with %d\n", rc);
 		return rc;
@@ -717,9 +973,8 @@
 }
 EXPORT_SYMBOL(qpnp_iadc_get_rsense);
 
-static int32_t qpnp_check_pmic_temp(void)
+static int32_t qpnp_check_pmic_temp(struct qpnp_iadc_chip *iadc)
 {
-	struct qpnp_iadc_drv *iadc = qpnp_iadc;
 	struct qpnp_vadc_result result_pmic_therm;
 	int64_t die_temp_offset;
 	int rc = 0;
@@ -736,7 +991,7 @@
 	if (die_temp_offset > QPNP_IADC_DIE_TEMP_CALIB_OFFSET) {
 		iadc->die_temp = result_pmic_therm.physical;
 		if (!iadc->skip_auto_calibrations) {
-			rc = qpnp_iadc_calibrate_for_trim(true);
+			rc = qpnp_iadc_calibrate_for_trim(iadc, true);
 			if (rc)
 				pr_err("IADC calibration failed rc = %d\n", rc);
 		}
@@ -745,20 +1000,20 @@
 	return rc;
 }
 
-int32_t qpnp_iadc_read(enum qpnp_iadc_channels channel,
+int32_t qpnp_iadc_read(struct qpnp_iadc_chip *iadc,
+				enum qpnp_iadc_channels channel,
 				struct qpnp_iadc_result *result)
 {
-	struct qpnp_iadc_drv *iadc = qpnp_iadc;
 	int32_t rc, rsense_n_ohms, sign = 0, num, mode_sel = 0;
 	int32_t rsense_u_ohms = 0;
 	int64_t result_current;
 	uint16_t raw_data;
 
-	if (!iadc || !iadc->iadc_initialized)
+	if (qpnp_iadc_is_valid(iadc) < 0)
 		return -EPROBE_DEFER;
 
 	if (!iadc->iadc_mode_sel) {
-		rc = qpnp_check_pmic_temp();
+		rc = qpnp_check_pmic_temp(iadc);
 		if (rc) {
 			pr_err("Error checking pmic therm temp\n");
 			return rc;
@@ -767,13 +1022,18 @@
 
 	mutex_lock(&iadc->adc->adc_lock);
 
-	rc = qpnp_iadc_configure(channel, &raw_data, mode_sel);
+	if (iadc->iadc_poll_eoc) {
+		pr_debug("acquiring iadc eoc wakelock\n");
+		pm_stay_awake(iadc->dev);
+	}
+
+	rc = qpnp_iadc_configure(iadc, channel, &raw_data, mode_sel);
 	if (rc < 0) {
 		pr_err("qpnp adc result read failed with %d\n", rc);
 		goto fail;
 	}
 
-	rc = qpnp_iadc_get_rsense(&rsense_n_ohms);
+	rc = qpnp_iadc_get_rsense(iadc, &rsense_n_ohms);
 	pr_debug("current raw:0%x and rsense:%d\n",
 			raw_data, rsense_n_ohms);
 	rsense_u_ohms = rsense_n_ohms/1000;
@@ -794,28 +1054,32 @@
 		result->result_uv = -result->result_uv;
 		result_current = -result_current;
 	}
-	rc = qpnp_iadc_comp_result(&result_current);
+	rc = qpnp_iadc_comp_result(iadc, &result_current);
 	if (rc < 0)
 		pr_err("Error during compensating the IADC\n");
 	rc = 0;
 
 	result->result_ua = (int32_t) result_current;
 fail:
+	if (iadc->iadc_poll_eoc) {
+		pr_debug("releasing iadc eoc wakelock\n");
+		pm_relax(iadc->dev);
+	}
 	mutex_unlock(&iadc->adc->adc_lock);
 
 	return rc;
 }
 EXPORT_SYMBOL(qpnp_iadc_read);
 
-int32_t qpnp_iadc_get_gain_and_offset(struct qpnp_iadc_calib *result)
+int32_t qpnp_iadc_get_gain_and_offset(struct qpnp_iadc_chip *iadc,
+					struct qpnp_iadc_calib *result)
 {
-	struct qpnp_iadc_drv *iadc = qpnp_iadc;
 	int rc;
 
-	if (!iadc || !iadc->iadc_initialized)
+	if (qpnp_iadc_is_valid(iadc) < 0)
 		return -EPROBE_DEFER;
 
-	rc = qpnp_check_pmic_temp();
+	rc = qpnp_check_pmic_temp(iadc);
 	if (rc) {
 		pr_err("Error checking pmic therm temp\n");
 		return rc;
@@ -839,43 +1103,37 @@
 }
 EXPORT_SYMBOL(qpnp_iadc_get_gain_and_offset);
 
-int qpnp_iadc_skip_calibration(void)
+int qpnp_iadc_skip_calibration(struct qpnp_iadc_chip *iadc)
 {
-	struct qpnp_iadc_drv *iadc = qpnp_iadc;
-
-	if (!iadc || !iadc->iadc_initialized)
-		return -EPROBE_DEFER;
-
 	iadc->skip_auto_calibrations = true;
 	return 0;
 }
 EXPORT_SYMBOL(qpnp_iadc_skip_calibration);
 
-int qpnp_iadc_resume_calibration(void)
+int qpnp_iadc_resume_calibration(struct qpnp_iadc_chip *iadc)
 {
-	struct qpnp_iadc_drv *iadc = qpnp_iadc;
-
-	if (!iadc || !iadc->iadc_initialized)
-		return -EPROBE_DEFER;
-
 	iadc->skip_auto_calibrations = false;
 	return 0;
 }
 EXPORT_SYMBOL(qpnp_iadc_resume_calibration);
 
-int32_t qpnp_iadc_vadc_sync_read(
+int32_t qpnp_iadc_vadc_sync_read(struct qpnp_iadc_chip *iadc,
 	enum qpnp_iadc_channels i_channel, struct qpnp_iadc_result *i_result,
 	enum qpnp_vadc_channels v_channel, struct qpnp_vadc_result *v_result)
 {
-	struct qpnp_iadc_drv *iadc = qpnp_iadc;
 	int rc = 0;
 
-	if (!iadc || !iadc->iadc_initialized)
+	if (qpnp_iadc_is_valid(iadc) < 0)
 		return -EPROBE_DEFER;
 
 	mutex_lock(&iadc->iadc_vadc_lock);
 
-	rc = qpnp_check_pmic_temp();
+	if (iadc->iadc_poll_eoc) {
+		pr_debug("acquiring iadc eoc wakelock\n");
+		pm_stay_awake(iadc->dev);
+	}
+
+	rc = qpnp_check_pmic_temp(iadc);
 	if (rc) {
 		pr_err("PMIC die temp check failed\n");
 		goto fail;
@@ -889,7 +1147,7 @@
 		goto fail;
 	}
 
-	rc = qpnp_iadc_read(i_channel, i_result);
+	rc = qpnp_iadc_read(iadc, i_channel, i_result);
 	if (rc)
 		pr_err("Configuring IADC failed\n");
 	/* Intentional fall through to release VADC */
@@ -901,6 +1159,10 @@
 fail:
 	iadc->iadc_mode_sel = false;
 
+	if (iadc->iadc_poll_eoc) {
+		pr_debug("releasing iadc eoc wakelock\n");
+		pm_relax(iadc->dev);
+	}
 	mutex_unlock(&iadc->iadc_vadc_lock);
 
 	return rc;
@@ -911,10 +1173,11 @@
 			struct device_attribute *devattr, char *buf)
 {
 	struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
+	struct qpnp_iadc_chip *iadc = dev_get_drvdata(dev);
 	struct qpnp_iadc_result result;
 	int rc = -1;
 
-	rc = qpnp_iadc_read(attr->index, &result);
+	rc = qpnp_iadc_read(iadc, attr->index, &result);
 
 	if (rc)
 		return 0;
@@ -926,9 +1189,9 @@
 static struct sensor_device_attribute qpnp_adc_attr =
 	SENSOR_ATTR(NULL, S_IRUGO, qpnp_iadc_show, NULL, 0);
 
-static int32_t qpnp_iadc_init_hwmon(struct spmi_device *spmi)
+static int32_t qpnp_iadc_init_hwmon(struct qpnp_iadc_chip *iadc,
+						struct spmi_device *spmi)
 {
-	struct qpnp_iadc_drv *iadc = qpnp_iadc;
 	struct device_node *child;
 	struct device_node *node = spmi->dev.of_node;
 	int rc = 0, i = 0, channel;
@@ -960,19 +1223,11 @@
 
 static int __devinit qpnp_iadc_probe(struct spmi_device *spmi)
 {
-	struct qpnp_iadc_drv *iadc;
+	struct qpnp_iadc_chip *iadc;
 	struct qpnp_adc_drv *adc_qpnp;
 	struct device_node *node = spmi->dev.of_node;
 	struct device_node *child;
-	int rc, count_adc_channel_list = 0;
-
-	if (!node)
-		return -EINVAL;
-
-	if (qpnp_iadc) {
-		pr_err("IADC already in use\n");
-		return -EBUSY;
-	}
+	int rc, count_adc_channel_list = 0, i = 0;
 
 	for_each_child_of_node(node, child)
 		count_adc_channel_list++;
@@ -982,7 +1237,7 @@
 		return -EINVAL;
 	}
 
-	iadc = devm_kzalloc(&spmi->dev, sizeof(struct qpnp_iadc_drv) +
+	iadc = devm_kzalloc(&spmi->dev, sizeof(struct qpnp_iadc_chip) +
 		(sizeof(struct sensor_device_attribute) *
 				count_adc_channel_list), GFP_KERNEL);
 	if (!iadc) {
@@ -994,16 +1249,16 @@
 			GFP_KERNEL);
 	if (!adc_qpnp) {
 		dev_err(&spmi->dev, "Unable to allocate memory\n");
-		rc = -ENOMEM;
-		goto fail;
+		return -ENOMEM;
 	}
 
+	iadc->dev = &(spmi->dev);
 	iadc->adc = adc_qpnp;
 
 	rc = qpnp_adc_get_devicetree_data(spmi, iadc->adc);
 	if (rc) {
 		dev_err(&spmi->dev, "failed to read device tree\n");
-		goto fail;
+		return rc;
 	}
 
 	iadc->vadc_dev = qpnp_get_vadc(&spmi->dev, "iadc");
@@ -1011,7 +1266,7 @@
 		rc = PTR_ERR(iadc->vadc_dev);
 		if (rc != -EPROBE_DEFER)
 			pr_err("vadc property missing, rc=%d\n", rc);
-		goto fail;
+		return rc;
 	}
 
 	mutex_init(&iadc->adc->adc_lock);
@@ -1025,55 +1280,68 @@
 		iadc->external_rsense = true;
 	}
 
-	rc = devm_request_irq(&spmi->dev, iadc->adc->adc_irq_eoc,
-				qpnp_iadc_isr,
-	IRQF_TRIGGER_RISING, "qpnp_iadc_interrupt", iadc);
-	if (rc) {
-		dev_err(&spmi->dev, "failed to request adc irq\n");
-		goto fail;
-	} else
-		enable_irq_wake(iadc->adc->adc_irq_eoc);
+	iadc->iadc_poll_eoc = of_property_read_bool(node,
+						"qcom,iadc-poll-eoc");
+	if (!iadc->iadc_poll_eoc) {
+		rc = devm_request_irq(&spmi->dev, iadc->adc->adc_irq_eoc,
+				qpnp_iadc_isr, IRQF_TRIGGER_RISING,
+				"qpnp_iadc_interrupt", iadc);
+		if (rc) {
+			dev_err(&spmi->dev, "failed to request adc irq\n");
+			return rc;
+		} else
+			enable_irq_wake(iadc->adc->adc_irq_eoc);
+	}
 
-	dev_set_drvdata(&spmi->dev, iadc);
-	qpnp_iadc = iadc;
-
-	rc = qpnp_iadc_init_hwmon(spmi);
+	rc = qpnp_iadc_init_hwmon(iadc, spmi);
 	if (rc) {
 		dev_err(&spmi->dev, "failed to initialize qpnp hwmon adc\n");
-		goto fail;
+		return rc;
 	}
 	iadc->iadc_hwmon = hwmon_device_register(&iadc->adc->spmi->dev);
 
-	rc = qpnp_iadc_version_check();
+	rc = qpnp_iadc_version_check(iadc);
 	if (rc) {
 		dev_err(&spmi->dev, "IADC version not supported\n");
 		goto fail;
 	}
 
 	mutex_init(&iadc->iadc_vadc_lock);
+	INIT_WORK(&iadc->trigger_completion_work, qpnp_iadc_trigger_completion);
 	INIT_DELAYED_WORK(&iadc->iadc_work, qpnp_iadc_work);
-	rc = qpnp_iadc_comp_info();
+	rc = qpnp_iadc_comp_info(iadc);
 	if (rc) {
 		dev_err(&spmi->dev, "abstracting IADC comp info failed!\n");
 		goto fail;
 	}
-	iadc->iadc_initialized = true;
 
-	rc = qpnp_iadc_calibrate_for_trim(true);
+	dev_set_drvdata(&spmi->dev, iadc);
+	list_add(&iadc->list, &qpnp_iadc_device_list);
+	rc = qpnp_iadc_calibrate_for_trim(iadc, true);
 	if (rc)
 		dev_err(&spmi->dev, "failed to calibrate for USR trim\n");
+
+	if (iadc->iadc_poll_eoc)
+		device_init_wakeup(iadc->dev, 1);
+
 	schedule_delayed_work(&iadc->iadc_work,
 			round_jiffies_relative(msecs_to_jiffies
 					(QPNP_IADC_CALIB_SECONDS)));
 	return 0;
 fail:
-	qpnp_iadc = NULL;
+	for_each_child_of_node(node, child) {
+		device_remove_file(&spmi->dev,
+			&iadc->sens_attr[i].dev_attr);
+		i++;
+	}
+	hwmon_device_unregister(iadc->iadc_hwmon);
+
 	return rc;
 }
 
 static int __devexit qpnp_iadc_remove(struct spmi_device *spmi)
 {
-	struct qpnp_iadc_drv *iadc = dev_get_drvdata(&spmi->dev);
+	struct qpnp_iadc_chip *iadc = dev_get_drvdata(&spmi->dev);
 	struct device_node *node = spmi->dev.of_node;
 	struct device_node *child;
 	int i = 0;
@@ -1085,6 +1353,9 @@
 			&iadc->sens_attr[i].dev_attr);
 		i++;
 	}
+	hwmon_device_unregister(iadc->iadc_hwmon);
+	if (iadc->iadc_poll_eoc)
+		pm_relax(iadc->dev);
 	dev_set_drvdata(&spmi->dev, NULL);
 
 	return 0;
diff --git a/drivers/hwmon/qpnp-adc-voltage.c b/drivers/hwmon/qpnp-adc-voltage.c
index 2fe69fb..b2b846a 100644
--- a/drivers/hwmon/qpnp-adc-voltage.c
+++ b/drivers/hwmon/qpnp-adc-voltage.c
@@ -99,7 +99,7 @@
 #define QPNP_VADC_CONV_TIME_MIN					2000
 #define QPNP_VADC_CONV_TIME_MAX					2100
 #define QPNP_ADC_COMPLETION_TIMEOUT				HZ
-#define QPNP_VADC_ERR_COUNT					5
+#define QPNP_VADC_ERR_COUNT					20
 
 struct qpnp_vadc_chip {
 	struct device			*dev;
@@ -112,6 +112,9 @@
 	bool				vadc_iadc_sync_lock;
 	u8				id;
 	struct work_struct		trigger_completion_work;
+	bool				vadc_poll_eoc;
+	u8				revision_ana_minor;
+	u8				revision_dig_major;
 	struct sensor_device_attribute	sens_attr[0];
 };
 
@@ -125,6 +128,7 @@
 	[SCALE_THERM_100K_PULLUP] = {qpnp_adc_scale_therm_pu2},
 	[SCALE_THERM_150K_PULLUP] = {qpnp_adc_scale_therm_pu1},
 	[SCALE_QRD_BATT_THERM] = {qpnp_adc_scale_qrd_batt_therm},
+	[SCALE_QRD_SKUAA_BATT_THERM] = {qpnp_adc_scale_qrd_skuaa_batt_therm},
 };
 
 static int32_t qpnp_vadc_read_reg(struct qpnp_vadc_chip *vadc, int16_t reg,
@@ -346,7 +350,8 @@
 		}
 	}
 
-	INIT_COMPLETION(vadc->adc->adc_rslt_completion);
+	if (!vadc->vadc_poll_eoc)
+		INIT_COMPLETION(vadc->adc->adc_rslt_completion);
 
 	rc = qpnp_vadc_enable(vadc, true);
 	if (rc)
@@ -491,29 +496,189 @@
 	return 0;
 }
 
-static int32_t qpnp_vbat_sns_comp(int64_t *result, u8 id, int64_t die_temp)
+#define QPNP_VBAT_COEFF_1	3000
+#define QPNP_VBAT_COEFF_2	45810000
+#define QPNP_VBAT_COEFF_3	100000
+#define QPNP_VBAT_COEFF_4	3500
+#define QPNP_VBAT_COEFF_5	80000000
+#define QPNP_VBAT_COEFF_6	4400
+#define QPNP_VBAT_COEFF_7	32200000
+#define QPNP_VBAT_COEFF_8	3880
+#define QPNP_VBAT_COEFF_9	5770
+#define QPNP_VBAT_COEFF_10	3660
+#define QPNP_VBAT_COEFF_11	5320
+#define QPNP_VBAT_COEFF_12	8060000
+#define QPNP_VBAT_COEFF_13	102640000
+#define QPNP_VBAT_COEFF_14	22220000
+#define QPNP_VBAT_COEFF_15	83060000
+
+#define QPNP_VADC_REV_ID_8941_3_1	1
+#define QPNP_VADC_REV_ID_8026_1_0	2
+#define QPNP_VADC_REV_ID_8026_2_0	3
+
+static void qpnp_temp_comp_version_check(struct qpnp_vadc_chip *vadc,
+							int32_t *version)
+{
+	if (vadc->revision_dig_major == 3 &&
+			vadc->revision_ana_minor == 2)
+		*version = QPNP_VADC_REV_ID_8941_3_1;
+	else if (vadc->revision_dig_major == 1 &&
+			vadc->revision_ana_minor == 2)
+		*version = QPNP_VADC_REV_ID_8026_1_0;
+	else if (vadc->revision_dig_major == 2 &&
+			vadc->revision_ana_minor == 2)
+		*version = QPNP_VADC_REV_ID_8026_2_0;
+	else
+		*version = -EINVAL;
+
+	return;
+}
+
+static int32_t qpnp_ocv_comp(int64_t *result,
+			struct qpnp_vadc_chip *vadc, int64_t die_temp)
 {
 	int64_t temp_var = 0;
 	int64_t old = *result;
+	int32_t version;
+
+	qpnp_temp_comp_version_check(vadc, &version);
+	if (version == -EINVAL)
+		return 0;
 
 	if (die_temp < 25000)
 		return 0;
 
-	switch (id) {
-	case COMP_ID_TSMC:
-		temp_var = (((die_temp *
-			(-QPNP_VBAT_SNS_COEFF_1_TYPEB))
-			+ QPNP_VBAT_SNS_COEFF_2_TYPEB));
-	break;
+	if (die_temp > 60000)
+		die_temp = 60000;
+
+	switch (version) {
+	case QPNP_VADC_REV_ID_8941_3_1:
+		switch (vadc->id) {
+		case COMP_ID_TSMC:
+			temp_var = (((die_temp *
+			(-QPNP_VBAT_COEFF_4))
+			+ QPNP_VBAT_COEFF_5));
+			break;
+		default:
+		case COMP_ID_GF:
+			temp_var = (((die_temp *
+			(-QPNP_VBAT_COEFF_1))
+			+ QPNP_VBAT_COEFF_2));
+			break;
+		}
+		break;
+	case QPNP_VADC_REV_ID_8026_1_0:
+		switch (vadc->id) {
+		case COMP_ID_TSMC:
+			temp_var = (((die_temp *
+			(-QPNP_VBAT_COEFF_10))
+			- QPNP_VBAT_COEFF_14));
+			break;
+		default:
+		case COMP_ID_GF:
+			temp_var = (((die_temp *
+			(-QPNP_VBAT_COEFF_8))
+			+ QPNP_VBAT_COEFF_12));
+			break;
+		}
+		break;
+	case QPNP_VADC_REV_ID_8026_2_0:
+		switch (vadc->id) {
+		case COMP_ID_TSMC:
+			temp_var = ((die_temp - 2500) *
+			(-QPNP_VBAT_COEFF_10));
+			break;
+		default:
+		case COMP_ID_GF:
+			temp_var = ((die_temp - 2500) *
+			(-QPNP_VBAT_COEFF_8));
+			break;
+		}
+		break;
 	default:
-	case COMP_ID_GF:
-		temp_var = (((die_temp *
-			(-QPNP_VBAT_SNS_COEFF_1_TYPEA))
-			+ QPNP_VBAT_SNS_COEFF_2_TYPEA));
-	break;
+		temp_var = 0;
+		break;
 	}
 
-	temp_var = div64_s64(temp_var, QPNP_VBAT_SNS_COEFF_3);
+	temp_var = div64_s64(temp_var, QPNP_VBAT_COEFF_3);
+
+	temp_var = 1000000 + temp_var;
+
+	*result = *result * temp_var;
+
+	*result = div64_s64(*result, 1000000);
+	pr_debug("%lld compensated into %lld\n", old, *result);
+
+	return 0;
+}
+
+static int32_t qpnp_vbat_sns_comp(int64_t *result,
+			struct qpnp_vadc_chip *vadc, int64_t die_temp)
+{
+	int64_t temp_var = 0;
+	int64_t old = *result;
+	int32_t version;
+
+	qpnp_temp_comp_version_check(vadc, &version);
+	if (version == -EINVAL)
+		return 0;
+
+	if (die_temp < 25000)
+		return 0;
+
+	/* min(die_temp_c, 60_degC) */
+	if (die_temp > 60000)
+		die_temp = 60000;
+
+	switch (version) {
+	case QPNP_VADC_REV_ID_8941_3_1:
+		switch (vadc->id) {
+		case COMP_ID_TSMC:
+			temp_var = (die_temp *
+			(-QPNP_VBAT_COEFF_1));
+			break;
+		default:
+		case COMP_ID_GF:
+			temp_var = (((die_temp *
+			(-QPNP_VBAT_COEFF_6))
+			+ QPNP_VBAT_COEFF_7));
+			break;
+		}
+		break;
+	case QPNP_VADC_REV_ID_8026_1_0:
+		switch (vadc->id) {
+		case COMP_ID_TSMC:
+			temp_var = (((die_temp *
+			(-QPNP_VBAT_COEFF_11))
+			+ QPNP_VBAT_COEFF_15));
+			break;
+		default:
+		case COMP_ID_GF:
+			temp_var = (((die_temp *
+			(-QPNP_VBAT_COEFF_9))
+			+ QPNP_VBAT_COEFF_13));
+			break;
+		}
+		break;
+	case QPNP_VADC_REV_ID_8026_2_0:
+		switch (vadc->id) {
+		case COMP_ID_TSMC:
+			temp_var = ((die_temp - 2500) *
+			(-QPNP_VBAT_COEFF_11));
+			break;
+		default:
+		case COMP_ID_GF:
+			temp_var = ((die_temp - 2500) *
+			(-QPNP_VBAT_COEFF_9));
+			break;
+		}
+		break;
+	default:
+		temp_var = 0;
+		break;
+	}
+
+	temp_var = div64_s64(temp_var, QPNP_VBAT_COEFF_3);
 
 	temp_var = 1000000 + temp_var;
 
@@ -542,8 +707,7 @@
 		return rc;
 	}
 
-	rc = qpnp_vbat_sns_comp(result, vadc->id,
-					die_temp_result.physical);
+	rc = qpnp_ocv_comp(result, vadc, die_temp_result.physical);
 	if (rc < 0)
 		pr_err("Error with vbat compensation\n");
 
@@ -799,13 +963,19 @@
 					struct qpnp_vadc_result *result)
 {
 	int rc = 0, scale_type, amux_prescaling, dt_index = 0;
-	uint32_t ref_channel;
+	uint32_t ref_channel, count = 0;
+	u8 status1 = 0;
 
 	if (qpnp_vadc_is_valid(vadc))
 		return -EPROBE_DEFER;
 
 	mutex_lock(&vadc->adc->adc_lock);
 
+	if (vadc->vadc_poll_eoc) {
+		pr_debug("requesting vadc eoc stay awake\n");
+		pm_stay_awake(vadc->dev);
+	}
+
 	if (!vadc->vadc_init_calib) {
 		rc = qpnp_vadc_version_check(vadc);
 		if (rc)
@@ -862,22 +1032,44 @@
 		goto fail_unlock;
 	}
 
-	rc = wait_for_completion_timeout(&vadc->adc->adc_rslt_completion,
-					QPNP_ADC_COMPLETION_TIMEOUT);
-	if (!rc) {
-		u8 status1 = 0;
-		rc = qpnp_vadc_read_reg(vadc, QPNP_VADC_STATUS1, &status1);
-		if (rc < 0)
-			goto fail_unlock;
-		status1 &= (QPNP_VADC_STATUS1_REQ_STS | QPNP_VADC_STATUS1_EOC);
-		if (status1 == QPNP_VADC_STATUS1_EOC)
-			pr_debug("End of conversion status set\n");
-		else {
-			rc = qpnp_vadc_status_debug(vadc);
+	if (vadc->vadc_poll_eoc) {
+		while (status1 != QPNP_VADC_STATUS1_EOC) {
+			rc = qpnp_vadc_read_reg(vadc, QPNP_VADC_STATUS1,
+								&status1);
 			if (rc < 0)
-				pr_err("VADC disable failed\n");
-			rc = -EINVAL;
-			goto fail_unlock;
+				goto fail_unlock;
+			status1 &= QPNP_VADC_STATUS1_REQ_STS_EOC_MASK;
+			usleep_range(QPNP_VADC_CONV_TIME_MIN,
+					QPNP_VADC_CONV_TIME_MAX);
+			count++;
+			if (count > QPNP_VADC_ERR_COUNT) {
+				pr_err("retry error exceeded\n");
+				rc = qpnp_vadc_status_debug(vadc);
+				if (rc < 0)
+					pr_err("VADC disable failed\n");
+				rc = -EINVAL;
+				goto fail_unlock;
+			}
+		}
+	} else {
+		rc = wait_for_completion_timeout(
+					&vadc->adc->adc_rslt_completion,
+					QPNP_ADC_COMPLETION_TIMEOUT);
+		if (!rc) {
+			rc = qpnp_vadc_read_reg(vadc, QPNP_VADC_STATUS1,
+								&status1);
+			if (rc < 0)
+				goto fail_unlock;
+			status1 &= QPNP_VADC_STATUS1_REQ_STS_EOC_MASK;
+			if (status1 == QPNP_VADC_STATUS1_EOC)
+				pr_debug("End of conversion status set\n");
+			else {
+				rc = qpnp_vadc_status_debug(vadc);
+				if (rc < 0)
+					pr_err("VADC disable failed\n");
+				rc = -EINVAL;
+				goto fail_unlock;
+			}
 		}
 	}
 
@@ -917,6 +1109,11 @@
 		vadc->adc->adc_prop, vadc->adc->amux_prop->chan_prop, result);
 
 fail_unlock:
+	if (vadc->vadc_poll_eoc) {
+		pr_debug("requesting vadc eoc stay awake\n");
+		pm_relax(vadc->dev);
+	}
+
 	mutex_unlock(&vadc->adc->adc_lock);
 
 	return rc;
@@ -945,7 +1142,7 @@
 			return rc;
 		}
 
-		rc = qpnp_vbat_sns_comp(&result->physical, vadc->id,
+		rc = qpnp_vbat_sns_comp(&result->physical, vadc,
 						die_temp_result.physical);
 		if (rc < 0)
 			pr_err("Error with vbat compensation\n");
@@ -1168,17 +1365,6 @@
 	}
 	mutex_init(&vadc->adc->adc_lock);
 
-	rc = devm_request_irq(&spmi->dev, vadc->adc->adc_irq_eoc,
-				qpnp_vadc_isr, IRQF_TRIGGER_RISING,
-				"qpnp_vadc_interrupt", vadc);
-	if (rc) {
-		dev_err(&spmi->dev,
-			"failed to request adc irq with error %d\n", rc);
-		return rc;
-	} else {
-		enable_irq_wake(vadc->adc->adc_irq_eoc);
-	}
-
 	rc = qpnp_vadc_init_hwmon(vadc, spmi);
 	if (rc) {
 		dev_err(&spmi->dev, "failed to initialize qpnp hwmon adc\n");
@@ -1194,6 +1380,20 @@
 	}
 	vadc->id = fab_id;
 
+	rc = qpnp_vadc_read_reg(vadc, QPNP_VADC_REVISION2,
+					&vadc->revision_dig_major);
+	if (rc < 0) {
+		pr_err("qpnp adc dig_major rev read failed with %d\n", rc);
+		goto err_setup;
+	}
+
+	rc = qpnp_vadc_read_reg(vadc, QPNP_VADC_REVISION3,
+					&vadc->revision_ana_minor);
+	if (rc < 0) {
+		pr_err("qpnp adc ana_minor rev read failed with %d\n", rc);
+		goto err_setup;
+	}
+
 	rc = qpnp_vadc_warm_rst_configure(vadc);
 	if (rc < 0) {
 		pr_err("Setting perp reset on warm reset failed %d\n", rc);
@@ -1201,8 +1401,24 @@
 	}
 
 	INIT_WORK(&vadc->trigger_completion_work, qpnp_vadc_work);
-	vadc->vadc_iadc_sync_lock = false;
 
+	vadc->vadc_poll_eoc = of_property_read_bool(node,
+						"qcom,vadc-poll-eoc");
+	if (!vadc->vadc_poll_eoc) {
+		rc = devm_request_irq(&spmi->dev, vadc->adc->adc_irq_eoc,
+				qpnp_vadc_isr, IRQF_TRIGGER_RISING,
+				"qpnp_vadc_interrupt", vadc);
+		if (rc) {
+			dev_err(&spmi->dev,
+			"failed to request adc irq with error %d\n", rc);
+			goto err_setup;
+		} else {
+			enable_irq_wake(vadc->adc->adc_irq_eoc);
+		}
+	} else
+		device_init_wakeup(vadc->dev, 1);
+
+	vadc->vadc_iadc_sync_lock = false;
 	dev_set_drvdata(&spmi->dev, vadc);
 	list_add(&vadc->list, &qpnp_vadc_device_list);
 
@@ -1233,6 +1449,8 @@
 	}
 	hwmon_device_unregister(vadc->vadc_hwmon);
 	list_del(&vadc->list);
+	if (vadc->vadc_poll_eoc)
+		pm_relax(vadc->dev);
 	dev_set_drvdata(&spmi->dev, NULL);
 
 	return 0;
diff --git a/drivers/input/misc/Kconfig b/drivers/input/misc/Kconfig
index a052bd3..716ea0d 100644
--- a/drivers/input/misc/Kconfig
+++ b/drivers/input/misc/Kconfig
@@ -692,4 +692,26 @@
 	default "0"
 	help
 	  this provide the sensor position setting , value is between 0~7
+
+config SENSORS_STK3X1X
+	tristate "STK3X1X device driver"
+	depends on I2C
+	default n
+	help
+	  Say Y here you want to enable for the sitronix stk3x1x
+	  light and proximity sensors driver.
+
+	  To compile this driver as a module, choose M here: the
+	  module will be called stk3x1x.
+
+config SENSORS_CAPELLA_CM36283
+	tristate "CM36283 proximity and light sensor"
+	depends on I2C
+	default n
+	help
+	  Say Y here to enable the CM36283 Proximity
+	  Sensor with Ambient Light Sensor.
+
+	  To compile this driver as a module, choose M here: the
+	  module will be called CM36283.
 endif
diff --git a/drivers/input/misc/Makefile b/drivers/input/misc/Makefile
index 4f29e05..c927e0e 100644
--- a/drivers/input/misc/Makefile
+++ b/drivers/input/misc/Makefile
@@ -64,3 +64,5 @@
 obj-$(CONFIG_BMP18X)			+= bmp18x-core.o
 obj-$(CONFIG_BMP18X_I2C)		+= bmp18x-i2c.o
 obj-$(CONFIG_SENSORS_MMA8X5X)	  	+= mma8x5x.o
+obj-$(CONFIG_SENSORS_STK3X1X)		+= stk3x1x.o
+obj-$(CONFIG_SENSORS_CAPELLA_CM36283)	+= cm36283.o
diff --git a/drivers/input/misc/cm36283.c b/drivers/input/misc/cm36283.c
index 6280013..d850a0e 100644
--- a/drivers/input/misc/cm36283.c
+++ b/drivers/input/misc/cm36283.c
@@ -2,7 +2,9 @@
  *
  * Copyright (C) 2012 Capella Microsystems Inc.
  * Author: Frank Hsieh <pengyueh@gmail.com>
- *                                    
+ *
+ * Copyright (c) 2013, 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.
@@ -27,15 +29,16 @@
 #include <linux/err.h>
 #include <linux/gpio.h>
 #include <linux/miscdevice.h>
-#include <linux/lightsensor.h>
 #include <linux/slab.h>
-#include <asm/uaccess.h>
-#include <asm/mach-types.h>
-#include <linux/cm36283.h>
-#include <linux/capella_cm3602.h>
-#include <asm/setup.h>
+#include <linux/regulator/consumer.h>
 #include <linux/wakelock.h>
 #include <linux/jiffies.h>
+#include <linux/cm36283.h>
+#include <linux/of_gpio.h>
+
+#include <asm/uaccess.h>
+#include <asm/mach-types.h>
+#include <asm/setup.h>
 
 #define D(x...) pr_info(x)
 
@@ -47,7 +50,37 @@
 #define CONTROL_ALS                   0x01
 #define CONTROL_PS                    0x02
 
+/* POWER SUPPLY VOLTAGE RANGE */
+#define CM36283_VDD_MIN_UV	2700000
+#define CM36283_VDD_MAX_UV	3300000
+#define CM36283_VI2C_MIN_UV	1750000
+#define CM36283_VI2C_MAX_UV	1950000
+
+/* cm36283 polling rate in ms */
+#define CM36283_LS_MIN_POLL_DELAY	1
+#define CM36283_LS_MAX_POLL_DELAY	1000
+#define CM36283_LS_DEFAULT_POLL_DELAY	100
+
+#define CM36283_PS_MIN_POLL_DELAY	1
+#define CM36283_PS_MAX_POLL_DELAY	1000
+#define CM36283_PS_DEFAULT_POLL_DELAY	100
+
 static int record_init_fail = 0;
+
+static const int als_range[] = {
+	[CM36283_ALS_IT0] = 6554,
+	[CM36283_ALS_IT1] = 3277,
+	[CM36283_ALS_IT2] = 1638,
+	[CM36283_ALS_IT3] = 819,
+};
+
+static const int als_sense[] = {
+	[CM36283_ALS_IT0] = 10,
+	[CM36283_ALS_IT1] = 20,
+	[CM36283_ALS_IT2] = 40,
+	[CM36283_ALS_IT3] = 80,
+};
+
 static void sensor_irq_do_work(struct work_struct *work);
 static DECLARE_WORK(sensor_irq_work, sensor_irq_do_work);
 
@@ -95,20 +128,30 @@
 
 	uint16_t ls_cmd;
 	uint8_t record_clear_int_fail;
+	bool polling;
+	atomic_t ls_poll_delay;
+	atomic_t ps_poll_delay;
+	struct regulator *vdd;
+	struct regulator *vio;
+	struct delayed_work ldwork;
+	struct delayed_work pdwork;
 };
 struct cm36283_info *lp_info;
 int fLevel=-1;
 static struct mutex als_enable_mutex, als_disable_mutex, als_get_adc_mutex;
 static struct mutex ps_enable_mutex, ps_disable_mutex, ps_get_adc_mutex;
 static struct mutex CM36283_control_mutex;
+static struct mutex wq_lock;
 static int lightsensor_enable(struct cm36283_info *lpi);
 static int lightsensor_disable(struct cm36283_info *lpi);
 static int initial_cm36283(struct cm36283_info *lpi);
 static void psensor_initial_cmd(struct cm36283_info *lpi);
+static int cm36283_power_set(struct cm36283_info *info, bool on);
 
 int32_t als_kadc;
 
-static int control_and_report(struct cm36283_info *lpi, uint8_t mode, uint16_t param);
+static int control_and_report(struct cm36283_info *lpi, uint8_t mode,
+		uint16_t param, int report);
 
 static int I2C_RxData(uint16_t slaveAddr, uint8_t cmd, uint8_t *rxData, int length)
 {
@@ -373,12 +416,91 @@
 {
 	struct cm36283_info *lpi = lp_info;
 	uint16_t intFlag;
-  _cm36283_I2C_Read_Word(lpi->slave_addr, INT_FLAG, &intFlag);
-	control_and_report(lpi, CONTROL_INT_ISR_REPORT, intFlag);  
-	  
+	_cm36283_I2C_Read_Word(lpi->slave_addr, INT_FLAG, &intFlag);
+	control_and_report(lpi, CONTROL_INT_ISR_REPORT, intFlag, 1);
+
 	enable_irq(lpi->irq);
 }
 
+static int get_als_range(void)
+{
+	uint16_t ls_conf;
+	int ret = 0;
+	int index = 0;
+	struct cm36283_info *lpi = lp_info;
+
+	ret = _cm36283_I2C_Read_Word(lpi->slave_addr, ALS_CONF, &ls_conf);
+	if (ret) {
+		dev_err(&lpi->i2c_client->dev, "read ALS_CONF from i2c error. %d\n",
+				ret);
+		return -EIO;
+	}
+
+	index = (ls_conf & 0xC0) >> 0x06;
+	return  als_range[index];
+}
+
+static int get_als_sense(void)
+{
+	uint16_t ls_conf;
+	int ret = 0;
+	int index = 0;
+	struct cm36283_info *lpi = lp_info;
+
+	ret = _cm36283_I2C_Read_Word(lpi->slave_addr, ALS_CONF, &ls_conf);
+	if (ret) {
+		dev_err(&lpi->i2c_client->dev, "read ALS_CONF from i2c error. %d\n",
+				ret);
+		return -EIO;
+	}
+
+	index = (ls_conf & 0xC0) >> 0x06;
+	return  als_sense[index];
+}
+
+static void psensor_delay_work_handler(struct work_struct *work)
+{
+	struct cm36283_info *lpi = lp_info;
+	uint16_t adc_value = 0;
+	int ret;
+
+	mutex_lock(&wq_lock);
+
+	ret = get_ps_adc_value(&adc_value);
+
+	mutex_unlock(&wq_lock);
+
+	if (ret >= 0) {
+		input_report_abs(lpi->ps_input_dev, ABS_DISTANCE,
+				adc_value > lpi->ps_close_thd_set ? 0 : 1);
+		input_sync(lpi->ps_input_dev);
+	}
+	schedule_delayed_work(&lpi->pdwork,
+			msecs_to_jiffies(atomic_read(&lpi->ps_poll_delay)));
+}
+
+static void lsensor_delay_work_handler(struct work_struct *work)
+{
+	struct cm36283_info *lpi = lp_info;
+	uint16_t adc_value = 0;
+	int sense;
+
+	mutex_lock(&wq_lock);
+
+	get_ls_adc_value(&adc_value, 0);
+	sense = get_als_sense();
+
+	mutex_unlock(&wq_lock);
+
+	if (sense > 0) {
+		lpi->current_adc = adc_value;
+		input_report_abs(lpi->ls_input_dev, ABS_MISC, adc_value/sense);
+		input_sync(lpi->ls_input_dev);
+	}
+	schedule_delayed_work(&lpi->ldwork,
+			msecs_to_jiffies(atomic_read(&lpi->ls_poll_delay)));
+}
+
 static irqreturn_t cm36283_irq_handler(int irq, void *data)
 {
 	struct cm36283_info *lpi = data;
@@ -422,33 +544,44 @@
 static int psensor_enable(struct cm36283_info *lpi)
 {
 	int ret = -EIO;
+	unsigned int delay;
 	
 	mutex_lock(&ps_enable_mutex);
 	D("[PS][CM36283] %s\n", __func__);
 
-	if ( lpi->ps_enable ) {
+	if (lpi->ps_enable) {
 		D("[PS][CM36283] %s: already enabled\n", __func__);
 		ret = 0;
-	} else
-  	ret = control_and_report(lpi, CONTROL_PS, 1);
-	
+	} else {
+		ret = control_and_report(lpi, CONTROL_PS, 1, 0);
+	}
+
 	mutex_unlock(&ps_enable_mutex);
+
+	delay = atomic_read(&lpi->ps_poll_delay);
+	if (lpi->polling)
+		schedule_delayed_work(&lpi->pdwork, msecs_to_jiffies(delay));
+
 	return ret;
 }
 
 static int psensor_disable(struct cm36283_info *lpi)
 {
 	int ret = -EIO;
-	
+
+	if (lpi->polling)
+		cancel_delayed_work_sync(&lpi->pdwork);
+
 	mutex_lock(&ps_disable_mutex);
 	D("[PS][CM36283] %s\n", __func__);
 
-	if ( lpi->ps_enable == 0 ) {
+	if (lpi->ps_enable == 0) {
 		D("[PS][CM36283] %s: already disabled\n", __func__);
 		ret = 0;
-	} else
-  	ret = control_and_report(lpi, CONTROL_PS,0);
-	
+	} else {
+		ret = control_and_report(lpi, CONTROL_PS, 0, 0);
+	}
+
 	mutex_unlock(&ps_disable_mutex);
 	return ret;
 }
@@ -572,6 +705,7 @@
 static int lightsensor_enable(struct cm36283_info *lpi)
 {
 	int ret = -EIO;
+	unsigned int delay;
 	
 	mutex_lock(&als_enable_mutex);
 	D("[LS][CM36283] %s\n", __func__);
@@ -579,10 +713,17 @@
 	if (lpi->als_enable) {
 		D("[LS][CM36283] %s: already enabled\n", __func__);
 		ret = 0;
-	} else
-  	ret = control_and_report(lpi, CONTROL_ALS, 1);
+	} else {
+		ret = control_and_report(lpi, CONTROL_ALS, 1, 0);
+	}
 	
 	mutex_unlock(&als_enable_mutex);
+
+	delay = atomic_read(&lpi->ls_poll_delay);
+	if (lpi->polling)
+		schedule_delayed_work(&lpi->ldwork,
+				msecs_to_jiffies(delay));
+
 	return ret;
 }
 
@@ -592,11 +733,15 @@
 	mutex_lock(&als_disable_mutex);
 	D("[LS][CM36283] %s\n", __func__);
 
+	if (lpi->polling)
+		cancel_delayed_work_sync(&lpi->ldwork);
+
 	if ( lpi->als_enable == 0 ) {
 		D("[LS][CM36283] %s: already disabled\n", __func__);
 		ret = 0;
-	} else
-    ret = control_and_report(lpi, CONTROL_ALS, 0);
+	} else {
+		ret = control_and_report(lpi, CONTROL_ALS, 0, 0);
+	}
 	
 	mutex_unlock(&als_disable_mutex);
 	return ret;
@@ -679,13 +824,14 @@
 	uint16_t value;
 	int ret;
 	struct cm36283_info *lpi = lp_info;
-	int intr_val;
-
-	intr_val = gpio_get_value(lpi->intr_pin);
+	int intr_val = -1;
 
 	get_ps_adc_value(&value);
+	if (gpio_is_valid(lpi->intr_pin))
+		intr_val = gpio_get_value(lpi->intr_pin);
 
-	ret = sprintf(buf, "ADC[0x%04X], ENABLE = %d, intr_pin = %d\n", value, lpi->ps_enable, intr_val);
+	ret = snprintf(buf, PAGE_SIZE, "ADC[0x%04X], ENABLE=%d intr_pin=%d\n",
+			value, lpi->ps_enable, intr_val);
 
 	return ret;
 }
@@ -1067,6 +1213,62 @@
 }
 static DEVICE_ATTR(ls_conf, 0664, ls_conf_show, ls_conf_store);
 
+static ssize_t ls_poll_delay_show(struct device *dev,
+		struct device_attribute *attr, char *buf)
+{
+	struct cm36283_info *lpi = lp_info;
+	return snprintf(buf, PAGE_SIZE, "%d\n",
+			atomic_read(&lpi->ls_poll_delay));
+}
+
+static ssize_t ls_poll_delay_store(struct device *dev,
+		struct device_attribute *attr, const char *buf, size_t count)
+{
+	struct cm36283_info *lpi = lp_info;
+	unsigned long interval_ms;
+
+	if (kstrtoul(buf, 10, &interval_ms))
+		return -EINVAL;
+
+	if ((interval_ms < CM36283_LS_MIN_POLL_DELAY) ||
+			(interval_ms > CM36283_LS_MAX_POLL_DELAY))
+		return -EINVAL;
+
+	atomic_set(&lpi->ls_poll_delay, (unsigned int) interval_ms);
+	return count;
+}
+
+static DEVICE_ATTR(ls_poll_delay, 0664, ls_poll_delay_show,
+		ls_poll_delay_store);
+
+static ssize_t ps_poll_delay_show(struct device *dev,
+		struct device_attribute *attr, char *buf)
+{
+	struct cm36283_info *lpi = lp_info;
+	return snprintf(buf, PAGE_SIZE, "%d\n",
+			atomic_read(&lpi->ps_poll_delay));
+}
+
+static ssize_t ps_poll_delay_store(struct device *dev,
+		struct device_attribute *attr, const char *buf, size_t count)
+{
+	struct cm36283_info *lpi = lp_info;
+	unsigned long interval_ms;
+
+	if (kstrtoul(buf, 10, &interval_ms))
+		return -EINVAL;
+
+	if ((interval_ms < CM36283_PS_MIN_POLL_DELAY) ||
+			(interval_ms > CM36283_PS_MAX_POLL_DELAY))
+		return -EINVAL;
+
+	atomic_set(&lpi->ps_poll_delay, (unsigned int) interval_ms);
+	return count;
+}
+
+static DEVICE_ATTR(ps_poll_delay, 0664, ps_poll_delay_show,
+		ps_poll_delay_store);
+
 static ssize_t ls_fLevel_show(struct device *dev,
 				  struct device_attribute *attr, char *buf)
 {
@@ -1094,6 +1296,7 @@
 static int lightsensor_setup(struct cm36283_info *lpi)
 {
 	int ret;
+	int range;
 
 	lpi->ls_input_dev = input_allocate_device();
 	if (!lpi->ls_input_dev) {
@@ -1104,7 +1307,9 @@
 	}
 	lpi->ls_input_dev->name = "cm36283-ls";
 	set_bit(EV_ABS, lpi->ls_input_dev->evbit);
-	input_set_abs_params(lpi->ls_input_dev, ABS_MISC, 0, 9, 0, 0);
+
+	range = get_als_range();
+	input_set_abs_params(lpi->ls_input_dev, ABS_MISC, 0, range, 0, 0);
 
 	ret = input_register_device(lpi->ls_input_dev);
 	if (ret < 0) {
@@ -1179,13 +1384,8 @@
 	D("[PS][CM36283] %s, INTERRUPT GPIO val = %d\n", __func__, val);
 
 	ret = _cm36283_I2C_Read_Word(lpi->slave_addr, ID_REG, &idReg);
-	if ((ret < 0) || (idReg != 0xC082)) {
-  		if (record_init_fail == 0)
-  			record_init_fail = 1;
-  		return -ENOMEM;/*If devices without cm36283 chip and did not probe driver*/	
-  }
-  
-	return 0;
+
+	return ret;
 }
 
 static int cm36283_setup(struct cm36283_info *lpi)
@@ -1219,14 +1419,15 @@
 	}
 	
 	/*Default disable P sensor and L sensor*/
-  ls_initial_cmd(lpi);
+	ls_initial_cmd(lpi);
 	psensor_initial_cmd(lpi);
 
-	ret = request_any_context_irq(lpi->irq,
-			cm36283_irq_handler,
-			IRQF_TRIGGER_LOW,
-			"cm36283",
-			lpi);
+	if (!lpi->polling)
+		ret = request_any_context_irq(lpi->irq,
+				cm36283_irq_handler,
+				IRQF_TRIGGER_LOW,
+				"cm36283",
+				lpi);
 	if (ret < 0) {
 		pr_err(
 			"[PS][CM36283 error]%s: req_irq(%d) fail for gpio %d (%d)\n",
@@ -1265,6 +1466,78 @@
 }
 #endif
 
+static int cm36283_parse_dt(struct device *dev,
+				struct cm36283_platform_data *pdata)
+{
+	struct device_node *np = dev->of_node;
+	u32	levels[CM36283_LEVELS_SIZE], i;
+	u32 temp_val;
+	int rc;
+
+	rc = of_get_named_gpio_flags(np, "capella,interrupt-gpio",
+			0, NULL);
+	if (rc < 0) {
+		dev_err(dev, "Unable to read interrupt pin number\n");
+		return rc;
+	} else {
+		pdata->intr = rc;
+	}
+
+	rc = of_property_read_u32_array(np, "capella,levels", levels,
+			CM36283_LEVELS_SIZE);
+	if (rc) {
+		dev_err(dev, "Unable to read levels data\n");
+		return rc;
+	} else {
+		for (i = 0; i < CM36283_LEVELS_SIZE; i++)
+			pdata->levels[i] = levels[i];
+	}
+
+	rc = of_property_read_u32(np, "capella,ps_close_thd_set", &temp_val);
+	if (rc) {
+		dev_err(dev, "Unable to read ps_close_thd_set\n");
+		return rc;
+	} else {
+		pdata->ps_close_thd_set = (u8)temp_val;
+	}
+
+	rc = of_property_read_u32(np, "capella,ps_away_thd_set", &temp_val);
+	if (rc) {
+		dev_err(dev, "Unable to read ps_away_thd_set\n");
+		return rc;
+	} else {
+		pdata->ps_away_thd_set = (u8)temp_val;
+	}
+
+	rc = of_property_read_u32(np, "capella,ls_cmd", &temp_val);
+	if (rc) {
+		dev_err(dev, "Unable to read ls_cmd\n");
+		return rc;
+	} else {
+		pdata->ls_cmd = (u16)temp_val;
+	}
+
+	rc = of_property_read_u32(np, "capella,ps_conf1_val", &temp_val);
+	if (rc) {
+		dev_err(dev, "Unable to read ps_conf1_val\n");
+		return rc;
+	} else {
+		pdata->ps_conf1_val = (u16)temp_val;
+	}
+
+	rc = of_property_read_u32(np, "capella,ps_conf3_val", &temp_val);
+	if (rc) {
+		dev_err(dev, "Unable to read ps_conf3_val\n");
+		return rc;
+	} else {
+		pdata->ps_conf3_val = (u16)temp_val;
+	}
+
+	pdata->polling = of_property_read_bool(np, "capella,use-polling");
+
+	return 0;
+}
+
 static int cm36283_probe(struct i2c_client *client,
 	const struct i2c_device_id *id)
 {
@@ -1282,12 +1555,29 @@
 	/*D("[CM36283] %s: client->irq = %d\n", __func__, client->irq);*/
 
 	lpi->i2c_client = client;
-	pdata = client->dev.platform_data;
-	if (!pdata) {
-		pr_err("[PS][CM36283 error]%s: Assign platform_data error!!\n",
-			__func__);
-		ret = -EBUSY;
-		goto err_platform_data_null;
+
+	if (client->dev.of_node) {
+		pdata = devm_kzalloc(&client->dev, sizeof(*pdata), GFP_KERNEL);
+		if (!pdata) {
+			dev_err(&client->dev, "Failed to allocate memory for pdata\n");
+			ret = -ENOMEM;
+			goto err_platform_data_null;
+		}
+
+		ret = cm36283_parse_dt(&client->dev, pdata);
+		pdata->slave_addr = client->addr;
+		if (ret) {
+			dev_err(&client->dev, "Failed to get pdata from device tree\n");
+			goto err_parse_dt;
+		}
+	} else {
+		pdata = client->dev.platform_data;
+		if (!pdata) {
+			dev_err(&client->dev, "%s: Assign platform_data error!!\n",
+					__func__);
+			ret = -EBUSY;
+			goto err_platform_data_null;
+		}
 	}
 
 	lpi->irq = client->irq;
@@ -1304,6 +1594,12 @@
 	lpi->ps_close_thd_set = pdata->ps_close_thd_set;	
 	lpi->ps_conf1_val = pdata->ps_conf1_val;
 	lpi->ps_conf3_val = pdata->ps_conf3_val;
+	lpi->polling = pdata->polling;
+	atomic_set(&lpi->ls_poll_delay,
+			(unsigned int) CM36283_LS_DEFAULT_POLL_DELAY);
+	atomic_set(&lpi->ps_poll_delay,
+			(unsigned int) CM36283_PS_DEFAULT_POLL_DELAY);
+
 	
 	lpi->ls_cmd  = pdata->ls_cmd;
 	
@@ -1324,23 +1620,11 @@
 	mutex_init(&als_disable_mutex);
 	mutex_init(&als_get_adc_mutex);
 
-	ret = lightsensor_setup(lpi);
-	if (ret < 0) {
-		pr_err("[LS][CM36283 error]%s: lightsensor_setup error!!\n",
-			__func__);
-		goto err_lightsensor_setup;
-	}
 
 	mutex_init(&ps_enable_mutex);
 	mutex_init(&ps_disable_mutex);
 	mutex_init(&ps_get_adc_mutex);
 
-	ret = psensor_setup(lpi);
-	if (ret < 0) {
-		pr_err("[PS][CM36283 error]%s: psensor_setup error!!\n",
-			__func__);
-		goto err_psensor_setup;
-	}
 
   //SET LUX STEP FACTOR HERE
   // if adc raw value one step = 5/100 = 1/20 = 0.05 lux
@@ -1370,11 +1654,32 @@
 	}
 	wake_lock_init(&(lpi->ps_wake_lock), WAKE_LOCK_SUSPEND, "proximity");
 
+	ret = cm36283_power_set(lpi, true);
+	if (ret < 0) {
+		dev_err(&client->dev, "%s:cm36283 power on error!\n", __func__);
+		goto err_cm36283_power_on;
+	}
+
 	ret = cm36283_setup(lpi);
 	if (ret < 0) {
 		pr_err("[PS_ERR][CM36283 error]%s: cm36283_setup error!\n", __func__);
 		goto err_cm36283_setup;
 	}
+
+	ret = lightsensor_setup(lpi);
+	if (ret < 0) {
+		pr_err("[LS][CM36283 error]%s: lightsensor_setup error!!\n",
+			__func__);
+		goto err_lightsensor_setup;
+	}
+
+	ret = psensor_setup(lpi);
+	if (ret < 0) {
+		pr_err("[PS][CM36283 error]%s: psensor_setup error!!\n",
+			__func__);
+		goto err_psensor_setup;
+	}
+
 	lpi->cm36283_class = class_create(THIS_MODULE, "optical_sensors");
 	if (IS_ERR(lpi->cm36283_class)) {
 		ret = PTR_ERR(lpi->cm36283_class);
@@ -1421,37 +1726,45 @@
 	if (ret)
 		goto err_create_ls_device_file;
 
+	ret = device_create_file(lpi->ls_dev, &dev_attr_ls_poll_delay);
+	if (ret)
+		goto err_create_ls_device_file;
+
 	lpi->ps_dev = device_create(lpi->cm36283_class,
 				NULL, 0, "%s", "proximity");
 	if (unlikely(IS_ERR(lpi->ps_dev))) {
 		ret = PTR_ERR(lpi->ps_dev);
 		lpi->ps_dev = NULL;
-		goto err_create_ls_device_file;
+		goto err_create_ps_device;
 	}
 
 	/* register the attributes */
 	ret = device_create_file(lpi->ps_dev, &dev_attr_ps_adc);
 	if (ret)
-		goto err_create_ps_device;
+		goto err_create_ps_device_file;
 
 	ret = device_create_file(lpi->ps_dev,
 		&dev_attr_ps_parameters);
 	if (ret)
-		goto err_create_ps_device;
+		goto err_create_ps_device_file;
 
 	/* register the attributes */
 	ret = device_create_file(lpi->ps_dev, &dev_attr_ps_conf);
 	if (ret)
-		goto err_create_ps_device;
+		goto err_create_ps_device_file;
 
 	/* register the attributes */
 	ret = device_create_file(lpi->ps_dev, &dev_attr_ps_thd);
 	if (ret)
-		goto err_create_ps_device;
+		goto err_create_ps_device_file;
 
 	ret = device_create_file(lpi->ps_dev, &dev_attr_ps_hw);
 	if (ret)
-		goto err_create_ps_device;
+		goto err_create_ps_device_file;
+
+	ret = device_create_file(lpi->ps_dev, &dev_attr_ps_poll_delay);
+	if (ret)
+		goto err_create_ps_device_file;
 
 #ifdef CONFIG_HAS_EARLYSUSPEND
 	lpi->early_suspend.level =
@@ -1461,47 +1774,59 @@
 	register_early_suspend(&lpi->early_suspend);
 #endif
 
+	mutex_init(&wq_lock);
+	INIT_DELAYED_WORK(&lpi->ldwork, lsensor_delay_work_handler);
+	INIT_DELAYED_WORK(&lpi->pdwork, psensor_delay_work_handler);
 	D("[PS][CM36283] %s: Probe success!\n", __func__);
 
 	return ret;
 
-err_create_ps_device:
+err_create_ps_device_file:
 	device_unregister(lpi->ps_dev);
+err_create_ps_device:
 err_create_ls_device_file:
 	device_unregister(lpi->ls_dev);
 err_create_ls_device:
 	class_destroy(lpi->cm36283_class);
 err_create_class:
-err_cm36283_setup:
-	destroy_workqueue(lpi->lp_wq);
-	wake_lock_destroy(&(lpi->ps_wake_lock));
-
-	input_unregister_device(lpi->ls_input_dev);
-	input_free_device(lpi->ls_input_dev);
+	misc_deregister(&psensor_misc);
 	input_unregister_device(lpi->ps_input_dev);
 	input_free_device(lpi->ps_input_dev);
+err_psensor_setup:
+	misc_deregister(&lightsensor_misc);
+	input_unregister_device(lpi->ls_input_dev);
+	input_free_device(lpi->ls_input_dev);
+err_lightsensor_setup:
+err_cm36283_setup:
+	cm36283_power_set(lpi, false);
+err_cm36283_power_on:
+	wake_lock_destroy(&(lpi->ps_wake_lock));
+	destroy_workqueue(lpi->lp_wq);
 err_create_singlethread_workqueue:
 err_lightsensor_update_table:
-	misc_deregister(&psensor_misc);
-err_psensor_setup:
 	mutex_destroy(&CM36283_control_mutex);
-	mutex_destroy(&ps_enable_mutex);
-	mutex_destroy(&ps_disable_mutex);
-	mutex_destroy(&ps_get_adc_mutex);
-	misc_deregister(&lightsensor_misc);
-err_lightsensor_setup:
 	mutex_destroy(&als_enable_mutex);
 	mutex_destroy(&als_disable_mutex);
 	mutex_destroy(&als_get_adc_mutex);
+	mutex_destroy(&ps_enable_mutex);
+	mutex_destroy(&ps_disable_mutex);
+	mutex_destroy(&ps_get_adc_mutex);
+err_parse_dt:
+	if (client->dev.of_node && (pdata != NULL))
+		devm_kfree(&client->dev, pdata);
 err_platform_data_null:
 	kfree(lpi);
+	dev_err(&client->dev, "%s:error exit! ret = %d\n", __func__, ret);
+
 	return ret;
 }
-   
-static int control_and_report( struct cm36283_info *lpi, uint8_t mode, uint16_t param ) {
-  int ret=0;
+
+static int control_and_report(struct cm36283_info *lpi, uint8_t mode,
+	uint16_t param, int report)
+{
+	int ret = 0;
 	uint16_t adc_value = 0;
-	uint16_t ps_data = 0;	
+	uint16_t ps_data = 0;
 	int level = 0, i, val;
 	
   mutex_lock(&CM36283_control_mutex);
@@ -1566,77 +1891,212 @@
       		  }
       	  }
     	  }
-    
-    	  ret = set_lsensor_range(((i == 0) || (adc_value == 0)) ? 0 :
-    		   	*(lpi->cali_table + (i - 1)) + 1,
-    		    *(lpi->cali_table + i));
-    	  
-        lpi->ls_cmd |= CM36283_ALS_INT_EN;
-    	  
-        ret = _cm36283_I2C_Write_Word(lpi->slave_addr, ALS_CONF, lpi->ls_cmd);  
-    	  
-    		if ((i == 0) || (adc_value == 0))
-    			D("[LS][CM3628] %s: ADC=0x%03X, Level=%d, l_thd equal 0, h_thd = 0x%x \n",
-    				__func__, adc_value, level, *(lpi->cali_table + i));
-    		else
-    			D("[LS][CM3628] %s: ADC=0x%03X, Level=%d, l_thd = 0x%x, h_thd = 0x%x \n",
-    				__func__, adc_value, level, *(lpi->cali_table + (i - 1)) + 1, *(lpi->cali_table + i));
-    		lpi->current_level = level;
-    		lpi->current_adc = adc_value;    
-        input_report_abs(lpi->ls_input_dev, ABS_MISC, level);
-        input_sync(lpi->ls_input_dev);
+	if (!lpi->polling) {
+		ret = set_lsensor_range(((i == 0) ||
+					(adc_value == 0)) ? 0 :
+				*(lpi->cali_table + (i - 1)) + 1,
+				*(lpi->cali_table + i));
+
+		lpi->ls_cmd |= CM36283_ALS_INT_EN;
+	}
+
+	ret = _cm36283_I2C_Write_Word(lpi->slave_addr, ALS_CONF,
+			lpi->ls_cmd);
+
+	if (report) {
+		lpi->current_level = level;
+		lpi->current_adc = adc_value;
+		input_report_abs(lpi->ls_input_dev, ABS_MISC, level);
+		input_sync(lpi->ls_input_dev);
+	}
     }
   }
 
 #define PS_CLOSE 1
 #define PS_AWAY  (1<<1)
 #define PS_CLOSE_AND_AWAY PS_CLOSE+PS_AWAY
+	if (report && (lpi->ps_enable)) {
+		int ps_status = 0;
+		if (mode == CONTROL_PS)
+			ps_status = PS_CLOSE_AND_AWAY;
+		else if (mode == CONTROL_INT_ISR_REPORT) {
+			if (param & INT_FLAG_PS_IF_CLOSE)
+				ps_status |= PS_CLOSE;
+			if (param & INT_FLAG_PS_IF_AWAY)
+				ps_status |= PS_AWAY;
+		}
 
-  if(lpi->ps_enable){
-    int ps_status = 0;
-    if( mode == CONTROL_PS )
-      ps_status = PS_CLOSE_AND_AWAY;   
-    else if(mode == CONTROL_INT_ISR_REPORT ){  
-      if ( param & INT_FLAG_PS_IF_CLOSE )
-        ps_status |= PS_CLOSE;      
-      if ( param & INT_FLAG_PS_IF_AWAY )
-        ps_status |= PS_AWAY;
-    }
-      
-    if (ps_status!=0){
-      switch(ps_status){
-        case PS_CLOSE_AND_AWAY:
-          get_stable_ps_adc_value(&ps_data);
-          val = (ps_data >= lpi->ps_close_thd_set) ? 0 : 1;
-          break;
-        case PS_AWAY:
-          val = 1;
-          break;
-        case PS_CLOSE:
-          val = 0;
-          break;
-        };
-      input_report_abs(lpi->ps_input_dev, ABS_DISTANCE, val);      
-      input_sync(lpi->ps_input_dev);        
-    }
-  }
+		if (ps_status != 0) {
+			switch (ps_status) {
+			case PS_CLOSE_AND_AWAY:
+				get_stable_ps_adc_value(&ps_data);
+				val = (ps_data >= lpi->ps_close_thd_set)
+					? 0 : 1;
+				break;
+			case PS_AWAY:
+				val = 1;
+				break;
+			case PS_CLOSE:
+				val = 0;
+				break;
+			};
+			input_report_abs(lpi->ps_input_dev, ABS_DISTANCE, val);
+			input_sync(lpi->ps_input_dev);
+		}
+	}
 
-  mutex_unlock(&CM36283_control_mutex);
-  return ret;
+	mutex_unlock(&CM36283_control_mutex);
+	return ret;
 }
 
+static int cm36283_power_set(struct cm36283_info *info, bool on)
+{
+	int rc;
+
+	if (on) {
+		info->vdd = regulator_get(&info->i2c_client->dev, "vdd");
+		if (IS_ERR(info->vdd)) {
+			rc = PTR_ERR(info->vdd);
+			dev_err(&info->i2c_client->dev,
+				"Regulator get failed vdd rc=%d\n", rc);
+			goto err_vdd_get;
+		}
+
+		if (regulator_count_voltages(info->vdd) > 0) {
+			rc = regulator_set_voltage(info->vdd,
+					CM36283_VDD_MIN_UV, CM36283_VDD_MAX_UV);
+			if (rc) {
+				dev_err(&info->i2c_client->dev,
+					"Regulator set failed vdd rc=%d\n", rc);
+				goto err_vdd_set_vtg;
+			}
+		}
+
+		info->vio = regulator_get(&info->i2c_client->dev, "vio");
+		if (IS_ERR(info->vio)) {
+			rc = PTR_ERR(info->vio);
+			dev_err(&info->i2c_client->dev,
+				"Regulator get failed vio rc=%d\n", rc);
+			goto err_vio_get;
+		}
+
+		if (regulator_count_voltages(info->vio) > 0) {
+			rc = regulator_set_voltage(info->vio,
+				CM36283_VI2C_MIN_UV, CM36283_VI2C_MAX_UV);
+			if (rc) {
+				dev_err(&info->i2c_client->dev,
+				"Regulator set failed vio rc=%d\n", rc);
+				goto err_vio_set_vtg;
+			}
+		}
+
+		rc = regulator_enable(info->vdd);
+		if (rc) {
+			dev_err(&info->i2c_client->dev,
+				"Regulator vdd enable failed rc=%d\n", rc);
+			goto err_vdd_ena;
+		}
+
+		rc = regulator_enable(info->vio);
+		if (rc) {
+			dev_err(&info->i2c_client->dev,
+				"Regulator vio enable failed rc=%d\n", rc);
+			goto err_vio_ena;
+		}
+
+	} else {
+		rc = regulator_disable(info->vdd);
+		if (rc) {
+			dev_err(&info->i2c_client->dev,
+				"Regulator vdd disable failed rc=%d\n", rc);
+			return rc;
+		}
+		if (regulator_count_voltages(info->vdd) > 0)
+			regulator_set_voltage(info->vdd, 0, CM36283_VDD_MAX_UV);
+
+		regulator_put(info->vdd);
+
+		rc = regulator_disable(info->vio);
+		if (rc) {
+			dev_err(&info->i2c_client->dev,
+				"Regulator vio disable failed rc=%d\n", rc);
+			return rc;
+		}
+		if (regulator_count_voltages(info->vio) > 0)
+			regulator_set_voltage(info->vio, 0,
+					CM36283_VI2C_MAX_UV);
+
+		regulator_put(info->vio);
+	}
+
+	return 0;
+
+err_vio_ena:
+	regulator_disable(info->vdd);
+err_vdd_ena:
+	if (regulator_count_voltages(info->vio) > 0)
+		regulator_set_voltage(info->vio, 0, CM36283_VI2C_MAX_UV);
+err_vio_set_vtg:
+	regulator_put(info->vio);
+err_vio_get:
+	if (regulator_count_voltages(info->vdd) > 0)
+		regulator_set_voltage(info->vdd, 0, CM36283_VDD_MAX_UV);
+err_vdd_set_vtg:
+	regulator_put(info->vdd);
+err_vdd_get:
+	return rc;
+}
+
+#ifdef CONFIG_PM_SLEEP
+static int cm36283_suspend(struct device *dev)
+{
+	struct cm36283_info *lpi = lp_info;
+
+	if (lpi->als_enable) {
+		lightsensor_disable(lpi);
+		lpi->als_enable = 1;
+	}
+	cm36283_power_set(lpi, 0);
+
+	return 0;
+}
+
+static int cm36283_resume(struct device *dev)
+{
+	struct cm36283_info *lpi = lp_info;
+
+	cm36283_power_set(lpi, 1);
+
+	if (lpi->als_enable) {
+		cm36283_setup(lpi);
+		lightsensor_setup(lpi);
+		psensor_setup(lpi);
+		lightsensor_enable(lpi);
+	}
+	return 0;
+}
+#endif
+
+static UNIVERSAL_DEV_PM_OPS(cm36283_pm, cm36283_suspend, cm36283_resume, NULL);
 
 static const struct i2c_device_id cm36283_i2c_id[] = {
 	{CM36283_I2C_NAME, 0},
 	{}
 };
 
+static struct of_device_id cm36283_match_table[] = {
+	{ .compatible = "capella,cm36283",},
+	{ },
+};
+
 static struct i2c_driver cm36283_driver = {
 	.id_table = cm36283_i2c_id,
 	.probe = cm36283_probe,
 	.driver = {
 		.name = CM36283_I2C_NAME,
 		.owner = THIS_MODULE,
+		.pm = &cm36283_pm,
+		.of_match_table = cm36283_match_table,
 	},
 };
 
diff --git a/drivers/input/misc/mma8x5x.c b/drivers/input/misc/mma8x5x.c
index 4b78903..f49ff14 100644
--- a/drivers/input/misc/mma8x5x.c
+++ b/drivers/input/misc/mma8x5x.c
@@ -43,7 +43,7 @@
 #define POLL_INTERVAL		100 /* msecs */
 
 /* if sensor is standby ,set POLL_STOP_TIME to slow down the poll */
-#define POLL_STOP_TIME		200
+#define POLL_STOP_TIME		10000
 #define INPUT_FUZZ			32
 #define INPUT_FLAT			32
 #define INPUT_DATA_DIVIDER	16
@@ -52,6 +52,8 @@
 #define MMA8X5X_STATUS_ZYXDR	0x08
 #define MMA8X5X_BUF_SIZE	7
 
+#define	MMA_SHUTTEDDOWN		(1 << 31)
+
 struct sensor_regulator {
 	struct regulator *vreg;
 	const char *name;
@@ -615,6 +617,9 @@
 	struct mma8x5x_data *pdata = i2c_get_clientdata(client);
 	if (pdata->active == MMA_ACTIVED)
 		mma8x5x_device_stop(client);
+	if (!mma8x5x_config_regulator(client, 0))
+		/* The highest bit sotres the power state */
+		pdata->active |= MMA_SHUTTEDDOWN;
 	return 0;
 }
 
@@ -623,11 +628,33 @@
 	int val = 0;
 	struct i2c_client *client = to_i2c_client(dev);
 	struct mma8x5x_data *pdata = i2c_get_clientdata(client);
+	if (pdata->active & MMA_SHUTTEDDOWN) {
+		if (mma8x5x_config_regulator(client, 1))
+			goto out;
+
+		if (i2c_smbus_write_byte_data(client, MMA8X5X_CTRL_REG1, 0))
+			goto out;
+
+		if (i2c_smbus_write_byte_data(client, MMA8X5X_XYZ_DATA_CFG,
+				pdata->mode))
+			goto out;
+
+		/* The BT(boot time) for mma8x5x is 1.55ms according to
+		Freescale mma8450Q document. Document Number:MMA8450Q
+		Rev: 9.1, 04/2012
+		*/
+		usleep_range(1600, 2000);
+		pdata->active &= ~MMA_SHUTTEDDOWN;
+	}
 	if (pdata->active == MMA_ACTIVED) {
 		val = i2c_smbus_read_byte_data(client, MMA8X5X_CTRL_REG1);
 		i2c_smbus_write_byte_data(client, MMA8X5X_CTRL_REG1, val|0x01);
 	}
+
 	return 0;
+out:
+	dev_err(&client->dev, "%s:failed during resume operation", __func__);
+	return -EIO;
 
 }
 #endif
diff --git a/drivers/input/misc/mpu3050.c b/drivers/input/misc/mpu3050.c
index ded2b6e..642975d 100644
--- a/drivers/input/misc/mpu3050.c
+++ b/drivers/input/misc/mpu3050.c
@@ -320,15 +320,19 @@
 		if (sensor->use_poll)
 			schedule_delayed_work(&sensor->input_work,
 				msecs_to_jiffies(sensor->poll_interval));
-		else
+		else {
 			i2c_smbus_write_byte_data(sensor->client,
 					MPU3050_INT_CFG,
 					MPU3050_ACTIVE_LOW |
 					MPU3050_OPEN_DRAIN |
 					MPU3050_RAW_RDY_EN);
+			enable_irq(sensor->client->irq);
+		}
 	} else {
 		if (sensor->use_poll)
 			cancel_delayed_work_sync(&sensor->input_work);
+		else
+			disable_irq(sensor->client->irq);
 		gpio_set_value(sensor->enable_gpio, 0);
 		pm_runtime_put(sensor->dev);
 	}
@@ -448,6 +452,7 @@
 		mpu3050_config_regulator(client, 1);
 		udelay(10);
 		gpio_set_value(sensor->enable_gpio, 1);
+		msleep(60);
 	}
 
 	value = i2c_smbus_read_byte_data(client, MPU3050_PWR_MGM);
@@ -709,7 +714,6 @@
 	}
 
 	mpu3050_set_power_mode(client, 1);
-	msleep(10);
 
 	ret = i2c_smbus_read_byte_data(client, MPU3050_CHIP_ID_REG);
 	if (ret < 0) {
@@ -730,7 +734,6 @@
 
 	idev->name = "MPU3050";
 	idev->id.bustype = BUS_I2C;
-	idev->dev.parent = &client->dev;
 
 	idev->open = mpu3050_input_open;
 	idev->close = mpu3050_input_close;
@@ -792,6 +795,7 @@
 				client->irq, error);
 			goto err_pm_set_suspended;
 		}
+		disable_irq(client->irq);
 	}
 
 	error = input_register_device(idev);
@@ -864,6 +868,10 @@
 static int mpu3050_suspend(struct device *dev)
 {
 	struct i2c_client *client = to_i2c_client(dev);
+	struct mpu3050_sensor *sensor = i2c_get_clientdata(client);
+
+	if (!sensor->use_poll)
+		disable_irq(client->irq);
 
 	mpu3050_set_power_mode(client, 0);
 
@@ -879,9 +887,12 @@
 static int mpu3050_resume(struct device *dev)
 {
 	struct i2c_client *client = to_i2c_client(dev);
+	struct mpu3050_sensor *sensor = i2c_get_clientdata(client);
 
 	mpu3050_set_power_mode(client, 1);
-	msleep(100);  /* wait for gyro chip resume */
+
+	if (!sensor->use_poll)
+		enable_irq(client->irq);
 
 	return 0;
 }
diff --git a/drivers/input/misc/stk3x1x.c b/drivers/input/misc/stk3x1x.c
index eee9a28..937bf6c 100644
--- a/drivers/input/misc/stk3x1x.c
+++ b/drivers/input/misc/stk3x1x.c
@@ -2,6 +2,7 @@
  *  stk3x1x.c - Linux kernel modules for sensortek stk301x, stk321x and stk331x
  *  proximity/ambient light sensor
  *
+ *  Copyright (c) 2013, The Linux Foundation. All Rights Reserved.
  *  Copyright (C) 2012 Lex Hsieh / sensortek <lex_hsieh@sitronix.com.tw> or
  *   <lex_hsieh@sensortek.com.tw>
  *
@@ -10,6 +11,9 @@
  *  the Free Software Foundation; either version 2 of the License, or
  *  (at your option) any later version.
  *
+ *  Linux Foundation chooses to take subject only to the GPLv2 license
+ *  terms, and distributes only under these 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
@@ -38,7 +42,11 @@
 #include <linux/interrupt.h>
 #include <linux/gpio.h>
 #include <linux/fs.h>
-#include <asm/uaccess.h>
+#include <linux/uaccess.h>
+#include <linux/regulator/consumer.h>
+#ifdef CONFIG_OF
+#include <linux/of_gpio.h>
+#endif
 #ifdef CONFIG_HAS_EARLYSUSPEND
 #include <linux/earlysuspend.h>
 #endif
@@ -162,9 +170,24 @@
 #define MIN_ALS_POLL_DELAY_NS	110000000
 
 #define DEVICE_NAME		"stk_ps"
-#define ALS_NAME "lightsensor-level"
+#define ALS_NAME		"stk3x1x-ls"
 #define PS_NAME "proximity"
 
+/* POWER SUPPLY VOLTAGE RANGE */
+#define STK3X1X_VDD_MIN_UV	2000000
+#define STK3X1X_VDD_MAX_UV	3300000
+#define STK3X1X_VIO_MIN_UV	1750000
+#define STK3X1X_VIO_MAX_UV	1950000
+
+#define STK_FIR_LEN 16
+#define MAX_FIR_LEN 32
+struct data_filter {
+	u16 raw[MAX_FIR_LEN];
+	int sum;
+	int number;
+	int idx;
+};
+
 struct stk3x1x_data {
 	struct i2c_client *client;
 #if (!defined(STK_POLL_PS) || !defined(STK_POLL_ALS))
@@ -201,6 +224,12 @@
     struct work_struct stk_als_work;
 	struct workqueue_struct *stk_als_wq;
 #endif
+	struct regulator *vdd;
+	struct regulator *vio;
+	bool power_enabled;
+	bool use_fir;
+	struct data_filter      fir;
+	atomic_t                firlength;
 };
 
 #if( !defined(CONFIG_STK_PS_ALS_USE_CHANGE_THRESHOLD))
@@ -370,6 +399,13 @@
 		printk(KERN_ERR "%s: write i2c error\n", __func__);
 		return ret;
 	}
+
+	ret = i2c_smbus_write_byte_data(ps_data->client, 0x87, 0x60);
+	if (ret < 0) {
+		dev_err(&ps_data->client->dev,
+			"%s: write i2c error\n", __func__);
+		return ret;
+	}
 	return 0;
 }
 
@@ -691,9 +727,32 @@
     return ret;
 }
 
+static inline int32_t stk3x1x_filter_reading(struct stk3x1x_data *ps_data,
+			int32_t word_data)
+{
+	int index;
+	int firlen = atomic_read(&ps_data->firlength);
+
+	if (ps_data->fir.number < firlen) {
+		ps_data->fir.raw[ps_data->fir.number] = word_data;
+		ps_data->fir.sum += word_data;
+		ps_data->fir.number++;
+		ps_data->fir.idx++;
+	} else {
+		index = ps_data->fir.idx % firlen;
+		ps_data->fir.sum -= ps_data->fir.raw[index];
+		ps_data->fir.raw[index] = word_data;
+		ps_data->fir.sum += word_data;
+		ps_data->fir.idx++;
+		word_data = ps_data->fir.sum/firlen;
+	}
+	return word_data;
+}
+
 static inline int32_t stk3x1x_get_als_reading(struct stk3x1x_data *ps_data)
 {
     int32_t word_data, tmp_word_data;
+
 	tmp_word_data = i2c_smbus_read_word_data(ps_data->client, STK_DATA1_ALS_REG);
 	if(tmp_word_data < 0)
 	{
@@ -701,6 +760,9 @@
 		return tmp_word_data;
 	}
 	word_data = ((tmp_word_data & 0xFF00) >> 8) | ((tmp_word_data & 0x00FF) << 8) ;
+	if (ps_data->use_fir)
+		word_data = stk3x1x_filter_reading(ps_data, word_data);
+
 	return word_data;
 }
 
@@ -842,10 +904,11 @@
 	struct stk3x1x_data *ps_data =  dev_get_drvdata(dev);
 	unsigned long value = 0;
 	int ret;
-	ret = strict_strtoul(buf, 16, &value);
+	ret = kstrtoul(buf, 16, &value);
 	if(ret < 0)
 	{
-		printk(KERN_ERR "%s:strict_strtoul failed, ret=0x%x\n", __func__, ret);
+		printk(KERN_ERR "%s:kstrtoul failed, ret=0x%x\n",
+			__func__, ret);
 		return ret;
 	}
     mutex_lock(&ps_data->io_lock);
@@ -875,10 +938,11 @@
 	struct stk3x1x_data *ps_data =  dev_get_drvdata(dev);
 	unsigned long value = 0;
 	int ret;
-	ret = strict_strtoul(buf, 10, &value);
+	ret = kstrtoul(buf, 10, &value);
 	if(ret < 0)
 	{
-		printk(KERN_ERR "%s:strict_strtoul failed, ret=0x%x\n", __func__, ret);
+		printk(KERN_ERR "%s:kstrtoul failed, ret=0x%x\n",
+			__func__, ret);
 		return ret;
 	}
 	mutex_lock(&ps_data->io_lock);
@@ -893,16 +957,22 @@
 	return scnprintf(buf, PAGE_SIZE, "%lld\n", ktime_to_ns(ps_data->als_poll_delay));
 }
 
-
+static inline void stk_als_delay_store_fir(struct stk3x1x_data *ps_data)
+{
+	ps_data->fir.number = 0;
+	ps_data->fir.idx = 0;
+	ps_data->fir.sum = 0;
+}
 static ssize_t stk_als_delay_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t size)
 {
     uint64_t value = 0;
 	int ret;
 	struct stk3x1x_data *ps_data =  dev_get_drvdata(dev);
-	ret = strict_strtoull(buf, 10, &value);
+	ret = kstrtoull(buf, 10, &value);
 	if(ret < 0)
 	{
-		printk(KERN_ERR "%s:strict_strtoull failed, ret=0x%x\n", __func__, ret);
+		printk(KERN_ERR "%s:kstrtoull failed, ret=0x%x\n",
+			__func__, ret);
 		return ret;
 	}
 #ifdef STK_DEBUG_PRINTF
@@ -916,6 +986,10 @@
 	mutex_lock(&ps_data->io_lock);
 	if(value != ktime_to_ns(ps_data->als_poll_delay))
 		ps_data->als_poll_delay = ns_to_ktime(value);
+
+	if (ps_data->use_fir)
+		stk_als_delay_store_fir(ps_data);
+
 	mutex_unlock(&ps_data->io_lock);
 	return size;
 }
@@ -928,6 +1002,77 @@
     return scnprintf(buf, PAGE_SIZE, "%d\n", reading);
 }
 
+static ssize_t stk_als_firlen_show(struct device *dev,
+			struct device_attribute *attr, char *buf)
+{
+	struct stk3x1x_data *ps_data =  dev_get_drvdata(dev);
+	int len = atomic_read(&ps_data->firlength);
+
+	dev_dbg(dev, "%s: len = %2d, idx = %2d\n",
+			__func__, len, ps_data->fir.idx);
+	dev_dbg(dev, "%s: sum = %5d, ave = %5d\n",
+			__func__, ps_data->fir.sum, ps_data->fir.sum/len);
+
+	return scnprintf(buf, PAGE_SIZE, "%d\n", len);
+}
+
+static ssize_t stk_als_firlen_store(struct device *dev,
+			struct device_attribute *attr,
+			const char *buf, size_t size)
+{
+	uint64_t value = 0;
+	int ret;
+	struct stk3x1x_data *ps_data =  dev_get_drvdata(dev);
+	ret = kstrtoull(buf, 10, &value);
+	if (ret < 0) {
+		dev_err(dev, "%s:strict_strtoull failed, ret=0x%x\n",
+			__func__, ret);
+		return ret;
+	}
+
+	if (value > MAX_FIR_LEN) {
+		dev_err(dev, "%s: firlen exceed maximum filter length\n",
+			__func__);
+	} else if (value < 1) {
+		atomic_set(&ps_data->firlength, 1);
+		memset(&ps_data->fir, 0x00, sizeof(ps_data->fir));
+	} else {
+		atomic_set(&ps_data->firlength, value);
+		memset(&ps_data->fir, 0x00, sizeof(ps_data->fir));
+	}
+	return size;
+}
+
+static ssize_t stk_als_fir_enable_show(struct device *dev,
+			struct device_attribute *attr, char *buf)
+{
+	struct stk3x1x_data *ps_data =  dev_get_drvdata(dev);
+
+	return scnprintf(buf, PAGE_SIZE, "%d\n", ps_data->use_fir);
+}
+
+static ssize_t stk_als_fir_enable_store(struct device *dev,
+			struct device_attribute *attr,
+			const char *buf, size_t size)
+{
+	uint64_t value = 0;
+	int ret;
+	struct stk3x1x_data *ps_data =  dev_get_drvdata(dev);
+	ret = kstrtoull(buf, 10, &value);
+	if (ret < 0) {
+		dev_err(dev, "%s:strict_strtoull failed, ret=0x%x\n",
+			__func__, ret);
+		return ret;
+	}
+
+	if (value) {
+		ps_data->use_fir = true;
+		memset(&ps_data->fir, 0x00, sizeof(ps_data->fir));
+	} else {
+		ps_data->use_fir = false;
+	}
+	return size;
+}
 static ssize_t stk_ps_code_show(struct device *dev, struct device_attribute *attr, char *buf)
 {
 	struct stk3x1x_data *ps_data =  dev_get_drvdata(dev);
@@ -1045,10 +1190,11 @@
 	int ret;
 	uint16_t offset;
 
-	ret = strict_strtoul(buf, 10, &value);
+	ret = kstrtoul(buf, 10, &value);
 	if(ret < 0)
 	{
-		printk(KERN_ERR "%s:strict_strtoul failed, ret=0x%x\n", __func__, ret);
+		printk(KERN_ERR "%s:kstrtoul failed, ret=0x%x\n",
+			__func__, ret);
 		return ret;
 	}
 	if(value > 65535)
@@ -1097,10 +1243,11 @@
 	struct stk3x1x_data *ps_data =  dev_get_drvdata(dev);
 	unsigned long value = 0;
 	int ret;
-	ret = strict_strtoul(buf, 10, &value);
+	ret = kstrtoul(buf, 10, &value);
 	if(ret < 0)
 	{
-		printk(KERN_ERR "%s:strict_strtoul failed, ret=0x%x\n", __func__, ret);
+		printk(KERN_ERR "%s:kstrtoul failed, ret=0x%x\n",
+			__func__, ret);
 		return ret;
 	}
     mutex_lock(&ps_data->io_lock);
@@ -1142,10 +1289,11 @@
 	struct stk3x1x_data *ps_data =  dev_get_drvdata(dev);
 	unsigned long value = 0;
 	int ret;
-	ret = strict_strtoul(buf, 10, &value);
+	ret = kstrtoul(buf, 10, &value);
 	if(ret < 0)
 	{
-		printk(KERN_ERR "%s:strict_strtoul failed, ret=0x%x\n", __func__, ret);
+		printk(KERN_ERR "%s:kstrtoul failed, ret=0x%x\n",
+			__func__, ret);
 		return ret;
 	}
     mutex_lock(&ps_data->io_lock);
@@ -1182,10 +1330,11 @@
 	struct stk3x1x_data *ps_data =  dev_get_drvdata(dev);
 	unsigned long value = 0;
 	int ret;
-	ret = strict_strtoul(buf, 10, &value);
+	ret = kstrtoul(buf, 10, &value);
 	if(ret < 0)
 	{
-		printk(KERN_ERR "%s:strict_strtoul failed, ret=0x%x\n", __func__, ret);
+		printk(KERN_ERR "%s:kstrtoul failed, ret=0x%x\n",
+			__func__, ret);
 		return ret;
 	}
     mutex_lock(&ps_data->io_lock);
@@ -1226,10 +1375,11 @@
 	struct stk3x1x_data *ps_data =  dev_get_drvdata(dev);
 	unsigned long value = 0;
 	int ret;
-	ret = strict_strtoul(buf, 10, &value);
+	ret = kstrtoul(buf, 10, &value);
 	if(ret < 0)
 	{
-		printk(KERN_ERR "%s:strict_strtoul failed, ret=0x%x\n", __func__, ret);
+		printk(KERN_ERR "%s:kstrtoul failed, ret=0x%x\n",
+			__func__, ret);
 		return ret;
 	}
     mutex_lock(&ps_data->io_lock);
@@ -1343,9 +1493,10 @@
 	int32_t recv_data;
 	struct stk3x1x_data *ps_data =  dev_get_drvdata(dev);
 
-	if((ret = strict_strtoul(buf, 16, &value)) < 0)
-	{
-		printk(KERN_ERR "%s:strict_strtoul failed, ret=0x%x\n", __func__, ret);
+	ret = kstrtoul(buf, 16, &value);
+	if (ret < 0) {
+		printk(KERN_ERR "%s:kstrtoul failed, ret=0x%x\n",
+			__func__, ret);
 		return ret;
 	}
 	recv_data = i2c_smbus_read_byte_data(ps_data->client,value);
@@ -1370,14 +1521,17 @@
 
 	for (i = 0; i < 2; i++)
 		token[i] = strsep((char **)&buf, " ");
-	if((ret = strict_strtoul(token[0], 16, (unsigned long *)&(addr))) < 0)
-	{
-		printk(KERN_ERR "%s:strict_strtoul failed, ret=0x%x\n", __func__, ret);
+	ret = kstrtoul(token[0], 16, (unsigned long *)&(addr));
+	if (ret < 0) {
+
+		printk(KERN_ERR "%s:kstrtoul failed, ret=0x%x\n",
+			__func__, ret);
 		return ret;
 	}
-	if((ret = strict_strtoul(token[1], 16, (unsigned long *)&(cmd))) < 0)
-	{
-		printk(KERN_ERR "%s:strict_strtoul failed, ret=0x%x\n", __func__, ret);
+	ret = kstrtoul(token[1], 16, (unsigned long *)&(cmd));
+	if (ret < 0) {
+		printk(KERN_ERR "%s:kstrtoul failed, ret=0x%x\n",
+			__func__, ret);
 		return ret;
 	}
 	printk(KERN_INFO "%s: write reg 0x%x=0x%x\n", __func__, addr, cmd);
@@ -1396,14 +1550,18 @@
 	return size;
 }
 
-
 static struct device_attribute als_enable_attribute = __ATTR(enable,0664,stk_als_enable_show,stk_als_enable_store);
 static struct device_attribute als_lux_attribute = __ATTR(lux,0664,stk_als_lux_show,stk_als_lux_store);
 static struct device_attribute als_code_attribute = __ATTR(code, 0444, stk_als_code_show, NULL);
 static struct device_attribute als_transmittance_attribute = __ATTR(transmittance,0664,stk_als_transmittance_show,stk_als_transmittance_store);
-static struct device_attribute als_poll_delay_attribute = __ATTR(delay,0664,stk_als_delay_show,stk_als_delay_store);
+static struct device_attribute als_poll_delay_attribute =
+	__ATTR(poll_delay, 0664, stk_als_delay_show, stk_als_delay_store);
 static struct device_attribute als_ir_code_attribute = __ATTR(ircode,0444,stk_als_ir_code_show,NULL);
-
+static struct device_attribute als_firlen_attribute =
+	__ATTR(firlen, 0664, stk_als_firlen_show, stk_als_firlen_store);
+static struct device_attribute als_fir_enable_attribute =
+	__ATTR(fir_enable, 0664, stk_als_fir_enable_show,
+	stk_als_fir_enable_store);
 
 static struct attribute *stk_als_attrs [] =
 {
@@ -1413,11 +1571,12 @@
     &als_transmittance_attribute.attr,
 	&als_poll_delay_attribute.attr,
 	&als_ir_code_attribute.attr,
+	&als_firlen_attribute.attr,
+	&als_fir_enable_attribute.attr,
     NULL
 };
 
 static struct attribute_group stk_als_attribute_group = {
-	.name = "driver",
 	.attrs = stk_als_attrs,
 };
 
@@ -1449,7 +1608,6 @@
 };
 
 static struct attribute_group stk_ps_attribute_group = {
-	.name = "driver",
 	.attrs = stk_ps_attrs,
 };
 
@@ -1647,6 +1805,13 @@
 	return IRQ_HANDLED;
 }
 #endif	/*	#if (!defined(STK_POLL_PS) || !defined(STK_POLL_ALS))	*/
+
+static inline void stk3x1x_init_fir(struct stk3x1x_data *ps_data)
+{
+	memset(&ps_data->fir, 0x00, sizeof(ps_data->fir));
+	atomic_set(&ps_data->firlength, STK_FIR_LEN);
+}
+
 static int32_t stk3x1x_init_all_setting(struct i2c_client *client, struct stk3x1x_platform_data *plat_data)
 {
 	int32_t ret;
@@ -1671,6 +1836,10 @@
 #ifndef CONFIG_STK_PS_ALS_USE_CHANGE_THRESHOLD
 	stk_init_code_threshold_table(ps_data);
 #endif
+
+	if (plat_data->use_fir)
+		stk3x1x_init_fir(ps_data);
+
     return 0;
 }
 
@@ -1777,6 +1946,207 @@
 }
 #endif	//#ifdef CONFIG_HAS_EARLYSUSPEND
 
+static int stk3x1x_power_on(struct stk3x1x_data *data, bool on)
+{
+	int ret = 0;
+
+	if (!on && data->power_enabled) {
+		ret = regulator_disable(data->vdd);
+		if (ret) {
+			dev_err(&data->client->dev,
+				"Regulator vdd disable failed ret=%d\n", ret);
+			return ret;
+		}
+
+		ret = regulator_disable(data->vio);
+		if (ret) {
+			dev_err(&data->client->dev,
+				"Regulator vio disable failed ret=%d\n", ret);
+			regulator_enable(data->vdd);
+		}
+	} else if (on && !data->power_enabled) {
+
+		ret = regulator_enable(data->vdd);
+		if (ret) {
+			dev_err(&data->client->dev,
+				"Regulator vdd enable failed ret=%d\n", ret);
+			return ret;
+		}
+
+		ret = regulator_enable(data->vio);
+		if (ret) {
+			dev_err(&data->client->dev,
+				"Regulator vio enable failed ret=%d\n", ret);
+			regulator_disable(data->vdd);
+		}
+	} else {
+		dev_warn(&data->client->dev,
+				"Power on=%d. enabled=%d\n",
+				on, data->power_enabled);
+	}
+
+	return ret;
+}
+
+static int stk3x1x_power_init(struct stk3x1x_data *data, bool on)
+{
+	int ret;
+
+	if (!on) {
+		if (regulator_count_voltages(data->vdd) > 0)
+			regulator_set_voltage(data->vdd,
+					0, STK3X1X_VDD_MAX_UV);
+
+		regulator_put(data->vdd);
+
+		if (regulator_count_voltages(data->vio) > 0)
+			regulator_set_voltage(data->vio,
+					0, STK3X1X_VIO_MAX_UV);
+
+		regulator_put(data->vio);
+	} else {
+		data->vdd = regulator_get(&data->client->dev, "vdd");
+		if (IS_ERR(data->vdd)) {
+			ret = PTR_ERR(data->vdd);
+			dev_err(&data->client->dev,
+				"Regulator get failed vdd ret=%d\n", ret);
+			return ret;
+		}
+
+		if (regulator_count_voltages(data->vdd) > 0) {
+			ret = regulator_set_voltage(data->vdd,
+					STK3X1X_VDD_MIN_UV,
+					STK3X1X_VDD_MAX_UV);
+			if (ret) {
+				dev_err(&data->client->dev,
+					"Regulator set failed vdd ret=%d\n",
+					ret);
+				goto reg_vdd_put;
+			}
+		}
+
+		data->vio = regulator_get(&data->client->dev, "vio");
+		if (IS_ERR(data->vio)) {
+			ret = PTR_ERR(data->vio);
+			dev_err(&data->client->dev,
+				"Regulator get failed vio ret=%d\n", ret);
+			goto reg_vdd_set;
+		}
+
+		if (regulator_count_voltages(data->vio) > 0) {
+			ret = regulator_set_voltage(data->vio,
+					STK3X1X_VIO_MIN_UV,
+					STK3X1X_VIO_MAX_UV);
+			if (ret) {
+				dev_err(&data->client->dev,
+				"Regulator set failed vio ret=%d\n", ret);
+				goto reg_vio_put;
+			}
+		}
+	}
+
+	return 0;
+
+reg_vio_put:
+	regulator_put(data->vio);
+reg_vdd_set:
+	if (regulator_count_voltages(data->vdd) > 0)
+		regulator_set_voltage(data->vdd, 0, STK3X1X_VDD_MAX_UV);
+reg_vdd_put:
+	regulator_put(data->vdd);
+	return ret;
+}
+
+#ifdef CONFIG_OF
+static int stk3x1x_parse_dt(struct device *dev,
+			struct stk3x1x_platform_data *pdata)
+{
+	int rc;
+	struct device_node *np = dev->of_node;
+	u32 temp_val;
+
+	pdata->int_pin = of_get_named_gpio_flags(np, "stk,irq-gpio",
+				0, &pdata->int_flags);
+	if (pdata->int_pin < 0) {
+		dev_err(dev, "Unable to read irq-gpio\n");
+		return pdata->int_pin;
+	}
+
+	rc = of_property_read_u32(np, "stk,transmittance", &temp_val);
+	if (!rc)
+		pdata->transmittance = temp_val;
+	else {
+		dev_err(dev, "Unable to read transmittance\n");
+		return rc;
+	}
+
+	rc = of_property_read_u32(np, "stk,state-reg", &temp_val);
+	if (!rc)
+		pdata->state_reg = temp_val;
+	else {
+		dev_err(dev, "Unable to read state-reg\n");
+		return rc;
+	}
+
+	rc = of_property_read_u32(np, "stk,psctrl-reg", &temp_val);
+	if (!rc)
+		pdata->psctrl_reg = (u8)temp_val;
+	else {
+		dev_err(dev, "Unable to read psctrl-reg\n");
+		return rc;
+	}
+
+	rc = of_property_read_u32(np, "stk,alsctrl-reg", &temp_val);
+	if (!rc)
+		pdata->alsctrl_reg = (u8)temp_val;
+	else {
+		dev_err(dev, "Unable to read alsctrl-reg\n");
+		return rc;
+	}
+
+	rc = of_property_read_u32(np, "stk,ledctrl-reg", &temp_val);
+	if (!rc)
+		pdata->ledctrl_reg = (u8)temp_val;
+	else {
+		dev_err(dev, "Unable to read ledctrl-reg\n");
+		return rc;
+	}
+
+	rc = of_property_read_u32(np, "stk,wait-reg", &temp_val);
+	if (!rc)
+		pdata->wait_reg = (u8)temp_val;
+	else {
+		dev_err(dev, "Unable to read wait-reg\n");
+		return rc;
+	}
+
+	rc = of_property_read_u32(np, "stk,ps-thdh", &temp_val);
+	if (!rc)
+		pdata->ps_thd_h = (u16)temp_val;
+	else {
+		dev_err(dev, "Unable to read ps-thdh\n");
+		return rc;
+	}
+
+	rc = of_property_read_u32(np, "stk,ps-thdl", &temp_val);
+	if (!rc)
+		pdata->ps_thd_l = (u16)temp_val;
+	else {
+		dev_err(dev, "Unable to read ps-thdl\n");
+		return rc;
+	}
+
+	pdata->use_fir = of_property_read_bool(np, "stk,use-fir");
+
+	return 0;
+}
+#else
+static int stk3x1x_parse_dt(struct device *dev,
+			struct stk3x1x_platform_data *pdata)
+{
+	return -ENODEV;
+}
+#endif /* !CONFIG_OF */
 
 static int stk3x1x_probe(struct i2c_client *client,
                         const struct i2c_device_id *id)
@@ -1811,20 +2181,34 @@
 #ifdef STK_POLL_PS
 	wake_lock_init(&ps_data->ps_nosuspend_wl,WAKE_LOCK_SUSPEND, "stk_nosuspend_wakelock");
 #endif
-	if(client->dev.platform_data != NULL)
-	{
-		plat_data = client->dev.platform_data;
-		ps_data->als_transmittance = plat_data->transmittance;
-		ps_data->int_pin = plat_data->int_pin;
-		if(ps_data->als_transmittance == 0)
-		{
-			printk(KERN_ERR "%s: Please set als_transmittance in platform data\n", __func__);
-			goto err_als_input_allocate;
+	if (client->dev.of_node) {
+		plat_data = devm_kzalloc(&client->dev,
+			sizeof(struct stk3x1x_platform_data), GFP_KERNEL);
+		if (!plat_data) {
+			dev_err(&client->dev, "Failed to allocate memory\n");
+			return -ENOMEM;
 		}
+
+		err = stk3x1x_parse_dt(&client->dev, plat_data);
+		dev_err(&client->dev,
+			"%s: stk3x1x_parse_dt ret=%d\n", __func__, err);
+		if (err)
+			return err;
+	} else
+		plat_data = client->dev.platform_data;
+
+	if (!plat_data) {
+		dev_err(&client->dev,
+			"%s: no stk3x1x platform data!\n", __func__);
+		goto err_als_input_allocate;
 	}
-	else
-	{
-		printk(KERN_ERR "%s: no stk3x1x platform data!\n", __func__);
+	ps_data->als_transmittance = plat_data->transmittance;
+	ps_data->int_pin = plat_data->int_pin;
+	ps_data->use_fir = plat_data->use_fir;
+
+	if (ps_data->als_transmittance == 0) {
+		dev_err(&client->dev,
+			"%s: Please set als_transmittance\n", __func__);
 		goto err_als_input_allocate;
 	}
 
@@ -1897,6 +2281,14 @@
 		goto err_stk3x1x_setup_irq;
 #endif
 
+	err = stk3x1x_power_init(ps_data, true);
+	if (err)
+		goto err_power_init;
+
+	err = stk3x1x_power_on(ps_data, true);
+	if (err)
+		goto err_power_on;
+
 	err = stk3x1x_init_all_setting(client, plat_data);
 	if(err < 0)
 		goto err_init_all_setting;
@@ -1910,6 +2302,10 @@
 	return 0;
 
 err_init_all_setting:
+	stk3x1x_power_on(ps_data, false);
+err_power_on:
+	stk3x1x_power_init(ps_data, false);
+err_power_init:
 #ifndef STK_POLL_PS
 	free_irq(ps_data->irq, ps_data);
 	gpio_free(plat_data->int_pin);
@@ -1985,11 +2381,17 @@
 };
 MODULE_DEVICE_TABLE(i2c, stk_ps_id);
 
+static struct of_device_id stk_match_table[] = {
+	{ .compatible = "stk,stk3x1x", },
+	{ },
+};
+
 static struct i2c_driver stk_ps_driver =
 {
     .driver = {
         .name = DEVICE_NAME,
 		.owner = THIS_MODULE,
+		.of_match_table = stk_match_table,
     },
     .probe = stk3x1x_probe,
     .remove = stk3x1x_remove,
diff --git a/drivers/input/touchscreen/Kconfig b/drivers/input/touchscreen/Kconfig
index b43c13e..9b0c5c7 100644
--- a/drivers/input/touchscreen/Kconfig
+++ b/drivers/input/touchscreen/Kconfig
@@ -1008,4 +1008,16 @@
 
 	  If unsure, say N.
 
+config TOUCHSCREEN_GT9XX
+	bool "Goodix touchpanel GT9xx series"
+	depends on I2C
+	help
+	  Say Y here if you have a Goodix GT9xx touchscreen.
+	  Gt9xx controllers are multi touch controllers which can
+	  report 5 touches at a time.
+
+          If unsure, say N.
+
+source "drivers/input/touchscreen/gt9xx/Kconfig"
+
 endif
diff --git a/drivers/input/touchscreen/Makefile b/drivers/input/touchscreen/Makefile
index 1f309d8..3acc612 100644
--- a/drivers/input/touchscreen/Makefile
+++ b/drivers/input/touchscreen/Makefile
@@ -82,3 +82,4 @@
 obj-$(CONFIG_TOUCHSCREEN_SYNAPTICS_I2C_RMI4)		+= synaptics_i2c_rmi4.o
 obj-$(CONFIG_TOUCHSCREEN_SYNAPTICS_DSX_RMI4_DEV)	+= synaptics_rmi_dev.o
 obj-$(CONFIG_TOUCHSCREEN_SYNAPTICS_DSX_FW_UPDATE) 	+= synaptics_fw_update.o
+obj-$(CONFIG_TOUCHSCREEN_GT9XX)		+= gt9xx/
diff --git a/drivers/input/touchscreen/atmel_mxt_ts.c b/drivers/input/touchscreen/atmel_mxt_ts.c
index b725200..06ca31c 100644
--- a/drivers/input/touchscreen/atmel_mxt_ts.c
+++ b/drivers/input/touchscreen/atmel_mxt_ts.c
@@ -394,7 +394,7 @@
 	const char *fw_name;
 	bool no_force_update;
 	bool lpm_support;
-	bool regs_enabled;
+	bool dev_sleep;
 
 #if defined(CONFIG_SECURE_TOUCH)
 	atomic_t st_enabled;
@@ -2162,11 +2162,6 @@
 	if (on == false)
 		goto power_off;
 
-	if (data->regs_enabled) {
-		dev_dbg(&data->client->dev, "regs are already enabled\n");
-		return 0;
-	}
-
 	rc = reg_set_optimum_mode_check(data->vcc_ana, MXT_ACTIVE_LOAD_UA);
 	if (rc < 0) {
 		dev_err(&data->client->dev,
@@ -2215,8 +2210,6 @@
 		}
 	}
 
-	data->regs_enabled = true;
-
 	msleep(130);
 
 	return 0;
@@ -2237,12 +2230,6 @@
 	return rc;
 
 power_off:
-
-	if (!data->regs_enabled) {
-		dev_dbg(&data->client->dev, "regs are already disabled\n");
-		return 0;
-	}
-
 	reg_set_optimum_mode_check(data->vcc_ana, 0);
 	regulator_disable(data->vcc_ana);
 	if (data->pdata->digital_pwr_regulator) {
@@ -2254,8 +2241,6 @@
 		regulator_disable(data->vcc_i2c);
 	}
 
-	data->regs_enabled = false;
-
 	msleep(50);
 	return 0;
 }
@@ -2455,6 +2440,11 @@
 	struct input_dev *input_dev = data->input_dev;
 	int error;
 
+	if (data->dev_sleep) {
+		dev_dbg(dev, "Device already in sleep\n");
+		return 0;
+	}
+
 	disable_irq(data->irq);
 
 	mutex_lock(&input_dev->mutex);
@@ -2485,6 +2475,7 @@
 		}
 	}
 
+	data->dev_sleep = true;
 	return 0;
 }
 
@@ -2495,6 +2486,11 @@
 	struct input_dev *input_dev = data->input_dev;
 	int error;
 
+	if (!data->dev_sleep) {
+		dev_dbg(dev, "Device already in resume\n");
+		return 0;
+	}
+
 	/* put regulators back in active power mode */
 	if (data->lpm_support) {
 		error = mxt_regulator_lpm(data, false);
@@ -2538,6 +2534,7 @@
 
 	enable_irq(data->irq);
 
+	data->dev_sleep = false;
 	return 0;
 }
 
@@ -2924,6 +2921,7 @@
 	data->pdata = pdata;
 	data->no_force_update = pdata->no_force_update;
 	data->lpm_support = !pdata->no_lpm_support;
+	data->dev_sleep = false;
 
 	__set_bit(EV_ABS, input_dev->evbit);
 	__set_bit(EV_KEY, input_dev->evbit);
diff --git a/drivers/input/touchscreen/ft5x06_ts.c b/drivers/input/touchscreen/ft5x06_ts.c
index 7fac726..2f9ea10 100644
--- a/drivers/input/touchscreen/ft5x06_ts.c
+++ b/drivers/input/touchscreen/ft5x06_ts.c
@@ -41,22 +41,23 @@
 #define FT_SUSPEND_LEVEL 1
 #endif
 
-#define CFG_MAX_TOUCH_POINTS	5
+#define FT_DRIVER_VERSION	0x02
 
-#define FT_STARTUP_DLY		150
-#define FT_RESET_DLY		20
+#define FT_META_REGS		3
+#define FT_ONE_TCH_LEN		6
+#define FT_TCH_LEN(x)		(FT_META_REGS + FT_ONE_TCH_LEN * x)
 
 #define FT_PRESS		0x7F
 #define FT_MAX_ID		0x0F
-#define FT_TOUCH_STEP		6
 #define FT_TOUCH_X_H_POS	3
 #define FT_TOUCH_X_L_POS	4
 #define FT_TOUCH_Y_H_POS	5
 #define FT_TOUCH_Y_L_POS	6
+#define FT_TD_STATUS		2
 #define FT_TOUCH_EVENT_POS	3
 #define FT_TOUCH_ID_POS		5
-
-#define POINT_READ_BUF	(3 + FT_TOUCH_STEP * CFG_MAX_TOUCH_POINTS)
+#define FT_TOUCH_DOWN		0
+#define FT_TOUCH_CONTACT	2
 
 /*register address*/
 #define FT_REG_DEV_MODE		0x00
@@ -68,6 +69,9 @@
 #define FT_REG_THGROUP		0x80
 #define FT_REG_ECC		0xCC
 #define FT_REG_RESET_FW		0x07
+#define FT_REG_FW_MAJ_VER	0xB1
+#define FT_REG_FW_MIN_VER	0xB2
+#define FT_REG_FW_SUB_MIN_VER	0xB3
 
 /* power register bits*/
 #define FT_PMODE_ACTIVE		0x00
@@ -76,7 +80,8 @@
 #define FT_PMODE_HIBERNATE	0x03
 #define FT_FACTORYMODE_VALUE	0x40
 #define FT_WORKMODE_VALUE	0x00
-#define FT_RST_CMD_REG		0xFC
+#define FT_RST_CMD_REG1		0xFC
+#define FT_RST_CMD_REG2		0xBC
 #define FT_READ_ID_REG		0x90
 #define FT_ERASE_APP_REG	0x61
 #define FT_ERASE_PANEL_REG	0x63
@@ -98,54 +103,19 @@
 
 #define FT5316_ID		0x0A
 #define FT5306I_ID		0x55
+#define FT6X06_ID		0x06
 
 #define FT_UPGRADE_AA		0xAA
 #define FT_UPGRADE_55		0x55
 
-/*upgrade config of FT5606*/
-#define FT5606_UPGRADE_AA_DELAY		50
-#define FT5606_UPGRADE_55_DELAY		10
-#define FT5606_UPGRADE_ID_1		0x79
-#define FT5606_UPGRADE_ID_2		0x06
-#define FT5606_UPGRADE_READID_DELAY	100
-#define FT5606_UPGRADE_EARSE_DELAY	2000
-
-/*upgrade config of FT5316*/
-#define FT5316_UPGRADE_AA_DELAY		50
-#define FT5316_UPGRADE_55_DELAY		30
-#define FT5316_UPGRADE_ID_1		0x79
-#define FT5316_UPGRADE_ID_2		0x07
-#define FT5316_UPGRADE_READID_DELAY	1
-#define FT5316_UPGRADE_EARSE_DELAY	1500
-
-/*upgrade config of FT5x06(x=2,3,4)*/
-#define FT5X06_UPGRADE_AA_DELAY		50
-#define FT5X06_UPGRADE_55_DELAY		30
-#define FT5X06_UPGRADE_ID_1		0x79
-#define FT5X06_UPGRADE_ID_2		0x03
-#define FT5X06_UPGRADE_READID_DELAY	1
-#define FT5X06_UPGRADE_EARSE_DELAY	2000
-
-/*upgrade config of FT6208*/
-#define FT6208_UPGRADE_AA_DELAY		60
-#define FT6208_UPGRADE_55_DELAY		10
-#define FT6208_UPGRADE_ID_1		0x79
-#define FT6208_UPGRADE_ID_2		0x05
-#define FT6208_UPGRADE_READID_DELAY	10
-#define FT6208_UPGRADE_EARSE_DELAY	2000
-
-#define FT_UPGRADE_INFO(x, y)	do { \
-		x->delay_55 = y##_UPGRADE_55_DELAY; \
-		x->delay_aa = y##_UPGRADE_AA_DELAY; \
-		x->upgrade_id_1 = y##_UPGRADE_ID_1; \
-		x->upgrade_id_2 = y##_UPGRADE_ID_2; \
-		x->delay_readid = y##_UPGRADE_READID_DELAY; \
-		x->delay_earse_flash = y##_UPGRADE_EARSE_DELAY; \
-		} while (0)
-
 #define FT_FW_MIN_SIZE		8
 #define FT_FW_MAX_SIZE		32768
-#define FT_FW_FILE_VER(x)	((x)->data[(x)->size - 2])
+
+/* Firmware file is not supporting minor and sub minor so use 0 */
+#define FT_FW_FILE_MAJ_VER(x)	((x)->data[(x)->size - 2])
+#define FT_FW_FILE_MIN_VER(x)	0
+#define FT_FW_FILE_SUB_MIN_VER(x) 0
+
 #define FT_FW_CHECK(x)		\
 	(((x)->data[(x)->size - 8] ^ (x)->data[(x)->size - 6]) == 0xFF \
 	&& (((x)->data[(x)->size - 7] ^ (x)->data[(x)->size - 5]) == 0xFF \
@@ -162,7 +132,7 @@
 #define FT_FW_LAST_PKT		0x6ffa
 #define FT_EARSE_DLY_MS		100
 
-#define FT_UPGRADE_LOOP		3
+#define FT_UPGRADE_LOOP		10
 #define FT_CAL_START		0x04
 #define FT_CAL_FIN		0x00
 #define FT_CAL_STORE		0x05
@@ -170,39 +140,29 @@
 #define FT_REG_CAL		0x00
 #define FT_CAL_MASK		0x70
 
-#define FT_INFO_MAX_LEN		200
+#define FT_INFO_MAX_LEN		512
 
-#define FT_STORE_TS_INFO(buf, id, fw_ver) \
+#define FT_STORE_TS_INFO(buf, id, name, max_tch, group_id, fw_vkey_support, \
+			fw_name, fw_maj, fw_min, fw_sub_min) \
 			snprintf(buf, FT_INFO_MAX_LEN, \
 				"controller\t= focaltech\n" \
 				"model\t\t= 0x%x\n" \
-				"fw_ver\t\t= 0x%x\n", id, fw_ver)
+				"name\t\t= %s\n" \
+				"max_touches\t= %d\n" \
+				"drv_ver\t\t= 0x%x\n" \
+				"group_id\t= 0x%x\n" \
+				"fw_vkey_support\t= %s\n" \
+				"fw_name\t\t= %s\n" \
+				"fw_ver\t\t= %d.%d.%d\n", id, name, \
+				max_tch, FT_DRIVER_VERSION, group_id, \
+				fw_vkey_support, fw_name, fw_maj, fw_min, \
+				fw_sub_min)
 
 #define FT_DEBUG_DIR_NAME	"ts_debug"
 
-struct ts_event {
-	u16 x[CFG_MAX_TOUCH_POINTS];	/*x coordinate */
-	u16 y[CFG_MAX_TOUCH_POINTS];	/*y coordinate */
-	/* touch event: 0 -- down; 1-- contact; 2 -- contact */
-	u8 touch_event[CFG_MAX_TOUCH_POINTS];
-	u8 finger_id[CFG_MAX_TOUCH_POINTS];	/*touch ID */
-	u16 pressure;
-	u8 touch_point;
-};
-
-struct upgrade_info {
-	u16 delay_aa;		/*delay of write FT_UPGRADE_AA */
-	u16 delay_55;		/*delay of write FT_UPGRADE_55 */
-	u8 upgrade_id_1;	/*upgrade id 1 */
-	u8 upgrade_id_2;	/*upgrade id 2 */
-	u16 delay_readid;	/*delay of read id */
-	u16 delay_earse_flash; /*delay of earse flash*/
-};
-
 struct ft5x06_ts_data {
 	struct i2c_client *client;
 	struct input_dev *input_dev;
-	struct ts_event event;
 	const struct ft5x06_ts_platform_data *pdata;
 	struct regulator *vdd;
 	struct regulator *vcc_i2c;
@@ -213,6 +173,9 @@
 	u16 addr;
 	bool suspended;
 	char *ts_info;
+	u8 *tch_data;
+	u32 tch_data_len;
+	u8 fw_ver[3];
 #if defined(CONFIG_FB)
 	struct notifier_block fb_notif;
 #elif defined(CONFIG_HAS_EARLYSUSPEND)
@@ -295,88 +258,92 @@
 	return ft5x06_i2c_read(client, &addr, 1, val, 1);
 }
 
-static void ft5x06_report_value(struct ft5x06_ts_data *data)
+static void ft5x06_update_fw_ver(struct ft5x06_ts_data *data)
 {
-	struct ts_event *event = &data->event;
-	int i;
-	int fingerdown = 0;
+	struct i2c_client *client = data->client;
+	u8 reg_addr;
+	int err;
 
-	for (i = 0; i < event->touch_point; i++) {
-		if (event->touch_event[i] == 0 || event->touch_event[i] == 2) {
-			event->pressure = FT_PRESS;
-			fingerdown++;
-		} else {
-			event->pressure = 0;
-		}
+	reg_addr = FT_REG_FW_MAJ_VER;
+	err = ft5x06_i2c_read(client, &reg_addr, 1, &data->fw_ver[0], 1);
+	if (err < 0)
+		dev_err(&client->dev, "fw major version read failed");
 
-		input_mt_slot(data->input_dev, event->finger_id[i]);
-		input_mt_report_slot_state(data->input_dev, MT_TOOL_FINGER,
-					!!event->pressure);
+	reg_addr = FT_REG_FW_MIN_VER;
+	err = ft5x06_i2c_read(client, &reg_addr, 1, &data->fw_ver[1], 1);
+	if (err < 0)
+		dev_err(&client->dev, "fw minor version read failed");
 
-		if (event->pressure == FT_PRESS) {
-			input_report_abs(data->input_dev, ABS_MT_POSITION_X,
-					 event->x[i]);
-			input_report_abs(data->input_dev, ABS_MT_POSITION_Y,
-					 event->y[i]);
-			input_report_abs(data->input_dev, ABS_MT_TOUCH_MAJOR,
-					 event->pressure);
-		}
-	}
+	reg_addr = FT_REG_FW_SUB_MIN_VER;
+	err = ft5x06_i2c_read(client, &reg_addr, 1, &data->fw_ver[2], 1);
+	if (err < 0)
+		dev_err(&client->dev, "fw sub minor version read failed");
 
-	input_report_key(data->input_dev, BTN_TOUCH, !!fingerdown);
-	input_sync(data->input_dev);
-}
-
-static int ft5x06_handle_touchdata(struct ft5x06_ts_data *data)
-{
-	struct ts_event *event = &data->event;
-	int num_points;
-	int ret, i;
-	u8 buf[POINT_READ_BUF] = { 0 };
-	u8 pointid = FT_MAX_ID;
-
-	ret = ft5x06_i2c_read(data->client, buf, 1, buf, POINT_READ_BUF);
-	if (ret < 0) {
-		dev_err(&data->client->dev, "%s read touchdata failed.\n",
-			__func__);
-		return ret;
-	}
-	memset(event, 0, sizeof(struct ts_event));
-
-	event->touch_point = 0;
-	num_points = buf[2] & FT_STATUS_NUM_TP_MASK;
-
-	for (i = 0; i < num_points; i++) {
-		pointid = (buf[FT_TOUCH_ID_POS + FT_TOUCH_STEP * i]) >> 4;
-		if (pointid >= FT_MAX_ID)
-			break;
-		else
-			event->touch_point++;
-		event->x[i] =
-		    (s16) (buf[FT_TOUCH_X_H_POS + FT_TOUCH_STEP * i] & 0x0F) <<
-		    8 | (s16) buf[FT_TOUCH_X_L_POS + FT_TOUCH_STEP * i];
-		event->y[i] =
-		    (s16) (buf[FT_TOUCH_Y_H_POS + FT_TOUCH_STEP * i] & 0x0F) <<
-		    8 | (s16) buf[FT_TOUCH_Y_L_POS + FT_TOUCH_STEP * i];
-		event->touch_event[i] =
-		    buf[FT_TOUCH_EVENT_POS + FT_TOUCH_STEP * i] >> 6;
-		event->finger_id[i] =
-		    (buf[FT_TOUCH_ID_POS + FT_TOUCH_STEP * i]) >> 4;
-	}
-
-	ft5x06_report_value(data);
-
-	return 0;
+	dev_info(&client->dev, "Firmware version = %d.%d.%d\n",
+		data->fw_ver[0], data->fw_ver[1], data->fw_ver[2]);
 }
 
 static irqreturn_t ft5x06_ts_interrupt(int irq, void *dev_id)
 {
 	struct ft5x06_ts_data *data = dev_id;
-	int rc;
+	struct input_dev *ip_dev;
+	int rc, i;
+	u32 id, x, y, pressure, status, num_touches;
+	u8 reg = 0x00, *buf;
+	bool update_input = false;
 
-	rc = ft5x06_handle_touchdata(data);
-	if (rc)
-		pr_err("%s: handling touchdata failed\n", __func__);
+	if (!data) {
+		pr_err("%s: Invalid data\n", __func__);
+		return IRQ_HANDLED;
+	}
+
+	ip_dev = data->input_dev;
+	buf = data->tch_data;
+
+	rc = ft5x06_i2c_read(data->client, &reg, 1,
+			buf, data->tch_data_len);
+	if (rc < 0) {
+		dev_err(&data->client->dev, "%s: read data fail\n", __func__);
+		return IRQ_HANDLED;
+	}
+
+	for (i = 0; i < data->pdata->num_max_touches; i++) {
+		id = (buf[FT_TOUCH_ID_POS + FT_ONE_TCH_LEN * i]) >> 4;
+		if (id >= FT_MAX_ID)
+			break;
+
+		update_input = true;
+
+		x = (buf[FT_TOUCH_X_H_POS + FT_ONE_TCH_LEN * i] & 0x0F) << 8 |
+			(buf[FT_TOUCH_X_L_POS + FT_ONE_TCH_LEN * i]);
+		y = (buf[FT_TOUCH_Y_H_POS + FT_ONE_TCH_LEN * i] & 0x0F) << 8 |
+			(buf[FT_TOUCH_Y_L_POS + FT_ONE_TCH_LEN * i]);
+
+		status = buf[FT_TOUCH_EVENT_POS + FT_ONE_TCH_LEN * i] >> 6;
+
+		num_touches = buf[FT_TD_STATUS] & FT_STATUS_NUM_TP_MASK;
+
+		/* invalid combination */
+		if (!num_touches && !status && !id)
+			break;
+
+		input_mt_slot(ip_dev, id);
+		if (status == FT_TOUCH_DOWN || status == FT_TOUCH_CONTACT) {
+			pressure = FT_PRESS;
+			input_mt_report_slot_state(ip_dev, MT_TOOL_FINGER, 1);
+			input_report_abs(ip_dev, ABS_MT_POSITION_X, x);
+			input_report_abs(ip_dev, ABS_MT_POSITION_Y, y);
+			input_report_abs(ip_dev, ABS_MT_PRESSURE, pressure);
+		} else {
+			input_mt_report_slot_state(ip_dev, MT_TOOL_FINGER, 0);
+			input_report_abs(ip_dev, ABS_MT_PRESSURE, 0);
+		}
+	}
+
+	if (update_input) {
+		input_mt_report_pointer_emulation(ip_dev, false);
+		input_sync(ip_dev);
+	}
 
 	return IRQ_HANDLED;
 }
@@ -509,7 +476,7 @@
 	disable_irq(data->client->irq);
 
 	/* release all touches */
-	for (i = 0; i < CFG_MAX_TOUCH_POINTS; i++) {
+	for (i = 0; i < data->pdata->num_max_touches; i++) {
 		input_mt_slot(data->input_dev, i);
 		input_mt_report_slot_state(data->input_dev, MT_TOOL_FINGER, 0);
 	}
@@ -543,7 +510,7 @@
 pwr_off_fail:
 	if (gpio_is_valid(data->pdata->reset_gpio)) {
 		gpio_set_value_cansleep(data->pdata->reset_gpio, 0);
-		msleep(FT_RESET_DLY);
+		msleep(data->pdata->hard_rst_dly);
 		gpio_set_value_cansleep(data->pdata->reset_gpio, 1);
 	}
 	enable_irq(data->client->irq);
@@ -556,7 +523,7 @@
 	int err;
 
 	if (!data->suspended) {
-		dev_info(dev, "Already in awake state\n");
+		dev_dbg(dev, "Already in awake state\n");
 		return 0;
 	}
 
@@ -576,9 +543,12 @@
 
 	if (gpio_is_valid(data->pdata->reset_gpio)) {
 		gpio_set_value_cansleep(data->pdata->reset_gpio, 0);
-		msleep(FT_RESET_DLY);
+		msleep(data->pdata->hard_rst_dly);
 		gpio_set_value_cansleep(data->pdata->reset_gpio, 1);
 	}
+
+	msleep(data->pdata->soft_rst_dly);
+
 	enable_irq(data->client->irq);
 
 	data->suspended = false;
@@ -636,16 +606,17 @@
 
 static int ft5x06_auto_cal(struct i2c_client *client)
 {
+	struct ft5x06_ts_data *data = i2c_get_clientdata(client);
 	u8 temp = 0, i;
 
 	/* set to factory mode */
-	msleep(2 * FT_STARTUP_DLY);
+	msleep(2 * data->pdata->soft_rst_dly);
 	ft5x0x_write_reg(client, FT_REG_DEV_MODE, FT_FACTORYMODE_VALUE);
-	msleep(FT_STARTUP_DLY);
+	msleep(data->pdata->soft_rst_dly);
 
 	/* start calibration */
 	ft5x0x_write_reg(client, FT_DEV_MODE_REG_CAL, FT_CAL_START);
-	msleep(2 * FT_STARTUP_DLY);
+	msleep(2 * data->pdata->soft_rst_dly);
 	for (i = 0; i < FT_CAL_RETRY; i++) {
 		ft5x0x_read_reg(client, FT_REG_CAL, &temp);
 		/*return to normal mode, calibration finish */
@@ -654,33 +625,17 @@
 	}
 
 	/*calibration OK */
-	msleep(2 * FT_STARTUP_DLY);
+	msleep(2 * data->pdata->soft_rst_dly);
 	ft5x0x_write_reg(client, FT_REG_DEV_MODE, FT_FACTORYMODE_VALUE);
-	msleep(FT_STARTUP_DLY);
+	msleep(data->pdata->soft_rst_dly);
 
 	/* store calibration data */
 	ft5x0x_write_reg(client, FT_DEV_MODE_REG_CAL, FT_CAL_STORE);
-	msleep(2 * FT_STARTUP_DLY);
+	msleep(2 * data->pdata->soft_rst_dly);
 
 	/* set to normal mode */
 	ft5x0x_write_reg(client, FT_REG_DEV_MODE, FT_WORKMODE_VALUE);
-	msleep(2 * FT_STARTUP_DLY);
-
-	return 0;
-}
-
-static int ft5x06_get_upgrade_info(u8 family_id, struct upgrade_info *info)
-{
-	switch (family_id) {
-	case FT5306I_ID:
-		FT_UPGRADE_INFO(info, FT5X06);
-		break;
-	case FT5316_ID:
-		FT_UPGRADE_INFO(info, FT5316);
-		break;
-	default:
-		return -EINVAL;
-	}
+	msleep(2 * data->pdata->soft_rst_dly);
 
 	return 0;
 }
@@ -689,35 +644,35 @@
 			const u8 *data, u32 data_len)
 {
 	struct ft5x06_ts_data *ts_data = i2c_get_clientdata(client);
-	struct upgrade_info info;
+	struct fw_upgrade_info info = ts_data->pdata->info;
+	u8 reset_reg;
 	u8 w_buf[FT_MAX_WR_BUF] = {0}, r_buf[FT_MAX_RD_BUF] = {0};
 	u8 pkt_buf[FT_FW_PKT_LEN + FT_FW_PKT_META_LEN];
 	int rc, i, j, temp;
 	u32 pkt_num, pkt_len;
 	u8 fw_ecc;
 
-	rc = ft5x06_get_upgrade_info(ts_data->family_id, &info);
-	if (rc < 0) {
-		dev_err(&client->dev, "Cannot get upgrade information!\n");
-		return -EINVAL;
-	}
+	for (i = 0, j = 0; i < FT_UPGRADE_LOOP; i++) {
+		/* reset - write 0xaa and 0x55 to reset register */
+		if (ts_data->family_id == FT6X06_ID)
+			reset_reg = FT_RST_CMD_REG2;
+		else
+			reset_reg = FT_RST_CMD_REG1;
 
-	for (i = 0; i < FT_UPGRADE_LOOP; i++) {
-		/* reset - write 0xaa and 0x55 to register 0xfc */
-		ft5x0x_write_reg(client, FT_RST_CMD_REG, FT_UPGRADE_AA);
+		ft5x0x_write_reg(client, reset_reg, FT_UPGRADE_AA);
 		msleep(info.delay_aa);
 
-		ft5x0x_write_reg(client, FT_RST_CMD_REG, FT_UPGRADE_55);
+		ft5x0x_write_reg(client, reset_reg, FT_UPGRADE_55);
 		msleep(info.delay_55);
 
 		/* Enter upgrade mode */
 		w_buf[0] = FT_UPGRADE_55;
 		w_buf[1] = FT_UPGRADE_AA;
 		do {
-			i++;
+			j++;
 			rc = ft5x06_i2c_write(client, w_buf, 2);
 			msleep(FT_RETRY_DLY);
-		} while (rc <= 0 && i < FT_MAX_TRIES);
+		} while (rc <= 0 && j < FT_MAX_TRIES);
 
 		/* check READ_ID */
 		msleep(info.delay_readid);
@@ -743,7 +698,7 @@
 	/* erase app and panel paramenter area */
 	w_buf[0] = FT_ERASE_APP_REG;
 	ft5x06_i2c_write(client, w_buf, 1);
-	msleep(info.delay_earse_flash);
+	msleep(info.delay_erase_flash);
 
 	w_buf[0] = FT_ERASE_PANEL_REG;
 	ft5x06_i2c_write(client, w_buf, 1);
@@ -818,7 +773,9 @@
 	/* reset */
 	w_buf[0] = FT_REG_RESET_FW;
 	ft5x06_i2c_write(client, w_buf, 1);
-	msleep(FT_STARTUP_DLY);
+	msleep(ts_data->pdata->soft_rst_dly);
+
+	dev_info(&client->dev, "Firmware upgrade successful\n");
 
 	return 0;
 }
@@ -828,7 +785,8 @@
 	struct ft5x06_ts_data *data = dev_get_drvdata(dev);
 	const struct firmware *fw = NULL;
 	int rc;
-	u8 val = 0;
+	u8 fw_file_maj, fw_file_min, fw_file_sub_min;
+	bool fw_upgrade = false;
 
 	rc = request_firmware(&fw, data->fw_name, dev);
 	if (rc < 0) {
@@ -843,35 +801,52 @@
 		goto rel_fw;
 	}
 
-	/* check firmware version */
-	rc = ft5x0x_read_reg(data->client, FT_REG_FW_VER, &val);
-	if (rc < 0) {
-		dev_err(dev, "Get firmware version failed\n");
-		goto rel_fw;
-	}
+	fw_file_maj = FT_FW_FILE_MAJ_VER(fw);
+	fw_file_min = FT_FW_FILE_MIN_VER(fw);
+	fw_file_sub_min = FT_FW_FILE_SUB_MIN_VER(fw);
 
-	if (val == FT_FW_FILE_VER(fw) && !force) {
-		dev_err(dev, "No need to update (0x%x)\n", val);
+	dev_info(dev, "Current firmware: %d.%d.%d", data->fw_ver[0],
+				data->fw_ver[1], data->fw_ver[2]);
+	dev_info(dev, "New firmware: %d.%d.%d", fw_file_maj,
+				fw_file_min, fw_file_sub_min);
+
+	if (force) {
+		fw_upgrade = true;
+	} else if (data->fw_ver[0] == fw_file_maj) {
+			if (data->fw_ver[1] < fw_file_min)
+				fw_upgrade = true;
+			else if (data->fw_ver[2] < fw_file_sub_min)
+				fw_upgrade = true;
+			else
+				dev_info(dev, "No need to upgrade\n");
+	} else
+		dev_info(dev, "Firmware versions do not match\n");
+
+	if (!fw_upgrade) {
+		dev_info(dev, "Exiting fw upgrade...\n");
 		rc = -EFAULT;
 		goto rel_fw;
 	}
 
-	dev_info(dev, "upgrade to fw ver 0x%x from 0x%x\n",
-					FT_FW_FILE_VER(fw), val);
-
 	/* start firmware upgrade */
 	if (FT_FW_CHECK(fw)) {
 		rc = ft5x06_fw_upgrade_start(data->client, fw->data, fw->size);
 		if (rc < 0)
-			dev_err(dev, "update failed (%d)\n", rc);
-		else
+			dev_err(dev, "update failed (%d). try later...\n", rc);
+		else if (data->pdata->info.auto_cal)
 			ft5x06_auto_cal(data->client);
 	} else {
 		dev_err(dev, "FW format error\n");
 		rc = -EIO;
 	}
 
-	FT_STORE_TS_INFO(data->ts_info, data->family_id, FT_FW_FILE_VER(fw));
+	ft5x06_update_fw_ver(data);
+
+	FT_STORE_TS_INFO(data->ts_info, data->family_id, data->pdata->name,
+			data->pdata->num_max_touches, data->pdata->group_id,
+			data->pdata->fw_vkey_support ? "yes" : "no",
+			data->pdata->fw_name, data->fw_ver[0],
+			data->fw_ver[1], data->fw_ver[2]);
 rel_fw:
 	release_firmware(fw);
 	return rc;
@@ -899,6 +874,11 @@
 	if (rc != 0)
 		return rc;
 
+	if (data->suspended) {
+		dev_info(dev, "In suspend state, try again later...\n");
+		return size;
+	}
+
 	mutex_lock(&data->input_dev->mutex);
 	if (!data->loading_fw  && val) {
 		data->loading_fw = true;
@@ -1153,6 +1133,13 @@
 	u32 temp_val, num_buttons;
 	u32 button_map[MAX_BUTTONS];
 
+	pdata->name = "focaltech";
+	rc = of_property_read_string(np, "focaltech,name", &pdata->name);
+	if (rc && (rc != -EINVAL)) {
+		dev_err(dev, "Unable to read name\n");
+		return rc;
+	}
+
 	rc = ft5x06_get_dt_coords(dev, "focaltech,panel-coords", pdata);
 	if (rc && (rc != -EINVAL))
 		return rc;
@@ -1177,6 +1164,89 @@
 	if (pdata->irq_gpio < 0)
 		return pdata->irq_gpio;
 
+	pdata->fw_name = "ft_fw.bin";
+	rc = of_property_read_string(np, "focaltech,fw-name", &pdata->fw_name);
+	if (rc && (rc != -EINVAL)) {
+		dev_err(dev, "Unable to read fw name\n");
+		return rc;
+	}
+
+	rc = of_property_read_u32(np, "focaltech,group-id", &temp_val);
+	if (!rc)
+		pdata->group_id = temp_val;
+	else
+		return rc;
+
+	rc = of_property_read_u32(np, "focaltech,hard-reset-delay-ms",
+							&temp_val);
+	if (!rc)
+		pdata->hard_rst_dly = temp_val;
+	else
+		return rc;
+
+	rc = of_property_read_u32(np, "focaltech,soft-reset-delay-ms",
+							&temp_val);
+	if (!rc)
+		pdata->soft_rst_dly = temp_val;
+	else
+		return rc;
+
+	rc = of_property_read_u32(np, "focaltech,num-max-touches", &temp_val);
+	if (!rc)
+		pdata->num_max_touches = temp_val;
+	else
+		return rc;
+
+	rc = of_property_read_u32(np, "focaltech,fw-delay-aa-ms", &temp_val);
+	if (rc && (rc != -EINVAL)) {
+		dev_err(dev, "Unable to read fw delay aa\n");
+		return rc;
+	} else if (rc != -EINVAL)
+		pdata->info.delay_aa =  temp_val;
+
+	rc = of_property_read_u32(np, "focaltech,fw-delay-55-ms", &temp_val);
+	if (rc && (rc != -EINVAL)) {
+		dev_err(dev, "Unable to read fw delay 55\n");
+		return rc;
+	} else if (rc != -EINVAL)
+		pdata->info.delay_55 =  temp_val;
+
+	rc = of_property_read_u32(np, "focaltech,fw-upgrade-id1", &temp_val);
+	if (rc && (rc != -EINVAL)) {
+		dev_err(dev, "Unable to read fw upgrade id1\n");
+		return rc;
+	} else if (rc != -EINVAL)
+		pdata->info.upgrade_id_1 =  temp_val;
+
+	rc = of_property_read_u32(np, "focaltech,fw-upgrade-id2", &temp_val);
+	if (rc && (rc != -EINVAL)) {
+		dev_err(dev, "Unable to read fw upgrade id2\n");
+		return rc;
+	} else if (rc != -EINVAL)
+		pdata->info.upgrade_id_2 =  temp_val;
+
+	rc = of_property_read_u32(np, "focaltech,fw-delay-readid-ms",
+							&temp_val);
+	if (rc && (rc != -EINVAL)) {
+		dev_err(dev, "Unable to read fw delay read id\n");
+		return rc;
+	} else if (rc != -EINVAL)
+		pdata->info.delay_readid =  temp_val;
+
+	rc = of_property_read_u32(np, "focaltech,fw-delay-era-flsh-ms",
+							&temp_val);
+	if (rc && (rc != -EINVAL)) {
+		dev_err(dev, "Unable to read fw delay erase flash\n");
+		return rc;
+	} else if (rc != -EINVAL)
+		pdata->info.delay_erase_flash =  temp_val;
+
+	pdata->info.auto_cal = of_property_read_bool(np,
+					"focaltech,fw-auto-cal");
+
+	pdata->fw_vkey_support = of_property_read_bool(np,
+						"focaltech,fw-vkey-support");
+
 	rc = of_property_read_u32(np, "focaltech,family-id", &temp_val);
 	if (!rc)
 		pdata->family_id = temp_val;
@@ -1217,7 +1287,7 @@
 	struct dentry *temp;
 	u8 reg_value;
 	u8 reg_addr;
-	int err;
+	int err, len;
 
 	if (client->dev.of_node) {
 		pdata = devm_kzalloc(&client->dev,
@@ -1228,8 +1298,10 @@
 		}
 
 		err = ft5x06_parse_dt(&client->dev, pdata);
-		if (err)
+		if (err) {
+			dev_err(&client->dev, "DT parsing failed\n");
 			return err;
+		}
 	} else
 		pdata = client->dev.platform_data;
 
@@ -1243,7 +1315,26 @@
 		return -ENODEV;
 	}
 
-	data = kzalloc(sizeof(struct ft5x06_ts_data), GFP_KERNEL);
+	data = devm_kzalloc(&client->dev,
+			sizeof(struct ft5x06_ts_data), GFP_KERNEL);
+	if (!data) {
+		dev_err(&client->dev, "Not enough memory\n");
+		return -ENOMEM;
+	}
+
+	if (pdata->fw_name) {
+		len = strlen(pdata->fw_name);
+		if (len > FT_FW_NAME_MAX_LEN - 1) {
+			dev_err(&client->dev, "Invalid firmware name\n");
+			return -EINVAL;
+		}
+
+		strlcpy(data->fw_name, pdata->fw_name, len + 1);
+	}
+
+	data->tch_data_len = FT_TCH_LEN(pdata->num_max_touches);
+	data->tch_data = devm_kzalloc(&client->dev,
+				data->tch_data_len, GFP_KERNEL);
 	if (!data) {
 		dev_err(&client->dev, "Not enough memory\n");
 		return -ENOMEM;
@@ -1251,9 +1342,8 @@
 
 	input_dev = input_allocate_device();
 	if (!input_dev) {
-		err = -ENOMEM;
 		dev_err(&client->dev, "failed to allocate input device\n");
-		goto free_mem;
+		return -ENOMEM;
 	}
 
 	data->input_dev = input_dev;
@@ -1272,12 +1362,12 @@
 	__set_bit(BTN_TOUCH, input_dev->keybit);
 	__set_bit(INPUT_PROP_DIRECT, input_dev->propbit);
 
-	input_mt_init_slots(input_dev, CFG_MAX_TOUCH_POINTS);
+	input_mt_init_slots(input_dev, pdata->num_max_touches);
 	input_set_abs_params(input_dev, ABS_MT_POSITION_X, pdata->x_min,
 			     pdata->x_max, 0, 0);
 	input_set_abs_params(input_dev, ABS_MT_POSITION_Y, pdata->y_min,
 			     pdata->y_max, 0, 0);
-	input_set_abs_params(input_dev, ABS_MT_TOUCH_MAJOR, 0, FT_PRESS, 0, 0);
+	input_set_abs_params(input_dev, ABS_MT_PRESSURE, 0, FT_PRESS, 0, 0);
 
 	err = input_register_device(input_dev);
 	if (err) {
@@ -1340,12 +1430,12 @@
 				"set_direction for reset gpio failed\n");
 			goto free_reset_gpio;
 		}
-		msleep(FT_RESET_DLY);
+		msleep(data->pdata->hard_rst_dly);
 		gpio_set_value_cansleep(data->pdata->reset_gpio, 1);
 	}
 
 	/* make sure CTP already finish startup process */
-	msleep(FT_STARTUP_DLY);
+	msleep(data->pdata->soft_rst_dly);
 
 	/* check the controller id */
 	reg_addr = FT_REG_ID;
@@ -1429,7 +1519,8 @@
 		goto free_debug_dir;
 	}
 
-	data->ts_info = kzalloc(FT_INFO_MAX_LEN, GFP_KERNEL);
+	data->ts_info = devm_kzalloc(&client->dev,
+				FT_INFO_MAX_LEN, GFP_KERNEL);
 	if (!data->ts_info) {
 		dev_err(&client->dev, "Not enough memory\n");
 		goto free_debug_dir;
@@ -1450,14 +1541,13 @@
 
 	dev_dbg(&client->dev, "touch threshold = %d\n", reg_value * 4);
 
-	reg_addr = FT_REG_FW_VER;
-	err = ft5x06_i2c_read(client, &reg_addr, 1, &reg_value, 1);
-	if (err < 0)
-		dev_err(&client->dev, "version read failed");
+	ft5x06_update_fw_ver(data);
 
-	dev_info(&client->dev, "Firmware version = 0x%x\n", reg_value);
-
-	FT_STORE_TS_INFO(data->ts_info, data->family_id, reg_value);
+	FT_STORE_TS_INFO(data->ts_info, data->family_id, data->pdata->name,
+			data->pdata->num_max_touches, data->pdata->group_id,
+			data->pdata->fw_vkey_support ? "yes" : "no",
+			data->pdata->fw_name, data->fw_ver[0],
+			data->fw_ver[1], data->fw_ver[2]);
 
 #if defined(CONFIG_FB)
 	data->fb_notif.notifier_call = fb_notifier_callback;
@@ -1508,8 +1598,6 @@
 	input_dev = NULL;
 free_inputdev:
 	input_free_device(input_dev);
-free_mem:
-	kfree(data);
 	return err;
 }
 
@@ -1547,8 +1635,6 @@
 		ft5x06_power_init(data, false);
 
 	input_unregister_device(data->input_dev);
-	kfree(data->ts_info);
-	kfree(data);
 
 	return 0;
 }
diff --git a/drivers/input/touchscreen/gt9xx/Kconfig b/drivers/input/touchscreen/gt9xx/Kconfig
new file mode 100644
index 0000000..9d36403
--- /dev/null
+++ b/drivers/input/touchscreen/gt9xx/Kconfig
@@ -0,0 +1,51 @@
+#
+# Goodix GT9xx Touchscreen driver
+#
+
+config GT9XX_TOUCHPANEL_DRIVER
+	tristate "Goodix GT9xx touchpanel driver"
+	depends on TOUCHSCREEN_GT9XX
+	default n
+	help
+	  This is the main file for touchpanel driver for Goodix GT9xx
+	  touchscreens.
+
+	  Say Y here if you have a Goodix GT9xx touchscreen connected
+	  to your system.
+
+	  If unsure, say N.
+
+	  To compile this driver as a module, choose M here: the
+	  module will be called gt9xx_update.
+
+config GT9XX_TOUCHPANEL_UPDATE
+	tristate "Goodix GT9xx touchpanel auto update support"
+	depends on GT9XX_TOUCHPANEL_DRIVER
+	default n
+	help
+	  This enables support for firmware update for Goodix GT9xx
+	  touchscreens.
+
+	  Say Y here if you have a Goodix GT9xx touchscreen connected
+	  to your system.
+
+	  If unsure, say N.
+
+	  To compile this driver as a module, choose M here: the
+	  module will be called gt9xx_update.
+
+config GT9XX_TOUCHPANEL_DEBUG
+	tristate "Goodix GT9xx Tools for debuging"
+	depends on GT9XX_TOUCHPANEL_DRIVER
+	default n
+	help
+	  This is application debug interface support for Goodix GT9xx
+	  touchscreens.
+
+	  Say Y here if you want to have a Android app debug interface
+	  to your system.
+
+	  If unsure, say N.
+
+	  To compile this driver as a module, choose M here: the
+	  module will be called gt9xx_update.
diff --git a/drivers/input/touchscreen/gt9xx/Makefile b/drivers/input/touchscreen/gt9xx/Makefile
new file mode 100644
index 0000000..482d869
--- /dev/null
+++ b/drivers/input/touchscreen/gt9xx/Makefile
@@ -0,0 +1,8 @@
+#gt915 touchpanel driver
+
+
+obj-$(CONFIG_GT9XX_TOUCHPANEL_DRIVER)	+= gt9xx.o
+#gt915 update file
+obj-$(CONFIG_GT9XX_TOUCHPANEL_UPDATE)	+= gt9xx_update.o
+#debug tool
+obj-$(CONFIG_GT9XX_TOUCHPANEL_DEBUG)	+= goodix_tool.o
diff --git a/drivers/input/touchscreen/gt9xx/goodix_tool.c b/drivers/input/touchscreen/gt9xx/goodix_tool.c
new file mode 100644
index 0000000..bdac3fd
--- /dev/null
+++ b/drivers/input/touchscreen/gt9xx/goodix_tool.c
@@ -0,0 +1,549 @@
+/* drivers/input/touchscreen/goodix_tool.c
+ *
+ * 2010 - 2012 Goodix Technology.
+ * Copyright (c) 2013, The Linux Foundation. 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 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 a reference
+ * to you, when you are integrating the GOODiX's CTP IC into your system,
+ * 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.
+ *
+ * Version:1.6
+ *        V1.0:2012/05/01,create file.
+ *        V1.2:2012/06/08,modify some warning.
+ *        V1.4:2012/08/28,modified to support GT9XX
+ *        V1.6:new proc name
+ */
+
+#include "gt9xx.h"
+
+#define DATA_LENGTH_UINT    512
+#define CMD_HEAD_LENGTH     (sizeof(st_cmd_head) - sizeof(u8 *))
+static char procname[20] = {0};
+
+#define UPDATE_FUNCTIONS
+
+#pragma pack(1)
+struct {
+	u8  wr;		/* write read flag£¬0:R  1:W  2:PID 3: */
+	u8  flag;	/* 0:no need flag/int 1: need flag  2:need int */
+	u8 flag_addr[2];/* flag address */
+	u8  flag_val;	/* flag val */
+	u8  flag_relation; /* flag_val:flag 0:not equal 1:equal 2:> 3:< */
+	u16 circle;	/* polling cycle */
+	u8  times;	/* plling times */
+	u8  retry;	/* I2C retry times */
+	u16 delay;	/* delay befor read or after write */
+	u16 data_len;	/* data length */
+	u8  addr_len;	/* address length */
+	u8  addr[2];	/* address */
+	u8  res[3];	/* reserved */
+	u8  *data;	/* data pointer */
+} st_cmd_head;
+#pragma pack()
+st_cmd_head cmd_head;
+
+static struct i2c_client *gt_client;
+
+static struct proc_dir_entry *goodix_proc_entry;
+
+static s32 goodix_tool_write(struct file *filp, const char __user *buff,
+						unsigned long len, void *data);
+static s32 goodix_tool_read(char *page, char **start, off_t off, int count,
+							int *eof, void *data);
+static s32 (*tool_i2c_read)(u8 *, u16);
+static s32 (*tool_i2c_write)(u8 *, u16);
+
+s32 DATA_LENGTH;
+s8 IC_TYPE[16] = {0};
+
+static void tool_set_proc_name(char *procname)
+{
+	char *months[12] = {"Jan", "Feb", "Mar", "Apr", "May",
+	"Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"};
+	char date[20] = {0};
+	char month[4] = {0};
+	int i = 0, n_month = 1, n_day = 0, n_year = 0;
+	snprintf(date, 20, "%s", __DATE__);
+
+	/* GTP_DEBUG("compile date: %s", date); */
+
+	sscanf(date, "%s %d %d", month, &n_day, &n_year);
+
+	for (i = 0; i < 12; ++i) {
+		if (!memcmp(months[i], month, 3)) {
+			n_month = i+1;
+			break;
+		}
+	}
+
+	snprintf(procname, 20, "gmnode%04d%02d%02d", n_year, n_month, n_day);
+	/* GTP_DEBUG("procname = %s", procname); */
+}
+
+static s32 tool_i2c_read_no_extra(u8 *buf, u16 len)
+{
+	s32 ret = -1;
+	s32 i = 0;
+	struct i2c_msg msgs[2];
+
+	msgs[0].flags = !I2C_M_RD;
+	msgs[0].addr  = gt_client->addr;
+	msgs[0].len   = cmd_head.addr_len;
+	msgs[0].buf   = &buf[0];
+
+	msgs[1].flags = I2C_M_RD;
+	msgs[1].addr  = gt_client->addr;
+	msgs[1].len   = len;
+	msgs[1].buf   = &buf[GTP_ADDR_LENGTH];
+
+	for (i = 0; i < cmd_head.retry; i++) {
+		ret = i2c_transfer(gt_client->adapter, msgs, 2);
+		if (ret > 0)
+			break;
+	}
+
+	return ret;
+}
+
+static s32 tool_i2c_write_no_extra(u8 *buf, u16 len)
+{
+	s32 ret = -1;
+	s32 i = 0;
+	struct i2c_msg msg;
+
+	msg.flags = !I2C_M_RD;
+	msg.addr  = gt_client->addr;
+	msg.len   = len;
+	msg.buf   = buf;
+
+	for (i = 0; i < cmd_head.retry; i++) {
+		ret = i2c_transfer(gt_client->adapter, &msg, 1);
+		if (ret > 0)
+			break;
+		}
+
+	return ret;
+}
+
+static s32 tool_i2c_read_with_extra(u8 *buf, u16 len)
+{
+	s32 ret = -1;
+	u8 pre[2] = {0x0f, 0xff};
+	u8 end[2] = {0x80, 0x00};
+
+	tool_i2c_write_no_extra(pre, 2);
+	ret = tool_i2c_read_no_extra(buf, len);
+	tool_i2c_write_no_extra(end, 2);
+
+	return ret;
+}
+
+static s32 tool_i2c_write_with_extra(u8 *buf, u16 len)
+{
+	s32 ret = -1;
+	u8 pre[2] = {0x0f, 0xff};
+	u8 end[2] = {0x80, 0x00};
+
+	tool_i2c_write_no_extra(pre, 2);
+	ret = tool_i2c_write_no_extra(buf, len);
+	tool_i2c_write_no_extra(end, 2);
+
+	return ret;
+}
+
+static void register_i2c_func(void)
+{
+	/* if (!strncmp(IC_TYPE, "GT818", 5) || !strncmp(IC_TYPE, "GT816", 5)
+	|| !strncmp(IC_TYPE, "GT811", 5) || !strncmp(IC_TYPE, "GT818F", 6)
+	|| !strncmp(IC_TYPE, "GT827", 5) || !strncmp(IC_TYPE,"GT828", 5)
+	|| !strncmp(IC_TYPE, "GT813", 5)) */
+
+	if (strncmp(IC_TYPE, "GT8110", 6) && strncmp(IC_TYPE, "GT8105", 6)
+	&& strncmp(IC_TYPE, "GT801", 5) && strncmp(IC_TYPE, "GT800", 5)
+	&& strncmp(IC_TYPE, "GT801PLUS", 9) && strncmp(IC_TYPE, "GT811", 5)
+	&& strncmp(IC_TYPE, "GTxxx", 5)) {
+		tool_i2c_read = tool_i2c_read_with_extra;
+		tool_i2c_write = tool_i2c_write_with_extra;
+		GTP_DEBUG("I2C function: with pre and end cmd!");
+	} else {
+		tool_i2c_read = tool_i2c_read_no_extra;
+		tool_i2c_write = tool_i2c_write_no_extra;
+		GTP_INFO("I2C function: without pre and end cmd!");
+	}
+}
+
+static void unregister_i2c_func(void)
+{
+	tool_i2c_read = NULL;
+	tool_i2c_write = NULL;
+	GTP_INFO("I2C function: unregister i2c transfer function!");
+}
+
+s32 init_wr_node(struct i2c_client *client)
+{
+	s32 i;
+
+	gt_client = client;
+	memset(&cmd_head, 0, sizeof(cmd_head));
+	cmd_head.data = NULL;
+
+	i = 5;
+	while ((!cmd_head.data) && i) {
+		cmd_head.data = kzalloc(i * DATA_LENGTH_UINT, GFP_KERNEL);
+		if (NULL != cmd_head.data)
+			break;
+		i--;
+	}
+	if (i) {
+		DATA_LENGTH = i * DATA_LENGTH_UINT + GTP_ADDR_LENGTH;
+		GTP_INFO("Applied memory size:%d.", DATA_LENGTH);
+	} else {
+		GTP_ERROR("Apply for memory failed.");
+		return FAIL;
+	}
+
+	cmd_head.addr_len = 2;
+	cmd_head.retry = 5;
+
+	register_i2c_func();
+
+	tool_set_proc_name(procname);
+	goodix_proc_entry = create_proc_entry(procname, 0666, NULL);
+	if (goodix_proc_entry == NULL) {
+		GTP_ERROR("Couldn't create proc entry!");
+		return FAIL;
+	} else {
+		GTP_INFO("Create proc entry success!");
+		goodix_proc_entry->write_proc = goodix_tool_write;
+		dix_proc_entry->read_proc = goodix_tool_read;
+	}
+
+	return SUCCESS;
+}
+
+void uninit_wr_node(void)
+{
+	kfree(cmd_head.data);
+	cmd_head.data = NULL;
+	unregister_i2c_func();
+	remove_proc_entry(procname, NULL);
+}
+
+static u8 relation(u8 src, u8 dst, u8 rlt)
+{
+	u8 ret = 0;
+
+	switch (rlt) {
+
+	case 0:
+		ret = (src != dst) ? true : false;
+		break;
+
+	case 1:
+		ret = (src == dst) ? true : false;
+		GTP_DEBUG("equal:src:0x%02x   dst:0x%02x  ret:%d.",
+					src, dst, (s32)ret);
+		break;
+
+	case 2:
+		ret = (src > dst) ? true : false;
+		break;
+
+	case 3:
+		ret = (src < dst) ? true : false;
+		break;
+
+	case 4:
+		ret = (src & dst) ? true : false;
+		break;
+
+	case 5:
+		ret = (!(src | dst)) ? true : false;
+		break;
+
+	default:
+		ret = false;
+		break;
+	}
+
+	return ret;
+}
+
+/*******************************************************
+Function:
+    Comfirm function.
+Input:
+  None.
+Output:
+    Return write length.
+********************************************************/
+static u8 comfirm(void)
+{
+	s32 i = 0;
+	u8 buf[32];
+
+/*    memcpy(&buf[GTP_ADDR_LENGTH - cmd_head.addr_len],
+			&cmd_head.flag_addr, cmd_head.addr_len);
+    memcpy(buf, &cmd_head.flag_addr, cmd_head.addr_len);
+		//Modified by Scott, 2012-02-17 */
+	memcpy(buf, cmd_head.flag_addr, cmd_head.addr_len);
+
+	for (i = 0; i < cmd_head.times; i++) {
+		if (tool_i2c_read(buf, 1) <= 0) {
+			GTP_ERROR("Read flag data failed!");
+			return FAIL;
+		}
+		if (true == relation(buf[GTP_ADDR_LENGTH], cmd_head.flag_val,
+						cmd_head.flag_relation)) {
+			GTP_DEBUG("value at flag addr:0x%02x.",
+						buf[GTP_ADDR_LENGTH]);
+			GTP_DEBUG("flag value:0x%02x.", cmd_head.flag_val);
+			break;
+		}
+
+		msleep(cmd_head.circle);
+	}
+
+	if (i >= cmd_head.times) {
+		GTP_ERROR("Didn't get the flag to continue!");
+		return FAIL;
+	}
+
+	return SUCCESS;
+}
+
+/********************************************************
+Function:
+    Goodix tool write function.
+nput:
+  standard proc write function param.
+Output:
+    Return write length.
+********************************************************/
+static s32 goodix_tool_write(struct file *filp, const char __user *buff,
+						unsigned long len, void *data)
+{
+	s32 ret = 0;
+	GTP_DEBUG_FUNC();
+	GTP_DEBUG_ARRAY((u8 *)buff, len);
+
+	ret = copy_from_user(&cmd_head, buff, CMD_HEAD_LENGTH);
+	if (ret)
+		GTP_ERROR("copy_from_user failed.");
+
+	GTP_DEBUG("wr  :0x%02x.", cmd_head.wr);
+	GTP_DEBUG("flag:0x%02x.", cmd_head.flag);
+	GTP_DEBUG("flag addr:0x%02x%02x.", cmd_head.flag_addr[0],
+						cmd_head.flag_addr[1]);
+	GTP_DEBUG("flag val:0x%02x.", cmd_head.flag_val);
+	GTP_DEBUG("flag rel:0x%02x.", cmd_head.flag_relation);
+	GTP_DEBUG("circle  :%d.", (s32)cmd_head.circle);
+	GTP_DEBUG("times   :%d.", (s32)cmd_head.times);
+	GTP_DEBUG("retry   :%d.", (s32)cmd_head.retry);
+	GTP_DEBUG("delay   :%d.", (s32)cmd_head.delay);
+	GTP_DEBUG("data len:%d.", (s32)cmd_head.data_len);
+	GTP_DEBUG("addr len:%d.", (s32)cmd_head.addr_len);
+	GTP_DEBUG("addr:0x%02x%02x.", cmd_head.addr[0], cmd_head.addr[1]);
+	GTP_DEBUG("len:%d.", (s32)len);
+	GTP_DEBUG("buf[20]:0x%02x.", buff[CMD_HEAD_LENGTH]);
+
+	if (cmd_head.wr == 1) {
+		/*  copy_from_user(&cmd_head.data[cmd_head.addr_len],
+				&buff[CMD_HEAD_LENGTH], cmd_head.data_len); */
+		ret = copy_from_user(&cmd_head.data[GTP_ADDR_LENGTH],
+				&buff[CMD_HEAD_LENGTH], cmd_head.data_len);
+		if (ret)
+			GTP_ERROR("copy_from_user failed.");
+
+		memcpy(&cmd_head.data[GTP_ADDR_LENGTH - cmd_head.addr_len],
+					cmd_head.addr, cmd_head.addr_len);
+
+		GTP_DEBUG_ARRAY(cmd_head.data,
+				cmd_head.data_len + cmd_head.addr_len);
+		GTP_DEBUG_ARRAY((u8 *)&buff[CMD_HEAD_LENGTH],
+							cmd_head.data_len);
+
+		if (cmd_head.flag == 1) {
+			if (FAIL == comfirm()) {
+				GTP_ERROR("[WRITE]Comfirm fail!");
+				return FAIL;
+			}
+		} else if (cmd_head.flag == 2) {
+			/* Need interrupt! */
+		}
+		if (tool_i2c_write(
+		&cmd_head.data[GTP_ADDR_LENGTH - cmd_head.addr_len],
+		cmd_head.data_len + cmd_head.addr_len) <= 0) {
+			GTP_ERROR("[WRITE]Write data failed!");
+			return FAIL;
+		}
+
+		GTP_DEBUG_ARRAY(
+			&cmd_head.data[GTP_ADDR_LENGTH - cmd_head.addr_len],
+			cmd_head.data_len + cmd_head.addr_len);
+		if (cmd_head.delay)
+			msleep(cmd_head.delay);
+
+		return cmd_head.data_len + CMD_HEAD_LENGTH;
+	} else if (cmd_head.wr == 3) {  /* Write ic type */
+
+		ret = copy_from_user(&cmd_head.data[0], &buff[CMD_HEAD_LENGTH],
+				cmd_head.data_len);
+		if (ret)
+			GTP_ERROR("copy_from_user failed.");
+
+		memcpy(IC_TYPE, cmd_head.data, cmd_head.data_len);
+
+		register_i2c_func();
+
+		return cmd_head.data_len + CMD_HEAD_LENGTH;
+	} else if (cmd_head.wr == 3) {
+
+		/* memcpy(IC_TYPE, cmd_head.data, cmd_head.data_len); */
+
+		return cmd_head.data_len + CMD_HEAD_LENGTH;
+	} else if (cmd_head.wr == 7) { /* disable irq! */
+		gtp_irq_disable(i2c_get_clientdata(gt_client));
+
+		#if GTP_ESD_PROTECT
+		gtp_esd_switch(gt_client, SWITCH_OFF);
+		#endif
+		return CMD_HEAD_LENGTH;
+	} else if (cmd_head.wr == 9) { /* enable irq! */
+		gtp_irq_enable(i2c_get_clientdata(gt_client));
+
+		#if GTP_ESD_PROTECT
+		gtp_esd_switch(gt_client, SWITCH_ON);
+		#endif
+		return CMD_HEAD_LENGTH;
+	} else if (cmd_head.wr == 17) {
+		struct goodix_ts_data *ts = i2c_get_clientdata(gt_client);
+		ret = copy_from_user(&cmd_head.data[GTP_ADDR_LENGTH],
+				&buff[CMD_HEAD_LENGTH], cmd_head.data_len);
+		if (ret)
+			GTP_DEBUG("copy_from_user failed.");
+		if (cmd_head.data[GTP_ADDR_LENGTH]) {
+			GTP_DEBUG("gtp enter rawdiff.");
+			ts->gtp_rawdiff_mode = true;
+		} else {
+			ts->gtp_rawdiff_mode = false;
+			GTP_DEBUG("gtp leave rawdiff.");
+		}
+		return CMD_HEAD_LENGTH;
+	}
+#ifdef UPDATE_FUNCTIONS
+	else if (cmd_head.wr == 11) { /* Enter update mode! */
+		if (FAIL == gup_enter_update_mode(gt_client))
+			return FAIL;
+	} else if (cmd_head.wr == 13) { /* Leave update mode! */
+		gup_leave_update_mode();
+	} else if (cmd_head.wr == 15) { /* Update firmware! */
+		show_len = 0;
+		total_len = 0;
+		memset(cmd_head.data, 0, cmd_head.data_len + 1);
+		memcpy(cmd_head.data, &buff[CMD_HEAD_LENGTH],
+					cmd_head.data_len);
+
+		if (FAIL == gup_update_proc((void *)cmd_head.data))
+			return FAIL;
+	}
+#endif
+
+	return CMD_HEAD_LENGTH;
+}
+
+/*******************************************************
+Function:
+    Goodix tool read function.
+Input:
+  standard proc read function param.
+Output:
+    Return read length.
+********************************************************/
+static s32 goodix_tool_read(char *page, char **start, off_t off, int count,
+							int *eof, void *data)
+{
+	GTP_DEBUG_FUNC();
+
+	if (cmd_head.wr % 2) {
+		return FAIL;
+	} else if (!cmd_head.wr) {
+		u16 len = 0;
+		s16 data_len = 0;
+		u16 loc = 0;
+
+		if (cmd_head.flag == 1) {
+			if (FAIL == comfirm()) {
+				GTP_ERROR("[READ]Comfirm fail!");
+				return FAIL;
+			}
+		} else if (cmd_head.flag == 2) {
+			/* Need interrupt! */
+		}
+
+		memcpy(cmd_head.data, cmd_head.addr, cmd_head.addr_len);
+
+		GTP_DEBUG("[CMD HEAD DATA] ADDR:0x%02x%02x.", cmd_head.data[0],
+							cmd_head.data[1]);
+		GTP_DEBUG("[CMD HEAD ADDR] ADDR:0x%02x%02x.", cmd_head.addr[0],
+							cmd_head.addr[1]);
+
+		if (cmd_head.delay)
+			msleep(cmd_head.delay);
+
+		data_len = cmd_head.data_len;
+		while (data_len > 0) {
+			if (data_len > DATA_LENGTH)
+				len = DATA_LENGTH;
+			else
+				len = data_len;
+
+			data_len -= DATA_LENGTH;
+
+			if (tool_i2c_read(cmd_head.data, len) <= 0) {
+				GTP_ERROR("[READ]Read data failed!");
+				return FAIL;
+			}
+			memcpy(&page[loc], &cmd_head.data[GTP_ADDR_LENGTH],
+									len);
+			loc += len;
+
+			GTP_DEBUG_ARRAY(&cmd_head.data[GTP_ADDR_LENGTH], len);
+			GTP_DEBUG_ARRAY(page, len);
+		}
+	} else if (cmd_head.wr == 2) {
+		/* memcpy(page, "gt8", cmd_head.data_len);
+		memcpy(page, "GT818", 5);
+		page[5] = 0; */
+
+		GTP_DEBUG("Return ic type:%s len:%d.", page,
+						(s32)cmd_head.data_len);
+		return cmd_head.data_len;
+		/* return sizeof(IC_TYPE_NAME); */
+	} else if (cmd_head.wr == 4) {
+		page[0] = show_len >> 8;
+		page[1] = show_len & 0xff;
+		page[2] = total_len >> 8;
+		page[3] = total_len & 0xff;
+
+		return cmd_head.data_len;
+	} else if (6 == cmd_head.wr) {
+		/* Read error code! */
+	} else if (8 == cmd_head.wr) { /*Read driver version */
+		/* memcpy(page, GTP_DRIVER_VERSION,
+				strlen(GTP_DRIVER_VERSION)); */
+		s32 tmp_len;
+		tmp_len = strlen(GTP_DRIVER_VERSION);
+		memcpy(page, GTP_DRIVER_VERSION, tmp_len);
+		page[tmp_len] = 0;
+	}
+
+	return cmd_head.data_len;
+}
diff --git a/drivers/input/touchscreen/gt9xx/gt9xx.c b/drivers/input/touchscreen/gt9xx/gt9xx.c
new file mode 100644
index 0000000..33ef141
--- /dev/null
+++ b/drivers/input/touchscreen/gt9xx/gt9xx.c
@@ -0,0 +1,2220 @@
+/* drivers/input/touchscreen/gt9xx.c
+ *
+ * Copyright (c) 2013, The Linux Foundation. All rights reserved.
+ *
+ * Linux Foundation chooses to take subject only to the GPLv2 license
+ * terms, and distributes only under these terms.
+ *
+ * 2010 - 2013 Goodix Technology.
+ *
+ * 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 a reference
+ * to you, when you are integrating the GOODiX's CTP IC into your system,
+ * 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.
+ *
+ * Version: 1.8
+ * Authors: andrew@goodix.com, meta@goodix.com
+ * Release Date: 2013/04/25
+ * Revision record:
+ *      V1.0:
+ *          first Release. By Andrew, 2012/08/31
+ *      V1.2:
+ *          modify gtp_reset_guitar,slot report,tracking_id & 0x0F.
+ *                  By Andrew, 2012/10/15
+ *      V1.4:
+ *          modify gt9xx_update.c. By Andrew, 2012/12/12
+ *      V1.6:
+ *          1. new heartbeat/esd_protect mechanism(add external watchdog)
+ *          2. doze mode, sliding wakeup
+ *          3. 3 more cfg_group(GT9 Sensor_ID: 0~5)
+ *          3. config length verification
+ *          4. names & comments
+ *                  By Meta, 2013/03/11
+ *      V1.8:
+ *          1. pen/stylus identification
+ *          2. read double check & fixed config support
+ *          2. new esd & slide wakeup optimization
+ *                  By Meta, 2013/06/08
+ */
+
+#include <linux/regulator/consumer.h>
+#include "gt9xx.h"
+
+#include <linux/of_gpio.h>
+
+#include <linux/input/mt.h>
+
+#define GOODIX_DEV_NAME	"Goodix-CTP"
+#define CFG_MAX_TOUCH_POINTS	5
+#define GOODIX_COORDS_ARR_SIZE	4
+#define MAX_BUTTONS		4
+
+/* HIGH: 0x28/0x29, LOW: 0xBA/0xBB */
+#define GTP_I2C_ADDRESS_HIGH	0x14
+#define GTP_I2C_ADDRESS_LOW	0x5D
+#define CFG_GROUP_LEN(p_cfg_grp)  (sizeof(p_cfg_grp) / sizeof(p_cfg_grp[0]))
+
+#define GOODIX_VTG_MIN_UV	2600000
+#define GOODIX_VTG_MAX_UV	3300000
+#define GOODIX_I2C_VTG_MIN_UV	1800000
+#define GOODIX_I2C_VTG_MAX_UV	1800000
+#define GOODIX_VDD_LOAD_MIN_UA	0
+#define GOODIX_VDD_LOAD_MAX_UA	10000
+#define GOODIX_VIO_LOAD_MIN_UA	0
+#define GOODIX_VIO_LOAD_MAX_UA	10000
+
+#define RESET_DELAY_T3_US	200	/* T3: > 100us */
+#define RESET_DELAY_T4		20	/* T4: > 5ms */
+
+#define	PHY_BUF_SIZE		32
+
+#define GTP_MAX_TOUCH		5
+#define GTP_ESD_CHECK_CIRCLE_MS	2000
+
+#if GTP_HAVE_TOUCH_KEY
+static const u16 touch_key_array[] = {KEY_MENU, KEY_HOMEPAGE, KEY_BACK};
+#define GTP_MAX_KEY_NUM  (sizeof(touch_key_array)/sizeof(touch_key_array[0]))
+
+#if GTP_DEBUG_ON
+static const int  key_codes[] = {
+	KEY_HOME, KEY_BACK, KEY_MENU, KEY_SEARCH
+};
+static const char *const key_names[] = {
+	"Key_Home", "Key_Back", "Key_Menu", "Key_Search"
+};
+#endif
+#endif
+
+static void gtp_reset_guitar(struct goodix_ts_data *ts, int ms);
+static void gtp_int_sync(struct goodix_ts_data *ts, int ms);
+static int gtp_i2c_test(struct i2c_client *client);
+
+#if defined(CONFIG_FB)
+static int fb_notifier_callback(struct notifier_block *self,
+				 unsigned long event, void *data);
+#elif defined(CONFIG_HAS_EARLYSUSPEND)
+static void goodix_ts_early_suspend(struct early_suspend *h);
+static void goodix_ts_late_resume(struct early_suspend *h);
+#endif
+
+#if GTP_ESD_PROTECT
+static struct delayed_work gtp_esd_check_work;
+static struct workqueue_struct *gtp_esd_check_workqueue;
+static void gtp_esd_check_func(struct work_struct *work);
+static int gtp_init_ext_watchdog(struct i2c_client *client);
+struct i2c_client  *i2c_connect_client;
+#endif
+
+#if GTP_SLIDE_WAKEUP
+enum doze_status {
+	DOZE_DISABLED = 0,
+	DOZE_ENABLED = 1,
+	DOZE_WAKEUP = 2,
+};
+static enum doze_status = DOZE_DISABLED;
+static s8 gtp_enter_doze(struct goodix_ts_data *ts);
+#endif
+bool init_done;
+static u8 chip_gt9xxs;  /* true if ic is gt9xxs, like gt915s */
+u8 grp_cfg_version;
+
+/*******************************************************
+Function:
+	Read data from the i2c slave device.
+Input:
+	client:     i2c device.
+	buf[0~1]:   read start address.
+	buf[2~len-1]:   read data buffer.
+	len:    GTP_ADDR_LENGTH + read bytes count
+Output:
+	numbers of i2c_msgs to transfer:
+		2: succeed, otherwise: failed
+*********************************************************/
+int gtp_i2c_read(struct i2c_client *client, u8 *buf, int len)
+{
+	struct goodix_ts_data *ts = i2c_get_clientdata(client);
+	struct i2c_msg msgs[2];
+	int ret = -EIO;
+	int retries = 0;
+
+	GTP_DEBUG_FUNC();
+
+	msgs[0].flags = !I2C_M_RD;
+	msgs[0].addr = client->addr;
+	msgs[0].len = GTP_ADDR_LENGTH;
+	msgs[0].buf = &buf[0];
+
+	msgs[1].flags = I2C_M_RD;
+	msgs[1].addr = client->addr;
+	msgs[1].len = len - GTP_ADDR_LENGTH;
+	msgs[1].buf = &buf[GTP_ADDR_LENGTH];
+
+	while (retries < 5) {
+		ret = i2c_transfer(client->adapter, msgs, 2);
+		if (ret == 2)
+			break;
+		retries++;
+	}
+	if (retries >= 5) {
+#if GTP_SLIDE_WAKEUP
+		/* reset chip would quit doze mode */
+		if (DOZE_ENABLED == doze_status)
+			return ret;
+#endif
+		GTP_DEBUG("I2C communication timeout, resetting chip...");
+		if (init_done)
+			gtp_reset_guitar(ts, 10);
+		else
+			dev_warn(&client->dev,
+				"<GTP> gtp_reset_guitar exit init_done=%d:\n",
+				init_done);
+	}
+	return ret;
+}
+
+/*******************************************************
+Function:
+	Write data to the i2c slave device.
+Input:
+	client:     i2c device.
+	buf[0~1]:   write start address.
+	buf[2~len-1]:   data buffer
+	len:    GTP_ADDR_LENGTH + write bytes count
+Output:
+	numbers of i2c_msgs to transfer:
+	1: succeed, otherwise: failed
+*********************************************************/
+int gtp_i2c_write(struct i2c_client *client, u8 *buf, int len)
+{
+	struct goodix_ts_data *ts = i2c_get_clientdata(client);
+	struct i2c_msg msg;
+	int ret = -EIO;
+	int retries = 0;
+
+	GTP_DEBUG_FUNC();
+
+	msg.flags = !I2C_M_RD;
+	msg.addr = client->addr;
+	msg.len = len;
+	msg.buf = buf;
+
+	while (retries < 5) {
+		ret = i2c_transfer(client->adapter, &msg, 1);
+		if (ret == 1)
+			break;
+		retries++;
+	}
+	if ((retries >= 5)) {
+#if GTP_SLIDE_WAKEUP
+		if (DOZE_ENABLED == doze_status)
+			return ret;
+#endif
+		GTP_DEBUG("I2C communication timeout, resetting chip...");
+		if (init_done)
+			gtp_reset_guitar(ts, 10);
+		else
+			dev_warn(&client->dev,
+				"<GTP> gtp_reset_guitar exit init_done=%d:\n",
+				init_done);
+	}
+	return ret;
+}
+/*******************************************************
+Function:
+	i2c read twice, compare the results
+Input:
+	client:  i2c device
+	addr:    operate address
+	rxbuf:   read data to store, if compare successful
+	len:     bytes to read
+Output:
+	FAIL:    read failed
+	SUCCESS: read successful
+*********************************************************/
+int gtp_i2c_read_dbl_check(struct i2c_client *client,
+			u16 addr, u8 *rxbuf, int len)
+{
+	u8 buf[16] = {0};
+	u8 confirm_buf[16] = {0};
+	u8 retry = 0;
+
+	while (retry++ < 3) {
+		memset(buf, 0xAA, 16);
+		buf[0] = (u8)(addr >> 8);
+		buf[1] = (u8)(addr & 0xFF);
+		gtp_i2c_read(client, buf, len + 2);
+
+		memset(confirm_buf, 0xAB, 16);
+		confirm_buf[0] = (u8)(addr >> 8);
+		confirm_buf[1] = (u8)(addr & 0xFF);
+		gtp_i2c_read(client, confirm_buf, len + 2);
+
+		if (!memcmp(buf, confirm_buf, len + 2))
+			break;
+	}
+	if (retry < 3) {
+		memcpy(rxbuf, confirm_buf + 2, len);
+		return SUCCESS;
+	} else {
+		dev_err(&client->dev,
+			"i2c read 0x%04X, %d bytes, double check failed!",
+			addr, len);
+		return FAIL;
+	}
+}
+
+/*******************************************************
+Function:
+	Send config data.
+Input:
+	client: i2c device.
+Output:
+	result of i2c write operation.
+	> 0: succeed, otherwise: failed
+*********************************************************/
+static int gtp_send_cfg(struct goodix_ts_data *ts)
+{
+	int ret;
+#if GTP_DRIVER_SEND_CFG
+	int retry = 0;
+
+	if (ts->fixed_cfg) {
+		dev_dbg(&ts->client->dev,
+			"Ic fixed config, no config sent!");
+		ret = 2;
+	} else {
+		for (retry = 0; retry < 5; retry++) {
+			ret = gtp_i2c_write(ts->client,
+				ts->config_data,
+				GTP_CONFIG_MAX_LENGTH + GTP_ADDR_LENGTH);
+			if (ret > 0)
+				break;
+		}
+	}
+#endif
+
+	return ret;
+}
+
+/*******************************************************
+Function:
+	Disable irq function
+Input:
+	ts: goodix i2c_client private data
+Output:
+	None.
+*********************************************************/
+void gtp_irq_disable(struct goodix_ts_data *ts)
+{
+	unsigned long irqflags;
+
+	GTP_DEBUG_FUNC();
+
+	spin_lock_irqsave(&ts->irq_lock, irqflags);
+	if (!ts->irq_is_disabled) {
+		ts->irq_is_disabled = true;
+		disable_irq_nosync(ts->client->irq);
+	}
+	spin_unlock_irqrestore(&ts->irq_lock, irqflags);
+}
+
+/*******************************************************
+Function:
+	Enable irq function
+Input:
+	ts: goodix i2c_client private data
+Output:
+	None.
+*********************************************************/
+void gtp_irq_enable(struct goodix_ts_data *ts)
+{
+	unsigned long irqflags = 0;
+
+	GTP_DEBUG_FUNC();
+
+	spin_lock_irqsave(&ts->irq_lock, irqflags);
+	if (ts->irq_is_disabled) {
+		enable_irq(ts->client->irq);
+		ts->irq_is_disabled = false;
+	}
+	spin_unlock_irqrestore(&ts->irq_lock, irqflags);
+}
+
+/*******************************************************
+Function:
+	Report touch point event
+Input:
+	ts: goodix i2c_client private data
+	id: trackId
+	x:  input x coordinate
+	y:  input y coordinate
+	w:  input pressure
+Output:
+	None.
+*********************************************************/
+static void gtp_touch_down(struct goodix_ts_data *ts, int id, int x, int y,
+		int w)
+{
+#if GTP_CHANGE_X2Y
+	GTP_SWAP(x, y);
+#endif
+
+	input_mt_slot(ts->input_dev, id);
+	input_mt_report_slot_state(ts->input_dev, MT_TOOL_FINGER, true);
+	input_report_abs(ts->input_dev, ABS_MT_POSITION_X, x);
+	input_report_abs(ts->input_dev, ABS_MT_POSITION_Y, y);
+	input_report_abs(ts->input_dev, ABS_MT_TOUCH_MAJOR, w);
+	input_report_abs(ts->input_dev, ABS_MT_WIDTH_MAJOR, w);
+
+	GTP_DEBUG("ID:%d, X:%d, Y:%d, W:%d", id, x, y, w);
+}
+
+/*******************************************************
+Function:
+	Report touch release event
+Input:
+	ts: goodix i2c_client private data
+Output:
+	None.
+*********************************************************/
+static void gtp_touch_up(struct goodix_ts_data *ts, int id)
+{
+	input_mt_slot(ts->input_dev, id);
+	input_mt_report_slot_state(ts->input_dev, MT_TOOL_FINGER, false);
+	GTP_DEBUG("Touch id[%2d] release!", id);
+}
+
+
+
+/*******************************************************
+Function:
+	Goodix touchscreen work function
+Input:
+	work: work struct of goodix_workqueue
+Output:
+	None.
+*********************************************************/
+static void goodix_ts_work_func(struct work_struct *work)
+{
+	u8 end_cmd[3] = { GTP_READ_COOR_ADDR >> 8,
+			GTP_READ_COOR_ADDR & 0xFF, 0};
+	u8 point_data[2 + 1 + 8 * GTP_MAX_TOUCH + 1] = {
+			GTP_READ_COOR_ADDR >> 8,
+			GTP_READ_COOR_ADDR & 0xFF};
+	u8 touch_num = 0;
+	u8 finger = 0;
+	static u16 pre_touch;
+	static u8 pre_key;
+#if GTP_WITH_PEN
+	static u8 pre_pen;
+#endif
+	u8 key_value = 0;
+	u8 *coor_data = NULL;
+	s32 input_x = 0;
+	s32 input_y = 0;
+	s32 input_w = 0;
+	s32 id = 0;
+	s32 i = 0;
+	int ret = -1;
+	struct goodix_ts_data *ts = NULL;
+
+#if GTP_SLIDE_WAKEUP
+	u8 doze_buf[3] = {0x81, 0x4B};
+#endif
+
+	GTP_DEBUG_FUNC();
+
+	ts = container_of(work, struct goodix_ts_data, work);
+#ifdef CONFIG_GT9XX_TOUCHPANEL_UPDATE
+	if (ts->enter_update)
+		return;
+#endif
+
+#if GTP_SLIDE_WAKEUP
+	if (DOZE_ENABLED == doze_status) {
+		ret = gtp_i2c_read(ts->client, doze_buf, 3);
+		GTP_DEBUG("0x814B = 0x%02X", doze_buf[2]);
+		if (ret > 0) {
+			if (doze_buf[2] == 0xAA) {
+				dev_dbg(&ts->client->dev,
+					"Slide(0xAA) To Light up the screen!");
+				doze_status = DOZE_WAKEUP;
+				input_report_key(
+					ts->input_dev, KEY_POWER, 1);
+				input_sync(ts->input_dev);
+				input_report_key(
+					ts->input_dev, KEY_POWER, 0);
+				input_sync(ts->input_dev);
+				/* clear 0x814B */
+				doze_buf[2] = 0x00;
+				gtp_i2c_write(ts->client, doze_buf, 3);
+			} else if (doze_buf[2] == 0xBB) {
+				dev_dbg(&ts->client->dev,
+					"Slide(0xBB) To Light up the screen!");
+				doze_status = DOZE_WAKEUP;
+				input_report_key(ts->input_dev, KEY_POWER, 1);
+				input_sync(ts->input_dev);
+				input_report_key(ts->input_dev, KEY_POWER, 0);
+				input_sync(ts->input_dev);
+				/* clear 0x814B*/
+				doze_buf[2] = 0x00;
+				gtp_i2c_write(ts->client, doze_buf, 3);
+			} else if (0xC0 == (doze_buf[2] & 0xC0)) {
+				dev_dbg(&ts->client->dev,
+					"double click to light up the screen!");
+				doze_status = DOZE_WAKEUP;
+				input_report_key(ts->input_dev, KEY_POWER, 1);
+				input_sync(ts->input_dev);
+				input_report_key(ts->input_dev, KEY_POWER, 0);
+				input_sync(ts->input_dev);
+				/* clear 0x814B */
+				doze_buf[2] = 0x00;
+				gtp_i2c_write(ts->client, doze_buf, 3);
+			} else {
+				gtp_enter_doze(ts);
+			}
+		}
+		if (ts->use_irq)
+			gtp_irq_enable(ts);
+
+		return;
+	}
+#endif
+
+	ret = gtp_i2c_read(ts->client, point_data, 12);
+	if (ret < 0) {
+		dev_err(&ts->client->dev,
+				"I2C transfer error. errno:%d\n ", ret);
+		goto exit_work_func;
+	}
+
+	finger = point_data[GTP_ADDR_LENGTH];
+	if ((finger & 0x80) == 0)
+		goto exit_work_func;
+
+	touch_num = finger & 0x0f;
+	if (touch_num > GTP_MAX_TOUCH)
+		goto exit_work_func;
+
+	if (touch_num > 1) {
+		u8 buf[8 * GTP_MAX_TOUCH] = { (GTP_READ_COOR_ADDR + 10) >> 8,
+				(GTP_READ_COOR_ADDR + 10) & 0xff };
+
+		ret = gtp_i2c_read(ts->client, buf,
+				2 + 8 * (touch_num - 1));
+		memcpy(&point_data[12], &buf[2], 8 * (touch_num - 1));
+	}
+
+#if GTP_HAVE_TOUCH_KEY
+	key_value = point_data[3 + 8 * touch_num];
+
+	if (key_value || pre_key) {
+		for (i = 0; i < GTP_MAX_KEY_NUM; i++) {
+#if GTP_DEBUG_ON
+			for (ret = 0; ret < 4; ++ret) {
+				if (key_codes[ret] == touch_key_array[i]) {
+					GTP_DEBUG("Key: %s %s",
+						key_names[ret],
+						(key_value & (0x01 << i))
+						? "Down" : "Up");
+					break;
+				}
+			}
+#endif
+
+			input_report_key(ts->input_dev,
+				touch_key_array[i], key_value & (0x01<<i));
+		}
+		touch_num = 0;
+		pre_touch = 0;
+	}
+#endif
+	pre_key = key_value;
+
+	GTP_DEBUG("pre_touch:%02x, finger:%02x.", pre_touch, finger);
+
+#if GTP_WITH_PEN
+	if (pre_pen && (touch_num == 0)) {
+		GTP_DEBUG("Pen touch UP(Slot)!");
+		input_report_key(ts->input_dev, BTN_TOOL_PEN, 0);
+		input_mt_slot(ts->input_dev, 5);
+		input_report_abs(ts->input_dev, ABS_MT_TRACKING_ID, -1);
+		pre_pen = 0;
+	}
+#endif
+	if (pre_touch || touch_num) {
+		s32 pos = 0;
+		u16 touch_index = 0;
+
+		coor_data = &point_data[3];
+		if (touch_num) {
+			id = coor_data[pos] & 0x0F;
+#if GTP_WITH_PEN
+			id = coor_data[pos];
+			if (id == 128) {
+				GTP_DEBUG("Pen touch DOWN(Slot)!");
+				input_x  = coor_data[pos + 1]
+					| (coor_data[pos + 2] << 8);
+				input_y  = coor_data[pos + 3]
+					| (coor_data[pos + 4] << 8);
+				input_w  = coor_data[pos + 5]
+					| (coor_data[pos + 6] << 8);
+
+				input_report_key(ts->input_dev,
+					BTN_TOOL_PEN, 1);
+				input_mt_slot(ts->input_dev, 5);
+				input_report_abs(ts->input_dev,
+					ABS_MT_TRACKING_ID, 5);
+				input_report_abs(ts->input_dev,
+					ABS_MT_POSITION_X, input_x);
+				input_report_abs(ts->input_dev,
+					ABS_MT_POSITION_Y, input_y);
+				input_report_abs(ts->input_dev,
+					ABS_MT_TOUCH_MAJOR, input_w);
+				GTP_DEBUG("Pen/Stylus: (%d, %d)[%d]",
+					input_x, input_y, input_w);
+				pre_pen = 1;
+				pre_touch = 0;
+			}
+#endif
+
+			touch_index |= (0x01<<id);
+		}
+
+		GTP_DEBUG("id = %d,touch_index = 0x%x, pre_touch = 0x%x\n",
+			id, touch_index, pre_touch);
+		for (i = 0; i < GTP_MAX_TOUCH; i++) {
+#if GTP_WITH_PEN
+			if (pre_pen == 1)
+				break;
+#endif
+			if (touch_index & (0x01<<i)) {
+				input_x = coor_data[pos + 1] |
+						coor_data[pos + 2] << 8;
+				input_y = coor_data[pos + 3] |
+						coor_data[pos + 4] << 8;
+				input_w = coor_data[pos + 5] |
+						coor_data[pos + 6] << 8;
+
+				gtp_touch_down(ts, id,
+						input_x, input_y, input_w);
+				pre_touch |= 0x01 << i;
+
+				pos += 8;
+				id = coor_data[pos] & 0x0F;
+				touch_index |= (0x01<<id);
+			} else {
+				gtp_touch_up(ts, i);
+				pre_touch &= ~(0x01 << i);
+			}
+		}
+	}
+	input_sync(ts->input_dev);
+
+exit_work_func:
+	if (!ts->gtp_rawdiff_mode) {
+		ret = gtp_i2c_write(ts->client, end_cmd, 3);
+		if (ret < 0)
+			dev_warn(&ts->client->dev, "I2C write end_cmd error!\n");
+
+	}
+	if (ts->use_irq)
+		gtp_irq_enable(ts);
+
+	return;
+}
+
+/*******************************************************
+Function:
+	Timer interrupt service routine for polling mode.
+Input:
+	timer: timer struct pointer
+Output:
+	Timer work mode.
+	HRTIMER_NORESTART: no restart mode
+*********************************************************/
+static enum hrtimer_restart goodix_ts_timer_handler(struct hrtimer *timer)
+{
+	struct goodix_ts_data
+		*ts = container_of(timer, struct goodix_ts_data, timer);
+
+	GTP_DEBUG_FUNC();
+
+	queue_work(ts->goodix_wq, &ts->work);
+	hrtimer_start(&ts->timer, ktime_set(0, (GTP_POLL_TIME + 6) * 1000000),
+			HRTIMER_MODE_REL);
+	return HRTIMER_NORESTART;
+}
+
+/*******************************************************
+Function:
+	External interrupt service routine for interrupt mode.
+Input:
+	irq:  interrupt number.
+	dev_id: private data pointer
+Output:
+	Handle Result.
+	IRQ_HANDLED: interrupt handled successfully
+*********************************************************/
+static irqreturn_t goodix_ts_irq_handler(int irq, void *dev_id)
+{
+	struct goodix_ts_data *ts = dev_id;
+
+	GTP_DEBUG_FUNC();
+
+	gtp_irq_disable(ts);
+
+	queue_work(ts->goodix_wq, &ts->work);
+
+	return IRQ_HANDLED;
+}
+/*******************************************************
+Function:
+	Synchronization.
+Input:
+	ms: synchronization time in millisecond.
+Output:
+	None.
+*******************************************************/
+void gtp_int_sync(struct goodix_ts_data *ts, int ms)
+{
+	gpio_direction_output(ts->pdata->irq_gpio, 0);
+	msleep(ms);
+	gpio_direction_input(ts->pdata->irq_gpio);
+}
+
+/*******************************************************
+Function:
+	Reset chip.
+Input:
+	ms: reset time in millisecond, must >10ms
+Output:
+	None.
+*******************************************************/
+static void gtp_reset_guitar(struct goodix_ts_data *ts, int ms)
+{
+	GTP_DEBUG_FUNC();
+
+	/* This reset sequence will selcet I2C slave address */
+	gpio_direction_output(ts->pdata->reset_gpio, 0);
+	msleep(ms);
+
+	if (ts->client->addr == GTP_I2C_ADDRESS_HIGH)
+		gpio_direction_output(ts->pdata->irq_gpio, 1);
+	else
+		gpio_direction_output(ts->pdata->irq_gpio, 0);
+
+	usleep(RESET_DELAY_T3_US);
+	gpio_direction_output(ts->pdata->reset_gpio, 1);
+	msleep(RESET_DELAY_T4);
+
+	gpio_direction_input(ts->pdata->reset_gpio);
+
+	gtp_int_sync(ts, 50);
+
+#if GTP_ESD_PROTECT
+	gtp_init_ext_watchdog(ts->client);
+#endif
+}
+
+#if defined(CONFIG_HAS_EARLYSUSPEND) || defined(CONFIG_FB)
+#if GTP_SLIDE_WAKEUP
+/*******************************************************
+Function:
+	Enter doze mode for sliding wakeup.
+Input:
+	ts: goodix tp private data
+Output:
+	1: succeed, otherwise failed
+*******************************************************/
+static s8 gtp_enter_doze(struct goodix_ts_data *ts)
+{
+	int ret = -1;
+	s8 retry = 0;
+	u8 i2c_control_buf[3] = {
+		(u8)(GTP_REG_SLEEP >> 8),
+		(u8)GTP_REG_SLEEP, 8};
+
+	GTP_DEBUG_FUNC();
+
+#if GTP_DBL_CLK_WAKEUP
+	i2c_control_buf[2] = 0x09;
+#endif
+	gtp_irq_disable(ts);
+
+	GTP_DEBUG("entering doze mode...");
+	while (retry++ < 5) {
+		i2c_control_buf[0] = 0x80;
+		i2c_control_buf[1] = 0x46;
+		ret = gtp_i2c_write(ts->client, i2c_control_buf, 3);
+		if (ret < 0) {
+			GTP_DEBUG(
+				"failed to set doze flag into 0x8046, %d",
+				retry);
+			continue;
+		}
+		i2c_control_buf[0] = 0x80;
+		i2c_control_buf[1] = 0x40;
+		ret = gtp_i2c_write(ts->client, i2c_control_buf, 3);
+		if (ret > 0) {
+			doze_status = DOZE_ENABLED;
+			dev_dbg(&ts->client->dev,
+				"GTP has been working in doze mode!");
+			gtp_irq_enable(ts);
+			return ret;
+		}
+		msleep(20);
+	}
+	dev_err(&ts->client->dev, "GTP send doze cmd failed.\n");
+	gtp_irq_enable(ts);
+	return ret;
+}
+#else
+/*******************************************************
+Function:
+	Enter sleep mode.
+Input:
+	ts: private data.
+Output:
+	Executive outcomes.
+	1: succeed, otherwise failed.
+*******************************************************/
+static s8 gtp_enter_sleep(struct goodix_ts_data  *ts)
+{
+	int ret = -1;
+	s8 retry = 0;
+	u8 i2c_control_buf[3] = {
+		(u8)(GTP_REG_SLEEP >> 8),
+		(u8)GTP_REG_SLEEP, 5};
+
+	GTP_DEBUG_FUNC();
+
+	ret = gpio_direction_output(ts->pdata->irq_gpio, 0);
+	usleep(5000);
+	while (retry++ < 5) {
+		ret = gtp_i2c_write(ts->client, i2c_control_buf, 3);
+		if (ret > 0) {
+			dev_dbg(&ts->client->dev,
+				"GTP enter sleep!");
+			return ret;
+		}
+		msleep(20);
+	}
+	dev_err(&ts->client->dev, "GTP send sleep cmd failed.\n");
+	return ret;
+}
+#endif
+
+/*******************************************************
+Function:
+	Wakeup from sleep.
+Input:
+	ts: private data.
+Output:
+	Executive outcomes.
+	>0: succeed, otherwise: failed.
+*******************************************************/
+static s8 gtp_wakeup_sleep(struct goodix_ts_data *ts)
+{
+	u8 retry = 0;
+	s8 ret = -1;
+
+	GTP_DEBUG_FUNC();
+
+#if GTP_POWER_CTRL_SLEEP
+	gtp_reset_guitar(ts, 20);
+
+	ret = gtp_send_cfg(ts);
+	if (ret > 0) {
+		dev_dbg(&ts->client->dev,
+			"Wakeup sleep send config success.");
+		return 1;
+	}
+#else
+	while (retry++ < 10) {
+#if GTP_SLIDE_WAKEUP
+		/* wakeup not by slide */
+		if (DOZE_WAKEUP != doze_status)
+			gtp_reset_guitar(ts, 10);
+		else
+			/* wakeup by slide */
+			doze_status = DOZE_DISABLED;
+#else
+		if (chip_gt9xxs == 1) {
+			gtp_reset_guitar(ts, 10);
+		} else {
+			ret = gpio_direction_output(ts->pdata->irq_gpio, 1);
+			usleep(5000);
+		}
+#endif
+		ret = gtp_i2c_test(ts->client);
+		if (ret > 0) {
+			dev_dbg(&ts->client->dev, "GTP wakeup sleep.");
+#if (!GTP_SLIDE_WAKEUP)
+			if (chip_gt9xxs == 0) {
+				gtp_int_sync(ts, 25);
+				msleep(20);
+#if GTP_ESD_PROTECT
+				gtp_init_ext_watchdog(ts->client);
+#endif
+			}
+#endif
+			return ret;
+		}
+		gtp_reset_guitar(ts, 20);
+	}
+#endif
+
+	dev_err(&ts->client->dev, "GTP wakeup sleep failed.\n");
+	return ret;
+}
+#endif /* !CONFIG_HAS_EARLYSUSPEND && !CONFIG_FB*/
+
+/*******************************************************
+Function:
+	Initialize gtp.
+Input:
+	ts: goodix private data
+Output:
+	Executive outcomes.
+	> =0: succeed, otherwise: failed
+*******************************************************/
+static int gtp_init_panel(struct goodix_ts_data *ts)
+{
+	struct i2c_client *client = ts->client;
+	unsigned char *config_data;
+	int ret = -EIO;
+
+#if GTP_DRIVER_SEND_CFG
+	int i;
+	u8 check_sum = 0;
+	u8 opr_buf[16];
+	u8 sensor_id = 0;
+
+	u8 cfg_info_group1[] = CTP_CFG_GROUP1;
+	u8 cfg_info_group2[] = CTP_CFG_GROUP2;
+	u8 cfg_info_group3[] = CTP_CFG_GROUP3;
+	u8 cfg_info_group4[] = CTP_CFG_GROUP4;
+	u8 cfg_info_group5[] = CTP_CFG_GROUP5;
+	u8 cfg_info_group6[] = CTP_CFG_GROUP6;
+	u8 *send_cfg_buf[] = {cfg_info_group1, cfg_info_group2,
+		cfg_info_group3, cfg_info_group4,
+		cfg_info_group5, cfg_info_group6};
+
+	u8 cfg_info_len[] = {CFG_GROUP_LEN(cfg_info_group1),
+		CFG_GROUP_LEN(cfg_info_group2),
+		CFG_GROUP_LEN(cfg_info_group3),
+		CFG_GROUP_LEN(cfg_info_group4),
+		CFG_GROUP_LEN(cfg_info_group5),
+		CFG_GROUP_LEN(cfg_info_group6)};
+
+	GTP_DEBUG("Config Groups\' Lengths: %d, %d, %d, %d, %d, %d",
+			cfg_info_len[0], cfg_info_len[1], cfg_info_len[2],
+			cfg_info_len[3], cfg_info_len[4], cfg_info_len[5]);
+
+	ret = gtp_i2c_read_dbl_check(ts->client, 0x41E4, opr_buf, 1);
+	if (SUCCESS == ret) {
+		if (opr_buf[0] != 0xBE) {
+			ts->fw_error = 1;
+			dev_err(&client->dev,
+				"Firmware error, no config sent!");
+			return -EINVAL;
+		}
+	}
+	if ((!cfg_info_len[1]) && (!cfg_info_len[2]) && (!cfg_info_len[3])
+		&& (!cfg_info_len[4]) && (!cfg_info_len[5])) {
+		sensor_id = 0;
+	} else {
+		ret = gtp_i2c_read_dbl_check(ts->client, GTP_REG_SENSOR_ID,
+			&sensor_id, 1);
+		if (SUCCESS == ret) {
+			if (sensor_id >= 0x06) {
+				dev_err(&client->dev,
+					"Invalid sensor_id(0x%02X), No Config Sent!",
+					sensor_id);
+				return -EINVAL;
+			}
+		} else {
+			dev_err(&client->dev,
+				"Failed to get sensor_id, No config sent!");
+			return -EINVAL;
+		}
+	}
+	GTP_DEBUG("Sensor_ID: %d", sensor_id);
+
+	ts->gtp_cfg_len = cfg_info_len[sensor_id];
+
+	if (ts->gtp_cfg_len < GTP_CONFIG_MIN_LENGTH) {
+		dev_err(&client->dev,
+				"Sensor_ID(%d) matches with NULL or INVALID CONFIG GROUP! NO Config Sent! You need to check you header file CFG_GROUP section!\n",
+				sensor_id);
+		return -EINVAL;
+	}
+	ret = gtp_i2c_read_dbl_check(ts->client, GTP_REG_CONFIG_DATA,
+		&opr_buf[0], 1);
+
+	if (ret == SUCCESS) {
+		if (opr_buf[0] < 90) {
+			/* backup group config version */
+			grp_cfg_version = send_cfg_buf[sensor_id][0];
+			send_cfg_buf[sensor_id][0] = 0x00;
+			ts->fixed_cfg = 0;
+		} else {
+			/* treated as fixed config, not send config */
+			dev_warn(&client->dev,
+				"Ic fixed config with config version(%d, 0x%02X)",
+				opr_buf[0], opr_buf[0]);
+			ts->fixed_cfg = 1;
+		}
+	} else {
+		dev_err(&client->dev,
+			"Failed to get ic config version!No config sent!");
+		return -EINVAL;
+	}
+
+	if (ts->pdata->gtp_cfg_len) {
+		config_data = ts->pdata->config_data;
+		ts->config_data = ts->pdata->config_data;
+		ts->gtp_cfg_len = ts->pdata->gtp_cfg_len;
+	} else {
+		config_data = devm_kzalloc(&client->dev,
+			GTP_CONFIG_MAX_LENGTH + GTP_ADDR_LENGTH,
+				GFP_KERNEL);
+		if (!config_data) {
+			dev_err(&client->dev,
+					"Not enough memory for panel config data\n");
+			return -ENOMEM;
+		}
+
+		ts->config_data = config_data;
+		config_data[0] = GTP_REG_CONFIG_DATA >> 8;
+		config_data[1] = GTP_REG_CONFIG_DATA & 0xff;
+		memset(&config_data[GTP_ADDR_LENGTH], 0, GTP_CONFIG_MAX_LENGTH);
+		memcpy(&config_data[GTP_ADDR_LENGTH], send_cfg_buf[sensor_id],
+				ts->gtp_cfg_len);
+	}
+
+#if GTP_CUSTOM_CFG
+	config_data[RESOLUTION_LOC] =
+	(unsigned char)(GTP_MAX_WIDTH && 0xFF);
+	config_data[RESOLUTION_LOC + 1] =
+	(unsigned char)(GTP_MAX_WIDTH >> 8);
+	config_data[RESOLUTION_LOC + 2] =
+	(unsigned char)(GTP_MAX_HEIGHT && 0xFF);
+	config_data[RESOLUTION_LOC + 3] =
+	(unsigned char)(GTP_MAX_HEIGHT >> 8);
+
+	if (GTP_INT_TRIGGER == 0)
+		config_data[TRIGGER_LOC] &= 0xfe;
+	else if (GTP_INT_TRIGGER == 1)
+		config_data[TRIGGER_LOC] |= 0x01;
+#endif  /* !GTP_CUSTOM_CFG */
+
+	check_sum = 0;
+	for (i = GTP_ADDR_LENGTH; i < ts->gtp_cfg_len; i++)
+		check_sum += config_data[i];
+
+	config_data[ts->gtp_cfg_len] = (~check_sum) + 1;
+
+#else /* DRIVER NOT SEND CONFIG */
+	ts->gtp_cfg_len = GTP_CONFIG_MAX_LENGTH;
+	ret = gtp_i2c_read(ts->client, config_data,
+			ts->gtp_cfg_len + GTP_ADDR_LENGTH);
+	if (ret < 0) {
+		dev_err(&client->dev,
+				"Read Config Failed, Using DEFAULT Resolution & INT Trigger!\n");
+		ts->abs_x_max = GTP_MAX_WIDTH;
+		ts->abs_y_max = GTP_MAX_HEIGHT;
+		ts->int_trigger_type = GTP_INT_TRIGGER;
+	}
+#endif /* !DRIVER NOT SEND CONFIG */
+
+	GTP_DEBUG_FUNC();
+	if ((ts->abs_x_max == 0) && (ts->abs_y_max == 0)) {
+		ts->abs_x_max = (config_data[RESOLUTION_LOC + 1] << 8)
+				+ config_data[RESOLUTION_LOC];
+		ts->abs_y_max = (config_data[RESOLUTION_LOC + 3] << 8)
+				+ config_data[RESOLUTION_LOC + 2];
+		ts->int_trigger_type = (config_data[TRIGGER_LOC]) & 0x03;
+	}
+	ret = gtp_send_cfg(ts);
+	if (ret < 0)
+		dev_err(&client->dev, "%s: Send config error.\n", __func__);
+
+	GTP_DEBUG("X_MAX = %d, Y_MAX = %d, TRIGGER = 0x%02x",
+			ts->abs_x_max, ts->abs_y_max,
+			ts->int_trigger_type);
+
+	msleep(20);
+	return ret;
+}
+
+/*******************************************************
+Function:
+	Read chip version.
+Input:
+	client:  i2c device
+	version: buffer to keep ic firmware version
+Output:
+	read operation return.
+	2: succeed, otherwise: failed
+*******************************************************/
+int gtp_read_version(struct i2c_client *client, u16 *version)
+{
+	int ret = -EIO;
+	u8 buf[8] = { GTP_REG_VERSION >> 8, GTP_REG_VERSION & 0xff };
+
+	GTP_DEBUG_FUNC();
+
+	ret = gtp_i2c_read(client, buf, sizeof(buf));
+	if (ret < 0) {
+		dev_err(&client->dev, "GTP read version failed.\n");
+		return ret;
+	}
+
+	if (version)
+		*version = (buf[7] << 8) | buf[6];
+
+	if (buf[5] == 0x00) {
+		dev_dbg(&client->dev, "IC Version: %c%c%c_%02x%02x\n", buf[2],
+				buf[3], buf[4], buf[7], buf[6]);
+	} else {
+		if (buf[5] == 'S' || buf[5] == 's')
+			chip_gt9xxs = 1;
+		dev_dbg(&client->dev, "IC Version: %c%c%c%c_%02x%02x\n", buf[2],
+				buf[3], buf[4], buf[5], buf[7], buf[6]);
+	}
+	return ret;
+}
+
+/*******************************************************
+Function:
+	I2c test Function.
+Input:
+	client:i2c client.
+Output:
+	Executive outcomes.
+	2: succeed, otherwise failed.
+*******************************************************/
+static int gtp_i2c_test(struct i2c_client *client)
+{
+	u8 buf[3] = { GTP_REG_CONFIG_DATA >> 8, GTP_REG_CONFIG_DATA & 0xff };
+	int retry = 5;
+	int ret = -EIO;
+
+	GTP_DEBUG_FUNC();
+
+	while (retry--) {
+		ret = gtp_i2c_read(client, buf, 3);
+		if (ret > 0)
+			return ret;
+		dev_err(&client->dev, "GTP i2c test failed time %d.\n", retry);
+		msleep(20);
+	}
+	return ret;
+}
+
+/*******************************************************
+Function:
+	Request gpio(INT & RST) ports.
+Input:
+	ts: private data.
+Output:
+	Executive outcomes.
+	= 0: succeed, != 0: failed
+*******************************************************/
+static int gtp_request_io_port(struct goodix_ts_data *ts)
+{
+	struct i2c_client *client = ts->client;
+	struct goodix_ts_platform_data *pdata = ts->pdata;
+	int ret;
+	if (gpio_is_valid(pdata->irq_gpio)) {
+		ret = gpio_request(pdata->irq_gpio, "goodix_ts_irq_gpio");
+		if (ret) {
+			dev_err(&client->dev, "irq gpio request failed\n");
+			goto pwr_off;
+		}
+		ret = gpio_direction_input(pdata->irq_gpio);
+		if (ret) {
+			dev_err(&client->dev,
+					"set_direction for irq gpio failed\n");
+			goto free_irq_gpio;
+		}
+	} else {
+		dev_err(&client->dev, "irq gpio is invalid!\n");
+		ret = -EINVAL;
+		goto free_irq_gpio;
+	}
+
+	if (gpio_is_valid(pdata->reset_gpio)) {
+		ret = gpio_request(pdata->reset_gpio, "goodix_ts__reset_gpio");
+		if (ret) {
+			dev_err(&client->dev, "reset gpio request failed\n");
+			goto free_irq_gpio;
+		}
+
+		ret = gpio_direction_output(pdata->reset_gpio, 0);
+		if (ret) {
+			dev_err(&client->dev,
+					"set_direction for reset gpio failed\n");
+			goto free_reset_gpio;
+		}
+	} else {
+		dev_err(&client->dev, "reset gpio is invalid!\n");
+		ret = -EINVAL;
+		goto free_reset_gpio;
+	}
+	gpio_direction_input(pdata->reset_gpio);
+
+	return ret;
+
+free_reset_gpio:
+	if (gpio_is_valid(pdata->reset_gpio))
+		gpio_free(pdata->reset_gpio);
+free_irq_gpio:
+	if (gpio_is_valid(pdata->irq_gpio))
+		gpio_free(pdata->irq_gpio);
+pwr_off:
+	return ret;
+}
+
+/*******************************************************
+Function:
+	Request interrupt.
+Input:
+	ts: private data.
+Output:
+	Executive outcomes.
+	0: succeed, -1: failed.
+*******************************************************/
+static int gtp_request_irq(struct goodix_ts_data *ts)
+{
+	int ret;
+	const u8 irq_table[] = GTP_IRQ_TAB;
+
+	GTP_DEBUG("INT trigger type:%x, irq=%d", ts->int_trigger_type,
+			ts->client->irq);
+
+	ret = request_irq(ts->client->irq, goodix_ts_irq_handler,
+			irq_table[ts->int_trigger_type],
+			ts->client->name, ts);
+	if (ret) {
+		dev_err(&ts->client->dev, "Request IRQ failed!ERRNO:%d.\n",
+				ret);
+		gpio_direction_input(ts->pdata->irq_gpio);
+
+		hrtimer_init(&ts->timer, CLOCK_MONOTONIC,
+				HRTIMER_MODE_REL);
+		ts->timer.function = goodix_ts_timer_handler;
+		hrtimer_start(&ts->timer, ktime_set(1, 0),
+				HRTIMER_MODE_REL);
+		ts->use_irq = false;
+		return ret;
+	} else {
+		gtp_irq_disable(ts);
+		ts->use_irq = true;
+		return 0;
+	}
+}
+
+/*******************************************************
+Function:
+	Request input device Function.
+Input:
+	ts:private data.
+Output:
+	Executive outcomes.
+	0: succeed, otherwise: failed.
+*******************************************************/
+static int gtp_request_input_dev(struct goodix_ts_data *ts)
+{
+	int ret;
+	char phys[PHY_BUF_SIZE];
+#if GTP_HAVE_TOUCH_KEY
+	int index = 0;
+#endif
+
+	GTP_DEBUG_FUNC();
+
+	ts->input_dev = input_allocate_device();
+	if (ts->input_dev == NULL) {
+		dev_err(&ts->client->dev,
+				"Failed to allocate input device.\n");
+		return -ENOMEM;
+	}
+
+	ts->input_dev->evbit[0] =
+		BIT_MASK(EV_SYN) | BIT_MASK(EV_KEY) | BIT_MASK(EV_ABS) ;
+	set_bit(BTN_TOOL_FINGER, ts->input_dev->keybit);
+	__set_bit(INPUT_PROP_DIRECT, ts->input_dev->propbit);
+	input_mt_init_slots(ts->input_dev, 10);/* in case of "out of memory" */
+
+#if GTP_HAVE_TOUCH_KEY
+	for (index = 0; index < GTP_MAX_KEY_NUM; index++) {
+		input_set_capability(ts->input_dev,
+				EV_KEY, touch_key_array[index]);
+	}
+#endif
+
+#if GTP_SLIDE_WAKEUP
+	input_set_capability(ts->input_dev, EV_KEY, KEY_POWER);
+#endif
+
+#if GTP_WITH_PEN
+	/* pen support */
+	__set_bit(BTN_TOOL_PEN, ts->input_dev->keybit);
+	__set_bit(INPUT_PROP_DIRECT, ts->input_dev->propbit);
+	__set_bit(INPUT_PROP_POINTER, ts->input_dev->propbit);
+#endif
+
+#if GTP_CHANGE_X2Y
+	GTP_SWAP(ts->abs_x_max, ts->abs_y_max);
+#endif
+
+	input_set_abs_params(ts->input_dev, ABS_MT_POSITION_X,
+				0, ts->abs_x_max, 0, 0);
+	input_set_abs_params(ts->input_dev, ABS_MT_POSITION_Y,
+				0, ts->abs_y_max, 0, 0);
+	input_set_abs_params(ts->input_dev, ABS_MT_WIDTH_MAJOR,
+				0, 255, 0, 0);
+	input_set_abs_params(ts->input_dev, ABS_MT_TOUCH_MAJOR,
+				0, 255, 0, 0);
+	input_set_abs_params(ts->input_dev, ABS_MT_TRACKING_ID,
+				0, 255, 0, 0);
+
+	snprintf(phys, PHY_BUF_SIZE, "input/ts");
+	ts->input_dev->name = GOODIX_DEV_NAME;
+	ts->input_dev->phys = phys;
+	ts->input_dev->id.bustype = BUS_I2C;
+	ts->input_dev->id.vendor = 0xDEAD;
+	ts->input_dev->id.product = 0xBEEF;
+	ts->input_dev->id.version = 10427;
+
+	ret = input_register_device(ts->input_dev);
+	if (ret) {
+		dev_err(&ts->client->dev,
+				"Register %s input device failed.\n",
+				ts->input_dev->name);
+		goto exit_free_inputdev;
+	}
+
+	return 0;
+
+exit_free_inputdev:
+	input_free_device(ts->input_dev);
+	ts->input_dev = NULL;
+	return ret;
+}
+
+static int reg_set_optimum_mode_check(struct regulator *reg, int load_uA)
+{
+	return (regulator_count_voltages(reg) > 0) ?
+		regulator_set_optimum_mode(reg, load_uA) : 0;
+}
+
+/**
+ * goodix_power_on - Turn device power ON
+ * @ts: driver private data
+ *
+ * Returns zero on success, else an error.
+ */
+static int goodix_power_on(struct goodix_ts_data *ts)
+{
+	int ret;
+
+	if (!IS_ERR(ts->avdd)) {
+		ret = reg_set_optimum_mode_check(ts->avdd,
+			GOODIX_VDD_LOAD_MAX_UA);
+		if (ret < 0) {
+			dev_err(&ts->client->dev,
+				"Regulator avdd set_opt failed rc=%d\n", ret);
+			goto err_set_opt_avdd;
+		}
+		ret = regulator_enable(ts->avdd);
+		if (ret) {
+			dev_err(&ts->client->dev,
+				"Regulator avdd enable failed ret=%d\n", ret);
+			goto err_enable_avdd;
+		}
+	}
+
+	if (!IS_ERR(ts->vdd)) {
+		ret = regulator_set_voltage(ts->vdd, GOODIX_VTG_MIN_UV,
+					   GOODIX_VTG_MAX_UV);
+		if (ret) {
+			dev_err(&ts->client->dev,
+				"Regulator set_vtg failed vdd ret=%d\n", ret);
+			goto err_set_vtg_vdd;
+		}
+		ret = reg_set_optimum_mode_check(ts->vdd,
+			GOODIX_VDD_LOAD_MAX_UA);
+		if (ret < 0) {
+			dev_err(&ts->client->dev,
+				"Regulator vdd set_opt failed rc=%d\n", ret);
+			goto err_set_opt_vdd;
+		}
+		ret = regulator_enable(ts->vdd);
+		if (ret) {
+			dev_err(&ts->client->dev,
+				"Regulator vdd enable failed ret=%d\n", ret);
+			goto err_enable_vdd;
+		}
+	}
+
+	if (!IS_ERR(ts->vcc_i2c)) {
+		ret = regulator_set_voltage(ts->vcc_i2c, GOODIX_I2C_VTG_MIN_UV,
+					   GOODIX_I2C_VTG_MAX_UV);
+		if (ret) {
+			dev_err(&ts->client->dev,
+				"Regulator set_vtg failed vcc_i2c ret=%d\n",
+				ret);
+			goto err_set_vtg_vcc_i2c;
+		}
+		ret = reg_set_optimum_mode_check(ts->vcc_i2c,
+			GOODIX_VIO_LOAD_MAX_UA);
+		if (ret < 0) {
+			dev_err(&ts->client->dev,
+				"Regulator vcc_i2c set_opt failed rc=%d\n",
+				ret);
+			goto err_set_opt_vcc_i2c;
+		}
+		ret = regulator_enable(ts->vcc_i2c);
+		if (ret) {
+			dev_err(&ts->client->dev,
+				"Regulator vcc_i2c enable failed ret=%d\n",
+				ret);
+			regulator_disable(ts->vdd);
+			goto err_enable_vcc_i2c;
+			}
+	}
+
+	return 0;
+
+err_enable_vcc_i2c:
+err_set_opt_vcc_i2c:
+	if (!IS_ERR(ts->vcc_i2c))
+		regulator_set_voltage(ts->vcc_i2c, 0, GOODIX_I2C_VTG_MAX_UV);
+err_set_vtg_vcc_i2c:
+	if (!IS_ERR(ts->vdd))
+		regulator_disable(ts->vdd);
+err_enable_vdd:
+err_set_opt_vdd:
+	if (!IS_ERR(ts->vdd))
+		regulator_set_voltage(ts->vdd, 0, GOODIX_VTG_MAX_UV);
+err_set_vtg_vdd:
+	if (!IS_ERR(ts->avdd))
+		regulator_disable(ts->avdd);
+err_enable_avdd:
+err_set_opt_avdd:
+	return ret;
+}
+
+/**
+ * goodix_power_off - Turn device power OFF
+ * @ts: driver private data
+ *
+ * Returns zero on success, else an error.
+ */
+static int goodix_power_off(struct goodix_ts_data *ts)
+{
+	int ret;
+
+	if (!IS_ERR(ts->vcc_i2c)) {
+		ret = regulator_set_voltage(ts->vcc_i2c, 0,
+			GOODIX_I2C_VTG_MAX_UV);
+		if (ret < 0)
+			dev_err(&ts->client->dev,
+				"Regulator vcc_i2c set_vtg failed ret=%d\n",
+				ret);
+		ret = regulator_disable(ts->vcc_i2c);
+		if (ret)
+			dev_err(&ts->client->dev,
+				"Regulator vcc_i2c disable failed ret=%d\n",
+				ret);
+	}
+
+	if (!IS_ERR(ts->vdd)) {
+		ret = regulator_set_voltage(ts->vdd, 0, GOODIX_VTG_MAX_UV);
+		if (ret < 0)
+			dev_err(&ts->client->dev,
+				"Regulator vdd set_vtg failed ret=%d\n", ret);
+		ret = regulator_disable(ts->vdd);
+		if (ret)
+			dev_err(&ts->client->dev,
+				"Regulator vdd disable failed ret=%d\n", ret);
+	}
+
+	if (!IS_ERR(ts->avdd)) {
+		ret = regulator_disable(ts->avdd);
+		if (ret)
+			dev_err(&ts->client->dev,
+				"Regulator avdd disable failed ret=%d\n", ret);
+	}
+
+	return 0;
+}
+
+/**
+ * goodix_power_init - Initialize device power
+ * @ts: driver private data
+ *
+ * Returns zero on success, else an error.
+ */
+static int goodix_power_init(struct goodix_ts_data *ts)
+{
+	int ret;
+
+	ts->avdd = regulator_get(&ts->client->dev, "avdd");
+	if (IS_ERR(ts->avdd)) {
+		ret = PTR_ERR(ts->avdd);
+		dev_info(&ts->client->dev,
+			"Regulator get failed avdd ret=%d\n", ret);
+	}
+
+	ts->vdd = regulator_get(&ts->client->dev, "vdd");
+	if (IS_ERR(ts->vdd)) {
+		ret = PTR_ERR(ts->vdd);
+		dev_info(&ts->client->dev,
+			"Regulator get failed vdd ret=%d\n", ret);
+	}
+
+	ts->vcc_i2c = regulator_get(&ts->client->dev, "vcc-i2c");
+	if (IS_ERR(ts->vcc_i2c)) {
+		ret = PTR_ERR(ts->vcc_i2c);
+		dev_info(&ts->client->dev,
+			"Regulator get failed vcc_i2c ret=%d\n", ret);
+	}
+
+	return 0;
+}
+
+/**
+ * goodix_power_deinit - Deinitialize device power
+ * @ts: driver private data
+ *
+ * Returns zero on success, else an error.
+ */
+static int goodix_power_deinit(struct goodix_ts_data *ts)
+{
+	regulator_put(ts->vdd);
+	regulator_put(ts->vcc_i2c);
+	regulator_put(ts->avdd);
+
+	return 0;
+}
+
+static int goodix_ts_get_dt_coords(struct device *dev, char *name,
+				struct goodix_ts_platform_data *pdata)
+{
+	struct property *prop;
+	struct device_node *np = dev->of_node;
+	int rc;
+	u32 coords[GOODIX_COORDS_ARR_SIZE];
+
+	prop = of_find_property(np, name, NULL);
+	if (!prop)
+		return -EINVAL;
+	if (!prop->value)
+		return -ENODATA;
+
+	rc = of_property_read_u32_array(np, name, coords,
+		GOODIX_COORDS_ARR_SIZE);
+	if (rc && (rc != -EINVAL)) {
+		dev_err(dev, "Unable to read %s\n", name);
+		return rc;
+	}
+
+	if (!strcmp(name, "goodix,panel-coords")) {
+		pdata->panel_minx = coords[0];
+		pdata->panel_miny = coords[1];
+		pdata->panel_maxx = coords[2];
+		pdata->panel_maxy = coords[3];
+	} else if (!strcmp(name, "goodix,display-coords")) {
+		pdata->x_min = coords[0];
+		pdata->y_min = coords[1];
+		pdata->x_max = coords[2];
+		pdata->y_max = coords[3];
+	} else {
+		dev_err(dev, "unsupported property %s\n", name);
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+static int goodix_parse_dt(struct device *dev,
+			struct goodix_ts_platform_data *pdata)
+{
+	int rc;
+	struct device_node *np = dev->of_node;
+	struct property *prop;
+	u32 temp_val, num_buttons;
+	u32 button_map[MAX_BUTTONS];
+
+	rc = goodix_ts_get_dt_coords(dev, "goodix,panel-coords", pdata);
+	if (rc && (rc != -EINVAL))
+		return rc;
+
+	rc = goodix_ts_get_dt_coords(dev, "goodix,display-coords", pdata);
+	if (rc)
+		return rc;
+
+	pdata->i2c_pull_up = of_property_read_bool(np,
+						"goodix,i2c-pull-up");
+
+	pdata->no_force_update = of_property_read_bool(np,
+						"goodix,no-force-update");
+	/* reset, irq gpio info */
+	pdata->reset_gpio = of_get_named_gpio_flags(np, "reset-gpios",
+				0, &pdata->reset_gpio_flags);
+	if (pdata->reset_gpio < 0)
+		return pdata->reset_gpio;
+
+	pdata->irq_gpio = of_get_named_gpio_flags(np, "interrupt-gpios",
+				0, &pdata->irq_gpio_flags);
+	if (pdata->irq_gpio < 0)
+		return pdata->irq_gpio;
+
+	rc = of_property_read_u32(np, "goodix,family-id", &temp_val);
+	if (!rc)
+		pdata->family_id = temp_val;
+	else
+		return rc;
+
+	prop = of_find_property(np, "goodix,button-map", NULL);
+	if (prop) {
+		num_buttons = prop->length / sizeof(temp_val);
+		if (num_buttons > MAX_BUTTONS)
+			return -EINVAL;
+
+		rc = of_property_read_u32_array(np,
+			"goodix,button-map", button_map,
+			num_buttons);
+		if (rc) {
+			dev_err(dev, "Unable to read key codes\n");
+			return rc;
+		}
+	}
+
+	prop = of_find_property(np, "goodix,cfg-data", &pdata->gtp_cfg_len);
+	if (prop && prop->value) {
+		pdata->config_data = devm_kzalloc(dev,
+			GTP_CONFIG_MAX_LENGTH + GTP_ADDR_LENGTH, GFP_KERNEL);
+		if (!pdata->config_data) {
+			dev_err(dev, "Not enough memory for panel config data\n");
+			return -ENOMEM;
+		}
+
+		pdata->config_data[0] = GTP_REG_CONFIG_DATA >> 8;
+		pdata->config_data[1] = GTP_REG_CONFIG_DATA & 0xff;
+		memset(&pdata->config_data[GTP_ADDR_LENGTH], 0,
+					GTP_CONFIG_MAX_LENGTH);
+		memcpy(&pdata->config_data[GTP_ADDR_LENGTH],
+				prop->value, pdata->gtp_cfg_len);
+	} else {
+		dev_err(dev,
+			"Unable to get configure data, default will be used.\n");
+		pdata->gtp_cfg_len = 0;
+	}
+
+	return 0;
+}
+
+/*******************************************************
+Function:
+	I2c probe.
+Input:
+	client: i2c device struct.
+	id: device id.
+Output:
+	Executive outcomes.
+	0: succeed.
+*******************************************************/
+
+static int goodix_ts_probe(struct i2c_client *client,
+			   const struct i2c_device_id *id)
+{
+	struct goodix_ts_platform_data *pdata;
+	struct goodix_ts_data *ts;
+	u16 version_info;
+	int ret;
+
+	dev_dbg(&client->dev, "GTP I2C Address: 0x%02x\n", client->addr);
+	if (client->dev.of_node) {
+		pdata = devm_kzalloc(&client->dev,
+			sizeof(struct goodix_ts_platform_data), GFP_KERNEL);
+		if (!pdata) {
+			dev_err(&client->dev,
+				"GTP Failed to allocate memory for pdata\n");
+			return -ENOMEM;
+		}
+
+		ret = goodix_parse_dt(&client->dev, pdata);
+		if (ret)
+			return ret;
+	} else {
+		pdata = client->dev.platform_data;
+	}
+
+	if (!pdata) {
+		dev_err(&client->dev, "GTP invalid pdata\n");
+		return -EINVAL;
+	}
+
+#if GTP_ESD_PROTECT
+	i2c_connect_client = client;
+#endif
+
+	if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) {
+		dev_err(&client->dev, "GTP I2C not supported\n");
+		return -ENODEV;
+	}
+
+	ts = kzalloc(sizeof(*ts), GFP_KERNEL);
+	if (!ts) {
+		dev_err(&client->dev, "GTP not enough memory for ts\n");
+		return -ENOMEM;
+	}
+
+	memset(ts, 0, sizeof(*ts));
+	ts->client = client;
+	ts->pdata = pdata;
+	/* For 2.6.39 & later use spin_lock_init(&ts->irq_lock)
+	 * For 2.6.39 & before, use ts->irq_lock = SPIN_LOCK_UNLOCKED
+	 */
+	spin_lock_init(&ts->irq_lock);
+	i2c_set_clientdata(client, ts);
+	ts->gtp_rawdiff_mode = 0;
+
+	ret = goodix_power_init(ts);
+	if (ret) {
+		dev_err(&client->dev, "GTP power init failed\n");
+		goto exit_free_client_data;
+	}
+
+	ret = goodix_power_on(ts);
+	if (ret) {
+		dev_err(&client->dev, "GTP power on failed\n");
+		goto exit_deinit_power;
+	}
+
+	ret = gtp_request_io_port(ts);
+	if (ret) {
+		dev_err(&client->dev, "GTP request IO port failed.\n");
+		goto exit_power_off;
+	}
+
+	gtp_reset_guitar(ts, 20);
+
+	ret = gtp_i2c_test(client);
+	if (ret != 2) {
+		dev_err(&client->dev, "I2C communication ERROR!\n");
+		goto exit_free_io_port;
+	}
+
+#if GTP_AUTO_UPDATE
+	ret = gup_init_update_proc(ts);
+	if (ret < 0) {
+		dev_err(&client->dev,
+			"GTP Create firmware update thread error.\n");
+		goto exit_free_io_port;
+	}
+#endif
+
+	ret = gtp_init_panel(ts);
+	if (ret < 0) {
+		dev_err(&client->dev, "GTP init panel failed.\n");
+		ts->abs_x_max = GTP_MAX_WIDTH;
+		ts->abs_y_max = GTP_MAX_HEIGHT;
+		ts->int_trigger_type = GTP_INT_TRIGGER;
+	}
+
+	ret = gtp_request_input_dev(ts);
+	if (ret) {
+		dev_err(&client->dev, "GTP request input dev failed.\n");
+		goto exit_free_inputdev;
+	}
+
+#if defined(CONFIG_FB)
+	ts->fb_notif.notifier_call = fb_notifier_callback;
+	ret = fb_register_client(&ts->fb_notif);
+	if (ret)
+		dev_err(&ts->client->dev,
+			"Unable to register fb_notifier: %d\n",
+			ret);
+#elif defined(CONFIG_HAS_EARLYSUSPEND)
+	ts->early_suspend.level = EARLY_SUSPEND_LEVEL_BLANK_SCREEN + 1;
+	ts->early_suspend.suspend = goodix_ts_early_suspend;
+	ts->early_suspend.resume = goodix_ts_late_resume;
+	register_early_suspend(&ts->early_suspend);
+#endif
+
+	ts->goodix_wq = create_singlethread_workqueue("goodix_wq");
+	INIT_WORK(&ts->work, goodix_ts_work_func);
+
+	ret = gtp_request_irq(ts);
+	if (ret < 0)
+		dev_info(&client->dev, "GTP works in polling mode.\n");
+	else
+		dev_info(&client->dev, "GTP works in interrupt mode.\n");
+
+	ret = gtp_read_version(client, &version_info);
+	if (ret != 2) {
+		dev_err(&client->dev, "Read version failed.\n");
+		goto exit_free_irq;
+	}
+	if (ts->use_irq)
+		gtp_irq_enable(ts);
+
+#if GTP_CREATE_WR_NODE
+	init_wr_node(client);
+#endif
+
+#if GTP_ESD_PROTECT
+	gtp_esd_switch(client, SWITCH_ON);
+#endif
+	init_done = true;
+	return 0;
+exit_free_irq:
+#if defined(CONFIG_FB)
+	if (fb_unregister_client(&ts->fb_notif))
+		dev_err(&client->dev,
+			"Error occurred while unregistering fb_notifier.\n");
+#elif defined(CONFIG_HAS_EARLYSUSPEND)
+	unregister_early_suspend(&ts->early_suspend);
+#endif
+	if (ts->use_irq)
+		free_irq(client->irq, ts);
+	else
+		hrtimer_cancel(&ts->timer);
+	cancel_work_sync(&ts->work);
+	flush_workqueue(ts->goodix_wq);
+	destroy_workqueue(ts->goodix_wq);
+
+	input_unregister_device(ts->input_dev);
+	if (ts->input_dev) {
+		input_free_device(ts->input_dev);
+		ts->input_dev = NULL;
+	}
+exit_free_inputdev:
+	kfree(ts->config_data);
+exit_free_io_port:
+	if (gpio_is_valid(pdata->reset_gpio))
+		gpio_free(pdata->reset_gpio);
+	if (gpio_is_valid(pdata->irq_gpio))
+		gpio_free(pdata->irq_gpio);
+exit_power_off:
+	goodix_power_off(ts);
+exit_deinit_power:
+	goodix_power_deinit(ts);
+exit_free_client_data:
+	i2c_set_clientdata(client, NULL);
+	kfree(ts);
+	return ret;
+}
+
+/*******************************************************
+Function:
+	Goodix touchscreen driver release function.
+Input:
+	client: i2c device struct.
+Output:
+	Executive outcomes. 0---succeed.
+*******************************************************/
+static int goodix_ts_remove(struct i2c_client *client)
+{
+	struct goodix_ts_data *ts = i2c_get_clientdata(client);
+
+	GTP_DEBUG_FUNC();
+#if defined(CONFIG_FB)
+	if (fb_unregister_client(&ts->fb_notif))
+		dev_err(&client->dev,
+			"Error occurred while unregistering fb_notifier.\n");
+#elif defined(CONFIG_HAS_EARLYSUSPEND)
+	unregister_early_suspend(&ts->early_suspend);
+#endif
+
+#if GTP_CREATE_WR_NODE
+	uninit_wr_node();
+#endif
+
+#if GTP_ESD_PROTECT
+	cancel_work_sync(gtp_esd_check_workqueue);
+	flush_workqueue(gtp_esd_check_workqueue);
+	destroy_workqueue(gtp_esd_check_workqueue);
+#endif
+
+	if (ts) {
+		if (ts->use_irq)
+			free_irq(client->irq, ts);
+		else
+			hrtimer_cancel(&ts->timer);
+
+		cancel_work_sync(&ts->work);
+		flush_workqueue(ts->goodix_wq);
+		destroy_workqueue(ts->goodix_wq);
+
+		input_unregister_device(ts->input_dev);
+		if (ts->input_dev) {
+			input_free_device(ts->input_dev);
+			ts->input_dev = NULL;
+		}
+		kfree(ts->config_data);
+
+		if (gpio_is_valid(ts->pdata->reset_gpio))
+			gpio_free(ts->pdata->reset_gpio);
+		if (gpio_is_valid(ts->pdata->irq_gpio))
+			gpio_free(ts->pdata->irq_gpio);
+
+		goodix_power_off(ts);
+		goodix_power_deinit(ts);
+		i2c_set_clientdata(client, NULL);
+		kfree(ts);
+	}
+
+	return 0;
+}
+
+#if defined(CONFIG_HAS_EARLYSUSPEND) || defined(CONFIG_FB)
+/*******************************************************
+Function:
+	Early suspend function.
+Input:
+	h: early_suspend struct.
+Output:
+	None.
+*******************************************************/
+static void goodix_ts_suspend(struct goodix_ts_data *ts)
+{
+	int ret = -1, i;
+
+	GTP_DEBUG_FUNC();
+
+#if GTP_ESD_PROTECT
+	ts->gtp_is_suspend = 1;
+	gtp_esd_switch(ts->client, SWITCH_OFF);
+#endif
+
+#if GTP_SLIDE_WAKEUP
+	ret = gtp_enter_doze(ts);
+#else
+	if (ts->use_irq)
+		gtp_irq_disable(ts);
+	else
+		hrtimer_cancel(&ts->timer);
+
+	for (i = 0; i < GTP_MAX_TOUCH; i++)
+		gtp_touch_up(ts, i);
+
+	input_sync(ts->input_dev);
+
+	ret = gtp_enter_sleep(ts);
+#endif
+	if (ret < 0)
+		dev_err(&ts->client->dev, "GTP early suspend failed.\n");
+	/* to avoid waking up while not sleeping,
+	 * delay 48 + 10ms to ensure reliability
+	 */
+	msleep(58);
+}
+
+/*******************************************************
+Function:
+	Late resume function.
+Input:
+	h: early_suspend struct.
+Output:
+	None.
+*******************************************************/
+static void goodix_ts_resume(struct goodix_ts_data *ts)
+{
+	int ret = -1;
+
+	GTP_DEBUG_FUNC();
+
+	ret = gtp_wakeup_sleep(ts);
+
+#if GTP_SLIDE_WAKEUP
+	doze_status = DOZE_DISABLED;
+#endif
+
+	if (ret < 0)
+		dev_err(&ts->client->dev, "GTP resume failed.\n");
+
+	if (ts->use_irq)
+		gtp_irq_enable(ts);
+	else
+		hrtimer_start(&ts->timer,
+			ktime_set(1, 0), HRTIMER_MODE_REL);
+
+#if GTP_ESD_PROTECT
+	ts->gtp_is_suspend = 0;
+	gtp_esd_switch(ts->client, SWITCH_ON);
+#endif
+}
+
+#if defined(CONFIG_FB)
+static int fb_notifier_callback(struct notifier_block *self,
+				 unsigned long event, void *data)
+{
+	struct fb_event *evdata = data;
+	int *blank;
+	struct goodix_ts_data *ts =
+		container_of(self, struct goodix_ts_data, fb_notif);
+
+	if (evdata && evdata->data && event == FB_EVENT_BLANK &&
+			ts && ts->client) {
+		blank = evdata->data;
+		if (*blank == FB_BLANK_UNBLANK)
+			goodix_ts_resume(ts);
+		else if (*blank == FB_BLANK_POWERDOWN)
+			goodix_ts_suspend(ts);
+	}
+
+	return 0;
+}
+#elif defined(CONFIG_HAS_EARLYSUSPEND)
+/*******************************************************
+Function:
+	Early suspend function.
+Input:
+	h: early_suspend struct.
+Output:
+	None.
+*******************************************************/
+static void goodix_ts_early_suspend(struct early_suspend *h)
+{
+	struct goodix_ts_data *ts;
+
+	ts = container_of(h, struct goodix_ts_data, early_suspend);
+	goodix_ts_suspend(ts);
+	return;
+}
+
+/*******************************************************
+Function:
+	Late resume function.
+Input:
+	h: early_suspend struct.
+Output:
+	None.
+*******************************************************/
+static void goodix_ts_late_resume(struct early_suspend *h)
+{
+	struct goodix_ts_data *ts;
+
+	ts = container_of(h, struct goodix_ts_data, early_suspend);
+	goodix_ts_late_resume(ts);
+	return;
+}
+#endif
+#endif /* !CONFIG_HAS_EARLYSUSPEND && !CONFIG_FB*/
+
+#if GTP_ESD_PROTECT
+/*******************************************************
+Function:
+	switch on & off esd delayed work
+Input:
+	client:  i2c device
+	on:	SWITCH_ON / SWITCH_OFF
+Output:
+	void
+*********************************************************/
+void gtp_esd_switch(struct i2c_client *client, int on)
+{
+	struct goodix_ts_data *ts;
+
+	ts = i2c_get_clientdata(client);
+	if (SWITCH_ON == on) {
+		/* switch on esd  */
+		if (!ts->esd_running) {
+			ts->esd_running = 1;
+			dev_dbg(&client->dev, "Esd started\n");
+			queue_delayed_work(gtp_esd_check_workqueue,
+				&gtp_esd_check_work, GTP_ESD_CHECK_CIRCLE);
+		}
+	} else {
+		/* switch off esd */
+		if (ts->esd_running) {
+			ts->esd_running = 0;
+			dev_dbg(&client->dev, "Esd cancelled\n");
+			cancel_delayed_work_sync(&gtp_esd_check_work);
+		}
+	}
+}
+
+/*******************************************************
+Function:
+	Initialize external watchdog for esd protect
+Input:
+	client:  i2c device.
+Output:
+	result of i2c write operation.
+		1: succeed, otherwise: failed
+*********************************************************/
+static int gtp_init_ext_watchdog(struct i2c_client *client)
+{
+	/* in case of recursively reset by calling gtp_i2c_write*/
+	struct i2c_msg msg;
+	u8 opr_buffer[4] = {0x80, 0x40, 0xAA, 0xAA};
+	int ret;
+	int retries = 0;
+
+	GTP_DEBUG("Init external watchdog...");
+	GTP_DEBUG_FUNC();
+
+	msg.flags = !I2C_M_RD;
+	msg.addr  = client->addr;
+	msg.len   = 4;
+	msg.buf   = opr_buffer;
+
+	while (retries < 5) {
+		ret = i2c_transfer(client->adapter, &msg, 1);
+		if (ret == 1)
+			return 1;
+		retries++;
+	}
+	if (retries >= 5)
+		dev_err(&client->dev, "init external watchdog failed!");
+	return 0;
+}
+
+/*******************************************************
+Function:
+	Esd protect function.
+	Added external watchdog by meta, 2013/03/07
+Input:
+	work: delayed work
+Output:
+	None.
+*******************************************************/
+static void gtp_esd_check_func(struct work_struct *work)
+{
+	s32 i;
+	s32 ret = -1;
+	struct goodix_ts_data *ts = NULL;
+	u8 test[4] = {0x80, 0x40};
+
+	GTP_DEBUG_FUNC();
+
+	ts = i2c_get_clientdata(i2c_connect_client);
+
+	if (ts->gtp_is_suspend) {
+		dev_dbg(&ts->client->dev, "Esd terminated!\n");
+		ts->esd_running = 0;
+		return;
+	}
+#ifdef CONFIG_GT9XX_TOUCHPANEL_UPDATE
+	if (ts->enter_update)
+		return;
+#endif
+
+	for (i = 0; i < 3; i++) {
+		ret = gtp_i2c_read(ts->client, test, 4);
+
+		GTP_DEBUG("0x8040 = 0x%02X, 0x8041 = 0x%02X", test[2], test[3]);
+		if ((ret < 0)) {
+			/* IC works abnormally..*/
+			continue;
+		} else {
+			if ((test[2] == 0xAA) || (test[3] != 0xAA)) {
+				/* IC works abnormally..*/
+				i = 3;
+				break;
+			} else {
+				/* IC works normally, Write 0x8040 0xAA*/
+				test[2] = 0xAA;
+				gtp_i2c_write(ts->client, test, 3);
+				break;
+			}
+		}
+	}
+	if (i >= 3) {
+		dev_err(&ts->client->dev,
+			"IC Working ABNORMALLY, Resetting Guitar...\n");
+		gtp_reset_guitar(ts, 50);
+	}
+
+	if (!ts->gtp_is_suspend)
+		queue_delayed_work(gtp_esd_check_workqueue,
+			&gtp_esd_check_work, GTP_ESD_CHECK_CIRCLE);
+	else {
+		dev_dbg(&ts->client->dev, "Esd terminated!\n");
+		ts->esd_running = 0;
+	}
+
+	return;
+}
+#endif
+
+static const struct i2c_device_id goodix_ts_id[] = {
+	{ GTP_I2C_NAME, 0 },
+	{ }
+};
+
+static struct of_device_id goodix_match_table[] = {
+	{ .compatible = "goodix,gt9xx", },
+	{ },
+};
+
+static struct i2c_driver goodix_ts_driver = {
+	.probe      = goodix_ts_probe,
+	.remove     = goodix_ts_remove,
+#ifdef CONFIG_HAS_EARLYSUSPEND
+	.suspend    = goodix_ts_early_suspend,
+	.resume     = goodix_ts_late_resume,
+#endif
+	.id_table   = goodix_ts_id,
+	.driver = {
+		.name     = GTP_I2C_NAME,
+		.owner    = THIS_MODULE,
+		.of_match_table = goodix_match_table,
+	},
+};
+
+/*******************************************************
+Function:
+    Driver Install function.
+Input:
+    None.
+Output:
+    Executive Outcomes. 0---succeed.
+********************************************************/
+static int __devinit goodix_ts_init(void)
+{
+	int ret;
+
+	GTP_DEBUG_FUNC();
+#if GTP_ESD_PROTECT
+	INIT_DELAYED_WORK(&gtp_esd_check_work, gtp_esd_check_func);
+	gtp_esd_check_workqueue = create_workqueue("gtp_esd_check");
+#endif
+	ret = i2c_add_driver(&goodix_ts_driver);
+	return ret;
+}
+
+/*******************************************************
+Function:
+	Driver uninstall function.
+Input:
+	None.
+Output:
+	Executive Outcomes. 0---succeed.
+********************************************************/
+static void __exit goodix_ts_exit(void)
+{
+	GTP_DEBUG_FUNC();
+	i2c_del_driver(&goodix_ts_driver);
+}
+
+late_initcall(goodix_ts_init);
+module_exit(goodix_ts_exit);
+
+MODULE_DESCRIPTION("GTP Series Driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/input/touchscreen/gt9xx/gt9xx.h b/drivers/input/touchscreen/gt9xx/gt9xx.h
new file mode 100644
index 0000000..c9b81e7
--- /dev/null
+++ b/drivers/input/touchscreen/gt9xx/gt9xx.h
@@ -0,0 +1,280 @@
+/* drivers/input/touchscreen/gt9xx.h
+ *
+ * Copyright (c) 2013, The Linux Foundation. All rights reserved.
+ *
+ * Linux Foundation chooses to take subject only to the GPLv2 license
+ * terms, and distributes only under these terms.
+ *
+ * 2010 - 2013 Goodix Technology.
+ *
+ * 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 a reference
+ * to you, when you are integrating the GOODiX's CTP IC into your system,
+ * 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 _GOODIX_GT9XX_H_
+#define _GOODIX_GT9XX_H_
+
+#include <linux/kernel.h>
+#include <linux/i2c.h>
+#include <linux/irq.h>
+#include <linux/input.h>
+#include <linux/slab.h>
+#include <linux/interrupt.h>
+#include <linux/delay.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/gpio.h>
+#include <linux/regulator/consumer.h>
+#include <linux/firmware.h>
+#include <linux/debugfs.h>
+
+#if defined(CONFIG_FB)
+#include <linux/notifier.h>
+#include <linux/fb.h>
+#elif defined(CONFIG_HAS_EARLYSUSPEND)
+#include <linux/earlysuspend.h>
+#define GOODIX_SUSPEND_LEVEL 1
+#endif
+
+struct goodix_ts_platform_data {
+	int irq_gpio;
+	u32 irq_gpio_flags;
+	int reset_gpio;
+	u32 reset_gpio_flags;
+	u32 family_id;
+	u32 x_max;
+	u32 y_max;
+	u32 x_min;
+	u32 y_min;
+	u32 panel_minx;
+	u32 panel_miny;
+	u32 panel_maxx;
+	u32 panel_maxy;
+	bool no_force_update;
+	bool i2c_pull_up;
+	int gtp_cfg_len;
+	u8 *config_data;
+};
+struct goodix_ts_data {
+	spinlock_t irq_lock;
+	struct i2c_client *client;
+	struct input_dev  *input_dev;
+	struct goodix_ts_platform_data *pdata;
+	struct hrtimer timer;
+	struct workqueue_struct *goodix_wq;
+	struct work_struct	work;
+	s32 irq_is_disabled;
+	s32 use_irq;
+	u16 abs_x_max;
+	u16 abs_y_max;
+	u8  max_touch_num;
+	u8  int_trigger_type;
+	u8  green_wake_mode;
+	u8  chip_type;
+	u8 *config_data;
+	u8  enter_update;
+	u8  gtp_is_suspend;
+	u8  gtp_rawdiff_mode;
+	u8  gtp_cfg_len;
+	u8  fixed_cfg;
+	u8  esd_running;
+	u8  fw_error;
+	struct regulator *avdd;
+	struct regulator *vdd;
+	struct regulator *vcc_i2c;
+#if defined(CONFIG_FB)
+	struct notifier_block fb_notif;
+#elif defined(CONFIG_HAS_EARLYSUSPEND)
+	struct early_suspend early_suspend;
+#endif
+};
+
+extern u16 show_len;
+extern u16 total_len;
+
+/***************************PART1:ON/OFF define*******************************/
+#define GTP_CUSTOM_CFG			0
+#define GTP_CHANGE_X2Y			0
+#define GTP_DRIVER_SEND_CFG		1
+#define GTP_HAVE_TOUCH_KEY		1
+#define GTP_POWER_CTRL_SLEEP	0
+
+/* auto updated by .bin file as default */
+#define GTP_AUTO_UPDATE			0
+/* auto updated by head_fw_array in gt9xx_firmware.h,
+ * function together with GTP_AUTO_UPDATE */
+#define GTP_HEADER_FW_UPDATE	0
+
+#define GTP_CREATE_WR_NODE		0
+#define GTP_ESD_PROTECT			0
+#define GTP_WITH_PEN			0
+
+#define GTP_SLIDE_WAKEUP		0
+/* double-click wakeup, function together with GTP_SLIDE_WAKEUP */
+#define GTP_DBL_CLK_WAKEUP		0
+
+#define GTP_DEBUG_ON			1
+#define GTP_DEBUG_ARRAY_ON		0
+#define GTP_DEBUG_FUNC_ON		0
+
+/*************************** PART2:TODO define *******************************/
+/* STEP_1(REQUIRED): Define Configuration Information Group(s) */
+/* Sensor_ID Map: */
+/* sensor_opt1 sensor_opt2 Sensor_ID
+ *	GND			GND			0
+ *	VDDIO		GND			1
+ *	NC			GND			2
+ *	GND			NC/300K		3
+ *	VDDIO		NC/300K		4
+ *	NC			NC/300K		5
+*/
+/* Define your own default or for Sensor_ID == 0 config here */
+/* The predefined one is just a sample config,
+ * which is not suitable for your tp in most cases. */
+#define CTP_CFG_GROUP1 {\
+	0x41, 0x1C, 0x02, 0xC0, 0x03, 0x0A, 0x05, 0x01, 0x01, 0x0F,\
+	0x23, 0x0F, 0x5F, 0x41, 0x03, 0x05, 0x00, 0x00, 0x00, 0x00,\
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x91, 0x00, 0x0A,\
+	0x28, 0x00, 0xB8, 0x0B, 0x00, 0x00, 0x00, 0x9A, 0x03, 0x25,\
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x64, 0x32, 0x00, 0x00,\
+	0x00, 0x32, 0x8C, 0x94, 0x05, 0x01, 0x05, 0x00, 0x00, 0x96,\
+	0x0C, 0x22, 0xD8, 0x0E, 0x23, 0x56, 0x11, 0x25, 0xFF, 0x13,\
+	0x28, 0xA7, 0x15, 0x2E, 0x00, 0x00, 0x10, 0x30, 0x48, 0x00,\
+	0x56, 0x4A, 0x3A, 0xFF, 0xFF, 0x16, 0x00, 0x00, 0x00, 0x00,\
+	0x00, 0x01, 0x1B, 0x14, 0x0D, 0x19, 0x00, 0x00, 0x01, 0x00,\
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\
+	0x00, 0x00, 0x1A, 0x18, 0x16, 0x14, 0x12, 0x10, 0x0E, 0x0C,\
+	0x0A, 0x08, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,\
+	0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,\
+	0xFF, 0xFF, 0x1D, 0x1E, 0x1F, 0x20, 0x22, 0x24, 0x28, 0x29,\
+	0x0C, 0x0A, 0x08, 0x00, 0x02, 0x04, 0x05, 0x06, 0x0E, 0xFF,\
+	0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,\
+	0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,\
+	0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x91, 0x01\
+	}
+
+/* Define your config for Sensor_ID == 1 here, if needed */
+#define CTP_CFG_GROUP2 {\
+	}
+
+/* Define your config for Sensor_ID == 2 here, if needed */
+#define CTP_CFG_GROUP3 {\
+	}
+
+/* Define your config for Sensor_ID == 3 here, if needed */
+#define CTP_CFG_GROUP4 {\
+	}
+
+/* Define your config for Sensor_ID == 4 here, if needed */
+#define CTP_CFG_GROUP5 {\
+	}
+
+/* Define your config for Sensor_ID == 5 here, if needed */
+#define CTP_CFG_GROUP6 {\
+	}
+
+#define GTP_IRQ_TAB		{\
+				IRQ_TYPE_EDGE_RISING,\
+				IRQ_TYPE_EDGE_FALLING,\
+				IRQ_TYPE_LEVEL_LOW,\
+				IRQ_TYPE_LEVEL_HIGH\
+				}
+
+/* STEP_3(optional): Specify your special config info if needed */
+#define GTP_IRQ_TAB_RISING	0
+#define GTP_IRQ_TAB_FALLING	1
+#if GTP_CUSTOM_CFG
+#define GTP_MAX_HEIGHT		800
+#define GTP_MAX_WIDTH		480
+#define GTP_INT_TRIGGER		GTP_IRQ_TAB_RISING
+#else
+#define GTP_MAX_HEIGHT		4096
+#define GTP_MAX_WIDTH		4096
+#define GTP_INT_TRIGGER		GTP_IRQ_TAB_FALLING
+#endif
+
+#define GTP_MAX_TOUCH         5
+#define GTP_ESD_CHECK_CIRCLE  2000      /* jiffy: ms */
+
+/***************************PART3:OTHER define*********************************/
+#define GTP_DRIVER_VERSION		"V1.8<2013/06/08>"
+#define GTP_I2C_NAME			"Goodix-TS"
+#define GTP_POLL_TIME			10     /* jiffy: ms*/
+#define GTP_ADDR_LENGTH			2
+#define GTP_CONFIG_MIN_LENGTH	186
+#define GTP_CONFIG_MAX_LENGTH	240
+#define FAIL					0
+#define SUCCESS					1
+#define SWITCH_OFF				0
+#define SWITCH_ON				1
+
+/* Registers define */
+#define GTP_READ_COOR_ADDR		0x814E
+#define GTP_REG_SLEEP			0x8040
+#define GTP_REG_SENSOR_ID		0x814A
+#define GTP_REG_CONFIG_DATA		0x8047
+#define GTP_REG_VERSION			0x8140
+
+#define RESOLUTION_LOC			3
+#define TRIGGER_LOC				8
+
+#define CFG_GROUP_LEN(p_cfg_grp) (sizeof(p_cfg_grp) / sizeof(p_cfg_grp[0]))
+/* Log define */
+#define GTP_DEBUG(fmt, arg...)	do {\
+		if (GTP_DEBUG_ON) {\
+			pr_debug("<<-GTP-DEBUG->> [%d]"fmt"\n",\
+				__LINE__, ##arg); } \
+		} while (0)
+
+#define GTP_DEBUG_ARRAY(array, num)    do {\
+		s32 i; \
+		u8 *a = array; \
+		if (GTP_DEBUG_ARRAY_ON) {\
+			pr_debug("<<-GTP-DEBUG-ARRAY->>\n");\
+			for (i = 0; i < (num); i++) { \
+				pr_debug("%02x   ", (a)[i]);\
+				if ((i + 1) % 10 == 0) { \
+					pr_debug("\n");\
+				} \
+			} \
+			pr_debug("\n");\
+		} \
+	} while (0)
+
+#define GTP_DEBUG_FUNC()	do {\
+	if (GTP_DEBUG_FUNC_ON)\
+		pr_debug("<<-GTP-FUNC->> Func:%s@Line:%d\n",\
+					__func__, __LINE__);\
+	} while (0)
+
+#define GTP_SWAP(x, y)		do {\
+					typeof(x) z = x;\
+					x = y;\
+					y = z;\
+				} while (0)
+/*****************************End of Part III********************************/
+
+void gtp_esd_switch(struct i2c_client *client, int on);
+
+#if GTP_CREATE_WR_NODE
+extern s32 init_wr_node(struct i2c_client *client);
+extern void uninit_wr_node(void);
+#endif
+
+#if GTP_AUTO_UPDATE
+extern u8 gup_init_update_proc(struct goodix_ts_data *ts);
+#endif
+#endif /* _GOODIX_GT9XX_H_ */
diff --git a/drivers/input/touchscreen/gt9xx/gt9xx_firmware.h b/drivers/input/touchscreen/gt9xx/gt9xx_firmware.h
new file mode 100644
index 0000000..81e3aff
--- /dev/null
+++ b/drivers/input/touchscreen/gt9xx/gt9xx_firmware.h
@@ -0,0 +1,6 @@
+/*
+ * make sense only when GTP_HEADER_FW_UPDATE & GTP_AUTO_UPDATE are enabled
+ * define your own firmware array here
+*/
+const unsigned char header_fw_array[] = {
+};
diff --git a/drivers/input/touchscreen/gt9xx/gt9xx_update.c b/drivers/input/touchscreen/gt9xx/gt9xx_update.c
new file mode 100644
index 0000000..cf83154
--- /dev/null
+++ b/drivers/input/touchscreen/gt9xx/gt9xx_update.c
@@ -0,0 +1,1777 @@
+/* drivers/input/touchscreen/gt9xx_update.c
+ *
+ * 2010 - 2012 Goodix Technology.
+ * Copyright (c) 2013, The Linux Foundation. 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 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 a reference
+ * to you, when you are integrating the GOODiX's CTP IC into your system,
+ * 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.
+ *
+ * Latest Version:1.6
+ * Author: andrew@goodix.com
+ * Revision Record:
+ *      V1.0:
+ *          first release. By Andrew, 2012/08/31
+ *      V1.2:
+ *          add force update,GT9110P pid map. By Andrew, 2012/10/15
+ *      V1.4:
+ *          1. add config auto update function;
+ *          2. modify enter_update_mode;
+ *          3. add update file cal checksum.
+ *                          By Andrew, 2012/12/12
+ *      V1.6:
+ *          1. replace guitar_client with i2c_connect_client;
+ *          2. support firmware header array update.
+ *                          By Meta, 2013/03/11
+ */
+#include <linux/kthread.h>
+#include "gt9xx.h"
+
+#if GTP_HEADER_FW_UPDATE
+#include <linux/namei.h>
+#include <linux/mount.h>
+#include "gt9xx_firmware.h"
+#endif
+
+#define GUP_REG_HW_INFO             0x4220
+#define GUP_REG_FW_MSG              0x41E4
+#define GUP_REG_PID_VID             0x8140
+
+#define GUP_SEARCH_FILE_TIMES       50
+#define UPDATE_FILE_PATH_2          "/data/_goodix_update_.bin"
+#define UPDATE_FILE_PATH_1          "/sdcard/_goodix_update_.bin"
+
+#define CONFIG_FILE_PATH_1          "/data/_goodix_config_.cfg"
+#define CONFIG_FILE_PATH_2          "/sdcard/_goodix_config_.cfg"
+
+#define FW_HEAD_LENGTH               14
+#define FW_SECTION_LENGTH            0x2000
+#define FW_DSP_ISP_LENGTH            0x1000
+#define FW_DSP_LENGTH                0x1000
+#define FW_BOOT_LENGTH               0x800
+
+#define PACK_SIZE                    256
+#define MAX_FRAME_CHECK_TIME         5
+
+#define _bRW_MISCTL__SRAM_BANK       0x4048
+#define _bRW_MISCTL__MEM_CD_EN       0x4049
+#define _bRW_MISCTL__CACHE_EN        0x404B
+#define _bRW_MISCTL__TMR0_EN         0x40B0
+#define _rRW_MISCTL__SWRST_B0_       0x4180
+#define _bWO_MISCTL__CPU_SWRST_PULSE 0x4184
+#define _rRW_MISCTL__BOOTCTL_B0_     0x4190
+#define _rRW_MISCTL__BOOT_OPT_B0_    0x4218
+#define _rRW_MISCTL__BOOT_CTL_       0x5094
+
+#define FAIL    0
+#define SUCCESS 1
+
+#pragma pack(1)
+struct {
+	u8  hw_info[4];		/* hardware info */
+	u8  pid[8];		/* product id   */
+	u16 vid;		/* version id   */
+} st_fw_head;
+#pragma pack()
+
+struct {
+	u8 force_update;
+	u8 fw_flag;
+	struct file *file;
+	struct file *cfg_file;
+	st_fw_head  ic_fw_msg;
+	mm_segment_t old_fs;
+} st_update_msg;
+
+st_update_msg update_msg;
+u16 show_len;
+u16 total_len;
+u8 got_file_flag;
+u8 searching_file;
+/*******************************************************
+Function:
+    Read data from the i2c slave device.
+Input:
+    client:     i2c device.
+    buf[0~1]:   read start address.
+    buf[2~len-1]:   read data buffer.
+    len:    GTP_ADDR_LENGTH + read bytes count
+Output:
+    numbers of i2c_msgs to transfer:
+      2: succeed, otherwise: failed
+*********************************************************/
+s32 gup_i2c_read(struct i2c_client *client, u8 *buf, s32 len)
+{
+	struct i2c_msg msgs[2];
+	s32 ret = -1;
+	s32 retries = 0;
+
+	GTP_DEBUG_FUNC();
+
+	msgs[0].flags = !I2C_M_RD;
+	msgs[0].addr  = client->addr;
+	msgs[0].len   = GTP_ADDR_LENGTH;
+	msgs[0].buf   = &buf[0];
+	/* msgs[0].scl_rate = 300 * 1000;  (for Rockchip) */
+
+	msgs[1].flags = I2C_M_RD;
+	msgs[1].addr  = client->addr;
+	msgs[1].len   = len - GTP_ADDR_LENGTH;
+	msgs[1].buf   = &buf[GTP_ADDR_LENGTH];
+	/* msgs[1].scl_rate = 300 * 1000; */
+
+	while (retries < 5) {
+		ret = i2c_transfer(client->adapter, msgs, 2);
+		if (ret == 2)
+			break;
+		retries++;
+	}
+
+	return ret;
+}
+
+/*******************************************************
+Function:
+    Write data to the i2c slave device.
+Input:
+    client:     i2c device.
+    buf[0~1]:   write start address.
+    buf[2~len-1]:   data buffer
+    len:    GTP_ADDR_LENGTH + write bytes count
+Output:
+    numbers of i2c_msgs to transfer:
+	1: succeed, otherwise: failed
+*********************************************************/
+s32 gup_i2c_write(struct i2c_client *client, u8 *buf, s32 len)
+{
+	struct i2c_msg msg;
+	s32 ret = -1;
+	s32 retries = 0;
+
+	GTP_DEBUG_FUNC();
+
+	msg.flags = !I2C_M_RD;
+	msg.addr  = client->addr;
+	msg.len   = len;
+	msg.buf   = buf;
+	/* msg.scl_rate = 300 * 1000;    (for Rockchip) */
+
+	while (retries < 5) {
+		ret = i2c_transfer(client->adapter, &msg, 1);
+		if (ret == 1)
+			break;
+		retries++;
+	}
+
+	return ret;
+}
+
+static s32 gup_init_panel(struct goodix_ts_data *ts)
+{
+	s32 ret = 0;
+	s32 i = 0;
+	u8 check_sum = 0;
+	u8 opr_buf[16];
+	u8 sensor_id = 0;
+
+	u8 cfg_info_group1[] = CTP_CFG_GROUP1;
+	u8 cfg_info_group2[] = CTP_CFG_GROUP2;
+	u8 cfg_info_group3[] = CTP_CFG_GROUP3;
+	u8 cfg_info_group4[] = CTP_CFG_GROUP4;
+	u8 cfg_info_group5[] = CTP_CFG_GROUP5;
+	u8 cfg_info_group6[] = CTP_CFG_GROUP6;
+	u8 *send_cfg_buf[] = {cfg_info_group1, cfg_info_group2, cfg_info_group3,
+			cfg_info_group4, cfg_info_group5, cfg_info_group6};
+	u8 cfg_info_len[] = { CFG_GROUP_LEN(cfg_info_group1),
+			CFG_GROUP_LEN(cfg_info_group2),
+			CFG_GROUP_LEN(cfg_info_group3),
+			CFG_GROUP_LEN(cfg_info_group4),
+			CFG_GROUP_LEN(cfg_info_group5),
+			CFG_GROUP_LEN(cfg_info_group6)};
+
+	if ((!cfg_info_len[1]) && (!cfg_info_len[2]) &&
+	(!cfg_info_len[3]) && (!cfg_info_len[4]) &&
+	(!cfg_info_len[5])) {
+		sensor_id = 0;
+	} else {
+		ret = gtp_i2c_read_dbl_check(ts->client, GTP_REG_SENSOR_ID,
+							&sensor_id, 1);
+		if (SUCCESS == ret) {
+			if (sensor_id >= 0x06) {
+				GTP_ERROR("Invalid sensor_id(0x%02X), " \
+					"No Config Sent!", sensor_id);
+				return -EINVAL;
+			}
+		} else {
+			GTP_ERROR("Failed to get sensor_id, No config sent!");
+			return -EINVAL;
+		}
+	}
+
+	GTP_DEBUG("Sensor_ID: %d", sensor_id);
+
+	ts->gtp_cfg_len = cfg_info_len[sensor_id];
+
+	if (ts->gtp_cfg_len < GTP_CONFIG_MIN_LENGTH) {
+		GTP_ERROR("Sensor_ID(%d) matches with NULL or INVALID CONFIG" \
+			" GROUP! NO Config Sent! You need to check you header" \
+			"  file CFG_GROUP section!", sensor_id);
+		return -EINVAL;
+	}
+
+	ret = gtp_i2c_read_dbl_check(ts->client, GTP_REG_CONFIG_DATA,
+					&opr_buf[0], 1);
+
+	if (ret == SUCCESS) {
+		GTP_DEBUG("CFG_GROUP%d Config Version: %d, IC Config Version:" \
+		" %d", sensor_id+1, send_cfg_buf[sensor_id][0],	opr_buf[0]);
+
+		send_cfg_buf[sensor_id][0] = opr_buf[0];
+		ts->fixed_cfg = 0;
+		/*
+		if (opr_buf[0] < 90) {
+			grp_cfg_version = send_cfg_buf[sensor_id][0];
+				*** backup group config version ***
+			send_cfg_buf[sensor_id][0] = 0x00;
+			ts->fixed_cfg = 0;
+		} else { *** treated as fixed config, not send config ***
+			GTP_INFO("Ic fixed config with config version(%d)",
+							opr_buf[0]);
+			ts->fixed_cfg = 1;
+		}*/
+	} else {
+		GTP_ERROR("Failed to get ic config version!No config sent!");
+		return -EINVAL;
+	}
+
+	memset(&config[GTP_ADDR_LENGTH], 0, GTP_CONFIG_MAX_LENGTH);
+	memcpy(&config[GTP_ADDR_LENGTH], send_cfg_buf[sensor_id],
+						ts->gtp_cfg_len);
+
+	GTP_DEBUG("X_MAX = %d, Y_MAX = %d, TRIGGER = 0x%02x",
+	ts->abs_x_max, ts->abs_y_max, ts->int_trigger_type);
+
+	config[RESOLUTION_LOC]     = (u8)GTP_MAX_WIDTH;
+	config[RESOLUTION_LOC + 1] = (u8)(GTP_MAX_WIDTH>>8);
+	config[RESOLUTION_LOC + 2] = (u8)GTP_MAX_HEIGHT;
+	config[RESOLUTION_LOC + 3] = (u8)(GTP_MAX_HEIGHT>>8);
+
+	if (GTP_INT_TRIGGER == 0)  /* RISING */
+		config[TRIGGER_LOC] &= 0xfe;
+	else if (GTP_INT_TRIGGER == 1)  /* FALLING */
+		config[TRIGGER_LOC] |= 0x01;
+
+	check_sum = 0;
+	for (i = GTP_ADDR_LENGTH; i < ts->gtp_cfg_len; i++)
+		check_sum += config[i];
+
+	config[ts->gtp_cfg_len] = (~check_sum) + 1;
+
+	GTP_DEBUG_FUNC();
+	ret = gtp_send_cfg(ts->client);
+	if (ret < 0)
+		GTP_ERROR("Send config error.");
+
+	msleep(20);
+	return 0;
+}
+
+
+static u8 gup_get_ic_msg(struct i2c_client *client, u16 addr, u8 *msg, s32 len)
+{
+	s32 i = 0;
+
+	msg[0] = (addr >> 8) & 0xff;
+	msg[1] = addr & 0xff;
+
+	for (i = 0; i < 5; i++)
+		if (gup_i2c_read(client, msg, GTP_ADDR_LENGTH + len) > 0)
+			break;
+
+	if (i >= 5) {
+		GTP_ERROR("Read data from 0x%02x%02x failed!", msg[0], msg[1]);
+		return FAIL;
+	}
+
+	return SUCCESS;
+}
+
+static u8 gup_set_ic_msg(struct i2c_client *client, u16 addr, u8 val)
+{
+	s32 i = 0;
+	u8 msg[3];
+
+	msg[0] = (addr >> 8) & 0xff;
+	msg[1] = addr & 0xff;
+	msg[2] = val;
+
+	for (i = 0; i < 5; i++)
+		if (gup_i2c_write(client, msg, GTP_ADDR_LENGTH + 1) > 0)
+			break;
+
+	if (i >= 5) {
+		GTP_ERROR("Set data to 0x%02x%02x failed!", msg[0], msg[1]);
+		return FAIL;
+	}
+
+	return SUCCESS;
+}
+
+static u8 gup_get_ic_fw_msg(struct i2c_client *client)
+{
+	s32 ret = -1;
+	u8  retry = 0;
+	u8  buf[16];
+	u8  i;
+
+	/* step1:get hardware info */
+	ret = gtp_i2c_read_dbl_check(client, GUP_REG_HW_INFO,
+					&buf[GTP_ADDR_LENGTH], 4);
+	if (ret == FAIL) {
+		GTP_ERROR("[get_ic_fw_msg]get hw_info failed,exit");
+		return FAIL;
+	}
+
+	/*  buf[2~5]: 00 06 90 00 */
+	/* hw_info: 00 90 06 00 */
+	for (i = 0; i < 4; i++)
+		update_msg.ic_fw_msg.hw_info[i] = buf[GTP_ADDR_LENGTH + 3 - i];
+
+	GTP_DEBUG("IC Hardware info:%02x%02x%02x%02x",
+		update_msg.ic_fw_msg.hw_info[0],
+		update_msg.ic_fw_msg.hw_info[1],
+		update_msg.ic_fw_msg.hw_info[2],
+		update_msg.ic_fw_msg.hw_info[3]);
+
+	/* step2:get firmware message */
+	for (retry = 0; retry < 2; retry++) {
+		ret = gup_get_ic_msg(client, GUP_REG_FW_MSG, buf, 1);
+		if (ret == FAIL) {
+			GTP_ERROR("Read firmware message fail.");
+			return ret;
+		}
+
+		update_msg.force_update = buf[GTP_ADDR_LENGTH];
+		if ((0xBE != update_msg.force_update) && (!retry)) {
+			GTP_INFO("The check sum in ic is error.");
+			GTP_INFO("The IC will be updated by force.");
+			continue;
+		}
+		break;
+	}
+	GTP_DEBUG("IC force update flag:0x%x", update_msg.force_update);
+
+	/*  step3:get pid & vid */
+	ret = gtp_i2c_read_dbl_check(client, GUP_REG_PID_VID,
+						&buf[GTP_ADDR_LENGTH], 6);
+	if (FAIL == ret) {
+		GTP_ERROR("[get_ic_fw_msg]get pid & vid failed,exit");
+		return FAIL;
+	}
+
+	memset(update_msg.ic_fw_msg.pid, 0, sizeof(update_msg.ic_fw_msg.pid));
+	memcpy(update_msg.ic_fw_msg.pid, &buf[GTP_ADDR_LENGTH], 4);
+	GTP_DEBUG("IC Product id:%s", update_msg.ic_fw_msg.pid);
+
+	/* GT9XX PID MAPPING
+	|-----FLASH-----RAM-----|
+	|------918------918-----|
+	|------968------968-----|
+	|------913------913-----|
+	|------913P-----913P----|
+	|------927------927-----|
+	|------927P-----927P----|
+	|------9110-----9110----|
+	|------9110P----9111----|*/
+	if (update_msg.ic_fw_msg.pid[0] != 0) {
+		if (!memcmp(update_msg.ic_fw_msg.pid, "9111", 4)) {
+			GTP_DEBUG("IC Mapping Product id:%s",
+					update_msg.ic_fw_msg.pid);
+			memcpy(update_msg.ic_fw_msg.pid, "9110P", 5);
+		}
+	}
+
+	update_msg.ic_fw_msg.vid = buf[GTP_ADDR_LENGTH + 4] +
+				(buf[GTP_ADDR_LENGTH + 5] << 8);
+	GTP_DEBUG("IC version id:%04x", update_msg.ic_fw_msg.vid);
+
+	return SUCCESS;
+}
+
+s32 gup_enter_update_mode(struct i2c_client *client)
+{
+	s32 ret = -1;
+	s32 retry = 0;
+	u8 rd_buf[3];
+
+	/* step1:RST output low last at least 2ms */
+	GTP_GPIO_OUTPUT(GTP_RST_PORT, 0);
+	msleep(20);
+
+	/* step2:select I2C slave addr,INT:0--0xBA;1--0x28. */
+	GTP_GPIO_OUTPUT(GTP_INT_PORT, (client->addr == 0x14));
+	msleep(20);
+
+	/* step3:RST output high reset guitar */
+	GTP_GPIO_OUTPUT(GTP_RST_PORT, 1);
+
+	/* 20121211 modify start */
+	msleep(20);
+	while (retry++ < 200) {
+		/* step4:Hold ss51 & dsp */
+		ret = gup_set_ic_msg(client, _rRW_MISCTL__SWRST_B0_, 0x0C);
+		if (ret <= 0) {
+			GTP_DEBUG("Hold ss51 & dsp I2C error,retry:%d", retry);
+			continue;
+		}
+
+		/* step5:Confirm hold */
+		ret = gup_get_ic_msg(client, _rRW_MISCTL__SWRST_B0_, rd_buf, 1);
+		if (ret <= 0) {
+			GTP_DEBUG("Hold ss51 & dsp I2C error,retry:%d", retry);
+			continue;
+		}
+		if (rd_buf[GTP_ADDR_LENGTH] == 0x0C) {
+			GTP_DEBUG("Hold ss51 & dsp confirm SUCCESS");
+			break;
+		}
+		GTP_DEBUG("Hold ss51 & dsp confirm 0x4180 failed,value:%d",
+					rd_buf[GTP_ADDR_LENGTH]);
+	}
+	if (retry >= 200) {
+		GTP_ERROR("Enter update Hold ss51 failed.");
+		return FAIL;
+	}
+
+	/* step6:DSP_CK and DSP_ALU_CK PowerOn */
+	ret = gup_set_ic_msg(client, 0x4010, 0x00);
+
+	/* 20121211 modify end */
+	return ret;
+}
+
+void gup_leave_update_mode(void)
+{
+	GTP_GPIO_AS_INT(GTP_INT_PORT);
+
+	GTP_DEBUG("[leave_update_mode]reset chip.");
+	gtp_reset_guitar(i2c_connect_client, 20);
+}
+
+/*	Get the correct nvram data
+	The correct conditions:
+	1. the hardware info is the same
+	2. the product id is the same
+	3. the firmware version in update file is greater than the firmware
+	version in ic or the check sum in ic is wrong
+
+	Update Conditions:
+	1. Same hardware info
+	2. Same PID
+	3. File PID > IC PID
+
+	Force Update Conditions:
+	1. Wrong ic firmware checksum
+	2. INVALID IC PID or VID
+	3. IC PID == 91XX || File PID == 91XX
+*/
+
+static u8 gup_enter_update_judge(st_fw_head *fw_head)
+{
+	u16 u16_tmp;
+	s32 i = 0;
+
+	u16_tmp = fw_head->vid;
+	fw_head->vid = (u16)(u16_tmp>>8) + (u16)(u16_tmp<<8);
+
+	GTP_DEBUG("FILE HARDWARE INFO:%02x%02x%02x%02x", fw_head->hw_info[0],
+		fw_head->hw_info[1], fw_head->hw_info[2], fw_head->hw_info[3]);
+	TP_DEBUG("FILE PID:%s", fw_head->pid);
+	TP_DEBUG("FILE VID:%04x", fw_head->vid);
+
+	TP_DEBUG("IC HARDWARE INFO:%02x%02x%02x%02x",
+		update_msg.ic_fw_msg.hw_info[0],
+		update_msg.ic_fw_msg.hw_info[1],
+		update_msg.ic_fw_msg.hw_info[2],
+		update_msg.ic_fw_msg.hw_info[3]);
+	TP_DEBUG("IC PID:%s", update_msg.ic_fw_msg.pid);
+	TP_DEBUG("IC VID:%04x", update_msg.ic_fw_msg.vid);
+
+	/* First two conditions */
+	if (!memcmp(fw_head->hw_info, update_msg.ic_fw_msg.hw_info,
+			sizeof(update_msg.ic_fw_msg.hw_info))) {
+		GTP_DEBUG("Get the same hardware info.");
+		if (update_msg.force_update != 0xBE) {
+			GTP_INFO("FW chksum error,need enter update.");
+			return SUCCESS;
+		}
+
+		/* 20130523 start */
+		if (strlen(update_msg.ic_fw_msg.pid) < 3) {
+			GTP_INFO("Illegal IC pid, need enter update");
+			return SUCCESS;
+		} else {
+			for (i = 0; i < 3; i++) {
+				if ((update_msg.ic_fw_msg.pid[i] < 0x30) ||
+					(update_msg.ic_fw_msg.pid[i] > 0x39)) {
+					GTP_INFO("Illegal IC pid, out of " \
+					"bound, need enter update");
+					return SUCCESS;
+				}
+			}
+		}
+		/* 20130523 end */
+
+		if ((!memcmp(fw_head->pid, update_msg.ic_fw_msg.pid,
+		(strlen(fw_head->pid) < 3 ? 3 : strlen(fw_head->pid)))) ||
+		(!memcmp(update_msg.ic_fw_msg.pid, "91XX", 4)) ||
+		(!memcmp(fw_head->pid, "91XX", 4))) {
+			if (!memcmp(fw_head->pid, "91XX", 4))
+				GTP_DEBUG("Force none same pid update mode.");
+			else
+				GTP_DEBUG("Get the same pid.");
+
+			/* The third condition */
+			if (fw_head->vid > update_msg.ic_fw_msg.vid) {
+				GTP_INFO("Need enter update.");
+				return SUCCESS;
+			}
+			GTP_ERROR("Don't meet the third condition.");
+			GTP_ERROR("File VID <= Ic VID, update aborted!");
+		} else {
+			GTP_ERROR("File PID != Ic PID, update aborted!");
+		}
+	} else {
+		GTP_ERROR("Different Hardware, update aborted!");
+	}
+
+	return FAIL;
+}
+
+static u8 ascii2hex(u8 a)
+{
+	s8 value = 0;
+
+	if (a >= '0' && a <= '9')
+		value = a - '0';
+	else if (a >= 'A' && a <= 'F')
+		value = a - 'A' + 0x0A;
+	else if (a >= 'a' && a <= 'f')
+		value = a - 'a' + 0x0A;
+	else
+		value = 0xff;
+
+	return value;
+}
+
+static s8 gup_update_config(struct i2c_client *client)
+{
+	s32 file_len = 0;
+	s32 ret = 0;
+	s32 i = 0;
+	s32 file_cfg_len = 0;
+	s32 chip_cfg_len = 0;
+	s32 count = 0;
+	u8 *buf;
+	u8 *pre_buf;
+	u8 *file_config;
+	/* u8 checksum = 0; */
+	u8 pid[8];
+
+	if (update_msg.cfg_file == NULL) {
+		GTP_ERROR("[update_cfg]No need to upgrade config!");
+		return FAIL;
+	}
+	file_len = update_msg.cfg_file->f_op->llseek(update_msg.cfg_file,
+							0, SEEK_END);
+
+	ret = gup_get_ic_msg(client, GUP_REG_PID_VID, pid, 6);
+	if (ret == FAIL) {
+		GTP_ERROR("[update_cfg]Read product id & version id fail.");
+		return FAIL;
+	}
+	pid[5] = '\0';
+	GTP_DEBUG("update cfg get pid:%s", &pid[GTP_ADDR_LENGTH]);
+
+	chip_cfg_len = 186;
+	if (!memcmp(&pid[GTP_ADDR_LENGTH], "968", 3) ||
+	!memcmp(&pid[GTP_ADDR_LENGTH], "910", 3) ||
+	!memcmp(&pid[GTP_ADDR_LENGTH], "960", 3)) {
+		chip_cfg_len = 228;
+	}
+	GTP_DEBUG("[update_cfg]config file len:%d", file_len);
+	GTP_DEBUG("[update_cfg]need config len:%d", chip_cfg_len);
+	if ((file_len+5) < chip_cfg_len*5) {
+		GTP_ERROR("Config length error");
+		return -EINVAL;
+	}
+
+	buf = kzalloc(file_len, GFP_KERNEL);
+	pre_buf = kzalloc(file_len, GFP_KERNEL);
+	file_config = kzalloc(chip_cfg_len + GTP_ADDR_LENGTH, GFP_KERNEL);
+	update_msg.cfg_file->f_op->llseek(update_msg.cfg_file, 0, SEEK_SET);
+
+	GTP_DEBUG("[update_cfg]Read config from file.");
+	ret = update_msg.cfg_file->f_op->read(update_msg.cfg_file,
+			(char *)pre_buf, file_len, &update_msg.cfg_file->f_pos);
+	if (ret < 0) {
+		GTP_ERROR("[update_cfg]Read config file failed.");
+		goto update_cfg_file_failed;
+	}
+
+	GTP_DEBUG("[update_cfg]Delete illgal charactor.");
+	for (i = 0, count = 0; i < file_len; i++) {
+		if (pre_buf[i] == ' ' || pre_buf[i] == '\r'
+					|| pre_buf[i] == '\n')
+			continue;
+		buf[count++] = pre_buf[i];
+	}
+
+	GTP_DEBUG("[update_cfg]Ascii to hex.");
+	file_config[0] = GTP_REG_CONFIG_DATA >> 8;
+	file_config[1] = GTP_REG_CONFIG_DATA & 0xff;
+	for (i = 0, file_cfg_len = GTP_ADDR_LENGTH; i < count; i + = 5) {
+		if ((buf[i] == '0') && ((buf[i+1] == 'x') ||
+						(buf[i+1] == 'X'))) {
+			u8 high, low;
+			high = ascii2hex(buf[i+2]);
+			low = ascii2hex(buf[i+3]);
+
+			if ((high == 0xFF) || (low == 0xFF)) {
+				ret = 0;
+				GTP_ERROR("[update_cfg]Illegal config file.");
+				goto update_cfg_file_failed;
+			}
+			file_config[file_cfg_len++] = (high<<4) + low;
+		} else {
+			ret = 0;
+			GTP_ERROR("[update_cfg]Illegal config file.");
+			goto update_cfg_file_failed;
+		}
+	}
+
+	/* cal checksum */
+	/* for(i=GTP_ADDR_LENGTH; i<chip_cfg_len; i++)
+		checksum += file_config[i];
+	file_config[chip_cfg_len] = (~checksum) + 1;
+	file_config[chip_cfg_len+1] = 0x01; */
+
+	GTP_DEBUG("config:");
+	GTP_DEBUG_ARRAY(file_config+2, file_cfg_len);
+
+	i = 0;
+	while (i++ < 5) {
+		ret = gup_i2c_write(client, file_config, file_cfg_len);
+		if (ret > 0) {
+			GTP_INFO("[update_cfg]Send config SUCCESS.");
+			break;
+		}
+		GTP_ERROR("[update_cfg]Send config i2c error.");
+	}
+
+update_cfg_file_failed:
+	kfree(pre_buf);
+	kfree(buf);
+	kfree(file_config);
+	return ret;
+}
+
+#if GTP_HEADER_FW_UPDATE
+static u8 gup_check_fs_mounted(char *path_name)
+{
+	struct path root_path;
+	struct path path;
+	int err;
+	err = kern_path("/", LOOKUP_FOLLOW, &root_path);
+
+	if (err) {
+		GTP_DEBUG("\"/\" NOT Mounted: %d", err);
+		return FAIL;
+	}
+	err = kern_path(path_name, LOOKUP_FOLLOW, &path);
+
+	if (err) {
+		GTP_DEBUG("/data/ NOT Mounted: %d", err);
+		return FAIL;
+	}
+
+	return SUCCESS;
+
+	/* if (path.mnt->mnt_sb == root_path.mnt->mnt_sb)
+		return FAIL;
+	else
+		return SUCCESS; */
+}
+#endif
+
+static u8 gup_check_update_file(struct i2c_client *client, st_fw_head *fw_head,
+								u8 *path)
+{
+	s32 ret = 0;
+	s32 i = 0;
+	s32 fw_checksum = 0;
+	u8 buf[FW_HEAD_LENGTH];
+
+	if (path) {
+		GTP_DEBUG("Update File path:%s, %d", path, strlen(path));
+		update_msg.file = file_open(path, O_RDONLY, 0);
+
+		if (IS_ERR(update_msg.file)) {
+			GTP_ERROR("Open update file(%s) error!", path);
+			return FAIL;
+		}
+	} else {
+#if GTP_HEADER_FW_UPDATE
+		for (i = 0; i < (GUP_SEARCH_FILE_TIMES); i++) {
+			GTP_DEBUG("Waiting for /data mounted [%d]", i);
+
+			if (gup_check_fs_mounted("/data") == SUCCESS) {
+				GTP_DEBUG("/data Mounted!");
+				break;
+			}
+			msleep(3000);
+		}
+		if (i >= (GUP_SEARCH_FILE_TIMES)) {
+			GTP_ERROR("Wait for /data mounted timeout!");
+			return FAIL;
+		}
+
+		/* update config */
+		update_msg.cfg_file = file_open(CONFIG_FILE_PATH_1,
+							O_RDONLY, 0);
+
+		if (IS_ERR(update_msg.cfg_file)) {
+			GTP_DEBUG("%s is unavailable", CONFIG_FILE_PATH_1);
+		} else {
+			GTP_INFO("Update Config File: %s", CONFIG_FILE_PATH_1);
+			ret = gup_update_config(client);
+			if (ret <= 0)
+				GTP_ERROR("Update config failed.");
+			filp_close(update_msg.cfg_file, NULL);
+		}
+
+		if (sizeof(header_fw_array) < (FW_HEAD_LENGTH+FW_SECTION_LENGTH
+		*4 + FW_DSP_ISP_LENGTH+FW_DSP_LENGTH + FW_BOOT_LENGTH)) {
+			GTP_ERROR("INVALID header_fw_array, check your " \
+				"gt9xx_firmware.h file!");
+			return FAIL;
+		}
+		update_msg.file = file_open(UPDATE_FILE_PATH_2, O_CREAT |
+								O_RDWR, 0666);
+		if ((IS_ERR(update_msg.file))) {
+			GTP_ERROR("Failed to Create file: %s for fw_header!",
+							UPDATE_FILE_PATH_2);
+			return FAIL;
+		}
+		update_msg.file->f_op->llseek(update_msg.file, 0, SEEK_SET);
+		update_msg.file->f_op->write(update_msg.file,
+			(char *)header_fw_array, sizeof(header_fw_array),
+			&update_msg.file->f_pos);
+		file_close(update_msg.file, NULL);
+		update_msg.file = file_open(UPDATE_FILE_PATH_2, O_RDONLY, 0);
+#else
+		u8 fp_len = max(sizeof(UPDATE_FILE_PATH_1),
+						sizeof(UPDATE_FILE_PATH_2));
+		u8 cfp_len = max(sizeof(CONFIG_FILE_PATH_1),
+						sizeof(CONFIG_FILE_PATH_2));
+		u8 *search_update_path = kzalloc(fp_len, GFP_KERNEL);
+		u8 *search_cfg_path = kzalloc(cfp_len, GFP_KERNEL);
+		/* Begin to search update file,the config file & firmware
+			file must be in the same path,single or double. */
+		searching_file = 1;
+		for (i = 0; i < GUP_SEARCH_FILE_TIMES; i++) {
+			if (searching_file == 0) {
+				kfree(search_update_path);
+				kfree(search_cfg_path);
+				GTP_INFO(".bin/.cfg update file search " \
+						"forcely terminated!");
+				return FAIL;
+			}
+			if (i % 2) {
+				memcpy(search_update_path, UPDATE_FILE_PATH_1,
+						sizeof(UPDATE_FILE_PATH_1));
+				memcpy(search_cfg_path, CONFIG_FILE_PATH_1,
+						sizeof(CONFIG_FILE_PATH_1));
+			} else {
+				memcpy(search_update_path, UPDATE_FILE_PATH_2,
+						sizeof(UPDATE_FILE_PATH_2));
+				memcpy(search_cfg_path, CONFIG_FILE_PATH_2,
+						sizeof(CONFIG_FILE_PATH_2));
+			}
+
+			if (!(got_file_flag&0x0F)) {
+				update_msg.file = file_open(search_update_path,
+						O_RDONLY, 0);
+				if (!IS_ERR(update_msg.file)) {
+					GTP_DEBUG("Find the bin file");
+					got_file_flag |= 0x0F;
+				}
+			}
+			if (!(got_file_flag & 0xF0)) {
+				update_msg.cfg_file = file_open(search_cfg_path,
+						O_RDONLY, 0);
+				if (!IS_ERR(update_msg.cfg_file)) {
+					GTP_DEBUG("Find the cfg file");
+					got_file_flag |= 0xF0;
+				}
+			}
+
+			if (got_file_flag) {
+				if (got_file_flag == 0xFF)
+					break;
+				else
+					i += 4;
+			}
+			GTP_DEBUG("%3d:Searching %s %s file...", i,
+			(got_file_flag & 0x0F) ? "" : "bin",
+			(got_file_flag & 0xF0) ? "" : "cfg");
+
+			msleep(3000);
+		}
+
+		searching_file = 0;
+		kfree(search_update_path);
+		kfree(search_cfg_path);
+
+		if (!got_file_flag) {
+			GTP_ERROR("Can't find update file.");
+			goto load_failed;
+		}
+
+		if (got_file_flag & 0xF0) {
+			GTP_DEBUG("Got the update config file.");
+			ret = gup_update_config(client);
+			if (ret <= 0)
+				GTP_ERROR("Update config failed.");
+			filp_close(update_msg.cfg_file, NULL);
+			msleep(500); /* waiting config to be stored in FLASH. */
+		}
+		if (got_file_flag & 0x0F) {
+			GTP_DEBUG("Got the update firmware file.");
+		} else {
+			GTP_ERROR("No need to upgrade firmware.");
+			goto load_failed;
+		}
+#endif
+	}
+
+	update_msg.old_fs = get_fs();
+	set_fs(KERNEL_DS);
+
+	update_msg.file->f_op->llseek(update_msg.file, 0, SEEK_SET);
+	/* update_msg.file->f_pos = 0; */
+
+	ret = update_msg.file->f_op->read(update_msg.file, (char *)buf,
+				FW_HEAD_LENGTH, &update_msg.file->f_pos);
+	if (ret < 0) {
+		GTP_ERROR("Read firmware head in update file error.");
+		goto load_failed;
+	}
+	memcpy(fw_head, buf, FW_HEAD_LENGTH);
+
+	/* check firmware legality */
+	fw_checksum = 0;
+	for (i = 0; i < FW_SECTION_LENGTH * 4 + FW_DSP_ISP_LENGTH +
+			FW_DSP_LENGTH + FW_BOOT_LENGTH; i + = 2) {
+		u16 temp;
+		ret = update_msg.file->f_op->read(update_msg.file, (char *)buf,
+						2, &update_msg.file->f_pos);
+		if (ret < 0) {
+			GTP_ERROR("Read firmware file error.");
+			goto load_failed;
+		}
+		/* GTP_DEBUG("BUF[0]:%x", buf[0]); */
+		temp = (buf[0]<<8) + buf[1];
+		fw_checksum += temp;
+	}
+
+	GTP_DEBUG("firmware checksum:%x", fw_checksum&0xFFFF);
+	if (fw_checksum & 0xFFFF) {
+		GTP_ERROR("Illegal firmware file.");
+		goto load_failed;
+	}
+
+	return SUCCESS;
+
+load_failed:
+	set_fs(update_msg.old_fs);
+	return FAIL;
+}
+
+#if 0
+static u8 gup_check_update_header(struct i2c_client *client,
+			st_fw_head *fw_head)
+{
+	const u8 *pos;
+	int i = 0;
+	u8 mask_num = 0;
+	s32 ret = 0;
+
+	pos = HEADER_UPDATE_DATA;
+
+	memcpy(fw_head, pos, FW_HEAD_LENGTH);
+	pos += FW_HEAD_LENGTH;
+
+	ret = gup_enter_update_judge(fw_head);
+	if (SUCCESS == ret)
+		return SUCCESS;
+	return FAIL;
+}
+#endif
+
+static u8 gup_burn_proc(struct i2c_client *client, u8 *burn_buf, u16 start_addr,
+							u16 total_length)
+{
+	s32 ret = 0;
+	u16 burn_addr = start_addr;
+	u16 frame_length = 0;
+	u16 burn_length = 0;
+	u8  wr_buf[PACK_SIZE + GTP_ADDR_LENGTH];
+	u8  rd_buf[PACK_SIZE + GTP_ADDR_LENGTH];
+	u8  retry = 0;
+
+	GTP_DEBUG("Begin burn %dk data to addr 0x%x", (total_length/1024),
+								start_addr);
+	while (burn_length < total_length) {
+		GTP_DEBUG("B/T:%04d/%04d", burn_length, total_length);
+		frame_length = ((total_length - burn_length) > PACK_SIZE)
+				? PACK_SIZE : (total_length - burn_length);
+		wr_buf[0] = (u8)(burn_addr>>8);
+		rd_buf[0] = wr_buf[0];
+		wr_buf[1] = (u8)burn_addr;
+		rd_buf[1] = wr_buf[1];
+		memcpy(&wr_buf[GTP_ADDR_LENGTH], &burn_buf[burn_length],
+								frame_length);
+
+		for (retry = 0; retry < MAX_FRAME_CHECK_TIME; retry++) {
+			ret = gup_i2c_write(client, wr_buf,
+					GTP_ADDR_LENGTH + frame_length);
+			if (ret <= 0) {
+				GTP_ERROR("Write frame data i2c error.");
+				continue;
+			}
+			ret = gup_i2c_read(client, rd_buf, GTP_ADDR_LENGTH +
+							frame_length);
+			if (ret <= 0) {
+				GTP_ERROR("Read back frame data i2c error.");
+				continue;
+			}
+
+			if (memcmp(&wr_buf[GTP_ADDR_LENGTH],
+				&rd_buf[GTP_ADDR_LENGTH], frame_length)) {
+				GTP_ERROR("Check frame data fail,not equal.");
+				GTP_DEBUG("write array:");
+				GTP_DEBUG_ARRAY(&wr_buf[GTP_ADDR_LENGTH],
+								frame_length);
+				GTP_DEBUG("read array:");
+				GTP_DEBUG_ARRAY(&rd_buf[GTP_ADDR_LENGTH],
+								frame_length);
+				continue;
+			} else {
+				/* GTP_DEBUG("Check frame data success."); */
+				break;
+			}
+		}
+		if (retry >= MAX_FRAME_CHECK_TIME) {
+			GTP_ERROR("Burn frame data time out,exit.");
+			return FAIL;
+		}
+		burn_length += frame_length;
+		burn_addr += frame_length;
+	}
+	return SUCCESS;
+}
+
+static u8 gup_load_section_file(u8 *buf, u16 offset, u16 length)
+{
+	s32 ret = 0;
+
+	if (update_msg.file == NULL) {
+		GTP_ERROR("cannot find update file,load section file fail.");
+		return FAIL;
+	}
+	update_msg.file->f_pos = FW_HEAD_LENGTH + offset;
+
+	ret = update_msg.file->f_op->read(update_msg.file, (char *)buf, length,
+						&update_msg.file->f_pos);
+	if (ret < 0) {
+		GTP_ERROR("Read update file fail.");
+		return FAIL;
+	}
+
+	return SUCCESS;
+}
+
+static u8 gup_recall_check(struct i2c_client *client, u8 *chk_src,
+					u16 start_rd_addr, u16 chk_length)
+{
+	u8  rd_buf[PACK_SIZE + GTP_ADDR_LENGTH];
+	s32 ret = 0;
+	u16 recall_addr = start_rd_addr;
+	u16 recall_length = 0;
+	u16 frame_length = 0;
+
+	while (recall_length < chk_length) {
+		frame_length = ((chk_length - recall_length) > PACK_SIZE)
+				? PACK_SIZE : (chk_length - recall_length);
+		ret = gup_get_ic_msg(client, recall_addr, rd_buf, frame_length);
+		if (ret <= 0) {
+			GTP_ERROR("recall i2c error,exit");
+			return FAIL;
+		}
+
+		if (memcmp(&rd_buf[GTP_ADDR_LENGTH], &chk_src[recall_length],
+			frame_length)) {
+			GTP_ERROR("Recall frame data fail,not equal.");
+			GTP_DEBUG("chk_src array:");
+			GTP_DEBUG_ARRAY(&chk_src[recall_length], frame_length);
+			GTP_DEBUG("recall array:");
+			GTP_DEBUG_ARRAY(&rd_buf[GTP_ADDR_LENGTH], frame_length);
+			return FAIL;
+		}
+
+		recall_length += frame_length;
+		recall_addr += frame_length;
+	}
+	GTP_DEBUG("Recall check %dk firmware success.", (chk_length/1024));
+
+	return SUCCESS;
+}
+
+static u8 gup_burn_fw_section(struct i2c_client *client, u8 *fw_section,
+					u16 start_addr, u8 bank_cmdi)
+{
+	s32 ret = 0;
+	u8  rd_buf[5];
+
+	/* step1:hold ss51 & dsp */
+	ret = gup_set_ic_msg(client, _rRW_MISCTL__SWRST_B0_, 0x0C);
+	if (ret <= 0) {
+		GTP_ERROR("[burn_fw_section]hold ss51 & dsp fail.");
+		return FAIL;
+	}
+
+	 /* step2:set scramble */
+	ret = gup_set_ic_msg(client, _rRW_MISCTL__BOOT_OPT_B0_, 0x00);
+	if (ret <= 0) {
+		GTP_ERROR("[burn_fw_section]set scramble fail.");
+		return FAIL;
+	}
+
+	/* step3:select bank */
+	ret = gup_set_ic_msg(client, _bRW_MISCTL__SRAM_BANK,
+						(bank_cmd >> 4)&0x0F);
+	if (ret <= 0) {
+		GTP_ERROR("[burn_fw_section]select bank %d fail.",
+					(bank_cmd >> 4)&0x0F);
+		return FAIL;
+	}
+
+	/* step4:enable accessing code */
+	ret = gup_set_ic_msg(client, _bRW_MISCTL__MEM_CD_EN, 0x01);
+	if (ret <= 0) {
+		GTP_ERROR("[burn_fw_section]enable accessing code fail.");
+		return FAIL;
+	}
+
+	/* step5:burn 8k fw section */
+	ret = gup_burn_proc(client, fw_section, start_addr, FW_SECTION_LENGTH);
+	if (ret == FAIL)  {
+		GTP_ERROR("[burn_fw_section]burn fw_section fail.");
+		return FAIL;
+	}
+
+	/* step6:hold ss51 & release dsp */
+	ret = gup_set_ic_msg(client, _rRW_MISCTL__SWRST_B0_, 0x04);
+	if (ret <= 0) {
+		GTP_ERROR("[burn_fw_section]hold ss51 & release dsp fail.");
+		return FAIL;
+	}
+	/* must delay */
+	msleep(20);
+
+	/* step7:send burn cmd to move data to flash from sram */
+	ret = gup_set_ic_msg(client, _rRW_MISCTL__BOOT_CTL_, bank_cmd&0x0f);
+	if (ret <= 0) {
+		GTP_ERROR("[burn_fw_section]send burn cmd fail.");
+		return FAIL;
+	}
+	GTP_DEBUG("[burn_fw_section]Wait for the burn is complete......");
+	do {
+		ret = gup_get_ic_msg(client, _rRW_MISCTL__BOOT_CTL_, rd_buf, 1);
+		if (ret <= 0) {
+			GTP_ERROR("[burn_fw_section]Get burn state fail");
+			return FAIL;
+		}
+		msleep(20);
+		/* GTP_DEBUG("[burn_fw_section]Get burn state:%d.",
+						rd_buf[GTP_ADDR_LENGTH]); */
+	} while (rd_buf[GTP_ADDR_LENGTH]);
+
+	/* step8:select bank */
+	ret = gup_set_ic_msg(client, _bRW_MISCTL__SRAM_BANK,
+							(bank_cmd >> 4)&0x0F);
+	if (ret <= 0) {
+		GTP_ERROR("[burn_fw_section]select bank %d fail.",
+							(bank_cmd >> 4)&0x0F);
+		return FAIL;
+	}
+
+	/* step9:enable accessing code */
+	ret = gup_set_ic_msg(client, _bRW_MISCTL__MEM_CD_EN, 0x01);
+	if (ret <= 0) {
+		GTP_ERROR("[burn_fw_section]enable accessing code fail.");
+		return FAIL;
+	}
+
+	/* step10:recall 8k fw section */
+	ret = gup_recall_check(client, fw_section, start_addr,
+							FW_SECTION_LENGTH);
+	if (ret == FAIL) {
+		GTP_ERROR("[burn_fw_section]recall check 8k firmware fail.");
+		return FAIL;
+	}
+
+	/* step11:disable accessing code */
+	ret = gup_set_ic_msg(client, _bRW_MISCTL__MEM_CD_EN, 0x00);
+	if (ret <= 0) {
+		GTP_ERROR("[burn_fw_section]disable accessing code fail.");
+		return FAIL;
+	}
+
+	return SUCCESS;
+}
+
+static u8 gup_burn_dsp_isp(struct i2c_client *client)
+{
+	s32 ret = 0;
+	u8 *fw_dsp_isp = NULL;
+	u8  retry = 0;
+
+	GTP_DEBUG("[burn_dsp_isp]Begin burn dsp isp---->>");
+
+	/* step1:alloc memory */
+	GTP_DEBUG("[burn_dsp_isp]step1:alloc memory");
+	while (retry++ < 5) {
+		fw_dsp_isp = kzalloc(FW_DSP_ISP_LENGTH, GFP_KERNEL);
+		if (fw_dsp_isp == NULL) {
+			continue;
+		} else {
+			GTP_INFO("[burn_dsp_isp]Alloc %dk byte memory success.",
+					(FW_DSP_ISP_LENGTH/1024));
+			break;
+		}
+	}
+	if (retry >= 5) {
+		GTP_ERROR("[burn_dsp_isp]Alloc memory fail,exit.");
+		return FAIL;
+	}
+
+	/* step2:load dsp isp file data */
+	GTP_DEBUG("[burn_dsp_isp]step2:load dsp isp file data");
+	ret = gup_load_section_file(fw_dsp_isp, (4 * FW_SECTION_LENGTH +
+		FW_DSP_LENGTH + FW_BOOT_LENGTH), FW_DSP_ISP_LENGTH);
+	if (ret == FAIL) {
+		GTP_ERROR("[burn_dsp_isp]load firmware dsp_isp fail.");
+		goto exit_burn_dsp_isp;
+	}
+
+	/* step3:disable wdt,clear cache enable */
+	GTP_DEBUG("[burn_dsp_isp]step3:disable wdt,clear cache enable");
+	ret = gup_set_ic_msg(client, _bRW_MISCTL__TMR0_EN, 0x00);
+	if (ret <= 0) {
+		GTP_ERROR("[burn_dsp_isp]disable wdt fail.");
+		ret = FAIL;
+		goto exit_burn_dsp_isp;
+	}
+	ret = gup_set_ic_msg(client, _bRW_MISCTL__CACHE_EN, 0x00);
+	if (ret <= 0) {
+		GTP_ERROR("[burn_dsp_isp]clear cache enable fail.");
+		ret = FAIL;
+		goto exit_burn_dsp_isp;
+	}
+
+	/* step4:hold ss51 & dsp */
+	GTP_DEBUG("[burn_dsp_isp]step4:hold ss51 & dsp");
+	ret = gup_set_ic_msg(client, _rRW_MISCTL__SWRST_B0_, 0x0C);
+	if (ret <= 0) {
+		GTP_ERROR("[burn_dsp_isp]hold ss51 & dsp fail.");
+		ret = FAIL;
+		goto exit_burn_dsp_isp;
+	}
+
+	/* step5:set boot from sram */
+	GTP_DEBUG("[burn_dsp_isp]step5:set boot from sram");
+	ret = gup_set_ic_msg(client, _rRW_MISCTL__BOOTCTL_B0_, 0x02);
+	if (ret <= 0) {
+		GTP_ERROR("[burn_dsp_isp]set boot from sram fail.");
+		ret = FAIL;
+		goto exit_burn_dsp_isp;
+	}
+
+	/* step6:software reboot */
+	GTP_DEBUG("[burn_dsp_isp]step6:software reboot");
+	ret = gup_set_ic_msg(client, _bWO_MISCTL__CPU_SWRST_PULSE, 0x01);
+	if (ret <= 0) {
+		GTP_ERROR("[burn_dsp_isp]software reboot fail.");
+		ret = FAIL;
+		goto exit_burn_dsp_isp;
+	}
+
+	/* step7:select bank2 */
+	GTP_DEBUG("[burn_dsp_isp]step7:select bank2");
+	ret = gup_set_ic_msg(client, _bRW_MISCTL__SRAM_BANK, 0x02);
+	if (ret <= 0) {
+		GTP_ERROR("[burn_dsp_isp]select bank2 fail.");
+		ret = FAIL;
+		goto exit_burn_dsp_isp;
+	}
+
+	/* step8:enable accessing code */
+	GTP_DEBUG("[burn_dsp_isp]step8:enable accessing code");
+	ret = gup_set_ic_msg(client, _bRW_MISCTL__MEM_CD_EN, 0x01);
+	if (ret <= 0) {
+		GTP_ERROR("[burn_dsp_isp]enable accessing code fail.");
+		ret = FAIL;
+		goto exit_burn_dsp_isp;
+	}
+
+	/* step9:burn 4k dsp_isp */
+	GTP_DEBUG("[burn_dsp_isp]step9:burn 4k dsp_isp");
+	ret = gup_burn_proc(client, fw_dsp_isp, 0xC000, FW_DSP_ISP_LENGTH);
+	if (ret == FAIL) {
+		GTP_ERROR("[burn_dsp_isp]burn dsp_isp fail.");
+		goto exit_burn_dsp_isp;
+	}
+
+	/* step10:set scramble */
+	GTP_DEBUG("[burn_dsp_isp]step10:set scramble");
+	ret = gup_set_ic_msg(client, _rRW_MISCTL__BOOT_OPT_B0_, 0x00);
+	if (ret <= 0) {
+		GTP_ERROR("[burn_dsp_isp]set scramble fail.");
+		ret = FAIL;
+		goto exit_burn_dsp_isp;
+	}
+	ret = SUCCESS;
+
+exit_burn_dsp_isp:
+	kfree(fw_dsp_isp);
+	return ret;
+}
+
+static u8 gup_burn_fw_ss51(struct i2c_client *client)
+{
+	u8 *fw_ss51 = NULL;
+	u8  retry = 0;
+	s32 ret = 0;
+
+	GTP_DEBUG("[burn_fw_ss51]Begin burn ss51 firmware---->>");
+
+	/* step1:alloc memory */
+	GTP_DEBUG("[burn_fw_ss51]step1:alloc memory");
+	while (retry++ < 5) {
+		fw_ss51 = kzalloc(FW_SECTION_LENGTH, GFP_KERNEL);
+		if (fw_ss51 == NULL) {
+			continue;
+		} else {
+			GTP_INFO("[burn_fw_ss51]Alloc %dk byte memory success.",
+						(FW_SECTION_LENGTH/1024));
+			break;
+		}
+	}
+	if (retry >= 5) {
+		GTP_ERROR("[burn_fw_ss51]Alloc memory fail,exit.");
+		return FAIL;
+	}
+
+	/* step2:load ss51 firmware section 1 file data */
+	GTP_DEBUG("[burn_fw_ss51]step2:load ss51 firmware section 1 file data");
+	ret = gup_load_section_file(fw_ss51, 0, FW_SECTION_LENGTH);
+	if (ret == FAIL) {
+		GTP_ERROR("[burn_fw_ss51]load ss51 firmware section 1 fail.");
+		goto exit_burn_fw_ss51;
+	}
+
+	/* step3:clear control flag */
+	GTP_DEBUG("[burn_fw_ss51]step3:clear control flag");
+	ret = gup_set_ic_msg(client, _rRW_MISCTL__BOOT_CTL_, 0x00);
+	if (ret <= 0) {
+		GTP_ERROR("[burn_fw_ss51]clear control flag fail.");
+		ret = FAIL;
+		goto exit_burn_fw_ss51;
+	}
+
+	/* step4:burn ss51 firmware section 1 */
+	GTP_DEBUG("[burn_fw_ss51]step4:burn ss51 firmware section 1");
+	ret = gup_burn_fw_section(client, fw_ss51, 0xC000, 0x01);
+	if (ret == FAIL) {
+		GTP_ERROR("[burn_fw_ss51]burn ss51 firmware section 1 fail.");
+		goto exit_burn_fw_ss51;
+	}
+
+	/* step5:load ss51 firmware section 2 file data */
+	GTP_DEBUG("[burn_fw_ss51]step5:load ss51 firmware section 2 file data");
+	ret = gup_load_section_file(fw_ss51, FW_SECTION_LENGTH,
+							FW_SECTION_LENGTH);
+	if (ret == FAIL) {
+		GTP_ERROR("[burn_fw_ss51]load ss51 firmware section 2 fail.");
+		goto exit_burn_fw_ss51;
+	}
+
+	/* step6:burn ss51 firmware section 2 */
+	GTP_DEBUG("[burn_fw_ss51]step6:burn ss51 firmware section 2");
+	ret = gup_burn_fw_section(client, fw_ss51, 0xE000, 0x02);
+	if (ret == FAIL) {
+		GTP_ERROR("[burn_fw_ss51]burn ss51 firmware section 2 fail.");
+		goto exit_burn_fw_ss51;
+	}
+
+	/* step7:load ss51 firmware section 3 file data */
+	GTP_DEBUG("[burn_fw_ss51]step7:load ss51 firmware section 3 file data");
+	ret = gup_load_section_file(fw_ss51, 2*FW_SECTION_LENGTH,
+							FW_SECTION_LENGTH);
+	if (ret == FAIL) {
+		GTP_ERROR("[burn_fw_ss51]load ss51 firmware section 3 fail.");
+		goto exit_burn_fw_ss51;
+	}
+
+	/* step8:burn ss51 firmware section 3 */
+	GTP_DEBUG("[burn_fw_ss51]step8:burn ss51 firmware section 3");
+	ret = gup_burn_fw_section(client, fw_ss51, 0xC000, 0x13);
+	if (ret == FAIL) {
+		GTP_ERROR("[burn_fw_ss51]burn ss51 firmware section 3 fail.");
+		goto exit_burn_fw_ss51;
+	}
+
+	/* step9:load ss51 firmware section 4 file data */
+	GTP_DEBUG("[burn_fw_ss51]step9:load ss51 firmware section 4 file data");
+	ret = gup_load_section_file(fw_ss51, 3*FW_SECTION_LENGTH,
+							FW_SECTION_LENGTH);
+	if (ret == FAIL) {
+		GTP_ERROR("[burn_fw_ss51]load ss51 firmware section 4 fail.");
+		goto exit_burn_fw_ss51;
+	}
+
+	/* step10:burn ss51 firmware section 4 */
+	GTP_DEBUG("[burn_fw_ss51]step10:burn ss51 firmware section 4");
+	ret = gup_burn_fw_section(client, fw_ss51, 0xE000, 0x14);
+	if (ret == FAIL) {
+		GTP_ERROR("[burn_fw_ss51]burn ss51 firmware section 4 fail.");
+		goto exit_burn_fw_ss51;
+	}
+
+	ret = SUCCESS;
+
+exit_burn_fw_ss51:
+	kfree(fw_ss51);
+	return ret;
+}
+
+static u8 gup_burn_fw_dsp(struct i2c_client *client)
+{
+	s32 ret = 0;
+	u8 *fw_dsp = NULL;
+	u8  retry = 0;
+	u8  rd_buf[5];
+
+	GTP_DEBUG("[burn_fw_dsp]Begin burn dsp firmware---->>");
+	/* step1:alloc memory */
+	GTP_DEBUG("[burn_fw_dsp]step1:alloc memory");
+	while (retry++ < 5) {
+		fw_dsp = kzalloc(FW_DSP_LENGTH, GFP_KERNEL);
+		if (fw_dsp == NULL) {
+			continue;
+		} else  {
+			GTP_INFO("[burn_fw_dsp]Alloc %dk byte memory success.",
+					(FW_SECTION_LENGTH/1024));
+			break;
+		}
+	}
+	if (retry >= 5) {
+		GTP_ERROR("[burn_fw_dsp]Alloc memory fail,exit.");
+		return FAIL;
+	}
+
+	/* step2:load firmware dsp */
+	GTP_DEBUG("[burn_fw_dsp]step2:load firmware dsp");
+	ret = gup_load_section_file(fw_dsp, 4*FW_SECTION_LENGTH, FW_DSP_LENGTH);
+	if (ret == FAIL) {
+		GTP_ERROR("[burn_fw_dsp]load firmware dsp fail.");
+		goto exit_burn_fw_dsp;
+	}
+
+	/* step3:select bank3 */
+	GTP_DEBUG("[burn_fw_dsp]step3:select bank3");
+	ret = gup_set_ic_msg(client, _bRW_MISCTL__SRAM_BANK, 0x03);
+	if (ret <= 0) {
+		GTP_ERROR("[burn_fw_dsp]select bank3 fail.");
+		ret = FAIL;
+		goto exit_burn_fw_dsp;
+	}
+
+	/* Step4:hold ss51 & dsp */
+	GTP_DEBUG("[burn_fw_dsp]step4:hold ss51 & dsp");
+	ret = gup_set_ic_msg(client, _rRW_MISCTL__SWRST_B0_, 0x0C);
+	if (ret <= 0) {
+		GTP_ERROR("[burn_fw_dsp]hold ss51 & dsp fail.");
+		ret = FAIL;
+		goto exit_burn_fw_dsp;
+	}
+
+	/* step5:set scramble */
+	GTP_DEBUG("[burn_fw_dsp]step5:set scramble");
+	ret = gup_set_ic_msg(client, _rRW_MISCTL__BOOT_OPT_B0_, 0x00);
+	if (ret <= 0) {
+		GTP_ERROR("[burn_fw_dsp]set scramble fail.");
+		ret = FAIL;
+		goto exit_burn_fw_dsp;
+	}
+
+	/* step6:release ss51 & dsp */
+	GTP_DEBUG("[burn_fw_dsp]step6:release ss51 & dsp");
+	ret = gup_set_ic_msg(client, _rRW_MISCTL__SWRST_B0_, 0x04);
+	if (ret <= 0) {
+		GTP_ERROR("[burn_fw_dsp]release ss51 & dsp fail.");
+		ret = FAIL;
+		goto exit_burn_fw_dsp;
+	}
+	/* must delay */
+	msleep(20);
+
+	/* step7:burn 4k dsp firmware */
+	GTP_DEBUG("[burn_fw_dsp]step7:burn 4k dsp firmware");
+	ret = gup_burn_proc(client, fw_dsp, 0x9000, FW_DSP_LENGTH);
+	if (FAIL == ret) {
+		GTP_ERROR("[burn_fw_dsp]burn fw_section fail.");
+		goto exit_burn_fw_dsp;
+	}
+
+	/* step8:send burn cmd to move data to flash from sram */
+	GTP_DEBUG("[burn_fw_dsp]step8:send burn cmd to move data to flash" \
+						"from sram");
+	ret = gup_set_ic_msg(client, _rRW_MISCTL__BOOT_CTL_, 0x05);
+	if (ret <= 0) {
+		GTP_ERROR("[burn_fw_dsp]send burn cmd fail.");
+		goto exit_burn_fw_dsp;
+	}
+	GTP_DEBUG("[burn_fw_dsp]Wait for the burn is complete......");
+	do {
+		ret = gup_get_ic_msg(client, _rRW_MISCTL__BOOT_CTL_, rd_buf, 1);
+		if (ret <= 0) {
+			GTP_ERROR("[burn_fw_dsp]Get burn state fail");
+			goto exit_burn_fw_dsp;
+		}
+		msleep(20);
+		/* GTP_DEBUG("[burn_fw_dsp]Get burn state:%d.",
+						rd_buf[GTP_ADDR_LENGTH]); */
+	} while (rd_buf[GTP_ADDR_LENGTH]);
+
+	/* step9:recall check 4k dsp firmware */
+	GTP_DEBUG("[burn_fw_dsp]step9:recall check 4k dsp firmware");
+	ret = gup_recall_check(client, fw_dsp, 0x9000, FW_DSP_LENGTH);
+	if (ret == FAIL) {
+		GTP_ERROR("[burn_fw_dsp]recall check 4k dsp firmware fail.");
+		goto exit_burn_fw_dsp;
+	}
+
+	ret = SUCCESS;
+
+exit_burn_fw_dsp:
+	kfree(fw_dsp);
+	return ret;
+}
+
+static u8 gup_burn_fw_boot(struct i2c_client *client)
+{
+	s32 ret = 0;
+	u8 *fw_boot = NULL;
+	u8  retry = 0;
+	u8  rd_buf[5];
+
+	GTP_DEBUG("[burn_fw_boot]Begin burn bootloader firmware---->>");
+
+	/* step1:Alloc memory */
+	GTP_DEBUG("[burn_fw_boot]step1:Alloc memory");
+	while (retry++ < 5) {
+		fw_boot = kzalloc(FW_BOOT_LENGTH, GFP_KERNEL);
+		if (fw_boot == NULL) {
+			continue;
+		} else {
+			GTP_INFO("[burn_fw_boot]Alloc %dk byte memory success.",
+						(FW_BOOT_LENGTH/1024));
+			break;
+		}
+	}
+	if (retry >= 5) {
+		GTP_ERROR("[burn_fw_boot]Alloc memory fail,exit.");
+		return FAIL;
+	}
+
+	/* step2:load firmware bootloader */
+	GTP_DEBUG("[burn_fw_boot]step2:load firmware bootloader");
+	ret = gup_load_section_file(fw_boot, (4 * FW_SECTION_LENGTH +
+				FW_DSP_LENGTH), FW_BOOT_LENGTH);
+	if (ret == FAIL) {
+		GTP_ERROR("[burn_fw_boot]load firmware dsp fail.");
+		goto exit_burn_fw_boot;
+	}
+
+	/* step3:hold ss51 & dsp */
+	GTP_DEBUG("[burn_fw_boot]step3:hold ss51 & dsp");
+	ret = gup_set_ic_msg(client, _rRW_MISCTL__SWRST_B0_, 0x0C);
+	if (ret <= 0) {
+		GTP_ERROR("[burn_fw_boot]hold ss51 & dsp fail.");
+		ret = FAIL;
+		goto exit_burn_fw_boot;
+	}
+
+	/* step4:set scramble */
+	GTP_DEBUG("[burn_fw_boot]step4:set scramble");
+	ret = gup_set_ic_msg(client, _rRW_MISCTL__BOOT_OPT_B0_, 0x00);
+	if (ret <= 0) {
+		GTP_ERROR("[burn_fw_boot]set scramble fail.");
+		ret = FAIL;
+		goto exit_burn_fw_boot;
+	}
+
+	/* step5:release ss51 & dsp */
+	GTP_DEBUG("[burn_fw_boot]step5:release ss51 & dsp");
+	ret = gup_set_ic_msg(client, _rRW_MISCTL__SWRST_B0_, 0x04);
+	if (ret <= 0) {
+		GTP_ERROR("[burn_fw_boot]release ss51 & dsp fail.");
+		ret = FAIL;
+		goto exit_burn_fw_boot;
+	}
+	/* must delay */
+	msleep(20);
+
+	/* step6:select bank3 */
+	GTP_DEBUG("[burn_fw_boot]step6:select bank3");
+	ret = gup_set_ic_msg(client, _bRW_MISCTL__SRAM_BANK, 0x03);
+	if (ret <= 0) {
+		GTP_ERROR("[burn_fw_boot]select bank3 fail.");
+		ret = FAIL;
+		goto exit_burn_fw_boot;
+	}
+
+	/* step7:burn 2k bootloader firmware */
+	GTP_DEBUG("[burn_fw_boot]step7:burn 2k bootloader firmware");
+	ret = gup_burn_proc(client, fw_boot, 0x9000, FW_BOOT_LENGTH);
+	if (ret == FAIL) {
+		GTP_ERROR("[burn_fw_boot]burn fw_section fail.");
+		goto exit_burn_fw_boot;
+	}
+
+	/* step7:send burn cmd to move data to flash from sram */
+	GTP_DEBUG("[burn_fw_boot]step7:send burn cmd to move data to" \
+				"flash from sram");
+	ret = gup_set_ic_msg(client, _rRW_MISCTL__BOOT_CTL_, 0x06);
+	if (ret <= 0) {
+		GTP_ERROR("[burn_fw_boot]send burn cmd fail.");
+		goto exit_burn_fw_boot;
+	}
+	GTP_DEBUG("[burn_fw_boot]Wait for the burn is complete......");
+	do {
+		ret = gup_get_ic_msg(client, _rRW_MISCTL__BOOT_CTL_, rd_buf, 1);
+		if (ret <= 0) {
+			GTP_ERROR("[burn_fw_boot]Get burn state fail");
+			goto exit_burn_fw_boot;
+		}
+		msleep(20);
+		/* GTP_DEBUG("[burn_fw_boot]Get burn state:%d.",
+						rd_buf[GTP_ADDR_LENGTH]); */
+	} while (rd_buf[GTP_ADDR_LENGTH]);
+
+	/* step8:recall check 2k bootloader firmware */
+	GTP_DEBUG("[burn_fw_boot]step8:recall check 2k bootloader firmware");
+	ret = gup_recall_check(client, fw_boot, 0x9000, FW_BOOT_LENGTH);
+	if (ret == FAIL) {
+		GTP_ERROR("[burn_fw_boot]recall check 4k dsp firmware fail.");
+		goto exit_burn_fw_boot;
+	}
+
+	/* step9:enable download DSP code  */
+	GTP_DEBUG("[burn_fw_boot]step9:enable download DSP code ");
+	ret = gup_set_ic_msg(client, _rRW_MISCTL__BOOT_CTL_, 0x99);
+	if (ret <= 0) {
+		GTP_ERROR("[burn_fw_boot]enable download DSP code fail.");
+		ret = FAIL;
+		goto exit_burn_fw_boot;
+	}
+
+	/* step10:release ss51 & hold dsp */
+	GTP_DEBUG("[burn_fw_boot]step10:release ss51 & hold dsp");
+	ret = gup_set_ic_msg(client, _rRW_MISCTL__SWRST_B0_, 0x08);
+	if (ret <= 0) {
+		GTP_ERROR("[burn_fw_boot]release ss51 & hold dsp fail.");
+		ret = FAIL;
+		goto exit_burn_fw_boot;
+	}
+
+	ret = SUCCESS;
+
+exit_burn_fw_boot:
+	kfree(fw_boot);
+	return ret;
+}
+
+s32 gup_update_proc(void *dir)
+{
+	s32 ret = 0;
+	u8  retry = 0;
+	st_fw_head fw_head;
+	struct goodix_ts_data *ts = NULL;
+
+	GTP_DEBUG("[update_proc]Begin update ......");
+
+	show_len = 1;
+	total_len = 100;
+	if (dir == NULL)
+		/* wait main thread to be completed */
+	msleep(3000);
+
+	ts = i2c_get_clientdata(i2c_connect_client);
+
+	if (searching_file) {
+		/* exit .bin update file searching  */
+		searching_file = 0;
+		GTP_INFO("Exiting searching .bin update file...");
+		/* wait for auto update quitted completely */
+		while ((show_len != 200) && (show_len != 100))
+			msleep(100);
+	}
+
+	update_msg.file = NULL;
+	ret = gup_check_update_file(i2c_connect_client, &fw_head, (u8 *)dir);
+	if (ret == FAIL) {
+		GTP_ERROR("[update_proc]check update file fail.");
+		goto file_fail;
+	}
+
+	/* gtp_reset_guitar(i2c_connect_client, 20); */
+	ret = gup_get_ic_fw_msg(i2c_connect_client);
+	if (ret == FAIL) {
+		GTP_ERROR("[update_proc]get ic message fail.");
+		goto file_fail;
+	}
+
+	ret = gup_enter_update_judge(&fw_head);
+	if (ret == FAIL) {
+		GTP_ERROR("[update_proc]Check *.bin file fail.");
+		goto file_fail;
+	}
+
+	ts->enter_update = 1;
+	gtp_irq_disable(ts);
+#if GTP_ESD_PROTECT
+	gtp_esd_switch(ts->client, SWITCH_OFF);
+#endif
+	ret = gup_enter_update_mode(i2c_connect_client);
+	if (ret == FAIL) {
+		GTP_ERROR("[update_proc]enter update mode fail.");
+		goto update_fail;
+	}
+
+	while (retry++ < 5) {
+		show_len = 10;
+		total_len = 100;
+		ret = gup_burn_dsp_isp(i2c_connect_client);
+		if (ret == FAIL) {
+			GTP_ERROR("[update_proc]burn dsp isp fail.");
+			continue;
+		}
+
+		show_len += 10;
+		ret = gup_burn_fw_ss51(i2c_connect_client);
+		if (ret == FAIL) {
+			GTP_ERROR("[update_proc]burn ss51 firmware fail.");
+			continue;
+		}
+
+		show_len += 40;
+		ret = gup_burn_fw_dsp(i2c_connect_client);
+		if (ret == FAIL) {
+			GTP_ERROR("[update_proc]burn dsp firmware fail.");
+			continue;
+		}
+
+		show_len += 20;
+		ret = gup_burn_fw_boot(i2c_connect_client);
+		if (ret == FAIL) {
+			GTP_ERROR("[update_proc]burn bootloader fw fail.");
+			continue;
+		}
+		show_len += 10;
+		GTP_INFO("[update_proc]UPDATE SUCCESS.");
+		break;
+	}
+	if (retry >= 5) {
+		GTP_ERROR("[update_proc]retry timeout,UPDATE FAIL.");
+		goto update_fail;
+	}
+
+	GTP_DEBUG("[update_proc]leave update mode.");
+	gup_leave_update_mode();
+
+	msleep(100);
+
+	/* GTP_DEBUG("[update_proc]send config.");
+	ret = gtp_send_cfg(i2c_connect_client);
+	if(ret < 0) {
+		GTP_ERROR("[update_proc]send config fail.");
+	} */
+
+	if (ts->fw_error) {
+		GTP_INFO("firmware error auto update, resent config!");
+		gup_init_panel(ts);
+	}
+	show_len = 100;
+	total_len = 100;
+	ts->enter_update = 0;
+	gtp_irq_enable(ts);
+
+#if GTP_ESD_PROTECT
+	gtp_esd_switch(ts->client, SWITCH_ON);
+#endif
+	filp_close(update_msg.file, NULL);
+	return SUCCESS;
+
+update_fail:
+	ts->enter_update = 0;
+	gtp_irq_enable(ts);
+
+#if GTP_ESD_PROTECT
+	gtp_esd_switch(ts->client, SWITCH_ON);
+#endif
+
+file_fail:
+	if (update_msg.file && !IS_ERR(update_msg.file))
+		filp_close(update_msg.file, NULL);
+
+	show_len = 200;
+	total_len = 100;
+	return FAIL;
+}
+
+#if GTP_AUTO_UPDATE
+u8 gup_init_update_proc(struct goodix_ts_data *ts)
+{
+	struct task_struct *thread = NULL;
+
+	GTP_INFO("Ready to run update thread.");
+	thread = kthread_run(gup_update_proc, (void *)NULL, "guitar_update");
+	if (IS_ERR(thread)) {
+		GTP_ERROR("Failed to create update thread.\n");
+		return -EINVAL;
+	}
+
+	return 0;
+}
+#endif
diff --git a/drivers/input/touchscreen/synaptics_fw_update.c b/drivers/input/touchscreen/synaptics_fw_update.c
index 2a5fea7..0a92d51 100644
--- a/drivers/input/touchscreen/synaptics_fw_update.c
+++ b/drivers/input/touchscreen/synaptics_fw_update.c
@@ -35,11 +35,8 @@
 #define INSIDE_FIRMWARE_UPDATE
 
 #define FW_IMAGE_OFFSET 0x100
-
-#define BOOTLOADER_ID_OFFSET 0
-#define FLASH_PROPERTIES_OFFSET 2
-#define BLOCK_SIZE_OFFSET 3
-#define FW_BLOCK_COUNT_OFFSET 5
+/* 0 to ignore flash block check to speed up flash time */
+#define CHECK_FLASH_BLOCK_STATUS 1
 
 #define REG_MAP (1 << 0)
 #define UNLOCKED (1 << 1)
@@ -49,9 +46,6 @@
 #define HAS_DISP_CONFIG (1 << 5)
 #define HAS_CTRL1 (1 << 6)
 
-#define BLOCK_NUMBER_OFFSET 0
-#define BLOCK_DATA_OFFSET 2
-
 #define RMI4_INFO_MAX_LEN	200
 
 #define RMI4_STORE_TS_INFO(buf, id, rev, fw_ver) \
@@ -70,6 +64,7 @@
 enum flash_command {
 	CMD_WRITE_FW_BLOCK		= 0x2,
 	CMD_ERASE_ALL			= 0x3,
+	CMD_WRITE_LOCKDOWN_BLOCK	= 0x4,
 	CMD_READ_CONFIG_BLOCK	= 0x5,
 	CMD_WRITE_CONFIG_BLOCK	= 0x6,
 	CMD_ERASE_CONFIG		= 0x7,
@@ -91,6 +86,23 @@
 	OPTION_CONTAIN_BOOTLOADER = 1,
 };
 
+enum flash_offset {
+	OFFSET_BOOTLOADER_ID,
+	OFFSET_FLASH_PROPERTIES,
+	OFFSET_BLOCK_SIZE,
+	OFFSET_FW_BLOCK_COUNT,
+	OFFSET_BLOCK_NUMBER,
+	OFFSET_BLOCK_DATA,
+	OFFSET_FLASH_CONTROL,
+	OFFSET_FLASH_STATUS
+};
+
+enum flash_update_mode {
+	NORMAL = 1,
+	FORCE = 2,
+	LOCKDOWN = 8
+};
+
 #define SLEEP_MODE_NORMAL (0x00)
 #define SLEEP_MODE_SENSOR_SLEEP (0x01)
 #define SLEEP_MODE_RESERVED0 (0x02)
@@ -101,9 +113,7 @@
 #define ERASE_WAIT_MS (5 * 1000)
 #define RESET_WAIT_MS (500)
 
-#define POLLING_MODE 0
-
-#define SLEEP_TIME_US 50
+#define SLEEP_TIME_US 100
 
 static int fwu_wait_for_idle(int timeout_ms);
 
@@ -141,7 +151,8 @@
 	};
 };
 
-struct image_header {
+struct image_content {
+	bool is_contain_build_info;
 	unsigned int checksum;
 	unsigned int image_size;
 	unsigned int config_size;
@@ -152,7 +163,10 @@
 	u16 package_id;
 	u16 package_revision_id;
 	unsigned int firmware_id;
-	bool is_contain_build_info;
+	const unsigned char *firmware_data;
+	const unsigned char *config_data;
+	const unsigned char *lockdown_data;
+	unsigned short lockdown_block_count;
 };
 
 struct pdt_properties {
@@ -194,11 +208,28 @@
 
 struct f34_flash_control {
 	union {
+	/* version 0 */
 		struct {
-			unsigned char command:4;
+			unsigned char command_v0:4;
 			unsigned char status:3;
 			unsigned char program_enabled:1;
 		} __packed;
+	/* version 1 */
+		struct {
+			unsigned char command_v1:6;
+			unsigned char reserved:2;
+		} __packed;
+		unsigned char data[1];
+	};
+};
+
+struct f34_flash_status {
+	union {
+		struct {
+			unsigned char status:6;
+			unsigned char reserved:1;
+			unsigned char program_enabled:1;
+		} __packed;
 		unsigned char data[1];
 	};
 };
@@ -222,6 +253,9 @@
 struct synaptics_rmi4_fwu_handle {
 	bool initialized;
 	bool force_update;
+	bool do_lockdown;
+	bool interrupt_flag;
+	bool polling_mode;
 	char product_id[SYNAPTICS_RMI4_PRODUCT_ID_SIZE + 1];
 	unsigned int image_size;
 	unsigned int data_pos;
@@ -233,31 +267,33 @@
 	unsigned char *read_config_buf;
 	const unsigned char *firmware_data;
 	const unsigned char *config_data;
+	const unsigned char *lockdown_data;
 	unsigned short block_size;
 	unsigned short fw_block_count;
 	unsigned short config_block_count;
+	unsigned short lockdown_block_count;
 	unsigned short perm_config_block_count;
 	unsigned short bl_config_block_count;
 	unsigned short disp_config_block_count;
 	unsigned short config_size;
 	unsigned short config_area;
-	unsigned short addr_f34_flash_control;
 	unsigned short addr_f01_interrupt_register;
+	const unsigned char *data_buffer;
 	struct synaptics_rmi4_fn_desc f01_fd;
 	struct synaptics_rmi4_fn_desc f34_fd;
 	struct synaptics_rmi4_exp_fn_ptr *fn_ptr;
 	struct synaptics_rmi4_data *rmi4_data;
-	struct f34_flash_control flash_control;
 	struct f34_flash_properties flash_properties;
 	struct workqueue_struct *fwu_workqueue;
 	struct delayed_work fwu_work;
-	char firmware_name[NAME_BUFFER_SIZE];
+	char image_name[NAME_BUFFER_SIZE];
+	struct image_content image_content;
 	char *ts_info;
 };
 
 static struct synaptics_rmi4_fwu_handle *fwu;
 
-static struct completion remove_complete;
+DECLARE_COMPLETION(fwu_remove_complete);
 
 static unsigned int extract_uint(const unsigned char *ptr)
 {
@@ -295,42 +331,80 @@
 		pkg_id[3] << 8 | pkg_id[2], build_id);
 }
 
-static void parse_header(struct image_header *header,
-		const unsigned char *fw_image)
+static void parse_header(void)
 {
-	struct image_header_data *data = (struct image_header_data *)fw_image;
-	header->checksum = extract_uint(data->file_checksum);
-	header->bootloader_version = data->bootloader_version;
-	header->image_size = extract_uint(data->firmware_size);
-	header->config_size = extract_uint(data->config_size);
-	memcpy(header->product_id, data->product_id,
+	struct image_content *img = &fwu->image_content;
+	struct image_header_data *data =
+		(struct image_header_data *)fwu->data_buffer;
+	img->checksum = extract_uint(data->file_checksum);
+	img->bootloader_version = data->bootloader_version;
+	img->image_size = extract_uint(data->firmware_size);
+	img->config_size = extract_uint(data->config_size);
+	memcpy(img->product_id, data->product_id,
 		sizeof(data->product_id));
-	header->product_id[sizeof(data->product_id)] = 0;
+	img->product_id[sizeof(data->product_id)] = 0;
 
-	memcpy(header->product_info, data->product_info,
+	img->product_id[sizeof(data->product_info)] = 0;
+	memcpy(img->product_info, data->product_info,
 		sizeof(data->product_info));
 
-	header->is_contain_build_info =
+	img->is_contain_build_info =
 		(data->options_firmware_id == (1 << OPTION_BUILD_INFO));
-	if (header->is_contain_build_info) {
-		header->package_id = (data->pkg_id_rev_msb << 8) |
+
+	if (img->is_contain_build_info) {
+		img->firmware_id = extract_uint(data->firmware_id);
+		img->package_id = (data->pkg_id_rev_msb << 8) |
 				data->pkg_id_lsb;
-		header->package_revision_id = (data->pkg_id_rev_msb << 8) |
+		img->package_revision_id = (data->pkg_id_rev_msb << 8) |
 				data->pkg_id_rev_lsb;
 		dev_info(&fwu->rmi4_data->i2c_client->dev,
 			"%s Package ID %d Rev %d\n", __func__,
-			header->package_id, header->package_revision_id);
+			img->package_id, img->package_revision_id);
 
-		header->firmware_id = extract_uint(data->firmware_id);
+		img->firmware_id = extract_uint(data->firmware_id);
 		dev_info(&fwu->rmi4_data->i2c_client->dev,
 			"%s Firwmare build id %d\n", __func__,
-			header->firmware_id);
+			img->firmware_id);
 	}
 
 	dev_dbg(&fwu->rmi4_data->i2c_client->dev,
 		"Firwmare size %d, config size %d\n",
-		header->image_size,
-		header->config_size);
+		img->image_size,
+		img->config_size);
+
+	/* get UI firmware offset */
+	if (img->image_size)
+		img->firmware_data = fwu->data_buffer + FW_IMAGE_OFFSET;
+	/* get config offset*/
+	if (img->config_size)
+		img->config_data = fwu->data_buffer + FW_IMAGE_OFFSET +
+				img->image_size;
+	/* get lockdown offset*/
+	switch (img->bootloader_version) {
+	case 3:
+	case 4:
+		img->lockdown_block_count = 4;
+		break;
+	case 5:
+	case 6:
+		img->lockdown_block_count = 5;
+		break;
+	default:
+		dev_warn(&fwu->rmi4_data->i2c_client->dev,
+			"%s: Not support lockdown in " \
+			"bootloader version V%d\n",
+			__func__, img->bootloader_version);
+		img->lockdown_data = NULL;
+	}
+
+	img->lockdown_data = fwu->data_buffer +
+				FW_IMAGE_OFFSET -
+				img->lockdown_block_count * fwu->block_size;
+
+	fwu->lockdown_block_count = img->lockdown_block_count;
+	fwu->lockdown_data = img->lockdown_data;
+	fwu->config_data = img->config_data;
+	fwu->firmware_data = img->firmware_data;
 	return;
 }
 
@@ -352,6 +426,62 @@
 	return 0;
 }
 
+static unsigned short fwu_get_address(enum flash_offset type)
+{
+	int offset;
+	unsigned short addr = 0;
+	struct i2c_client *i2c_client = fwu->rmi4_data->i2c_client;
+
+	switch (type) {
+	case OFFSET_BOOTLOADER_ID:
+		offset = 0;
+		addr = fwu->f34_fd.query_base_addr + offset;
+		break;
+	case OFFSET_FLASH_PROPERTIES:
+		offset = ((fwu->f34_fd.version == 0) ? 2 : 1);
+		addr = fwu->f34_fd.query_base_addr + offset;
+		break;
+	case OFFSET_BLOCK_SIZE:
+		offset = ((fwu->f34_fd.version == 0) ? 3 : 2);
+		addr = fwu->f34_fd.query_base_addr + offset;
+		break;
+	case OFFSET_FW_BLOCK_COUNT:
+		offset = ((fwu->f34_fd.version == 0) ? 5 : 3);
+		addr = fwu->f34_fd.query_base_addr + offset;
+		break;
+	case OFFSET_BLOCK_NUMBER:
+		offset = 0;
+		addr = fwu->f34_fd.data_base_addr + offset;
+		break;
+	case OFFSET_BLOCK_DATA:
+		offset = ((fwu->f34_fd.version == 0) ? 2 : 1);
+		addr = fwu->f34_fd.data_base_addr + offset;
+		break;
+	case OFFSET_FLASH_CONTROL:
+		offset = ((fwu->f34_fd.version == 0) ?
+			2 + (fwu->block_size) : 2);
+		addr = fwu->f34_fd.data_base_addr + offset;
+		break;
+	case OFFSET_FLASH_STATUS:
+		if (fwu->f34_fd.version == 1) {
+			offset = 3;
+			addr = fwu->f34_fd.data_base_addr + offset;
+		} else if (fwu->f34_fd.version == 0) {
+			dev_warn(&i2c_client->dev,
+			"%s: F$34 version 0 does not contain " \
+			"flash status register\n",
+			__func__);
+		}
+		break;
+	default:
+		dev_err(&i2c_client->dev,
+			"%s: Unknown flash offset (%d)\n",
+			__func__, type);
+		break;
+	}
+	return addr;
+}
+
 static int fwu_read_f34_queries(void)
 {
 	int retval;
@@ -360,7 +490,7 @@
 	struct i2c_client *i2c_client = fwu->rmi4_data->i2c_client;
 
 	retval = fwu->fn_ptr->read(fwu->rmi4_data,
-			fwu->f34_fd.query_base_addr + BOOTLOADER_ID_OFFSET,
+			fwu_get_address(OFFSET_BOOTLOADER_ID),
 			fwu->bootloader_id,
 			sizeof(fwu->bootloader_id));
 	if (retval < 0) {
@@ -371,7 +501,7 @@
 	}
 
 	retval = fwu->fn_ptr->read(fwu->rmi4_data,
-			fwu->f34_fd.query_base_addr + FLASH_PROPERTIES_OFFSET,
+			fwu_get_address(OFFSET_FLASH_PROPERTIES),
 			fwu->flash_properties.data,
 			sizeof(fwu->flash_properties.data));
 	if (retval < 0) {
@@ -397,7 +527,7 @@
 		count += 2;
 
 	retval = fwu->fn_ptr->read(fwu->rmi4_data,
-			fwu->f34_fd.query_base_addr + BLOCK_SIZE_OFFSET,
+			fwu_get_address(OFFSET_BLOCK_SIZE),
 			buf,
 			2);
 	if (retval < 0) {
@@ -410,13 +540,13 @@
 	batohs(&fwu->block_size, &(buf[0]));
 
 	retval = fwu->fn_ptr->read(fwu->rmi4_data,
-			fwu->f34_fd.query_base_addr + FW_BLOCK_COUNT_OFFSET,
+			fwu_get_address(OFFSET_FW_BLOCK_COUNT),
 			buf,
 			count);
 	if (retval < 0) {
 		dev_err(&i2c_client->dev,
-				"%s: Failed to read block count info\n",
-				__func__);
+			"%s: Failed to read block count info\n",
+			__func__);
 		return retval;
 	}
 
@@ -438,9 +568,6 @@
 	if (fwu->flash_properties.has_display_config)
 		batohs(&fwu->disp_config_block_count, &(buf[count]));
 
-	fwu->addr_f34_flash_control = fwu->f34_fd.data_base_addr +
-					BLOCK_DATA_OFFSET +
-					fwu->block_size;
 	return 0;
 }
 
@@ -461,18 +588,36 @@
 	return interrupt_status;
 }
 
-static int fwu_read_f34_flash_status(void)
+static int fwu_read_f34_flash_status(unsigned char *status)
 {
 	int retval;
-	retval = fwu->fn_ptr->read(fwu->rmi4_data,
-			fwu->addr_f34_flash_control,
-			fwu->flash_control.data,
-			sizeof(fwu->flash_control.data));
-	if (retval < 0) {
-		dev_err(&fwu->rmi4_data->i2c_client->dev,
+	struct f34_flash_control flash_control;
+	struct f34_flash_status flash_status;
+
+	if (fwu->f34_fd.version == 1) {
+		retval = fwu->fn_ptr->read(fwu->rmi4_data,
+			fwu_get_address(OFFSET_FLASH_STATUS),
+			flash_status.data,
+			sizeof(flash_status.data));
+		if (retval < 0) {
+			dev_err(&fwu->rmi4_data->i2c_client->dev,
 				"%s: Failed to read flash status\n",
 				__func__);
-		return retval;
+			return -EIO;
+		}
+		*status = flash_status.status;
+	} else {
+		retval = fwu->fn_ptr->read(fwu->rmi4_data,
+			fwu_get_address(OFFSET_FLASH_CONTROL),
+			flash_control.data,
+			sizeof(flash_control.data));
+		if (retval < 0) {
+			dev_err(&fwu->rmi4_data->i2c_client->dev,
+				"%s: Failed to read flash status\n",
+				__func__);
+			return -EIO;
+		}
+		*status = flash_control.status;
 	}
 	return 0;
 }
@@ -492,22 +637,27 @@
 				__func__);
 		return retval;
 	}
+
+	fwu->polling_mode = false;
+
 	return 0;
 }
 
 static int fwu_write_f34_command(unsigned char cmd)
 {
 	int retval;
+	struct f34_flash_control flash_control;
 
-	fwu->flash_control.data[0] = cmd;
+	flash_control.data[0] = cmd;
+	fwu->interrupt_flag = false;
 	retval = fwu->fn_ptr->write(fwu->rmi4_data,
-			fwu->addr_f34_flash_control,
-			fwu->flash_control.data,
-			sizeof(fwu->flash_control.data));
+			fwu_get_address(OFFSET_FLASH_CONTROL),
+			flash_control.data,
+			sizeof(flash_control.data));
 	if (retval < 0) {
 		dev_err(&fwu->rmi4_data->i2c_client->dev,
 				"%s: Failed to write command 0x%02x\n",
-				__func__, fwu->flash_control.data[0]);
+				__func__, flash_control.data[0]);
 		return retval;
 	}
 	return 0;
@@ -518,18 +668,21 @@
 	int count = 0;
 	int timeout_count = ((timeout_ms * 1000) / SLEEP_TIME_US) + 1;
 	do {
-		#if POLLING_MODE
-		fwu_read_f34_flash_status();
-		#endif
-		if (fwu->flash_control.command == 0x00)
+		if (fwu->interrupt_flag)
 			return 0;
-
-		usleep_range(SLEEP_TIME_US, SLEEP_TIME_US + 100);
+		if (fwu->polling_mode)
+			if (fwu->intr_mask & fwu_read_interrupt_status())
+				return 0;
+		usleep_range(SLEEP_TIME_US, SLEEP_TIME_US + 1);
 	} while (count++ < timeout_count);
 
-	fwu_read_f34_flash_status();
-	if (fwu->flash_control.command == 0x00)
+	if (fwu->intr_mask & fwu_read_interrupt_status()) {
+		fwu->polling_mode = true;
+		dev_info(&fwu->rmi4_data->i2c_client->dev,
+			"%s: Switch to polling mode\n",
+			__func__);
 		return 0;
+	}
 
 	dev_err(&fwu->rmi4_data->i2c_client->dev,
 			"%s: Timed out waiting for idle status\n",
@@ -538,7 +691,7 @@
 	return -ETIMEDOUT;
 }
 
-static enum flash_area fwu_go_nogo(struct image_header *header)
+static enum flash_area fwu_go_nogo(void)
 {
 	int retval = 0;
 	int index = 0;
@@ -554,30 +707,53 @@
 	enum flash_area flash_area = NONE;
 	struct i2c_client *i2c_client = fwu->rmi4_data->i2c_client;
 	struct f01_device_status f01_device_status;
+	struct image_content *img = &fwu->image_content;
 
 	if (fwu->force_update) {
 		flash_area = UI_FIRMWARE;
 		goto exit;
 	}
 
-	if (header->is_contain_build_info) {
+	if (img->is_contain_build_info) {
 		/* if package id does not match, do not update firmware */
 		fwu->fn_ptr->read(fwu->rmi4_data,
 					fwu->f01_fd.query_base_addr + 17,
 					pkg_id,
 					sizeof(pkg_id));
 
-		if (header->package_id != ((pkg_id[1] << 8) | pkg_id[0])) {
+		if (img->package_id != ((pkg_id[1] << 8) | pkg_id[0])) {
 			flash_area = MISMATCH;
 			goto exit;
 		}
-		if (header->package_revision_id !=
+		if (img->package_revision_id !=
 				((pkg_id[3] << 8) | pkg_id[2])) {
 			flash_area = MISMATCH;
 			goto exit;
 		}
 	}
 
+	/* check firmware size */
+	if (fwu->fw_block_count*fwu->block_size != img->image_size) {
+		dev_err(&i2c_client->dev,
+			"%s: firmware size of device (%d) != .img (%d)\n",
+			__func__,
+			fwu->config_block_count * fwu->block_size,
+			img->image_size);
+		flash_area = NONE;
+		goto exit;
+	}
+
+	/* check config size */
+	if (fwu->config_block_count*fwu->block_size != img->config_size) {
+		dev_err(&i2c_client->dev,
+			"%s: config size of device (%d) != .img (%d)\n",
+			__func__,
+			fwu->config_block_count * fwu->block_size,
+			img->config_size);
+		flash_area = NONE;
+		goto exit;
+	}
+
 	retval = fwu_read_f01_device_status(&f01_device_status);
 	if (retval < 0) {
 		flash_area = NONE;
@@ -608,14 +784,21 @@
 	deviceFirmwareID = extract_uint(firmware_id);
 
 	/* .img firmware id */
-	if (header->is_contain_build_info) {
+	if (img->is_contain_build_info) {
 		dev_err(&i2c_client->dev,
 			"%s: Image option contains build info.\n",
 			__func__);
-		imageFirmwareID = header->firmware_id;
+		imageFirmwareID = img->firmware_id;
 	} else {
-		strptr = strnstr(fwu->firmware_name, "PR",
-				sizeof(fwu->firmware_name));
+		if (!fwu->image_name) {
+			dev_info(&i2c_client->dev,
+				"%s: Unknown image file name\n",
+				__func__);
+			flash_area = UI_FIRMWARE;
+			goto exit;
+		}
+		strptr = strnstr(fwu->image_name, "PR",
+				sizeof(fwu->image_name));
 		if (!strptr) {
 			dev_err(&i2c_client->dev,
 				"No valid PR number (PRxxxxxxx)" \
@@ -771,21 +954,41 @@
 		unsigned char command)
 {
 	int retval;
+	unsigned char flash_status;
 	unsigned char block_offset[] = {0, 0};
 	unsigned short block_num;
+	unsigned short addr_block_data = fwu_get_address(OFFSET_BLOCK_DATA);
+	unsigned short addr_block_num = fwu_get_address(OFFSET_BLOCK_NUMBER);
 	struct i2c_client *i2c_client = fwu->rmi4_data->i2c_client;
 #ifdef SHOW_PROGRESS
-	unsigned int progress = (command == CMD_WRITE_CONFIG_BLOCK) ?
-				10 : 100;
+	unsigned int progress;
+	unsigned char command_str[10];
+	switch (command) {
+	case CMD_WRITE_CONFIG_BLOCK:
+		progress = 10;
+		strlcpy(command_str, "config", 10);
+		break;
+	case CMD_WRITE_FW_BLOCK:
+		progress = 100;
+		strlcpy(command_str, "firmware", 10);
+		break;
+	case CMD_WRITE_LOCKDOWN_BLOCK:
+		progress = 1;
+		strlcpy(command_str, "lockdown", 10);
+		break;
+	default:
+		progress = 1;
+		strlcpy(command_str, "unknown", 10);
+		break;
+	}
 #endif
 
 	dev_dbg(&i2c_client->dev,
 			"%s: Start to update %s blocks\n",
 			__func__,
-			command == CMD_WRITE_CONFIG_BLOCK ?
-			"config" : "firmware");
+			command_str);
 	retval = fwu->fn_ptr->write(fwu->rmi4_data,
-			fwu->f34_fd.data_base_addr + BLOCK_NUMBER_OFFSET,
+			addr_block_num,
 			block_offset,
 			sizeof(block_offset));
 	if (retval < 0) {
@@ -801,12 +1004,11 @@
 			dev_info(&i2c_client->dev,
 					"%s: update %s %3d / %3d\n",
 					__func__,
-					command == CMD_WRITE_CONFIG_BLOCK ?
-					"config" : "firmware",
+					command_str,
 					block_num, block_cnt);
 #endif
 		retval = fwu->fn_ptr->write(fwu->rmi4_data,
-			fwu->f34_fd.data_base_addr + BLOCK_DATA_OFFSET,
+			addr_block_data,
 			block_ptr,
 			fwu->block_size);
 		if (retval < 0) {
@@ -832,21 +1034,28 @@
 			return retval;
 		}
 
-		if (fwu->flash_control.status != 0x00) {
+		#if CHECK_FLASH_BLOCK_STATUS
+		retval = fwu_read_f34_flash_status(&flash_status);
+		if (retval < 0) {
 			dev_err(&i2c_client->dev,
-					"%s: Flash block %d failed, status 0x%02X\n",
-					__func__, block_num, retval);
+					"%s: Failed to read flash status (block %d)\n",
+					__func__, block_num);
 			return retval;
 		}
-
+		if (flash_status != 0x00) {
+			dev_err(&i2c_client->dev,
+				"%s: Flash block %d failed, status 0x%02X\n",
+				__func__, block_num, flash_status);
+			return -EINVAL;
+		}
+		#endif
 		block_ptr += fwu->block_size;
 	}
 #ifdef SHOW_PROGRESS
 	dev_info(&i2c_client->dev,
 			"%s: update %s %3d / %3d\n",
 			__func__,
-			command == CMD_WRITE_CONFIG_BLOCK ?
-			"config" : "firmware",
+			command_str,
 			block_cnt, block_cnt);
 #endif
 	return 0;
@@ -864,6 +1073,12 @@
 		fwu->config_block_count, CMD_WRITE_CONFIG_BLOCK);
 }
 
+static int fwu_write_lockdown_block(void)
+{
+	return fwu_write_blocks((unsigned char *)fwu->lockdown_data,
+		fwu->lockdown_block_count, CMD_WRITE_LOCKDOWN_BLOCK);
+}
+
 static int fwu_write_bootloader_id(void)
 {
 	int retval;
@@ -874,7 +1089,7 @@
 			fwu->bootloader_id[1]);
 
 	retval = fwu->fn_ptr->write(fwu->rmi4_data,
-			fwu->f34_fd.data_base_addr + BLOCK_DATA_OFFSET,
+			fwu_get_address(OFFSET_BLOCK_DATA),
 			fwu->bootloader_id,
 			sizeof(fwu->bootloader_id));
 	if (retval < 0) {
@@ -887,7 +1102,7 @@
 	return 0;
 }
 
-static int fwu_enter_flash_prog(void)
+static int fwu_enter_flash_prog(bool force)
 {
 	int retval;
 	struct f01_device_status f01_device_status;
@@ -899,7 +1114,11 @@
 	if (retval < 0)
 		return retval;
 
-	if (f01_device_status.flash_prog) {
+	if (force) {
+		dev_info(&fwu->rmi4_data->i2c_client->dev,
+			"%s: Force to enter flash prog mode\n",
+			__func__);
+	} else if (f01_device_status.flash_prog) {
 		dev_info(&fwu->rmi4_data->i2c_client->dev,
 				"%s: Already in flash prog mode\n",
 				__func__);
@@ -961,63 +1180,7 @@
 				__func__);
 		return retval;
 	}
-
-	return retval;
-}
-
-static int fwu_do_reflash(void)
-{
-	int retval;
-
-	retval = fwu_enter_flash_prog();
-	if (retval < 0)
-		return retval;
-
-	dev_dbg(&fwu->rmi4_data->i2c_client->dev,
-			"%s: Entered flash prog mode\n",
-			__func__);
-
-	retval = fwu_write_bootloader_id();
-	if (retval < 0)
-		return retval;
-
-	dev_dbg(&fwu->rmi4_data->i2c_client->dev,
-			"%s: Bootloader ID written\n",
-			__func__);
-
-	retval = fwu_write_f34_command(CMD_ERASE_ALL);
-	if (retval < 0)
-		return retval;
-
-	dev_dbg(&fwu->rmi4_data->i2c_client->dev,
-			"%s: Erase all command written\n",
-			__func__);
-
-	retval = fwu_wait_for_idle(ERASE_WAIT_MS);
-	if (retval < 0)
-		return retval;
-
-	if (fwu->flash_control.status != 0x00) {
-		dev_err(&fwu->rmi4_data->i2c_client->dev,
-				"%s: Erase all command failed, status 0x%02X\n",
-				__func__, retval);
-		return -1;
-	}
-
-	if (fwu->firmware_data) {
-		retval = fwu_write_firmware();
-		if (retval < 0)
-			return retval;
-		pr_notice("%s: Firmware programmed\n", __func__);
-	}
-
-	if (fwu->config_data) {
-		retval = fwu_write_configuration();
-		if (retval < 0)
-			return retval;
-		pr_notice("%s: Configuration programmed\n", __func__);
-	}
-
+	fwu->polling_mode = false;
 	return retval;
 }
 
@@ -1025,7 +1188,7 @@
 {
 	int retval;
 
-	retval = fwu_enter_flash_prog();
+	retval = fwu_enter_flash_prog(false);
 	if (retval < 0)
 		return retval;
 
@@ -1087,42 +1250,38 @@
 static int fwu_start_write_config(void)
 {
 	int retval;
-	struct image_header header;
+	int block_count;
 
 	switch (fwu->config_area) {
 	case UI_CONFIG_AREA:
+		block_count = fwu->config_block_count;
 		break;
 	case PERM_CONFIG_AREA:
 		if (!fwu->flash_properties.has_perm_config)
 			return -EINVAL;
+		block_count = fwu->perm_config_block_count;
 		break;
 	case BL_CONFIG_AREA:
 		if (!fwu->flash_properties.has_bl_config)
 			return -EINVAL;
+		block_count = fwu->bl_config_block_count;
 		break;
 	case DISP_CONFIG_AREA:
 		if (!fwu->flash_properties.has_display_config)
 			return -EINVAL;
+		block_count = fwu->disp_config_block_count;
 		break;
 	default:
 		return -EINVAL;
 	}
 
-	if (fwu->ext_data_source)
-		fwu->config_data = fwu->ext_data_source;
-	else
-		return -EINVAL;
-
-	if (fwu->config_area == UI_CONFIG_AREA) {
-		parse_header(&header, fwu->ext_data_source);
-
-		if (header.config_size) {
-			fwu->config_data = fwu->ext_data_source +
-					FW_IMAGE_OFFSET +
-					header.image_size;
-		} else {
-			return -EINVAL;
-		}
+	if (fwu->image_size == block_count*fwu->block_size) {
+		dev_info(&fwu->rmi4_data->i2c_client->dev,
+				"%s: write config from config file\n",
+				__func__);
+		fwu->config_data = fwu->data_buffer;
+	} else {
+		parse_header();
 	}
 
 	pr_notice("%s: Start of write config process\n", __func__);
@@ -1141,6 +1300,58 @@
 	return retval;
 }
 
+static int fwu_do_write_lockdown(bool reset)
+{
+	int retval;
+
+	pr_notice("%s: Start of lockdown process\n", __func__);
+
+	retval = fwu_enter_flash_prog(false);
+	if (retval < 0)
+		return retval;
+
+	dev_dbg(&fwu->rmi4_data->i2c_client->dev,
+			"%s: Entered flash prog mode\n",
+			__func__);
+
+	if (fwu->flash_properties.unlocked == 0) {
+		dev_err(&fwu->rmi4_data->i2c_client->dev,
+			"%s: Device has been locked!\n",
+			__func__);
+		if (reset)
+			goto exit;
+		else
+			return -EINVAL;
+	}
+
+	retval = fwu_write_lockdown_block();
+	if (retval < 0)
+		return retval;
+
+	dev_dbg(&fwu->rmi4_data->i2c_client->dev,
+			"%s:Lockdown device\n",
+			__func__);
+
+exit:
+	if (reset)
+		retval = fwu->rmi4_data->reset_device(fwu->rmi4_data);
+	else
+		retval = fwu_enter_flash_prog(true);
+
+	if (retval < 0)
+		return retval;
+
+	pr_notice("%s: End of lockdown process\n", __func__);
+
+	return retval;
+}
+
+static int fwu_start_write_lockdown(void)
+{
+	parse_header();
+	return fwu_do_write_lockdown(true);
+}
+
 static int fwu_do_read_config(void)
 {
 	int retval;
@@ -1149,14 +1360,6 @@
 	unsigned short block_count;
 	unsigned short index = 0;
 
-	retval = fwu_enter_flash_prog();
-	if (retval < 0)
-		goto exit;
-
-	dev_dbg(&fwu->rmi4_data->i2c_client->dev,
-			"%s: Entered flash prog mode\n",
-			__func__);
-
 	switch (fwu->config_area) {
 	case UI_CONFIG_AREA:
 		block_count = fwu->config_block_count;
@@ -1195,7 +1398,7 @@
 	block_offset[1] |= (fwu->config_area << 5);
 
 	retval = fwu->fn_ptr->write(fwu->rmi4_data,
-			fwu->f34_fd.data_base_addr + BLOCK_NUMBER_OFFSET,
+			fwu_get_address(OFFSET_BLOCK_NUMBER),
 			block_offset,
 			sizeof(block_offset));
 	if (retval < 0) {
@@ -1223,7 +1426,7 @@
 		}
 
 		retval = fwu->fn_ptr->read(fwu->rmi4_data,
-				fwu->f34_fd.data_base_addr + BLOCK_DATA_OFFSET,
+				fwu_get_address(OFFSET_BLOCK_DATA),
 				&fwu->read_config_buf[index],
 				fwu->block_size);
 		if (retval < 0) {
@@ -1237,7 +1440,74 @@
 	}
 
 exit:
-	fwu->rmi4_data->reset_device(fwu->rmi4_data);
+	return retval;
+}
+
+static int fwu_do_reflash(void)
+{
+	int retval;
+	unsigned char flash_status;
+
+	if (fwu->do_lockdown) {
+		retval = fwu_do_write_lockdown(false);
+		if (retval < 0)
+			dev_warn(&fwu->rmi4_data->i2c_client->dev,
+			"%s: Skip lockdown process.\n",
+			__func__);
+	}
+	retval = fwu_enter_flash_prog(false);
+	if (retval < 0)
+		return retval;
+	dev_dbg(&fwu->rmi4_data->i2c_client->dev,
+			"%s: Entered flash prog mode\n",
+			__func__);
+
+	retval = fwu_write_bootloader_id();
+	if (retval < 0)
+		return retval;
+
+	dev_dbg(&fwu->rmi4_data->i2c_client->dev,
+			"%s: Bootloader ID written\n",
+			__func__);
+
+	retval = fwu_write_f34_command(CMD_ERASE_ALL);
+	if (retval < 0)
+		return retval;
+
+	dev_dbg(&fwu->rmi4_data->i2c_client->dev,
+			"%s: Erase all command written\n",
+			__func__);
+
+	if (fwu->polling_mode)
+		msleep(100);
+
+	retval = fwu_wait_for_idle(ERASE_WAIT_MS);
+	if (retval < 0)
+		return retval;
+
+	retval = fwu_read_f34_flash_status(&flash_status);
+	if (retval < 0)
+		return retval;
+	if (flash_status != 0x00) {
+		dev_err(&fwu->rmi4_data->i2c_client->dev,
+				"%s: Erase all command failed, status 0x%02X\n",
+				__func__, flash_status);
+		return -EINVAL;
+	}
+
+	if (fwu->firmware_data) {
+		retval = fwu_write_firmware();
+		if (retval < 0)
+			return retval;
+		pr_notice("%s: Firmware programmed\n", __func__);
+	}
+
+	if (fwu->config_data) {
+		retval = fwu_write_configuration();
+		if (retval < 0)
+			return retval;
+		pr_notice("%s: Configuration programmed\n", __func__);
+	}
 
 	return retval;
 }
@@ -1245,45 +1515,47 @@
 static int fwu_start_reflash(void)
 {
 	int retval = 0;
-	struct image_header header;
-	const unsigned char *fw_image;
 	const struct firmware *fw_entry = NULL;
 	struct f01_device_status f01_device_status;
 	enum flash_area flash_area;
 
 	pr_notice("%s: Start of reflash process\n", __func__);
 
-	if (strnlen(fwu->rmi4_data->fw_image_name, NAME_BUFFER_SIZE) == 0) {
-		dev_err(&fwu->rmi4_data->i2c_client->dev,
-			"Firmware image name not given, skipping update\n");
-		return 0;
-	}
-
-	if (strnlen(fwu->rmi4_data->fw_image_name, NAME_BUFFER_SIZE) ==
-		NAME_BUFFER_SIZE) {
-		dev_err(&fwu->rmi4_data->i2c_client->dev,
-			"Firmware image name exceeds max length (%d), " \
-			"skipping update\n", NAME_BUFFER_SIZE);
-		return 0;
-	}
-
 	if (fwu->ext_data_source)
-		fw_image = fwu->ext_data_source;
+		dev_info(&fwu->rmi4_data->i2c_client->dev,
+				"%s Load .img file from commandline.\n",
+				__func__);
 	else {
-		snprintf(fwu->firmware_name, NAME_BUFFER_SIZE, "%s",
+		if (strnlen(fwu->rmi4_data->fw_image_name,
+				NAME_BUFFER_SIZE) == 0) {
+			dev_err(&fwu->rmi4_data->i2c_client->dev,
+				"Firmware image name not given, "\
+				"skipping update\n");
+			return 0;
+		}
+
+		if (strnlen(fwu->rmi4_data->fw_image_name, NAME_BUFFER_SIZE) ==
+			NAME_BUFFER_SIZE) {
+			dev_err(&fwu->rmi4_data->i2c_client->dev,
+				"Firmware image name exceeds max length " \
+				"(%d), skipping update\n", NAME_BUFFER_SIZE);
+			return 0;
+		}
+
+		snprintf(fwu->image_name, NAME_BUFFER_SIZE, "%s",
 			fwu->rmi4_data->fw_image_name);
 		dev_info(&fwu->rmi4_data->i2c_client->dev,
 			"%s: Requesting firmware image %s\n",
-			__func__, fwu->firmware_name);
+			__func__, fwu->image_name);
 
 		retval = request_firmware(&fw_entry,
-				fwu->firmware_name,
+				fwu->image_name,
 				&fwu->rmi4_data->i2c_client->dev);
 		if (retval != 0) {
 			dev_err(&fwu->rmi4_data->i2c_client->dev,
 					"%s: Firmware image %s not available\n",
 					__func__,
-					fwu->firmware_name);
+					fwu->image_name);
 			return -EINVAL;
 		}
 
@@ -1291,22 +1563,20 @@
 				"%s: Firmware image size = %d\n",
 				__func__, fw_entry->size);
 
-		fw_image = fw_entry->data;
+		fwu->data_buffer = fw_entry->data;
 	}
 
-	parse_header(&header, fw_image);
+	parse_header();
+	flash_area = fwu_go_nogo();
 
-	if (header.image_size)
-		fwu->firmware_data = fw_image + FW_IMAGE_OFFSET;
-	if (header.config_size) {
-		fwu->config_data = fw_image + FW_IMAGE_OFFSET +
-				header.image_size;
+	if (fwu->rmi4_data->sensor_sleep) {
+		dev_err(&fwu->rmi4_data->i2c_client->dev,
+			"%s: Sensor sleeping\n",
+			__func__);
+		retval = -ENODEV;
+		goto exit;
 	}
-
-	if (fwu->ext_data_source)
-		flash_area = UI_FIRMWARE;
-	else
-		flash_area = fwu_go_nogo(&header);
+	fwu->rmi4_data->stay_awake = true;
 
 	switch (flash_area) {
 	case NONE:
@@ -1326,14 +1596,14 @@
 		dev_err(&fwu->rmi4_data->i2c_client->dev,
 				"%s: Unknown flash area\n",
 				__func__);
+		retval = -EINVAL;
 		goto exit;
 	}
 
-	if (retval < 0) {
+	if (retval < 0)
 		dev_err(&fwu->rmi4_data->i2c_client->dev,
 				"%s: Failed to do reflash\n",
 				__func__);
-	}
 
 	/* reset device */
 	fwu_reset_device();
@@ -1353,8 +1623,6 @@
 		dev_info(&fwu->rmi4_data->i2c_client->dev,
 				"%s: Device is in flash prog mode 0x%02X\n",
 				__func__, f01_device_status.status_code);
-		retval = 0;
-		goto exit;
 	}
 
 exit:
@@ -1362,10 +1630,11 @@
 		release_firmware(fw_entry);
 
 	pr_notice("%s: End of reflash process\n", __func__);
+	fwu->rmi4_data->stay_awake = false;
 	return retval;
 }
 
-int synaptics_fw_updater(unsigned char *fw_data)
+int synaptics_fw_updater(void)
 {
 	int retval;
 
@@ -1383,7 +1652,6 @@
 		return -EBUSY;
 	}
 
-	fwu->ext_data_source = fw_data;
 	fwu->config_area = UI_CONFIG_AREA;
 
 	retval = fwu_start_reflash();
@@ -1421,12 +1689,13 @@
 			(const void *)buf,
 			count);
 
+	fwu->data_buffer = fwu->ext_data_source;
 	fwu->data_pos += count;
 
 	return count;
 }
 
-static ssize_t fwu_sysfs_fw_name_store(struct device *dev,
+static ssize_t fwu_sysfs_image_name_store(struct device *dev,
 		struct device_attribute *attr, const char *buf, size_t count)
 {
 	struct synaptics_rmi4_data *rmi4_data = fwu->rmi4_data;
@@ -1450,7 +1719,7 @@
 	return count;
 }
 
-static ssize_t fwu_sysfs_fw_name_show(struct device *dev,
+static ssize_t fwu_sysfs_image_name_show(struct device *dev,
 		struct device_attribute *attr, char *buf)
 {
 	if (strnlen(fwu->rmi4_data->fw_image_name, NAME_BUFFER_SIZE) > 0)
@@ -1476,9 +1745,11 @@
 		retval = -EINVAL;
 		goto exit;
 	}
+	if (LOCKDOWN)
+		fwu->do_lockdown = true;
 
 	fwu->force_update = true;
-	retval = synaptics_fw_updater(fwu->ext_data_source);
+	retval = synaptics_fw_updater();
 	if (retval < 0) {
 		dev_err(&rmi4_data->i2c_client->dev,
 				"%s: Failed to do reflash\n",
@@ -1491,6 +1762,8 @@
 exit:
 	kfree(fwu->ext_data_source);
 	fwu->ext_data_source = NULL;
+	fwu->force_update = FORCE_UPDATE;
+	fwu->do_lockdown = rmi4_data->board->do_lockdown;
 	return retval;
 }
 
@@ -1506,15 +1779,58 @@
 		goto exit;
 	}
 
+	if (input & LOCKDOWN) {
+		fwu->do_lockdown = true;
+		input &= ~LOCKDOWN;
+	}
+
+	if ((input != NORMAL) && (input != FORCE)) {
+		retval = -EINVAL;
+		goto exit;
+	}
+
+	if (input == FORCE)
+		fwu->force_update = true;
+
+	retval = synaptics_fw_updater();
+	if (retval < 0) {
+		dev_err(&rmi4_data->i2c_client->dev,
+				"%s: Failed to do reflash\n",
+				__func__);
+		goto exit;
+	}
+
+	retval = count;
+
+exit:
+	kfree(fwu->ext_data_source);
+	fwu->ext_data_source = NULL;
+	fwu->force_update = FORCE_UPDATE;
+	fwu->do_lockdown = rmi4_data->board->do_lockdown;
+	return retval;
+}
+
+static ssize_t fwu_sysfs_write_lockdown_store(struct device *dev,
+		struct device_attribute *attr, const char *buf, size_t count)
+{
+	int retval;
+	unsigned int input;
+	struct synaptics_rmi4_data *rmi4_data = fwu->rmi4_data;
+
+	if (sscanf(buf, "%u", &input) != 1) {
+		retval = -EINVAL;
+		goto exit;
+	}
+
 	if (input != 1) {
 		retval = -EINVAL;
 		goto exit;
 	}
 
-	retval = synaptics_fw_updater(fwu->ext_data_source);
+	retval = fwu_start_write_lockdown();
 	if (retval < 0) {
 		dev_err(&rmi4_data->i2c_client->dev,
-				"%s: Failed to do reflash\n",
+				"%s: Failed to write lockdown block\n",
 				__func__);
 		goto exit;
 	}
@@ -1524,6 +1840,8 @@
 exit:
 	kfree(fwu->ext_data_source);
 	fwu->ext_data_source = NULL;
+	fwu->force_update = FORCE_UPDATE;
+	fwu->do_lockdown = rmi4_data->board->do_lockdown;
 	return retval;
 }
 
@@ -1714,7 +2032,7 @@
 		unsigned char intr_mask)
 {
 	if (fwu->intr_mask & intr_mask)
-		fwu_read_f34_flash_status();
+		fwu->interrupt_flag = true;
 
 	return;
 }
@@ -1731,8 +2049,8 @@
 
 static struct device_attribute attrs[] = {
 	__ATTR(fw_name, S_IRUGO | S_IWUSR | S_IWGRP,
-			fwu_sysfs_fw_name_show,
-			fwu_sysfs_fw_name_store),
+			fwu_sysfs_image_name_show,
+			fwu_sysfs_image_name_store),
 	__ATTR(force_update_fw, S_IRUGO | S_IWUSR | S_IWGRP,
 			synaptics_rmi4_show_error,
 			fwu_sysfs_force_reflash_store),
@@ -1742,6 +2060,9 @@
 	__ATTR(writeconfig, S_IRUGO | S_IWUSR | S_IWGRP,
 			synaptics_rmi4_show_error,
 			fwu_sysfs_write_config_store),
+	__ATTR(writelockdown, S_IRUGO | S_IWUSR | S_IWGRP,
+			synaptics_rmi4_show_error,
+			fwu_sysfs_write_lockdown_store),
 	__ATTR(readconfig, S_IRUGO | S_IWUSR | S_IWGRP,
 			synaptics_rmi4_show_error,
 			fwu_sysfs_read_config_store),
@@ -1851,6 +2172,9 @@
 
 	fwu->initialized = true;
 	fwu->force_update = FORCE_UPDATE;
+	fwu->do_lockdown = rmi4_data->board->do_lockdown;
+	fwu->initialized = true;
+	fwu->polling_mode = false;
 
 	retval = sysfs_create_bin_file(&rmi4_data->i2c_client->dev.kobj,
 			&dev_attr_data);
@@ -1900,24 +2224,23 @@
 			msecs_to_jiffies(1000));
 #endif
 
-	init_completion(&remove_complete);
-
 	return 0;
 exit_free_ts_info:
 	debugfs_remove(temp);
 exit_remove_attrs:
-for (attr_count--; attr_count >= 0; attr_count--) {
-	sysfs_remove_file(&rmi4_data->input_dev->dev.kobj,
-			&attrs[attr_count].attr);
-}
+	for (attr_count--; attr_count >= 0; attr_count--) {
+		sysfs_remove_file(&rmi4_data->input_dev->dev.kobj,
+				&attrs[attr_count].attr);
+	}
 
-sysfs_remove_bin_file(&rmi4_data->input_dev->dev.kobj, &dev_attr_data);
+	sysfs_remove_bin_file(&rmi4_data->input_dev->dev.kobj, &dev_attr_data);
 
 exit_free_mem:
 	kfree(fwu->fn_ptr);
 
 exit_free_fwu:
 	kfree(fwu);
+	fwu = NULL;
 
 exit:
 	return 0;
@@ -1934,10 +2257,11 @@
 				&attrs[attr_count].attr);
 	}
 
+	kfree(fwu->read_config_buf);
 	kfree(fwu->fn_ptr);
 	kfree(fwu);
 
-	complete(&remove_complete);
+	complete(&fwu_remove_complete);
 
 	return;
 }
@@ -1957,7 +2281,7 @@
 			synaptics_rmi4_fwu_init,
 			synaptics_rmi4_fwu_remove,
 			synaptics_rmi4_fwu_attn);
-	wait_for_completion(&remove_complete);
+	wait_for_completion(&fwu_remove_complete);
 	return;
 }
 
diff --git a/drivers/input/touchscreen/synaptics_i2c_rmi4.c b/drivers/input/touchscreen/synaptics_i2c_rmi4.c
index ba0be2b..aec655c 100644
--- a/drivers/input/touchscreen/synaptics_i2c_rmi4.c
+++ b/drivers/input/touchscreen/synaptics_i2c_rmi4.c
@@ -93,6 +93,10 @@
 #define RMI4_I2C_LPM_LOAD_UA	10
 
 #define RMI4_GPIO_SLEEP_LOW_US 10000
+#define F12_FINGERS_TO_SUPPORT 10
+#define MAX_F11_TOUCH_WIDTH 15
+
+#define RMI4_COORDS_ARR_SIZE 4
 
 static int synaptics_rmi4_i2c_read(struct synaptics_rmi4_data *rmi4_data,
 		unsigned short addr, unsigned char *data,
@@ -168,6 +172,131 @@
 	};
 };
 
+struct synaptics_rmi4_f12_query_5 {
+	union {
+		struct {
+			unsigned char size_of_query6;
+			struct {
+				unsigned char ctrl0_is_present:1;
+				unsigned char ctrl1_is_present:1;
+				unsigned char ctrl2_is_present:1;
+				unsigned char ctrl3_is_present:1;
+				unsigned char ctrl4_is_present:1;
+				unsigned char ctrl5_is_present:1;
+				unsigned char ctrl6_is_present:1;
+				unsigned char ctrl7_is_present:1;
+			} __packed;
+			struct {
+				unsigned char ctrl8_is_present:1;
+				unsigned char ctrl9_is_present:1;
+				unsigned char ctrl10_is_present:1;
+				unsigned char ctrl11_is_present:1;
+				unsigned char ctrl12_is_present:1;
+				unsigned char ctrl13_is_present:1;
+				unsigned char ctrl14_is_present:1;
+				unsigned char ctrl15_is_present:1;
+			} __packed;
+			struct {
+				unsigned char ctrl16_is_present:1;
+				unsigned char ctrl17_is_present:1;
+				unsigned char ctrl18_is_present:1;
+				unsigned char ctrl19_is_present:1;
+				unsigned char ctrl20_is_present:1;
+				unsigned char ctrl21_is_present:1;
+				unsigned char ctrl22_is_present:1;
+				unsigned char ctrl23_is_present:1;
+			} __packed;
+			struct {
+				unsigned char ctrl24_is_present:1;
+				unsigned char ctrl25_is_present:1;
+				unsigned char ctrl26_is_present:1;
+				unsigned char ctrl27_is_present:1;
+				unsigned char ctrl28_is_present:1;
+				unsigned char ctrl29_is_present:1;
+				unsigned char ctrl30_is_present:1;
+				unsigned char ctrl31_is_present:1;
+			} __packed;
+		};
+		unsigned char data[5];
+	};
+};
+
+struct synaptics_rmi4_f12_query_8 {
+	union {
+		struct {
+			unsigned char size_of_query9;
+			struct {
+				unsigned char data0_is_present:1;
+				unsigned char data1_is_present:1;
+				unsigned char data2_is_present:1;
+				unsigned char data3_is_present:1;
+				unsigned char data4_is_present:1;
+				unsigned char data5_is_present:1;
+				unsigned char data6_is_present:1;
+				unsigned char data7_is_present:1;
+			} __packed;
+			struct {
+				unsigned char data8_is_present:1;
+				unsigned char data9_is_present:1;
+				unsigned char data10_is_present:1;
+				unsigned char data11_is_present:1;
+				unsigned char data12_is_present:1;
+				unsigned char data13_is_present:1;
+				unsigned char data14_is_present:1;
+				unsigned char data15_is_present:1;
+			} __packed;
+		};
+		unsigned char data[3];
+	};
+};
+
+struct synaptics_rmi4_f12_ctrl_8 {
+	union {
+		struct {
+			unsigned char max_x_coord_lsb;
+			unsigned char max_x_coord_msb;
+			unsigned char max_y_coord_lsb;
+			unsigned char max_y_coord_msb;
+			unsigned char rx_pitch_lsb;
+			unsigned char rx_pitch_msb;
+			unsigned char tx_pitch_lsb;
+			unsigned char tx_pitch_msb;
+			unsigned char low_rx_clip;
+			unsigned char high_rx_clip;
+			unsigned char low_tx_clip;
+			unsigned char high_tx_clip;
+			unsigned char num_of_rx;
+			unsigned char num_of_tx;
+		};
+		unsigned char data[14];
+	};
+};
+
+struct synaptics_rmi4_f12_ctrl_23 {
+	union {
+		struct {
+			unsigned char obj_type_enable;
+			unsigned char max_reported_objects;
+		};
+		unsigned char data[2];
+	};
+};
+
+struct synaptics_rmi4_f12_finger_data {
+	unsigned char object_type_and_status;
+	unsigned char x_lsb;
+	unsigned char x_msb;
+	unsigned char y_lsb;
+	unsigned char y_msb;
+#ifdef REPORT_2D_Z
+	unsigned char z;
+#endif
+#ifdef REPORT_2D_W
+	unsigned char wx;
+	unsigned char wy;
+#endif
+};
+
 struct synaptics_rmi4_f1a_query {
 	union {
 		struct {
@@ -223,6 +352,13 @@
 	struct synaptics_rmi4_f1a_control button_control;
 };
 
+struct synaptics_rmi4_f12_extra_data {
+	unsigned char data1_offset;
+	unsigned char data15_offset;
+	unsigned char data15_size;
+	unsigned char data15_data[(F12_FINGERS_TO_SUPPORT + 7) / 8];
+};
+
 struct synaptics_rmi4_exp_fn {
 	enum exp_fn fn_type;
 	bool inserted;
@@ -360,8 +496,8 @@
 	retval = synaptics_rmi4_reset_device(rmi4_data);
 	if (retval < 0) {
 		dev_err(dev,
-				"%s: Failed to issue reset command, error = %d\n",
-				__func__, retval);
+			"%s: Failed to issue reset command, error = %d\n",
+			__func__, retval);
 		return retval;
 	}
 
@@ -686,6 +822,32 @@
 	return retval;
 }
 
+/**
+ * synaptics_rmi4_release_all()
+ *
+ * Called by synaptics_rmi4_suspend()
+ *
+ * Release all touch data during the touch device switch to suspend state.
+ */
+
+static void synaptics_rmi4_release_all(struct synaptics_rmi4_data *rmi4_data)
+{
+	int finger;
+	int max_num_fingers = rmi4_data->num_of_fingers;
+
+	for (finger = 0; finger < max_num_fingers; finger++) {
+		input_mt_slot(rmi4_data->input_dev, finger);
+		input_mt_report_slot_state(rmi4_data->input_dev,
+				MT_TOOL_FINGER, 0);
+	}
+
+	input_report_key(rmi4_data->input_dev, BTN_TOUCH, 0);
+	input_report_key(rmi4_data->input_dev,
+			BTN_TOOL_FINGER, 0);
+
+	input_sync(rmi4_data->input_dev);
+}
+
  /**
  * synaptics_rmi4_f11_abs_report()
  *
@@ -817,10 +979,7 @@
 	if (!touch_count)
 		input_mt_sync(rmi4_data->input_dev);
 #else
-	/* sync after groups of events */
-	#ifdef KERNEL_ABOVE_3_7
-	input_mt_sync_frame(rmi4_data->input_dev);
-	#endif
+	input_mt_report_pointer_emulation(rmi4_data->input_dev, false);
 #endif
 
 	input_sync(rmi4_data->input_dev);
@@ -828,6 +987,125 @@
 	return touch_count;
 }
 
+ /**
+ * synaptics_rmi4_f12_abs_report()
+ *
+ * Called by synaptics_rmi4_report_touch() when valid Function $12
+ * finger data has been detected.
+ *
+ * This function reads the Function $12 data registers, determines the
+ * status of each finger supported by the Function, processes any
+ * necessary coordinate manipulation, reports the finger data to
+ * the input subsystem, and returns the number of fingers detected.
+ */
+static int synaptics_rmi4_f12_abs_report(struct synaptics_rmi4_data *rmi4_data,
+		struct synaptics_rmi4_fn *fhandler)
+{
+	int retval;
+	unsigned char touch_count = 0; /* number of touch points */
+	unsigned char finger;
+	unsigned char fingers_to_process;
+	unsigned char finger_status;
+	unsigned char size_of_2d_data;
+	unsigned short data_addr;
+	int x;
+	int y;
+	int wx;
+	int wy;
+	struct synaptics_rmi4_f12_extra_data *extra_data;
+	struct synaptics_rmi4_f12_finger_data *data;
+	struct synaptics_rmi4_f12_finger_data *finger_data;
+
+	fingers_to_process = fhandler->num_of_data_points;
+	data_addr = fhandler->full_addr.data_base;
+	extra_data = (struct synaptics_rmi4_f12_extra_data *)fhandler->extra;
+	size_of_2d_data = sizeof(struct synaptics_rmi4_f12_finger_data);
+
+	retval = synaptics_rmi4_i2c_read(rmi4_data,
+			data_addr + extra_data->data1_offset,
+			(unsigned char *)fhandler->data,
+			fingers_to_process * size_of_2d_data);
+	if (retval < 0)
+		return 0;
+
+	data = (struct synaptics_rmi4_f12_finger_data *)fhandler->data;
+
+	for (finger = 0; finger < fingers_to_process; finger++) {
+		finger_data = data + finger;
+		finger_status = finger_data->object_type_and_status & MASK_2BIT;
+
+		/*
+		 * Each 2-bit finger status field represents the following:
+		 * 00 = finger not present
+		 * 01 = finger present and data accurate
+		 * 10 = finger present but data may be inaccurate
+		 * 11 = reserved
+		 */
+#ifdef TYPE_B_PROTOCOL
+		input_mt_slot(rmi4_data->input_dev, finger);
+		input_mt_report_slot_state(rmi4_data->input_dev,
+				MT_TOOL_FINGER, finger_status != 0);
+#endif
+
+		if (finger_status) {
+			x = (finger_data->x_msb << 8) | (finger_data->x_lsb);
+			y = (finger_data->y_msb << 8) | (finger_data->y_lsb);
+#ifdef REPORT_2D_W
+			wx = finger_data->wx;
+			wy = finger_data->wy;
+#endif
+
+			if (rmi4_data->flip_x)
+				x = rmi4_data->sensor_max_x - x;
+			if (rmi4_data->flip_y)
+				y = rmi4_data->sensor_max_y - y;
+
+			dev_dbg(&rmi4_data->i2c_client->dev,
+					"%s: Finger %d:\n"
+					"status = 0x%02x\n"
+					"x = %d\n"
+					"y = %d\n"
+					"wx = %d\n"
+					"wy = %d\n",
+					__func__, finger,
+					finger_status,
+					x, y, wx, wy);
+
+			input_report_key(rmi4_data->input_dev,
+					BTN_TOUCH, 1);
+			input_report_key(rmi4_data->input_dev,
+					BTN_TOOL_FINGER, 1);
+			input_report_abs(rmi4_data->input_dev,
+					ABS_MT_POSITION_X, x);
+			input_report_abs(rmi4_data->input_dev,
+					ABS_MT_POSITION_Y, y);
+#ifdef REPORT_2D_W
+			input_report_abs(rmi4_data->input_dev,
+					ABS_MT_TOUCH_MAJOR, max(wx, wy));
+			input_report_abs(rmi4_data->input_dev,
+					ABS_MT_TOUCH_MINOR, min(wx, wy));
+#endif
+#ifndef TYPE_B_PROTOCOL
+			input_mt_sync(rmi4_data->input_dev);
+#endif
+			touch_count++;
+		}
+	}
+
+	input_report_key(rmi4_data->input_dev,
+			BTN_TOUCH, touch_count > 0);
+	input_report_key(rmi4_data->input_dev,
+			BTN_TOOL_FINGER, touch_count > 0);
+#ifndef TYPE_B_PROTOCOL
+	if (!touch_count)
+		input_mt_sync(rmi4_data->input_dev);
+#endif
+	input_mt_report_pointer_emulation(rmi4_data->input_dev, false);
+	input_sync(rmi4_data->input_dev);
+
+	return touch_count;
+}
+
 static void synaptics_rmi4_f1a_report(struct synaptics_rmi4_data *rmi4_data,
 		struct synaptics_rmi4_fn *fhandler)
 {
@@ -955,6 +1233,16 @@
 			rmi4_data->fingers_on_2d = false;
 		break;
 
+	case SYNAPTICS_RMI4_F12:
+		touch_count_2d = synaptics_rmi4_f12_abs_report(rmi4_data,
+				fhandler);
+
+		if (touch_count_2d)
+			rmi4_data->fingers_on_2d = true;
+		else
+			rmi4_data->fingers_on_2d = false;
+		break;
+
 	case SYNAPTICS_RMI4_F1A:
 		synaptics_rmi4_f1a_report(rmi4_data, fhandler);
 		break;
@@ -1045,6 +1333,51 @@
 	return IRQ_HANDLED;
 }
 
+#ifdef CONFIG_OF
+static int synaptics_rmi4_get_dt_coords(struct device *dev, char *name,
+				struct synaptics_rmi4_platform_data *pdata)
+{
+	u32 coords[RMI4_COORDS_ARR_SIZE];
+	struct property *prop;
+	struct device_node *np = dev->of_node;
+	int coords_size, rc;
+
+	prop = of_find_property(np, name, NULL);
+	if (!prop)
+		return -EINVAL;
+	if (!prop->value)
+		return -ENODATA;
+
+	coords_size = prop->length / sizeof(u32);
+	if (coords_size != RMI4_COORDS_ARR_SIZE) {
+		dev_err(dev, "invalid %s\n", name);
+		return -EINVAL;
+	}
+
+	rc = of_property_read_u32_array(np, name, coords, coords_size);
+	if (rc && (rc != -EINVAL)) {
+		dev_err(dev, "Unable to read %s\n", name);
+		return rc;
+	}
+
+	if (strcmp(name, "synaptics,panel-coords") == 0) {
+		pdata->panel_minx = coords[0];
+		pdata->panel_miny = coords[1];
+		pdata->panel_maxx = coords[2];
+		pdata->panel_maxy = coords[3];
+	} else if (strcmp(name, "synaptics,display-coords") == 0) {
+		pdata->disp_minx = coords[0];
+		pdata->disp_miny = coords[1];
+		pdata->disp_maxx = coords[2];
+		pdata->disp_maxy = coords[3];
+	} else {
+		dev_err(dev, "unsupported property %s\n", name);
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
 static int synaptics_rmi4_parse_dt(struct device *dev,
 				struct synaptics_rmi4_platform_data *rmi4_pdata)
 {
@@ -1056,23 +1389,32 @@
 
 	rmi4_pdata->i2c_pull_up = of_property_read_bool(np,
 			"synaptics,i2c-pull-up");
+	rmi4_pdata->power_down_enable = of_property_read_bool(np,
+			"synaptics,power-down");
+	rmi4_pdata->disable_gpios = of_property_read_bool(np,
+			"synaptics,disable-gpios");
 	rmi4_pdata->x_flip = of_property_read_bool(np, "synaptics,x-flip");
 	rmi4_pdata->y_flip = of_property_read_bool(np, "synaptics,y-flip");
+	rmi4_pdata->do_lockdown = of_property_read_bool(np,
+			"synaptics,do-lockdown");
 
-	rc = of_property_read_u32(np, "synaptics,panel-x", &temp_val);
-	if (rc && (rc != -EINVAL)) {
-		dev_err(dev, "Unable to read panel X dimension\n");
+	rc = synaptics_rmi4_get_dt_coords(dev, "synaptics,display-coords",
+				rmi4_pdata);
+	if (rc && (rc != -EINVAL))
 		return rc;
-	} else {
-		rmi4_pdata->panel_x = temp_val;
-	}
 
-	rc = of_property_read_u32(np, "synaptics,panel-y", &temp_val);
-	if (rc && (rc != -EINVAL)) {
-		dev_err(dev, "Unable to read panel Y dimension\n");
+	rc = synaptics_rmi4_get_dt_coords(dev, "synaptics,panel-coords",
+				rmi4_pdata);
+	if (rc && (rc != -EINVAL))
 		return rc;
-	} else {
-		rmi4_pdata->panel_y = temp_val;
+
+	rmi4_pdata->reset_delay = RESET_DELAY;
+	rc = of_property_read_u32(np, "synaptics,reset-delay", &temp_val);
+	if (!rc)
+		rmi4_pdata->reset_delay = temp_val;
+	else if (rc != -EINVAL) {
+		dev_err(dev, "Unable to read reset delay\n");
+		return rc;
 	}
 
 	rc = of_property_read_string(np, "synaptics,fw-image-name",
@@ -1123,6 +1465,13 @@
 	}
 	return 0;
 }
+#else
+static inline int synaptics_rmi4_parse_dt(struct device *dev,
+				struct synaptics_rmi4_platform_data *rmi4_pdata)
+{
+	return 0;
+}
+#endif
 
  /**
  * synaptics_rmi4_irq_enable()
@@ -1233,6 +1582,8 @@
 			rmi4_data->sensor_max_x,
 			rmi4_data->sensor_max_y);
 
+	rmi4_data->max_touch_width = MAX_F11_TOUCH_WIDTH;
+
 	fhandler->intr_reg_num = (intr_count + 7) / 8;
 	if (fhandler->intr_reg_num != 0)
 		fhandler->intr_reg_num -= 1;
@@ -1253,6 +1604,212 @@
 	return retval;
 }
 
+static int synaptics_rmi4_f12_set_enables(struct synaptics_rmi4_data *rmi4_data,
+		unsigned short ctrl28)
+{
+	int retval;
+	static unsigned short ctrl_28_address;
+
+	if (ctrl28)
+		ctrl_28_address = ctrl28;
+
+	retval = synaptics_rmi4_i2c_write(rmi4_data,
+			ctrl_28_address,
+			&rmi4_data->report_enable,
+			sizeof(rmi4_data->report_enable));
+	if (retval < 0)
+		return retval;
+
+	return retval;
+}
+
+ /**
+ * synaptics_rmi4_f12_init()
+ *
+ * Called by synaptics_rmi4_query_device().
+ *
+ * This funtion parses information from the Function 12 registers and
+ * determines the number of fingers supported, offset to the data1
+ * register, x and y data ranges, offset to the associated interrupt
+ * status register, interrupt bit mask, and allocates memory resources
+ * for finger data acquisition.
+ */
+static int synaptics_rmi4_f12_init(struct synaptics_rmi4_data *rmi4_data,
+		struct synaptics_rmi4_fn *fhandler,
+		struct synaptics_rmi4_fn_desc *fd,
+		unsigned int intr_count)
+{
+	int retval;
+	unsigned char ii;
+	unsigned char intr_offset;
+	unsigned char size_of_2d_data;
+	unsigned char size_of_query8;
+	unsigned char ctrl_8_offset;
+	unsigned char ctrl_23_offset;
+	unsigned char ctrl_28_offset;
+	unsigned char num_of_fingers;
+	struct synaptics_rmi4_f12_extra_data *extra_data;
+	struct synaptics_rmi4_f12_query_5 query_5;
+	struct synaptics_rmi4_f12_query_8 query_8;
+	struct synaptics_rmi4_f12_ctrl_8 ctrl_8;
+	struct synaptics_rmi4_f12_ctrl_23 ctrl_23;
+
+	fhandler->fn_number = fd->fn_number;
+	fhandler->num_of_data_sources = fd->intr_src_count;
+	fhandler->extra = kmalloc(sizeof(*extra_data), GFP_KERNEL);
+	extra_data = (struct synaptics_rmi4_f12_extra_data *)fhandler->extra;
+	size_of_2d_data = sizeof(struct synaptics_rmi4_f12_finger_data);
+
+	retval = synaptics_rmi4_i2c_read(rmi4_data,
+			fhandler->full_addr.query_base + 5,
+			query_5.data,
+			sizeof(query_5.data));
+	if (retval < 0)
+		return retval;
+
+	ctrl_8_offset = query_5.ctrl0_is_present +
+			query_5.ctrl1_is_present +
+			query_5.ctrl2_is_present +
+			query_5.ctrl3_is_present +
+			query_5.ctrl4_is_present +
+			query_5.ctrl5_is_present +
+			query_5.ctrl6_is_present +
+			query_5.ctrl7_is_present;
+
+	ctrl_23_offset = ctrl_8_offset +
+			query_5.ctrl8_is_present +
+			query_5.ctrl9_is_present +
+			query_5.ctrl10_is_present +
+			query_5.ctrl11_is_present +
+			query_5.ctrl12_is_present +
+			query_5.ctrl13_is_present +
+			query_5.ctrl14_is_present +
+			query_5.ctrl15_is_present +
+			query_5.ctrl16_is_present +
+			query_5.ctrl17_is_present +
+			query_5.ctrl18_is_present +
+			query_5.ctrl19_is_present +
+			query_5.ctrl20_is_present +
+			query_5.ctrl21_is_present +
+			query_5.ctrl22_is_present;
+
+	ctrl_28_offset = ctrl_23_offset +
+			query_5.ctrl23_is_present +
+			query_5.ctrl24_is_present +
+			query_5.ctrl25_is_present +
+			query_5.ctrl26_is_present +
+			query_5.ctrl27_is_present;
+
+	retval = synaptics_rmi4_i2c_read(rmi4_data,
+			fhandler->full_addr.ctrl_base + ctrl_23_offset,
+			ctrl_23.data,
+			sizeof(ctrl_23.data));
+	if (retval < 0)
+		return retval;
+
+	/* Maximum number of fingers supported */
+	fhandler->num_of_data_points = min(ctrl_23.max_reported_objects,
+			(unsigned char)F12_FINGERS_TO_SUPPORT);
+
+	num_of_fingers = fhandler->num_of_data_points;
+	rmi4_data->num_of_fingers = num_of_fingers;
+
+	retval = synaptics_rmi4_i2c_read(rmi4_data,
+			fhandler->full_addr.query_base + 7,
+			&size_of_query8,
+			sizeof(size_of_query8));
+	if (retval < 0)
+		return retval;
+
+	retval = synaptics_rmi4_i2c_read(rmi4_data,
+			fhandler->full_addr.query_base + 8,
+			query_8.data,
+			size_of_query8);
+	if (retval < 0)
+		return retval;
+
+	/* Determine the presence of the Data0 register */
+	extra_data->data1_offset = query_8.data0_is_present;
+
+	if ((size_of_query8 >= 3) && (query_8.data15_is_present)) {
+		extra_data->data15_offset = query_8.data0_is_present +
+				query_8.data1_is_present +
+				query_8.data2_is_present +
+				query_8.data3_is_present +
+				query_8.data4_is_present +
+				query_8.data5_is_present +
+				query_8.data6_is_present +
+				query_8.data7_is_present +
+				query_8.data8_is_present +
+				query_8.data9_is_present +
+				query_8.data10_is_present +
+				query_8.data11_is_present +
+				query_8.data12_is_present +
+				query_8.data13_is_present +
+				query_8.data14_is_present;
+		extra_data->data15_size = (num_of_fingers + 7) / 8;
+	} else {
+		extra_data->data15_size = 0;
+	}
+
+	rmi4_data->report_enable = RPT_DEFAULT;
+#ifdef REPORT_2D_Z
+	rmi4_data->report_enable |= RPT_Z;
+#endif
+#ifdef REPORT_2D_W
+	rmi4_data->report_enable |= (RPT_WX | RPT_WY);
+#endif
+
+	retval = synaptics_rmi4_f12_set_enables(rmi4_data,
+			fhandler->full_addr.ctrl_base + ctrl_28_offset);
+	if (retval < 0)
+		return retval;
+
+	retval = synaptics_rmi4_i2c_read(rmi4_data,
+			fhandler->full_addr.ctrl_base + ctrl_8_offset,
+			ctrl_8.data,
+			sizeof(ctrl_8.data));
+	if (retval < 0)
+		return retval;
+
+	/* Maximum x and y */
+	rmi4_data->sensor_max_x =
+			((unsigned short)ctrl_8.max_x_coord_lsb << 0) |
+			((unsigned short)ctrl_8.max_x_coord_msb << 8);
+	rmi4_data->sensor_max_y =
+			((unsigned short)ctrl_8.max_y_coord_lsb << 0) |
+			((unsigned short)ctrl_8.max_y_coord_msb << 8);
+	dev_dbg(&rmi4_data->i2c_client->dev,
+			"%s: Function %02x max x = %d max y = %d\n",
+			__func__, fhandler->fn_number,
+			rmi4_data->sensor_max_x,
+			rmi4_data->sensor_max_y);
+
+	rmi4_data->num_of_rx = ctrl_8.num_of_rx;
+	rmi4_data->num_of_tx = ctrl_8.num_of_tx;
+	rmi4_data->max_touch_width = max(rmi4_data->num_of_rx,
+			rmi4_data->num_of_tx);
+
+	fhandler->intr_reg_num = (intr_count + 7) / 8;
+	if (fhandler->intr_reg_num != 0)
+		fhandler->intr_reg_num -= 1;
+
+	/* Set an enable bit for each data source */
+	intr_offset = intr_count % 8;
+	fhandler->intr_mask = 0;
+	for (ii = intr_offset;
+			ii < ((fd->intr_src_count & MASK_3BIT) +
+			intr_offset);
+			ii++)
+		fhandler->intr_mask |= 1 << ii;
+
+	/* Allocate memory for finger data storage space */
+	fhandler->data_size = num_of_fingers * size_of_2d_data;
+	fhandler->data = kmalloc(fhandler->data_size, GFP_KERNEL);
+
+	return retval;
+}
+
 static int synaptics_rmi4_f1a_alloc_mem(struct synaptics_rmi4_data *rmi4_data,
 		struct synaptics_rmi4_fn *fhandler)
 {
@@ -1313,11 +1870,10 @@
 	const struct synaptics_rmi4_platform_data *pdata = rmi4_data->board;
 
 	if (!pdata->capacitance_button_map) {
-		dev_err(&rmi4_data->i2c_client->dev,
-				"%s: capacitance_button_map is" \
-				"NULL in board file\n",
+		dev_info(&rmi4_data->i2c_client->dev,
+				"%s: capacitance_button_map not in use\n",
 				__func__);
-		return -ENODEV;
+		return 0;
 	} else if (!pdata->capacitance_button_map->map) {
 		dev_err(&rmi4_data->i2c_client->dev,
 				"%s: Button map is missing in board file\n",
@@ -1597,6 +2153,26 @@
 					return retval;
 				break;
 
+			case SYNAPTICS_RMI4_F12:
+				if (rmi_fd.intr_src_count == 0)
+					break;
+
+				retval = synaptics_rmi4_alloc_fh(&fhandler,
+						&rmi_fd, page_number);
+				if (retval < 0) {
+					dev_err(&rmi4_data->i2c_client->dev,
+							"%s: Failed to alloc for F%d\n",
+							__func__,
+							rmi_fd.fn_number);
+					return retval;
+				}
+
+				retval = synaptics_rmi4_f12_init(rmi4_data,
+						fhandler, &rmi_fd, intr_count);
+				if (retval < 0)
+					return retval;
+				break;
+
 			case SYNAPTICS_RMI4_F1A:
 				if (rmi_fd.intr_src_count == 0)
 					break;
@@ -1732,7 +2308,7 @@
 		return retval;
 	}
 
-	msleep(RESET_DELAY);
+	msleep(rmi4_data->board->reset_delay);
 	return retval;
 };
 
@@ -1740,6 +2316,7 @@
 {
 	int retval;
 	struct synaptics_rmi4_fn *fhandler;
+	struct synaptics_rmi4_fn *next_fhandler;
 	struct synaptics_rmi4_device_info *rmi;
 
 	rmi = &(rmi4_data->rmi4_mod_info);
@@ -1753,11 +2330,14 @@
 	}
 
 	if (!list_empty(&rmi->support_fn_list)) {
-		list_for_each_entry(fhandler, &rmi->support_fn_list, link) {
+		list_for_each_entry_safe(fhandler, next_fhandler,
+					&rmi->support_fn_list, link) {
 			if (fhandler->fn_number == SYNAPTICS_RMI4_F1A)
 				synaptics_rmi4_f1a_kfree(fhandler);
-			else
+			else {
 				kfree(fhandler->data);
+				kfree(fhandler->extra);
+			}
 			kfree(fhandler);
 		}
 	}
@@ -2003,7 +2583,7 @@
 
 error_reg_en_vcc_i2c:
 	if (rmi4_data->board->i2c_pull_up)
-		reg_set_optimum_mode_check(rmi4_data->vdd, 0);
+		reg_set_optimum_mode_check(rmi4_data->vcc_i2c, 0);
 error_reg_opt_i2c:
 	regulator_disable(rmi4_data->vdd);
 error_reg_en_vdd:
@@ -2020,6 +2600,85 @@
 	return 0;
 }
 
+static int synaptics_rmi4_gpio_configure(struct synaptics_rmi4_data *rmi4_data,
+					bool on)
+{
+	int retval = 0;
+
+	if (on) {
+		if (gpio_is_valid(rmi4_data->board->irq_gpio)) {
+			/* configure touchscreen irq gpio */
+			retval = gpio_request(rmi4_data->board->irq_gpio,
+				"rmi4_irq_gpio");
+			if (retval) {
+				dev_err(&rmi4_data->i2c_client->dev,
+					"unable to request gpio [%d]\n",
+					rmi4_data->board->irq_gpio);
+				goto err_irq_gpio_req;
+			}
+			retval = gpio_direction_input(rmi4_data->board->\
+				irq_gpio);
+			if (retval) {
+				dev_err(&rmi4_data->i2c_client->dev,
+					"unable to set direction for gpio " \
+					"[%d]\n", rmi4_data->board->irq_gpio);
+				goto err_irq_gpio_dir;
+			}
+		} else {
+			dev_err(&rmi4_data->i2c_client->dev,
+				"irq gpio not provided\n");
+			goto err_irq_gpio_req;
+		}
+
+		if (gpio_is_valid(rmi4_data->board->reset_gpio)) {
+			/* configure touchscreen reset out gpio */
+			retval = gpio_request(rmi4_data->board->reset_gpio,
+					"rmi4_reset_gpio");
+			if (retval) {
+				dev_err(&rmi4_data->i2c_client->dev,
+					"unable to request gpio [%d]\n",
+					rmi4_data->board->reset_gpio);
+				goto err_irq_gpio_dir;
+			}
+
+			retval = gpio_direction_output(rmi4_data->board->\
+				reset_gpio, 1);
+			if (retval) {
+				dev_err(&rmi4_data->i2c_client->dev,
+					"unable to set direction for gpio " \
+					"[%d]\n", rmi4_data->board->reset_gpio);
+				goto err_reset_gpio_dir;
+			}
+
+			gpio_set_value(rmi4_data->board->reset_gpio, 0);
+			usleep(RMI4_GPIO_SLEEP_LOW_US);
+			gpio_set_value(rmi4_data->board->reset_gpio, 1);
+			msleep(rmi4_data->board->reset_delay);
+		} else
+			synaptics_rmi4_reset_command(rmi4_data);
+
+		return 0;
+	} else {
+		if (rmi4_data->board->disable_gpios) {
+			if (gpio_is_valid(rmi4_data->board->irq_gpio))
+				gpio_free(rmi4_data->board->irq_gpio);
+			if (gpio_is_valid(rmi4_data->board->reset_gpio))
+				gpio_free(rmi4_data->board->reset_gpio);
+		}
+
+		return 0;
+	}
+
+err_reset_gpio_dir:
+	if (gpio_is_valid(rmi4_data->board->reset_gpio))
+		gpio_free(rmi4_data->board->reset_gpio);
+err_irq_gpio_dir:
+	if (gpio_is_valid(rmi4_data->board->irq_gpio))
+		gpio_free(rmi4_data->board->irq_gpio);
+err_irq_gpio_req:
+	return retval;
+}
+
  /**
  * synaptics_rmi4_probe()
  *
@@ -2042,6 +2701,7 @@
 	unsigned char attr_count;
 	struct synaptics_rmi4_f1a_handle *f1a;
 	struct synaptics_rmi4_fn *fhandler;
+	struct synaptics_rmi4_fn *next_fhandler;
 	struct synaptics_rmi4_data *rmi4_data;
 	struct synaptics_rmi4_device_info *rmi;
 	struct synaptics_rmi4_platform_data *platform_data =
@@ -2149,52 +2809,12 @@
 		goto err_power_device;
 	}
 
-	if (gpio_is_valid(platform_data->irq_gpio)) {
-		/* configure touchscreen irq gpio */
-		retval = gpio_request(platform_data->irq_gpio, "rmi4_irq_gpio");
-		if (retval) {
-			dev_err(&client->dev, "unable to request gpio [%d]\n",
-						platform_data->irq_gpio);
-			goto err_irq_gpio_req;
-		}
-		retval = gpio_direction_input(platform_data->irq_gpio);
-		if (retval) {
-			dev_err(&client->dev,
-				"unable to set direction for gpio [%d]\n",
-				platform_data->irq_gpio);
-			goto err_irq_gpio_dir;
-		}
-	} else {
-		dev_err(&client->dev, "irq gpio not provided\n");
-		goto err_irq_gpio_req;
+	retval = synaptics_rmi4_gpio_configure(rmi4_data, true);
+	if (retval < 0) {
+		dev_err(&client->dev, "Failed to configure gpios\n");
+		goto err_gpio_config;
 	}
 
-	if (gpio_is_valid(platform_data->reset_gpio)) {
-		/* configure touchscreen reset out gpio */
-		retval = gpio_request(platform_data->reset_gpio,
-				"rmi4_reset_gpio");
-		if (retval) {
-			dev_err(&client->dev, "unable to request gpio [%d]\n",
-						platform_data->reset_gpio);
-			goto err_irq_gpio_dir;
-		}
-
-		retval = gpio_direction_output(platform_data->reset_gpio, 1);
-		if (retval) {
-			dev_err(&client->dev,
-				"unable to set direction for gpio [%d]\n",
-				platform_data->reset_gpio);
-			goto err_reset_gpio_dir;
-		}
-
-		gpio_set_value(platform_data->reset_gpio, 0);
-		usleep(RMI4_GPIO_SLEEP_LOW_US);
-		gpio_set_value(platform_data->reset_gpio, 1);
-		msleep(RESET_DELAY);
-	} else
-		synaptics_rmi4_reset_command(rmi4_data);
-
-
 	init_waitqueue_head(&rmi4_data->wait);
 	mutex_init(&(rmi4_data->rmi4_io_ctrl_mutex));
 
@@ -2203,21 +2823,44 @@
 		dev_err(&client->dev,
 				"%s: Failed to query device\n",
 				__func__);
-		goto err_reset_gpio_dir;
+		goto err_free_gpios;
 	}
 
+	if (rmi4_data->board->disp_maxx)
+		rmi4_data->disp_maxx = rmi4_data->board->disp_maxx;
+	else
+		rmi4_data->disp_maxx = rmi4_data->sensor_max_x;
+
+	if (rmi4_data->board->disp_maxy)
+		rmi4_data->disp_maxy = rmi4_data->board->disp_maxy;
+	else
+		rmi4_data->disp_maxy = rmi4_data->sensor_max_y;
+
+	if (rmi4_data->board->disp_minx)
+		rmi4_data->disp_minx = rmi4_data->board->disp_minx;
+	else
+		rmi4_data->disp_minx = 0;
+
+	if (rmi4_data->board->disp_miny)
+		rmi4_data->disp_miny = rmi4_data->board->disp_miny;
+	else
+		rmi4_data->disp_miny = 0;
+
 	input_set_abs_params(rmi4_data->input_dev,
-			ABS_MT_POSITION_X, 0,
-			rmi4_data->sensor_max_x, 0, 0);
+			ABS_MT_POSITION_X, rmi4_data->disp_minx,
+			rmi4_data->disp_maxx, 0, 0);
 	input_set_abs_params(rmi4_data->input_dev,
-			ABS_MT_POSITION_Y, 0,
-			rmi4_data->sensor_max_y, 0, 0);
+			ABS_MT_POSITION_Y, rmi4_data->disp_miny,
+			rmi4_data->disp_maxy, 0, 0);
 	input_set_abs_params(rmi4_data->input_dev,
 			ABS_PRESSURE, 0, 255, 0, 0);
 #ifdef REPORT_2D_W
 	input_set_abs_params(rmi4_data->input_dev,
 			ABS_MT_TOUCH_MAJOR, 0,
-			MAX_ABS_MT_TOUCH_MAJOR, 0, 0);
+			rmi4_data->max_touch_width, 0, 0);
+	input_set_abs_params(rmi4_data->input_dev,
+			ABS_MT_TOUCH_MINOR, 0,
+			rmi4_data->max_touch_width, 0, 0);
 #endif
 
 #ifdef TYPE_B_PROTOCOL
@@ -2338,21 +2981,23 @@
 
 err_register_input:
 	if (!list_empty(&rmi->support_fn_list)) {
-		list_for_each_entry(fhandler, &rmi->support_fn_list, link) {
+		list_for_each_entry_safe(fhandler, next_fhandler,
+					&rmi->support_fn_list, link) {
 			if (fhandler->fn_number == SYNAPTICS_RMI4_F1A)
 				synaptics_rmi4_f1a_kfree(fhandler);
-			else
+			else {
 				kfree(fhandler->data);
+				kfree(fhandler->extra);
+			}
 			kfree(fhandler);
 		}
 	}
-err_reset_gpio_dir:
-	if (gpio_is_valid(platform_data->reset_gpio))
-		gpio_free(platform_data->reset_gpio);
-err_irq_gpio_dir:
-	if (gpio_is_valid(platform_data->irq_gpio))
-		gpio_free(platform_data->irq_gpio);
-err_irq_gpio_req:
+err_free_gpios:
+	if (gpio_is_valid(rmi4_data->board->reset_gpio))
+		gpio_free(rmi4_data->board->reset_gpio);
+	if (gpio_is_valid(rmi4_data->board->irq_gpio))
+		gpio_free(rmi4_data->board->irq_gpio);
+err_gpio_config:
 	synaptics_rmi4_power_on(rmi4_data, false);
 err_power_device:
 	synaptics_rmi4_regulator_configure(rmi4_data, false);
@@ -2379,6 +3024,7 @@
 {
 	unsigned char attr_count;
 	struct synaptics_rmi4_fn *fhandler;
+	struct synaptics_rmi4_fn *next_fhandler;
 	struct synaptics_rmi4_data *rmi4_data = i2c_get_clientdata(client);
 	struct synaptics_rmi4_device_info *rmi;
 
@@ -2402,11 +3048,14 @@
 	input_unregister_device(rmi4_data->input_dev);
 
 	if (!list_empty(&rmi->support_fn_list)) {
-		list_for_each_entry(fhandler, &rmi->support_fn_list, link) {
+		list_for_each_entry_safe(fhandler, next_fhandler,
+					&rmi->support_fn_list, link) {
 			if (fhandler->fn_number == SYNAPTICS_RMI4_F1A)
 				synaptics_rmi4_f1a_kfree(fhandler);
-			else
+			else {
 				kfree(fhandler->data);
+				kfree(fhandler->extra);
+			}
 			kfree(fhandler);
 		}
 	}
@@ -2549,6 +3198,11 @@
 			container_of(h, struct synaptics_rmi4_data,
 			early_suspend);
 
+	if (rmi4_data->stay_awake)
+		rmi4_data->staying_awake = true;
+	else
+		rmi4_data->staying_awake = false;
+
 	rmi4_data->touch_stopped = true;
 	wake_up(&rmi4_data->wait);
 	synaptics_rmi4_irq_enable(rmi4_data, false);
@@ -2575,6 +3229,9 @@
 			container_of(h, struct synaptics_rmi4_data,
 			early_suspend);
 
+	if (rmi4_data->staying_awake)
+		return;
+
 	if (rmi4_data->full_pm_cycle)
 		synaptics_rmi4_resume(&(rmi4_data->input_dev->dev));
 
@@ -2592,24 +3249,48 @@
 						bool on)
 {
 	int retval;
+	int load_ua;
 
 	if (on == false)
 		goto regulator_hpm;
 
-	retval = reg_set_optimum_mode_check(rmi4_data->vdd, RMI4_LPM_LOAD_UA);
+	if (rmi4_data->board->i2c_pull_up) {
+		load_ua = rmi4_data->board->power_down_enable ?
+			0 : RMI4_I2C_LPM_LOAD_UA;
+		retval = reg_set_optimum_mode_check(rmi4_data->vcc_i2c,
+			load_ua);
+		if (retval < 0) {
+			dev_err(&rmi4_data->i2c_client->dev,
+				"Regulator vcc_i2c set_opt failed " \
+				"rc=%d\n", retval);
+			goto fail_regulator_lpm;
+		}
+
+		if (rmi4_data->board->power_down_enable) {
+			retval = regulator_disable(rmi4_data->vcc_i2c);
+			if (retval) {
+				dev_err(&rmi4_data->i2c_client->dev,
+					"Regulator vcc_i2c disable failed " \
+					"rc=%d\n", retval);
+				goto fail_regulator_lpm;
+			}
+		}
+	}
+
+	load_ua = rmi4_data->board->power_down_enable ? 0 : RMI4_LPM_LOAD_UA;
+	retval = reg_set_optimum_mode_check(rmi4_data->vdd, load_ua);
 	if (retval < 0) {
 		dev_err(&rmi4_data->i2c_client->dev,
-			"Regulator vcc_ana set_opt failed rc=%d\n",
+			"Regulator vdd_ana set_opt failed rc=%d\n",
 			retval);
 		goto fail_regulator_lpm;
 	}
 
-	if (rmi4_data->board->i2c_pull_up) {
-		retval = reg_set_optimum_mode_check(rmi4_data->vcc_i2c,
-			RMI4_I2C_LPM_LOAD_UA);
-		if (retval < 0) {
+	if (rmi4_data->board->power_down_enable) {
+		retval = regulator_disable(rmi4_data->vdd);
+		if (retval) {
 			dev_err(&rmi4_data->i2c_client->dev,
-				"Regulator vcc_i2c set_opt failed rc=%d\n",
+				"Regulator vdd disable failed rc=%d\n",
 				retval);
 			goto fail_regulator_lpm;
 		}
@@ -2628,6 +3309,16 @@
 		goto fail_regulator_hpm;
 	}
 
+	if (rmi4_data->board->power_down_enable) {
+		retval = regulator_enable(rmi4_data->vdd);
+		if (retval) {
+			dev_err(&rmi4_data->i2c_client->dev,
+				"Regulator vdd enable failed rc=%d\n",
+				retval);
+			goto fail_regulator_hpm;
+		}
+	}
+
 	if (rmi4_data->board->i2c_pull_up) {
 		retval = reg_set_optimum_mode_check(rmi4_data->vcc_i2c,
 			RMI4_I2C_LOAD_UA);
@@ -2637,6 +3328,16 @@
 				retval);
 			goto fail_regulator_hpm;
 		}
+
+		if (rmi4_data->board->power_down_enable) {
+			retval = regulator_enable(rmi4_data->vcc_i2c);
+			if (retval) {
+				dev_err(&rmi4_data->i2c_client->dev,
+					"Regulator vcc_i2c enable failed " \
+					"rc=%d\n", retval);
+				goto fail_regulator_hpm;
+			}
+		}
 	}
 
 	return 0;
@@ -2650,10 +3351,13 @@
 	return retval;
 
 fail_regulator_hpm:
-	reg_set_optimum_mode_check(rmi4_data->vdd, RMI4_LPM_LOAD_UA);
-	if (rmi4_data->board->i2c_pull_up)
-		reg_set_optimum_mode_check(rmi4_data->vcc_i2c,
-						RMI4_I2C_LPM_LOAD_UA);
+	load_ua = rmi4_data->board->power_down_enable ? 0 : RMI4_LPM_LOAD_UA;
+	reg_set_optimum_mode_check(rmi4_data->vdd, load_ua);
+	if (rmi4_data->board->i2c_pull_up) {
+		load_ua = rmi4_data->board->power_down_enable ?
+				0 : RMI4_I2C_LPM_LOAD_UA;
+		reg_set_optimum_mode_check(rmi4_data->vcc_i2c, load_ua);
+	}
 	return retval;
 }
 
@@ -2672,6 +3376,12 @@
 	struct synaptics_rmi4_data *rmi4_data = dev_get_drvdata(dev);
 	int retval;
 
+	if (rmi4_data->stay_awake) {
+		rmi4_data->staying_awake = true;
+		return 0;
+	} else
+		rmi4_data->staying_awake = false;
+
 	if (rmi4_data->suspended) {
 		dev_info(dev, "Already in suspend state\n");
 		return 0;
@@ -2685,6 +3395,8 @@
 			synaptics_rmi4_sensor_sleep(rmi4_data);
 		}
 
+		synaptics_rmi4_release_all(rmi4_data);
+
 		retval = synaptics_rmi4_regulator_lpm(rmi4_data, true);
 		if (retval < 0) {
 			dev_err(dev, "failed to enter low power mode\n");
@@ -2696,6 +3408,13 @@
 		return 0;
 	}
 
+	if (rmi4_data->board->disable_gpios) {
+		retval = synaptics_rmi4_gpio_configure(rmi4_data, false);
+		if (retval < 0) {
+			dev_err(dev, "failed to put gpios in suspend state\n");
+			return retval;
+		}
+	}
 	rmi4_data->suspended = true;
 
 	return 0;
@@ -2716,11 +3435,22 @@
 	struct synaptics_rmi4_data *rmi4_data = dev_get_drvdata(dev);
 	int retval;
 
+	if (rmi4_data->staying_awake)
+		return 0;
+
 	if (!rmi4_data->suspended) {
 		dev_info(dev, "Already in awake state\n");
 		return 0;
 	}
 
+	if (rmi4_data->board->disable_gpios) {
+		retval = synaptics_rmi4_gpio_configure(rmi4_data, true);
+		if (retval < 0) {
+			dev_err(dev, "failed to put gpios in active state\n");
+			return retval;
+		}
+	}
+
 	retval = synaptics_rmi4_regulator_lpm(rmi4_data, false);
 	if (retval < 0) {
 		dev_err(dev, "failed to enter active power mode\n");
diff --git a/drivers/input/touchscreen/synaptics_i2c_rmi4.h b/drivers/input/touchscreen/synaptics_i2c_rmi4.h
index 5f6d6ce..ef39bb7 100644
--- a/drivers/input/touchscreen/synaptics_i2c_rmi4.h
+++ b/drivers/input/touchscreen/synaptics_i2c_rmi4.h
@@ -45,6 +45,7 @@
 
 #define SYNAPTICS_RMI4_F01 (0x01)
 #define SYNAPTICS_RMI4_F11 (0x11)
+#define SYNAPTICS_RMI4_F12 (0x12)
 #define SYNAPTICS_RMI4_F1A (0x1a)
 #define SYNAPTICS_RMI4_F34 (0x34)
 #define SYNAPTICS_RMI4_F54 (0x54)
@@ -69,7 +70,7 @@
 #define MASK_2BIT 0x03
 #define MASK_1BIT 0x01
 
-#define NAME_BUFFER_SIZE 128
+#define NAME_BUFFER_SIZE 256
 
 /*
  * struct synaptics_rmi4_fn_desc - function descriptor fields in PDT
@@ -85,9 +86,12 @@
 	unsigned char cmd_base_addr;
 	unsigned char ctrl_base_addr;
 	unsigned char data_base_addr;
-	unsigned char intr_src_count;
+	unsigned char intr_src_count:3;
+	unsigned char reserved_b3_b4:2;
+	unsigned char version:2;
+	unsigned char reserved_b7:1;
 	unsigned char fn_number;
-};
+} __packed;
 
 /*
  * synaptics_rmi4_fn_full_addr - full 16-bit base addresses
@@ -129,6 +133,7 @@
 	struct list_head link;
 	int data_size;
 	void *data;
+	void *extra;
 };
 
 /*
@@ -181,6 +186,10 @@
  * @irq: attention interrupt
  * @sensor_max_x: sensor maximum x value
  * @sensor_max_y: sensor maximum y value
+ * @disp_maxx: max x value of display
+ * @disp_maxy: max y value of display
+ * @disp_minx: min x value of display
+ * @disp_miny: min y value of display
  * @irq_enabled: flag for indicating interrupt enable status
  * @touch_stopped: flag to stop interrupt thread processing
  * @fingers_on_2d: flag to indicate presence of fingers in 2d area
@@ -214,6 +223,8 @@
 	unsigned char num_of_rx;
 	unsigned char num_of_tx;
 	unsigned char num_of_fingers;
+	unsigned char max_touch_width;
+	unsigned char report_enable;
 	unsigned char intr_mask[MAX_INTR_REGISTERS];
 	unsigned short num_of_intr_regs;
 	unsigned short f01_query_base_addr;
@@ -223,6 +234,10 @@
 	int irq;
 	int sensor_max_x;
 	int sensor_max_y;
+	int disp_maxx;
+	int disp_maxy;
+	int disp_minx;
+	int disp_miny;
 	bool irq_enabled;
 	bool touch_stopped;
 	bool fingers_on_2d;
@@ -232,6 +247,8 @@
 	bool fw_updating;
 	bool suspended;
 	wait_queue_head_t wait;
+	bool stay_awake;
+	bool staying_awake;
 	int (*i2c_read)(struct synaptics_rmi4_data *pdata, unsigned short addr,
 			unsigned char *data, unsigned short length);
 	int (*i2c_write)(struct synaptics_rmi4_data *pdata, unsigned short addr,
diff --git a/drivers/iommu/msm_iommu-v1.c b/drivers/iommu/msm_iommu-v1.c
index 53c7c30..b9c4cae 100644
--- a/drivers/iommu/msm_iommu-v1.c
+++ b/drivers/iommu/msm_iommu-v1.c
@@ -692,6 +692,7 @@
 	if (ret)
 		goto fail;
 
+	ret = __flush_iotlb_va(domain, va);
 fail:
 	mutex_unlock(&msm_iommu_lock);
 	return ret;
@@ -741,6 +742,7 @@
 	if (ret)
 		goto fail;
 
+	__flush_iotlb(domain);
 fail:
 	mutex_unlock(&msm_iommu_lock);
 	return ret;
diff --git a/drivers/iommu/msm_iommu_sec.c b/drivers/iommu/msm_iommu_sec.c
index 78fffb2..474efdf 100644
--- a/drivers/iommu/msm_iommu_sec.c
+++ b/drivers/iommu/msm_iommu_sec.c
@@ -371,7 +371,7 @@
 	map.info.ctx_id = ctx_drvdata->num;
 	map.info.va = va;
 	map.info.size = len;
-	map.flags = 0;
+	map.flags = IOMMU_TLBINVAL_FLAG;
 	flush_va = &pa;
 	flush_pa = virt_to_phys(&pa);
 
@@ -421,7 +421,7 @@
 	map.info.ctx_id = ctx_drvdata->num;
 	map.info.va = va;
 	map.info.size = len;
-	map.flags = 0;
+	map.flags = IOMMU_TLBINVAL_FLAG;
 
 	if (sg->length == len) {
 		pa = get_phys_addr(sg);
diff --git a/drivers/leds/leds-qpnp.c b/drivers/leds/leds-qpnp.c
index b896f65..bf59d03 100644
--- a/drivers/leds/leds-qpnp.c
+++ b/drivers/leds/leds-qpnp.c
@@ -23,6 +23,7 @@
 #include <linux/spmi.h>
 #include <linux/qpnp/pwm.h>
 #include <linux/workqueue.h>
+#include <linux/delay.h>
 #include <linux/regulator/consumer.h>
 
 #define WLED_MOD_EN_REG(base, n)	(base + 0x60 + n*0x10)
@@ -43,6 +44,7 @@
 #define WLED_HIGH_POLE_CAP_REG(base)		(base + 0x58)
 #define WLED_CURR_SINK_MASK		0xE0
 #define WLED_CURR_SINK_SHFT		0x05
+#define WLED_DISABLE_ALL_SINKS		0x00
 #define WLED_SWITCH_FREQ_MASK		0x0F
 #define WLED_OVP_VAL_MASK		0x03
 #define WLED_OVP_VAL_BIT_SHFT		0x00
@@ -58,8 +60,10 @@
 #define WLED_CTL_DLY_STEP		200
 #define WLED_CTL_DLY_MAX		1400
 #define WLED_MAX_CURR			25
+#define WLED_NO_CURRENT			0x00
+#define WLED_OVP_DELAY			1000
 #define WLED_MSB_MASK			0x0F
-#define WLED_MAX_CURR_MASK		0x19
+#define WLED_MAX_CURR_MASK		0x1F
 #define WLED_OP_FDBCK_MASK		0x07
 #define WLED_OP_FDBCK_BIT_SHFT		0x00
 #define WLED_OP_FDBCK_DEFAULT		0x00
@@ -73,6 +77,9 @@
 #define WLED_SYNC_VAL			0x07
 #define WLED_SYNC_RESET_VAL		0x00
 
+#define PMIC_VER_8026			0x04
+#define PMIC_VERSION_REG		0x0105
+
 #define WLED_DEFAULT_STRINGS		0x01
 #define WLED_DEFAULT_OVP_VAL		0x02
 #define WLED_BOOST_LIM_DEFAULT		0x03
@@ -95,6 +102,7 @@
 #define FLASH_LED_UNLOCK_SECURE(base)	(base + 0xD0)
 #define FLASH_LED_TORCH(base)		(base + 0xE4)
 #define FLASH_FAULT_DETECT(base)	(base + 0x51)
+#define FLASH_PERIPHERAL_SUBTYPE(base)	(base + 0x05)
 
 #define FLASH_MAX_LEVEL			0x4F
 #define TORCH_MAX_LEVEL			0x0F
@@ -119,13 +127,13 @@
 #define FLASH_ENABLE_MODULE_MASK	0x80
 #define FLASH_DISABLE_ALL		0x00
 #define FLASH_ENABLE_MASK		0xE0
-#define FLASH_ENABLE_LED_0		0x40
-#define FLASH_ENABLE_LED_1		0x20
+#define FLASH_ENABLE_LED_0		0xC0
+#define FLASH_ENABLE_LED_1		0xA0
 #define FLASH_INIT_MASK			0xE0
 #define	FLASH_SELFCHECK_ENABLE		0x80
 
 #define FLASH_STROBE_SW			0xC0
-#define FLASH_STROBE_HW			0xC4
+#define FLASH_STROBE_HW			0x04
 #define FLASH_STROBE_MASK		0xC7
 #define FLASH_LED_0_OUTPUT		0x80
 #define FLASH_LED_1_OUTPUT		0x40
@@ -144,6 +152,9 @@
 #define FLASH_UNLOCK_SECURE		0xA5
 #define FLASH_SECURE_MASK		0xFF
 
+#define FLASH_SUBTYPE_DUAL		0x01
+#define FLASH_SUBTYPE_SINGLE		0x02
+
 #define LED_TRIGGER_DEFAULT		"none"
 
 #define RGB_LED_SRC_SEL(base)		(base + 0x45)
@@ -169,7 +180,8 @@
 #define LED_MPP_EN_CTRL(base)		(base + 0x46)
 #define LED_MPP_SINK_CTRL(base)		(base + 0x4C)
 
-#define LED_MPP_CURRENT_DEFAULT		5
+#define LED_MPP_CURRENT_MIN		5
+#define LED_MPP_CURRENT_MAX		40
 #define LED_MPP_VIN_CTRL_DEFAULT	0
 #define LED_MPP_CURRENT_PER_SETTING	5
 #define LED_MPP_SOURCE_SEL_DEFAULT	LED_MPP_MODE_ENABLE
@@ -332,6 +344,7 @@
 	u8	ctrl_delay_us;
 	u8	switch_freq;
 	u8	op_fdbck;
+	u8	pmic_version;
 	bool	dig_mod_gen_en;
 	bool	cs_out_en;
 };
@@ -366,13 +379,16 @@
  *  @trigger_flash - trigger flash
  *  @startup_dly - startup delay for flash
  *  @strobe_type - select between sw and hw strobe
+ *  @peripheral_subtype - module peripheral subtype
  *  @current_addr - address to write for current
  *  @second_addr - address of secondary flash to be written
  *  @safety_timer - enable safety timer or watchdog timer
  *  @torch_enable - enable flash LED torch mode
  *  @flash_reg_get - flash regulator attached or not
  *  @flash_on - flash status, on or off
+ *  @torch_on - torch status, on or off
  *  @flash_boost_reg - boost regulator for flash
+ *  @torch_boost_reg - boost regulator for torch
  */
 struct flash_config_data {
 	u8	current_prgm;
@@ -383,13 +399,16 @@
 	u8	trigger_flash;
 	u8	startup_dly;
 	u8	strobe_type;
+	u8	peripheral_subtype;
 	u16	current_addr;
 	u16	second_addr;
 	bool	safety_timer;
 	bool	torch_enable;
 	bool	flash_reg_get;
 	bool	flash_on;
+	bool	torch_on;
 	struct regulator *flash_boost_reg;
+	struct regulator *torch_boost_reg;
 };
 
 /**
@@ -500,16 +519,86 @@
 	pr_debug("===== %s LED register dump end =====\n", led->cdev.name);
 }
 
+static int qpnp_wled_sync(struct qpnp_led_data *led)
+{
+	int rc;
+	u8 val;
+
+	/* sync */
+	val = WLED_SYNC_VAL;
+	rc = spmi_ext_register_writel(led->spmi_dev->ctrl, led->spmi_dev->sid,
+		WLED_SYNC_REG(led->base), &val, 1);
+	if (rc) {
+		dev_err(&led->spmi_dev->dev,
+				"WLED set sync reg failed(%d)\n", rc);
+		return rc;
+	}
+
+	val = WLED_SYNC_RESET_VAL;
+	rc = spmi_ext_register_writel(led->spmi_dev->ctrl, led->spmi_dev->sid,
+		WLED_SYNC_REG(led->base), &val, 1);
+	if (rc) {
+		dev_err(&led->spmi_dev->dev,
+				"WLED reset sync reg failed(%d)\n", rc);
+		return rc;
+	}
+	return 0;
+}
+
 static int qpnp_wled_set(struct qpnp_led_data *led)
 {
 	int rc, duty, level;
-	u8 val, i, num_wled_strings;
+	u8 val, i, num_wled_strings, sink_val;
+
+	num_wled_strings = led->wled_cfg->num_strings;
 
 	level = led->cdev.brightness;
 
 	if (level > WLED_MAX_LEVEL)
 		level = WLED_MAX_LEVEL;
 	if (level == 0) {
+		for (i = 0; i < num_wled_strings; i++) {
+			rc = qpnp_led_masked_write(led,
+				WLED_FULL_SCALE_REG(led->base, i),
+				WLED_MAX_CURR_MASK, WLED_NO_CURRENT);
+			if (rc) {
+				dev_err(&led->spmi_dev->dev,
+					"Write max current failure (%d)\n",
+					rc);
+				return rc;
+			}
+		}
+
+		rc = qpnp_wled_sync(led);
+		if (rc) {
+			dev_err(&led->spmi_dev->dev,
+				"WLED sync failed(%d)\n", rc);
+			return rc;
+		}
+
+		rc = spmi_ext_register_readl(led->spmi_dev->ctrl,
+			led->spmi_dev->sid, WLED_CURR_SINK_REG(led->base),
+			&sink_val, 1);
+		if (rc) {
+			dev_err(&led->spmi_dev->dev,
+				"WLED read sink reg failed(%d)\n", rc);
+			return rc;
+		}
+
+		if (led->wled_cfg->pmic_version == PMIC_VER_8026) {
+			val = WLED_DISABLE_ALL_SINKS;
+			rc = spmi_ext_register_writel(led->spmi_dev->ctrl,
+				led->spmi_dev->sid,
+				WLED_CURR_SINK_REG(led->base), &val, 1);
+			if (rc) {
+				dev_err(&led->spmi_dev->dev,
+					"WLED write sink reg failed(%d)\n", rc);
+				return rc;
+			}
+
+			usleep(WLED_OVP_DELAY);
+		}
+
 		val = WLED_BOOST_OFF;
 		rc = spmi_ext_register_writel(led->spmi_dev->ctrl,
 			led->spmi_dev->sid, WLED_MOD_CTRL_REG(led->base),
@@ -519,6 +608,35 @@
 				"WLED write ctrl reg failed(%d)\n", rc);
 			return rc;
 		}
+
+		for (i = 0; i < num_wled_strings; i++) {
+			rc = qpnp_led_masked_write(led,
+				WLED_FULL_SCALE_REG(led->base, i),
+				WLED_MAX_CURR_MASK, led->max_current);
+			if (rc) {
+				dev_err(&led->spmi_dev->dev,
+					"Write max current failure (%d)\n",
+					rc);
+				return rc;
+			}
+		}
+
+		rc = qpnp_wled_sync(led);
+		if (rc) {
+			dev_err(&led->spmi_dev->dev,
+				"WLED sync failed(%d)\n", rc);
+			return rc;
+		}
+
+		rc = spmi_ext_register_writel(led->spmi_dev->ctrl,
+			led->spmi_dev->sid, WLED_CURR_SINK_REG(led->base),
+			&sink_val, 1);
+		if (rc) {
+			dev_err(&led->spmi_dev->dev,
+				"WLED write sink reg failed(%d)\n", rc);
+			return rc;
+		}
+
 	} else {
 		val = WLED_BOOST_ON;
 		rc = spmi_ext_register_writel(led->spmi_dev->ctrl,
@@ -533,8 +651,6 @@
 
 	duty = (WLED_MAX_DUTY_CYCLE * level) / WLED_MAX_LEVEL;
 
-	num_wled_strings = led->wled_cfg->num_strings;
-
 	/* program brightness control registers */
 	for (i = 0; i < num_wled_strings; i++) {
 		rc = qpnp_led_masked_write(led,
@@ -556,22 +672,9 @@
 		}
 	}
 
-	/* sync */
-	val = WLED_SYNC_VAL;
-	rc = spmi_ext_register_writel(led->spmi_dev->ctrl, led->spmi_dev->sid,
-		WLED_SYNC_REG(led->base), &val, 1);
+	rc = qpnp_wled_sync(led);
 	if (rc) {
-		dev_err(&led->spmi_dev->dev,
-				"WLED set sync reg failed(%d)\n", rc);
-		return rc;
-	}
-
-	val = WLED_SYNC_RESET_VAL;
-	rc = spmi_ext_register_writel(led->spmi_dev->ctrl, led->spmi_dev->sid,
-		WLED_SYNC_REG(led->base), &val, 1);
-	if (rc) {
-		dev_err(&led->spmi_dev->dev,
-				"WLED reset sync reg failed(%d)\n", rc);
+		dev_err(&led->spmi_dev->dev, "WLED sync failed(%d)\n", rc);
 		return rc;
 	}
 	return 0;
@@ -615,6 +718,21 @@
 
 		if (led->mpp_cfg->pwm_mode != MANUAL_MODE)
 			pwm_enable(led->mpp_cfg->pwm_cfg->pwm_dev);
+		else {
+			if (led->cdev.brightness < LED_MPP_CURRENT_MIN)
+				led->cdev.brightness = LED_MPP_CURRENT_MIN;
+
+			val = (led->cdev.brightness / LED_MPP_CURRENT_MIN) - 1;
+
+			rc = qpnp_led_masked_write(led,
+					LED_MPP_SINK_CTRL(led->base),
+					LED_MPP_SINK_MASK, val);
+			if (rc) {
+				dev_err(&led->spmi_dev->dev,
+					"Failed to write sink control reg\n");
+				return rc;
+			}
+		}
 
 		val = (led->mpp_cfg->source_sel & LED_MPP_SRC_MASK) |
 			(led->mpp_cfg->mode_ctrl & LED_MPP_MODE_CTRL_MASK);
@@ -716,6 +834,16 @@
 	if (regulator_on && led->flash_cfg->flash_on) {
 		for (i = 0; i < led->num_leds; i++) {
 			if (led_array[i].flash_cfg->flash_reg_get) {
+				rc = qpnp_led_masked_write(led,
+					FLASH_ENABLE_CONTROL(led->base),
+					FLASH_ENABLE_MASK,
+					FLASH_DISABLE_ALL);
+				if (rc) {
+					dev_err(&led->spmi_dev->dev,
+						"Enable reg write failed(%d)\n",
+						rc);
+				}
+
 				rc = regulator_disable(led_array[i].flash_cfg->\
 							flash_boost_reg);
 				if (rc) {
@@ -733,9 +861,47 @@
 	return 0;
 }
 
-static int qpnp_flash_set(struct qpnp_led_data *led)
+static int qpnp_torch_regulator_operate(struct qpnp_led_data *led, bool on)
 {
 	int rc;
+
+	if (!on)
+		goto regulator_turn_off;
+
+	if (!led->flash_cfg->torch_on) {
+		rc = regulator_enable(led->flash_cfg->torch_boost_reg);
+		if (rc) {
+			dev_err(&led->spmi_dev->dev,
+				"Regulator enable failed(%d)\n", rc);
+				return rc;
+		}
+		led->flash_cfg->torch_on = true;
+	}
+	return 0;
+
+regulator_turn_off:
+	if (led->flash_cfg->torch_on) {
+		rc = qpnp_led_masked_write(led,	FLASH_ENABLE_CONTROL(led->base),
+				FLASH_ENABLE_MODULE_MASK, FLASH_DISABLE_ALL);
+		if (rc) {
+			dev_err(&led->spmi_dev->dev,
+				"Enable reg write failed(%d)\n", rc);
+		}
+
+		rc = regulator_disable(led->flash_cfg->torch_boost_reg);
+		if (rc) {
+			dev_err(&led->spmi_dev->dev,
+				"Regulator disable failed(%d)\n", rc);
+			return rc;
+		}
+		led->flash_cfg->torch_on = false;
+	}
+	return 0;
+}
+
+static int qpnp_flash_set(struct qpnp_led_data *led)
+{
+	int rc, error;
 	int val = led->cdev.brightness;
 
 	if (led->flash_cfg->torch_enable)
@@ -745,21 +911,52 @@
 		led->flash_cfg->current_prgm =
 			(val * FLASH_MAX_LEVEL / led->max_current);
 
-	led->flash_cfg->current_prgm =
-		led->flash_cfg->current_prgm >> FLASH_CURRENT_PRGM_SHIFT;
-	if (!led->flash_cfg->current_prgm)
-		led->flash_cfg->current_prgm = FLASH_CURRENT_PRGM_MIN;
-
 	/* Set led current */
 	if (val > 0) {
 		if (led->flash_cfg->torch_enable) {
+			if (led->flash_cfg->peripheral_subtype ==
+							FLASH_SUBTYPE_DUAL) {
+				rc = qpnp_torch_regulator_operate(led, true);
+				if (rc) {
+					dev_err(&led->spmi_dev->dev,
+					"Torch regulator operate failed(%d)\n",
+					rc);
+					return rc;
+				}
+			} else if (led->flash_cfg->peripheral_subtype ==
+							FLASH_SUBTYPE_SINGLE) {
+				rc = qpnp_flash_regulator_operate(led, true);
+				if (rc) {
+					dev_err(&led->spmi_dev->dev,
+					"Flash regulator operate failed(%d)\n",
+					rc);
+					goto error_flash_set;
+				}
+
+				/*
+				 * Write 0x80 to MODULE_ENABLE before writing
+				 * 0xE0 in order to avoid a hardware bug caused
+				 * by register value going from 0x00 to 0xE0.
+				 */
+				rc = qpnp_led_masked_write(led,
+					FLASH_ENABLE_CONTROL(led->base),
+					FLASH_ENABLE_MODULE_MASK,
+					FLASH_ENABLE_MODULE);
+				if (rc) {
+					dev_err(&led->spmi_dev->dev,
+						"Enable reg write failed(%d)\n",
+						rc);
+					return rc;
+				}
+			}
+
 			rc = qpnp_led_masked_write(led,
 				FLASH_LED_UNLOCK_SECURE(led->base),
 				FLASH_SECURE_MASK, FLASH_UNLOCK_SECURE);
 			if (rc) {
 				dev_err(&led->spmi_dev->dev,
 					"Secure reg write failed(%d)\n", rc);
-				return rc;
+				goto error_reg_write;
 			}
 
 			rc = qpnp_led_masked_write(led,
@@ -768,7 +965,7 @@
 			if (rc) {
 				dev_err(&led->spmi_dev->dev,
 					"Torch reg write failed(%d)\n", rc);
-				return rc;
+				goto error_reg_write;
 			}
 
 			rc = qpnp_led_masked_write(led,
@@ -778,7 +975,7 @@
 			if (rc) {
 				dev_err(&led->spmi_dev->dev,
 					"Current reg write failed(%d)\n", rc);
-				return rc;
+				goto error_reg_write;
 			}
 
 			rc = qpnp_led_masked_write(led,
@@ -789,7 +986,7 @@
 				dev_err(&led->spmi_dev->dev,
 					"2nd Current reg write failed(%d)\n",
 					rc);
-				return rc;
+				goto error_reg_write;
 			}
 
 			qpnp_led_masked_write(led, FLASH_MAX_CURR(led->base),
@@ -799,16 +996,29 @@
 				dev_err(&led->spmi_dev->dev,
 					"Max current reg write failed(%d)\n",
 					rc);
-				return rc;
+				goto error_reg_write;
 			}
 
 			rc = qpnp_led_masked_write(led,
 				FLASH_ENABLE_CONTROL(led->base),
-				FLASH_ENABLE_MODULE_MASK, FLASH_ENABLE_MODULE);
+				FLASH_ENABLE_MASK,
+				led->flash_cfg->enable_module);
 			if (rc) {
 				dev_err(&led->spmi_dev->dev,
-					"Enable reg write failed(%d)\n", rc);
-				return rc;
+					"Enable reg write failed(%d)\n",
+					rc);
+				goto error_reg_write;
+			}
+
+			rc = qpnp_led_masked_write(led,
+				FLASH_LED_STROBE_CTRL(led->base),
+				led->flash_cfg->trigger_flash,
+				led->flash_cfg->trigger_flash);
+			if (rc) {
+				dev_err(&led->spmi_dev->dev,
+					"LED %d strobe reg write failed(%d)\n",
+					led->id, rc);
+				goto error_reg_write;
 			}
 		} else {
 			rc = qpnp_flash_regulator_operate(led, true);
@@ -816,7 +1026,7 @@
 				dev_err(&led->spmi_dev->dev,
 					"Flash regulator operate failed(%d)\n",
 					rc);
-				return rc;
+				goto error_flash_set;
 			}
 
 			/* Set flash safety timer */
@@ -828,7 +1038,7 @@
 				dev_err(&led->spmi_dev->dev,
 					"Safety timer reg write failed(%d)\n",
 					rc);
-				return rc;
+				goto error_flash_set;
 			}
 
 			/* Set max current */
@@ -839,7 +1049,7 @@
 				dev_err(&led->spmi_dev->dev,
 					"Max current reg write failed(%d)\n",
 					rc);
-				return rc;
+				goto error_flash_set;
 			}
 
 			/* Set clamp current */
@@ -851,20 +1061,23 @@
 				dev_err(&led->spmi_dev->dev,
 					"Clamp current reg write failed(%d)\n",
 					rc);
-				return rc;
+				goto error_flash_set;
 			}
 
-			/* Write 0x80 to MODULE_ENABLE before writing 0xE0
-			 * in order to avoid reg value goes from 0x00 to
-			 * 0xE0. This causes a hardware bug.
+			/*
+			 * Write 0x80 to MODULE_ENABLE before writing
+			 * 0xE0 in order to avoid a hardware bug caused
+			 * by register value going from 0x00 to 0xE0.
 			 */
 			rc = qpnp_led_masked_write(led,
 				FLASH_ENABLE_CONTROL(led->base),
-				FLASH_ENABLE_MODULE_MASK, FLASH_ENABLE_MODULE);
+				FLASH_ENABLE_MODULE_MASK,
+				FLASH_ENABLE_MODULE);
 			if (rc) {
 				dev_err(&led->spmi_dev->dev,
-					"Enable reg write failed(%d)\n", rc);
-				return rc;
+					"Enable reg write failed(%d)\n",
+					rc);
+				goto error_flash_set;
 			}
 
 			rc = qpnp_led_masked_write(led,
@@ -874,52 +1087,59 @@
 			if (rc) {
 				dev_err(&led->spmi_dev->dev,
 					"Current reg write failed(%d)\n", rc);
-				return rc;
-			}
-
-			rc = qpnp_led_masked_write(led,
-				led->flash_cfg->second_addr,
-				FLASH_CURRENT_MASK,
-				led->flash_cfg->current_prgm);
-			if (rc) {
-				dev_err(&led->spmi_dev->dev,
-					"2nd Current reg write failed(%d)\n",
-					rc);
-				return rc;
+				goto error_flash_set;
 			}
 
 			rc = qpnp_led_masked_write(led,
 				FLASH_ENABLE_CONTROL(led->base),
-				FLASH_ENABLE_MASK, FLASH_ENABLE_ALL);
+				led->flash_cfg->enable_module,
+				led->flash_cfg->enable_module);
 			if (rc) {
 				dev_err(&led->spmi_dev->dev,
 					"Enable reg write failed(%d)\n", rc);
-				return rc;
+				goto error_flash_set;
 			}
-		}
 
-		if (!led->flash_cfg->strobe_type) {
-			rc = qpnp_led_masked_write(led,
-				FLASH_LED_STROBE_CTRL(led->base),
-				FLASH_STROBE_MASK, FLASH_STROBE_SW);
-			if (rc) {
-				dev_err(&led->spmi_dev->dev,
+			if (!led->flash_cfg->strobe_type) {
+				rc = qpnp_led_masked_write(led,
+					FLASH_LED_STROBE_CTRL(led->base),
+					led->flash_cfg->trigger_flash,
+					led->flash_cfg->trigger_flash);
+				if (rc) {
+					dev_err(&led->spmi_dev->dev,
 					"LED %d strobe reg write failed(%d)\n",
 					led->id, rc);
-				return rc;
-			}
-		} else {
-			rc = qpnp_led_masked_write(led,
-				FLASH_LED_STROBE_CTRL(led->base),
-				FLASH_STROBE_MASK, FLASH_STROBE_HW);
-			if (rc) {
-				dev_err(&led->spmi_dev->dev,
+					goto error_flash_set;
+				}
+			} else {
+				rc = qpnp_led_masked_write(led,
+					FLASH_LED_STROBE_CTRL(led->base),
+					(led->flash_cfg->trigger_flash |
+					FLASH_STROBE_HW),
+					(led->flash_cfg->trigger_flash |
+					FLASH_STROBE_HW));
+				if (rc) {
+					dev_err(&led->spmi_dev->dev,
 					"LED %d strobe reg write failed(%d)\n",
 					led->id, rc);
-				return rc;
+					goto error_flash_set;
+				}
 			}
 		}
 	} else {
+		rc = qpnp_led_masked_write(led,
+			FLASH_LED_STROBE_CTRL(led->base),
+			led->flash_cfg->trigger_flash,
+			FLASH_DISABLE_ALL);
+		if (rc) {
+			dev_err(&led->spmi_dev->dev,
+				"LED %d flash write failed(%d)\n", led->id, rc);
+			if (led->flash_cfg->torch_enable)
+				goto error_torch_set;
+			else
+				goto error_flash_set;
+		}
+
 		if (led->flash_cfg->torch_enable) {
 			rc = qpnp_led_masked_write(led,
 				FLASH_LED_UNLOCK_SECURE(led->base),
@@ -927,7 +1147,7 @@
 			if (rc) {
 				dev_err(&led->spmi_dev->dev,
 					"Secure reg write failed(%d)\n", rc);
-				return rc;
+				goto error_torch_set;
 			}
 
 			rc = qpnp_led_masked_write(led,
@@ -937,40 +1157,78 @@
 			if (rc) {
 				dev_err(&led->spmi_dev->dev,
 					"Torch reg write failed(%d)\n", rc);
+				goto error_torch_set;
+			}
+
+			if (led->flash_cfg->peripheral_subtype ==
+							FLASH_SUBTYPE_DUAL) {
+				rc = qpnp_torch_regulator_operate(led, false);
+				if (rc) {
+					dev_err(&led->spmi_dev->dev,
+						"Torch regulator operate failed(%d)\n",
+						rc);
+					return rc;
+				}
+			} else if (led->flash_cfg->peripheral_subtype ==
+							FLASH_SUBTYPE_SINGLE) {
+				rc = qpnp_flash_regulator_operate(led, false);
+				if (rc) {
+					dev_err(&led->spmi_dev->dev,
+						"Flash regulator operate failed(%d)\n",
+						rc);
+					return rc;
+				}
+			}
+		} else {
+			rc = qpnp_led_masked_write(led,
+				FLASH_ENABLE_CONTROL(led->base),
+				led->flash_cfg->enable_module &
+				~FLASH_ENABLE_MODULE_MASK,
+				FLASH_DISABLE_ALL);
+			if (rc) {
+				dev_err(&led->spmi_dev->dev,
+					"Enable reg write failed(%d)\n", rc);
+				if (led->flash_cfg->torch_enable)
+					goto error_torch_set;
+				else
+					goto error_flash_set;
+			}
+
+			rc = qpnp_flash_regulator_operate(led, false);
+			if (rc) {
+				dev_err(&led->spmi_dev->dev,
+					"Flash regulator operate failed(%d)\n",
+					rc);
 				return rc;
 			}
 		}
-
-		rc = qpnp_led_masked_write(led,
-			FLASH_LED_STROBE_CTRL(led->base),
-			FLASH_STROBE_MASK,
-			FLASH_DISABLE_ALL);
-		if (rc) {
-			dev_err(&led->spmi_dev->dev,
-				"LED %d flash write failed(%d)\n", led->id, rc);
-			return rc;
-		}
-
-		rc = qpnp_led_masked_write(led, FLASH_ENABLE_CONTROL(led->base),
-			FLASH_ENABLE_MASK,
-			FLASH_DISABLE_ALL);
-		if (rc) {
-			dev_err(&led->spmi_dev->dev,
-				"Enable reg write failed(%d)\n", rc);
-			return rc;
-		}
-
-		rc = qpnp_flash_regulator_operate(led, false);
-		if (rc) {
-			dev_err(&led->spmi_dev->dev,
-				"Flash regulator operate failed(%d)\n", rc);
-			return rc;
-		}
 	}
 
 	qpnp_dump_regs(led, flash_debug_regs, ARRAY_SIZE(flash_debug_regs));
 
 	return 0;
+
+error_reg_write:
+	if (led->flash_cfg->peripheral_subtype == FLASH_SUBTYPE_SINGLE)
+		goto error_flash_set;
+
+error_torch_set:
+	error = qpnp_torch_regulator_operate(led, false);
+	if (error) {
+		dev_err(&led->spmi_dev->dev,
+			"Torch regulator operate failed(%d)\n", rc);
+		return error;
+	}
+	return rc;
+
+error_flash_set:
+	error = qpnp_flash_regulator_operate(led, false);
+	if (error) {
+		dev_err(&led->spmi_dev->dev,
+			"Flash regulator operate failed(%d)\n", rc);
+		return error;
+	}
+	return rc;
 }
 
 static int qpnp_kpdbl_set(struct qpnp_led_data *led)
@@ -1201,7 +1459,10 @@
 		led->cdev.max_brightness = RGB_MAX_LEVEL;
 		break;
 	case QPNP_ID_LED_MPP:
-		led->cdev.max_brightness = MPP_MAX_LEVEL;
+		if (led->mpp_cfg->pwm_mode == MANUAL_MODE)
+			led->cdev.max_brightness = led->max_current;
+		else
+			led->cdev.max_brightness = MPP_MAX_LEVEL;
 		break;
 	case QPNP_ID_KPDBL:
 		led->cdev.max_brightness = KPDBL_MAX_LEVEL;
@@ -1997,6 +2258,18 @@
 		return rc;
 	}
 
+	/* Disable flash LED module */
+	rc = qpnp_led_masked_write(led, FLASH_ENABLE_CONTROL(led->base),
+		FLASH_ENABLE_MODULE_MASK, FLASH_DISABLE_ALL);
+	if (rc) {
+		dev_err(&led->spmi_dev->dev,
+			"Enable reg write failed(%d)\n", rc);
+		return rc;
+	}
+
+	if (led->flash_cfg->torch_enable)
+		return 0;
+
 	/* Set headroom */
 	rc = qpnp_led_masked_write(led, FLASH_HEADROOM(led->base),
 		FLASH_HEADROOM_MASK, led->flash_cfg->headroom);
@@ -2056,15 +2329,6 @@
 		return rc;
 	}
 
-	/* Disable flash LED module */
-	rc = qpnp_led_masked_write(led, FLASH_ENABLE_CONTROL(led->base),
-		FLASH_ENABLE_MODULE_MASK, FLASH_DISABLE_ALL);
-	if (rc) {
-		dev_err(&led->spmi_dev->dev,
-			"Enable reg write failed(%d)\n", rc);
-		return rc;
-	}
-
 	led->flash_cfg->strobe_type = 0;
 
 	/* dump flash registers */
@@ -2179,6 +2443,14 @@
 {
 	int rc, val;
 
+
+	if (led->max_current < LED_MPP_CURRENT_MIN ||
+		led->max_current > LED_MPP_CURRENT_MAX) {
+		dev_err(&led->spmi_dev->dev,
+			"max current for mpp is not valid\n");
+		return -EINVAL;
+	}
+
 	val = (led->mpp_cfg->current_setting / LED_MPP_CURRENT_PER_SETTING) - 1;
 
 	if (val < 0)
@@ -2196,7 +2468,7 @@
 		LED_MPP_SINK_MASK, val);
 	if (rc) {
 		dev_err(&led->spmi_dev->dev,
-			"Failed to write led enable reg\n");
+			"Failed to write sink control reg\n");
 		return rc;
 	}
 
@@ -2309,6 +2581,13 @@
 		return -ENOMEM;
 	}
 
+	rc = spmi_ext_register_readl(led->spmi_dev->ctrl, led->spmi_dev->sid,
+		PMIC_VERSION_REG, &led->wled_cfg->pmic_version, 1);
+	if (rc) {
+		dev_err(&led->spmi_dev->dev,
+			"Unable to read pmic ver, rc(%d)\n", rc);
+	}
+
 	led->wled_cfg->num_strings = WLED_DEFAULT_STRINGS;
 	rc = of_property_read_u32(node, "qcom,num-strings", &val);
 	if (!rc)
@@ -2380,62 +2659,102 @@
 		return -ENOMEM;
 	}
 
-	if (led->id == QPNP_ID_FLASH1_LED0) {
-		led->flash_cfg->enable_module = FLASH_ENABLE_ALL;
-		led->flash_cfg->current_addr = FLASH_LED_0_CURR(led->base);
-		led->flash_cfg->second_addr = FLASH_LED_1_CURR(led->base);
-		led->flash_cfg->trigger_flash = FLASH_LED_0_OUTPUT;
-		if (!*reg_set) {
-			led->flash_cfg->flash_boost_reg =
-				regulator_get(&led->spmi_dev->dev,
-							"flash_boost");
-			if (IS_ERR(led->flash_cfg->flash_boost_reg)) {
-				rc = PTR_ERR(led->flash_cfg->flash_boost_reg);
-				dev_err(&led->spmi_dev->dev,
-					"Regulator get failed(%d)\n", rc);
-				return rc;
-			}
-			led->flash_cfg->flash_reg_get = true;
-			*reg_set = true;
-		} else
-			led->flash_cfg->flash_reg_get = false;
-	} else if (led->id == QPNP_ID_FLASH1_LED1) {
-		led->flash_cfg->enable_module = FLASH_ENABLE_ALL;
-		led->flash_cfg->current_addr = FLASH_LED_1_CURR(led->base);
-		led->flash_cfg->second_addr = FLASH_LED_0_CURR(led->base);
-		led->flash_cfg->trigger_flash = FLASH_LED_1_OUTPUT;
-		if (!*reg_set) {
-			led->flash_cfg->flash_boost_reg =
-					regulator_get(&led->spmi_dev->dev,
-								"flash_boost");
-			if (IS_ERR(led->flash_cfg->flash_boost_reg)) {
-				rc = PTR_ERR(led->flash_cfg->flash_boost_reg);
-				dev_err(&led->spmi_dev->dev,
-					"Regulator get failed(%d)\n", rc);
-				return rc;
-			}
-			led->flash_cfg->flash_reg_get = true;
-			*reg_set = true;
-		} else
-			led->flash_cfg->flash_reg_get = false;
-	} else {
-		dev_err(&led->spmi_dev->dev, "Unknown flash LED name given\n");
-		return -EINVAL;
+	rc = spmi_ext_register_readl(led->spmi_dev->ctrl, led->spmi_dev->sid,
+			FLASH_PERIPHERAL_SUBTYPE(led->base),
+			&led->flash_cfg->peripheral_subtype, 1);
+	if (rc) {
+		dev_err(&led->spmi_dev->dev,
+			"Unable to read from addr=%x, rc(%d)\n",
+			FLASH_PERIPHERAL_SUBTYPE(led->base), rc);
 	}
 
 	led->flash_cfg->torch_enable =
 		of_property_read_bool(node, "qcom,torch-enable");
 
+	if (led->id == QPNP_ID_FLASH1_LED0) {
+		led->flash_cfg->enable_module = FLASH_ENABLE_LED_0;
+		led->flash_cfg->current_addr = FLASH_LED_0_CURR(led->base);
+		led->flash_cfg->trigger_flash = FLASH_LED_0_OUTPUT;
+		if (!*reg_set) {
+			led->flash_cfg->flash_boost_reg =
+				regulator_get(&led->spmi_dev->dev,
+							"flash-boost");
+			if (IS_ERR(led->flash_cfg->flash_boost_reg)) {
+				rc = PTR_ERR(led->flash_cfg->flash_boost_reg);
+				dev_err(&led->spmi_dev->dev,
+					"Regulator get failed(%d)\n", rc);
+				goto error_get_flash_reg;
+			}
+			led->flash_cfg->flash_reg_get = true;
+			*reg_set = true;
+		} else
+			led->flash_cfg->flash_reg_get = false;
+
+		if (led->flash_cfg->torch_enable) {
+			led->flash_cfg->second_addr =
+						FLASH_LED_1_CURR(led->base);
+		}
+	} else if (led->id == QPNP_ID_FLASH1_LED1) {
+		led->flash_cfg->enable_module = FLASH_ENABLE_LED_1;
+		led->flash_cfg->current_addr = FLASH_LED_1_CURR(led->base);
+		led->flash_cfg->trigger_flash = FLASH_LED_1_OUTPUT;
+		if (!*reg_set) {
+			led->flash_cfg->flash_boost_reg =
+					regulator_get(&led->spmi_dev->dev,
+								"flash-boost");
+			if (IS_ERR(led->flash_cfg->flash_boost_reg)) {
+				rc = PTR_ERR(led->flash_cfg->flash_boost_reg);
+				dev_err(&led->spmi_dev->dev,
+					"Regulator get failed(%d)\n", rc);
+				goto error_get_flash_reg;
+			}
+			led->flash_cfg->flash_reg_get = true;
+			*reg_set = true;
+		} else
+			led->flash_cfg->flash_reg_get = false;
+
+		if (led->flash_cfg->torch_enable) {
+			led->flash_cfg->second_addr =
+						FLASH_LED_0_CURR(led->base);
+		}
+	} else {
+		dev_err(&led->spmi_dev->dev, "Unknown flash LED name given\n");
+		return -EINVAL;
+	}
+
+	if (led->flash_cfg->torch_enable) {
+		if (of_find_property(of_get_parent(node), "torch-boost-supply",
+									NULL)) {
+			led->flash_cfg->torch_boost_reg =
+				regulator_get(&led->spmi_dev->dev,
+								"torch-boost");
+			if (IS_ERR(led->flash_cfg->torch_boost_reg)) {
+				rc = PTR_ERR(led->flash_cfg->torch_boost_reg);
+				dev_err(&led->spmi_dev->dev,
+					"Torch regulator get failed(%d)\n", rc);
+				goto error_get_torch_reg;
+			}
+			led->flash_cfg->enable_module = FLASH_ENABLE_MODULE;
+		} else
+			led->flash_cfg->enable_module = FLASH_ENABLE_ALL;
+		led->flash_cfg->trigger_flash = FLASH_STROBE_SW;
+	}
+
 	rc = of_property_read_u32(node, "qcom,current", &val);
 	if (!rc) {
-		if (led->flash_cfg->torch_enable)
+		if (led->flash_cfg->torch_enable) {
 			led->flash_cfg->current_prgm = (val *
 				TORCH_MAX_LEVEL / led->max_current);
+			return 0;
+		}
 		else
 			led->flash_cfg->current_prgm = (val *
 				FLASH_MAX_LEVEL / led->max_current);
 	} else
-		return -EINVAL;
+		if (led->flash_cfg->torch_enable)
+			goto error_get_torch_reg;
+		else
+			goto error_get_flash_reg;
 
 	rc = of_property_read_u32(node, "qcom,headroom", &val);
 	if (!rc)
@@ -2443,7 +2762,7 @@
 	else if (rc == -EINVAL)
 		led->flash_cfg->headroom = HEADROOM_500mV;
 	else
-		return rc;
+		goto error_get_flash_reg;
 
 	rc = of_property_read_u32(node, "qcom,duration", &val);
 	if (!rc)
@@ -2451,7 +2770,7 @@
 	else if (rc == -EINVAL)
 		led->flash_cfg->duration = FLASH_DURATION_200ms;
 	else
-		return rc;
+		goto error_get_flash_reg;
 
 	rc = of_property_read_u32(node, "qcom,clamp-curr", &val);
 	if (!rc)
@@ -2460,7 +2779,7 @@
 	else if (rc == -EINVAL)
 		led->flash_cfg->clamp_curr = FLASH_CLAMP_200mA;
 	else
-		return rc;
+		goto error_get_flash_reg;
 
 	rc = of_property_read_u32(node, "qcom,startup-dly", &val);
 	if (!rc)
@@ -2468,12 +2787,20 @@
 	else if (rc == -EINVAL)
 		led->flash_cfg->startup_dly = DELAY_128us;
 	else
-		return rc;
+		goto error_get_flash_reg;
 
 	led->flash_cfg->safety_timer =
 		of_property_read_bool(node, "qcom,safety-timer");
 
 	return 0;
+
+error_get_torch_reg:
+	regulator_put(led->flash_cfg->torch_boost_reg);
+
+error_get_flash_reg:
+	regulator_put(led->flash_cfg->flash_boost_reg);
+	return rc;
+
 }
 
 static int __devinit qpnp_get_config_pwm(struct pwm_config_data *pwm_cfg,
@@ -2753,11 +3080,16 @@
 		return -ENOMEM;
 	}
 
-	led->mpp_cfg->current_setting = LED_MPP_CURRENT_DEFAULT;
+	led->mpp_cfg->current_setting = LED_MPP_CURRENT_MIN;
 	rc = of_property_read_u32(node, "qcom,current-setting", &val);
-	if (!rc)
-		led->mpp_cfg->current_setting = (u8) val;
-	else if (rc != -EINVAL)
+	if (!rc) {
+		if (led->mpp_cfg->current_setting < LED_MPP_CURRENT_MIN)
+			led->mpp_cfg->current_setting = LED_MPP_CURRENT_MIN;
+		else if (led->mpp_cfg->current_setting > LED_MPP_CURRENT_MAX)
+			led->mpp_cfg->current_setting = LED_MPP_CURRENT_MAX;
+		else
+			led->mpp_cfg->current_setting = (u8) val;
+	} else if (rc != -EINVAL)
 		return rc;
 
 	led->mpp_cfg->source_sel = LED_MPP_SOURCE_SEL_DEFAULT;
@@ -2909,7 +3241,7 @@
 			}
 		} else if (strncmp(led_label, "flash", sizeof("flash"))
 				== 0) {
-			if (!of_find_property(node, "flash_boost-supply", NULL))
+			if (!of_find_property(node, "flash-boost-supply", NULL))
 				regulator_probe = true;
 			rc = qpnp_get_config_flash(led, temp, &regulator_probe);
 			if (rc < 0) {
@@ -3065,6 +3397,9 @@
 			if (led_array[i].flash_cfg->flash_reg_get)
 				regulator_put(led_array[i].flash_cfg-> \
 							flash_boost_reg);
+			if (led_array[i].flash_cfg->torch_enable)
+				regulator_put(led_array[i].flash_cfg->\
+							torch_boost_reg);
 			sysfs_remove_group(&led_array[i].cdev.dev->kobj,
 							&led_attr_group);
 			break;
diff --git a/drivers/media/platform/msm/camera_v1/gemini/msm_gemini_hw.c b/drivers/media/platform/msm/camera_v1/gemini/msm_gemini_hw.c
index 79c533e..de0ed97 100644
--- a/drivers/media/platform/msm/camera_v1/gemini/msm_gemini_hw.c
+++ b/drivers/media/platform/msm/camera_v1/gemini/msm_gemini_hw.c
@@ -433,7 +433,7 @@
 	}
 }
 
-int msm_gemini_hw_exec_cmds(struct msm_gemini_hw_cmd *hw_cmd_p, int m_cmds)
+int msm_gemini_hw_exec_cmds(struct msm_gemini_hw_cmd *hw_cmd_p, uint32_t m_cmds)
 {
 	int is_copy_to_user = -1;
 	uint32_t data;
diff --git a/drivers/media/platform/msm/camera_v1/gemini/msm_gemini_hw.h b/drivers/media/platform/msm/camera_v1/gemini/msm_gemini_hw.h
index aa6c4aa1..4d08282 100644
--- a/drivers/media/platform/msm/camera_v1/gemini/msm_gemini_hw.h
+++ b/drivers/media/platform/msm/camera_v1/gemini/msm_gemini_hw.h
@@ -94,7 +94,8 @@
 void msm_gemini_hw_write(struct msm_gemini_hw_cmd *hw_cmd_p);
 int msm_gemini_hw_wait(struct msm_gemini_hw_cmd *hw_cmd_p, int m_us);
 void msm_gemini_hw_delay(struct msm_gemini_hw_cmd *hw_cmd_p, int m_us);
-int msm_gemini_hw_exec_cmds(struct msm_gemini_hw_cmd *hw_cmd_p, int m_cmds);
+int msm_gemini_hw_exec_cmds(struct msm_gemini_hw_cmd *hw_cmd_p,
+	uint32_t m_cmds);
 void msm_gemini_io_dump(int size);
 
 #define MSM_GEMINI_PIPELINE_CLK_128MHZ 128 /* 8MP  128MHz */
diff --git a/drivers/media/platform/msm/camera_v1/gemini/msm_gemini_sync.c b/drivers/media/platform/msm/camera_v1/gemini/msm_gemini_sync.c
index 50c7284..0796b8d 100644
--- a/drivers/media/platform/msm/camera_v1/gemini/msm_gemini_sync.c
+++ b/drivers/media/platform/msm/camera_v1/gemini/msm_gemini_sync.c
@@ -23,6 +23,8 @@
 #include "msm_gemini_platform.h"
 #include "msm_gemini_common.h"
 
+#define UINT32_MAX (0xFFFFFFFFU)
+
 static int release_buf;
 
 /* size is based on 4k page size */
@@ -804,7 +806,7 @@
 	void * __user arg)
 {
 	int is_copy_to_user;
-	int len;
+	uint32_t len;
 	uint32_t m;
 	struct msm_gemini_hw_cmds *hw_cmds_p;
 	struct msm_gemini_hw_cmd *hw_cmd_p;
@@ -814,6 +816,12 @@
 		return -EFAULT;
 	}
 
+	if ((m == 0) || (m > ((UINT32_MAX - sizeof(struct msm_gemini_hw_cmds)) /
+		sizeof(struct msm_gemini_hw_cmd)))) {
+		GMN_PR_ERR("%s:%d] m_cmds out of range\n", __func__, __LINE__);
+		return -EFAULT;
+	}
+
 	len = sizeof(struct msm_gemini_hw_cmds) +
 		sizeof(struct msm_gemini_hw_cmd) * (m - 1);
 	hw_cmds_p = kmalloc(len, GFP_KERNEL);
diff --git a/drivers/media/platform/msm/camera_v1/mercury/msm_mercury_sync.c b/drivers/media/platform/msm/camera_v1/mercury/msm_mercury_sync.c
index 9293aad..e6483c1 100644
--- a/drivers/media/platform/msm/camera_v1/mercury/msm_mercury_sync.c
+++ b/drivers/media/platform/msm/camera_v1/mercury/msm_mercury_sync.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2012, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2012-2013, The Linux Foundation. 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 and
@@ -196,6 +196,7 @@
 	int rc = 0;
 
 	MCR_DBG("(%d)%s() Enter\n", __LINE__, __func__);
+	memset(&ctrl_cmd, 0, sizeof(ctrl_cmd));
 	ctrl_cmd.type = (uint32_t)msm_mercury_q_wait(&pmercury_dev->evt_q);
 
 	rc = copy_to_user(arg, &ctrl_cmd, sizeof(ctrl_cmd));
diff --git a/drivers/media/platform/msm/camera_v1/server/msm_cam_server.c b/drivers/media/platform/msm/camera_v1/server/msm_cam_server.c
index 78d15d9..d9fba33 100644
--- a/drivers/media/platform/msm/camera_v1/server/msm_cam_server.c
+++ b/drivers/media/platform/msm/camera_v1/server/msm_cam_server.c
@@ -2777,40 +2777,6 @@
 	return rc;
 }
 
-static int msm_mmap_config(struct file *fp, struct vm_area_struct *vma)
-{
-	struct msm_cam_config_dev *config_cam = fp->private_data;
-	int rc = 0;
-	int phyaddr;
-	int retval;
-	unsigned long size;
-
-	D("%s: phy_addr=0x%x", __func__, config_cam->mem_map.cookie);
-	phyaddr = (int)config_cam->mem_map.cookie;
-	if (!phyaddr) {
-		pr_err("%s: no physical memory to map", __func__);
-		return -EFAULT;
-	}
-	memset(&config_cam->mem_map, 0,
-		sizeof(struct msm_mem_map_info));
-	size = vma->vm_end - vma->vm_start;
-	vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot);
-	retval = remap_pfn_range(vma, vma->vm_start,
-					phyaddr >> PAGE_SHIFT,
-					size, vma->vm_page_prot);
-	if (retval) {
-		pr_err("%s: remap failed, rc = %d",
-					__func__, retval);
-		rc = -ENOMEM;
-		goto end;
-	}
-	D("%s: phy_addr=0x%x: %08lx-%08lx, pgoff %08lx\n",
-			__func__, (uint32_t)phyaddr,
-			vma->vm_start, vma->vm_end, vma->vm_pgoff);
-end:
-	return rc;
-}
-
 static int msm_open_config(struct inode *inode, struct file *fp)
 {
 	int rc;
@@ -3081,12 +3047,6 @@
 		rc = msm_v4l2_evt_notify(config_cam->p_mctl, cmd, arg);
 		break;
 
-	case MSM_CAM_IOCTL_SET_MEM_MAP_INFO:
-		if (copy_from_user(&config_cam->mem_map, (void __user *)arg,
-				sizeof(struct msm_mem_map_info)))
-			rc = -EINVAL;
-		break;
-
 	case MSM_CAM_IOCTL_SET_MCTL_SDEV:{
 		struct msm_mctl_set_sdev_data set_data;
 		if (copy_from_user(&set_data, (void __user *)arg,
@@ -3148,7 +3108,6 @@
 	.open  = msm_open_config,
 	.poll  = msm_poll_config,
 	.unlocked_ioctl = msm_ioctl_config,
-	.mmap	= msm_mmap_config,
 	.release = msm_close_config,
 };
 
diff --git a/drivers/media/platform/msm/camera_v2/Kconfig b/drivers/media/platform/msm/camera_v2/Kconfig
index 4668d02..bc7d135 100644
--- a/drivers/media/platform/msm/camera_v2/Kconfig
+++ b/drivers/media/platform/msm/camera_v2/Kconfig
@@ -191,6 +191,15 @@
 		snapshot config = 3264 * 2448 at 18 fps.
 		2 lanes max fps is 18, 4 lanes max fps is 24.
 
+config OV8865
+	bool "OmniVision OV8865 (BAYER 8MP)"
+	depends on MSMB_CAMERA
+	---help---
+		OmniVision 8 MP Bayer Sensor with auto focus.uses
+		4 mipi lanes, preview config = 1632*1224 30 fps,
+		snapshot config = 3264 * 2448 at 30 fps.
+		Max fps is 30fps at 3264 * 2448, 60fps at 1632 * 1224
+
 config s5k4e1
 	bool "Sensor s5k4e1 (BAYER 5MP)"
 	depends on MSMB_CAMERA
diff --git a/drivers/media/platform/msm/camera_v2/camera/camera.c b/drivers/media/platform/msm/camera_v2/camera/camera.c
index c70e151..0313161 100644
--- a/drivers/media/platform/msm/camera_v2/camera/camera.c
+++ b/drivers/media/platform/msm/camera_v2/camera/camera.c
@@ -353,6 +353,7 @@
 
 set_fmt_fail:
 	kzfree(sp->vb2_q.drv_priv);
+	sp->vb2_q.drv_priv = NULL;
 	return rc;
 }
 
diff --git a/drivers/media/platform/msm/camera_v2/gemini/msm_gemini_hw.c b/drivers/media/platform/msm/camera_v2/gemini/msm_gemini_hw.c
index 96470fd..da6f69f 100644
--- a/drivers/media/platform/msm/camera_v2/gemini/msm_gemini_hw.c
+++ b/drivers/media/platform/msm/camera_v2/gemini/msm_gemini_hw.c
@@ -426,7 +426,7 @@
 	}
 }
 
-int msm_gemini_hw_exec_cmds(struct msm_gemini_hw_cmd *hw_cmd_p, int m_cmds)
+int msm_gemini_hw_exec_cmds(struct msm_gemini_hw_cmd *hw_cmd_p, uint32_t m_cmds)
 {
 	int is_copy_to_user = -1;
 	uint32_t data;
diff --git a/drivers/media/platform/msm/camera_v2/gemini/msm_gemini_hw.h b/drivers/media/platform/msm/camera_v2/gemini/msm_gemini_hw.h
index 84eed72..f4c32a7 100644
--- a/drivers/media/platform/msm/camera_v2/gemini/msm_gemini_hw.h
+++ b/drivers/media/platform/msm/camera_v2/gemini/msm_gemini_hw.h
@@ -94,7 +94,8 @@
 void msm_gemini_hw_write(struct msm_gemini_hw_cmd *hw_cmd_p);
 int msm_gemini_hw_wait(struct msm_gemini_hw_cmd *hw_cmd_p, int m_us);
 void msm_gemini_hw_delay(struct msm_gemini_hw_cmd *hw_cmd_p, int m_us);
-int msm_gemini_hw_exec_cmds(struct msm_gemini_hw_cmd *hw_cmd_p, int m_cmds);
+int msm_gemini_hw_exec_cmds(struct msm_gemini_hw_cmd *hw_cmd_p,
+	uint32_t m_cmds);
 void msm_gemini_io_dump(int size);
 
 #define MSM_GEMINI_PIPELINE_CLK_128MHZ 128 /* 8MP  128MHz */
diff --git a/drivers/media/platform/msm/camera_v2/gemini/msm_gemini_sync.c b/drivers/media/platform/msm/camera_v2/gemini/msm_gemini_sync.c
index 8f84a2c..ebf8d4b 100644
--- a/drivers/media/platform/msm/camera_v2/gemini/msm_gemini_sync.c
+++ b/drivers/media/platform/msm/camera_v2/gemini/msm_gemini_sync.c
@@ -23,6 +23,8 @@
 #include "msm_gemini_platform.h"
 #include "msm_gemini_common.h"
 
+#define UINT32_MAX (0xFFFFFFFFU)
+
 static int release_buf;
 
 /* size is based on 4k page size */
@@ -808,7 +810,7 @@
 	void * __user arg)
 {
 	int is_copy_to_user;
-	int len;
+	uint32_t len;
 	uint32_t m;
 	struct msm_gemini_hw_cmds *hw_cmds_p;
 	struct msm_gemini_hw_cmd *hw_cmd_p;
@@ -818,6 +820,12 @@
 		return -EFAULT;
 	}
 
+	if ((m == 0) || (m > ((UINT32_MAX - sizeof(struct msm_gemini_hw_cmds)) /
+		sizeof(struct msm_gemini_hw_cmd)))) {
+		GMN_PR_ERR("%s:%d] m_cmds out of range\n", __func__, __LINE__);
+		return -EFAULT;
+	}
+
 	len = sizeof(struct msm_gemini_hw_cmds) +
 		sizeof(struct msm_gemini_hw_cmd) * (m - 1);
 	hw_cmds_p = kmalloc(len, GFP_KERNEL);
diff --git a/drivers/media/platform/msm/camera_v2/isp/msm_buf_mgr.c b/drivers/media/platform/msm/camera_v2/isp/msm_buf_mgr.c
index 2a2656f..2be1f01 100644
--- a/drivers/media/platform/msm/camera_v2/isp/msm_buf_mgr.c
+++ b/drivers/media/platform/msm/camera_v2/isp/msm_buf_mgr.c
@@ -288,6 +288,10 @@
 		pr_err("%s: Invalid bufq\n", __func__);
 		return rc;
 	}
+	if (!bufq->bufq_handle) {
+		pr_err("%s: Invalid bufq handle\n", __func__);
+		return rc;
+	}
 
 	*buf_info = NULL;
 	spin_lock_irqsave(&bufq->bufq_lock, flags);
diff --git a/drivers/media/platform/msm/camera_v2/isp/msm_isp.h b/drivers/media/platform/msm/camera_v2/isp/msm_isp.h
index 8c42ed2..4aa423f 100644
--- a/drivers/media/platform/msm/camera_v2/isp/msm_isp.h
+++ b/drivers/media/platform/msm/camera_v2/isp/msm_isp.h
@@ -49,6 +49,16 @@
 	uint32_t active;
 };
 
+enum msm_isp_pack_fmt {
+	QCOM,
+	MIPI,
+	DPCM6,
+	DPCM8,
+	PLAIN8,
+	PLAIN16,
+	MAX_ISP_PACK_FMT,
+};
+
 enum msm_isp_camif_update_state {
 	NO_UPDATE,
 	ENABLE_CAMIF,
@@ -290,7 +300,7 @@
 	enum msm_vfe_inputmux input_mux;
 	uint32_t width;
 	long pixel_clock;
-	uint32_t input_format;
+	uint32_t input_format;/*V4L2 pix format with bayer pattern*/
 };
 
 enum msm_wm_ub_cfg_type {
@@ -386,10 +396,12 @@
 	struct resource *vfe_irq;
 	struct resource *vfe_mem;
 	struct resource *vfe_vbif_mem;
+	struct resource *tcsr_mem;
 	struct resource *vfe_io;
 	struct resource *vfe_vbif_io;
 	void __iomem *vfe_base;
 	void __iomem *vfe_vbif_base;
+	void __iomem *tcsr_base;
 
 	struct device *iommu_ctx[MAX_IOMMU_CTX];
 
@@ -414,6 +426,7 @@
 	struct msm_vfe_tasklet_queue_cmd
 		tasklet_queue_cmd[MSM_VFE_TASKLETQ_SIZE];
 
+	uint32_t soc_hw_version;
 	uint32_t vfe_hw_version;
 	struct msm_vfe_hardware_info *hw_info;
 	struct msm_vfe_axi_shared_data axi_data;
diff --git a/drivers/media/platform/msm/camera_v2/isp/msm_isp32.c b/drivers/media/platform/msm/camera_v2/isp/msm_isp32.c
index aac973e..a6972e4 100644
--- a/drivers/media/platform/msm/camera_v2/isp/msm_isp32.c
+++ b/drivers/media/platform/msm/camera_v2/isp/msm_isp32.c
@@ -24,7 +24,7 @@
 
 #define VFE32_BURST_LEN 2
 #define VFE32_UB_SIZE 1024
-#define VFE32_EQUAL_SLICE_UB 204
+#define VFE32_EQUAL_SLICE_UB 198
 #define VFE32_WM_BASE(idx) (0x4C + 0x18 * idx)
 #define VFE32_RDI_BASE(idx) (idx ? 0x734 + 0x4 * (idx - 1) : 0x06FC)
 #define VFE32_XBAR_BASE(idx) (0x40 + 0x4 * (idx / 4))
@@ -149,6 +149,7 @@
 	msm_camera_io_w_mb(0x1CFFFFFF, vfe_dev->vfe_base + 0x20);
 	msm_camera_io_w(0xFFFFFFFF, vfe_dev->vfe_base + 0x24);
 	msm_camera_io_w_mb(0x1FFFFFFF, vfe_dev->vfe_base + 0x28);
+
 }
 
 static void msm_vfe32_process_reset_irq(struct vfe_device *vfe_dev,
@@ -483,7 +484,7 @@
 static void msm_vfe32_cfg_io_format(struct vfe_device *vfe_dev,
 	enum msm_vfe_axi_stream_src stream_src, uint32_t io_format)
 {
-	int bpp, bpp_reg = 0;
+	int bpp, bpp_reg = 0, pack_fmt = 0, pack_reg = 0;
 	uint32_t io_format_reg;
 	bpp = msm_isp_get_bit_per_pixel(io_format);
 
@@ -498,6 +499,34 @@
 		bpp_reg = 1 << 1;
 		break;
 	}
+
+	if (stream_src == IDEAL_RAW) {
+		pack_fmt = msm_isp_get_pack_format(io_format);
+		switch (pack_fmt) {
+		case QCOM:
+			pack_reg = 0x0;
+			break;
+		case MIPI:
+			pack_reg = 0x1;
+			break;
+		case DPCM6:
+			pack_reg = 0x2;
+			break;
+		case DPCM8:
+			pack_reg = 0x3;
+			break;
+		case PLAIN8:
+			pack_reg = 0x4;
+			break;
+		case PLAIN16:
+			pack_reg = 0x5;
+			break;
+		default:
+			pr_err("%s: invalid pack fmt!\n", __func__);
+			return;
+		}
+	}
+
 	io_format_reg = msm_camera_io_r(vfe_dev->vfe_base + 0x6F8);
 	switch (stream_src) {
 	case PIX_ENCODER:
@@ -508,7 +537,7 @@
 		break;
 	case IDEAL_RAW:
 		io_format_reg &= 0xFFFFFFC8;
-		io_format_reg |= bpp_reg << 4;
+		io_format_reg |= bpp_reg << 4 | pack_reg;
 		break;
 	case RDI_INTF_0:
 	case RDI_INTF_1:
@@ -852,13 +881,13 @@
 	int i;
 	uint32_t ub_offset = VFE32_UB_SIZE;
 	uint32_t ub_size[VFE32_NUM_STATS_TYPE] = {
-		64, /*MSM_ISP_STATS_BG*/
-		64, /*MSM_ISP_STATS_BF*/
-		16, /*MSM_ISP_STATS_AWB*/
-		8,  /*MSM_ISP_STATS_RS*/
+		107, /*MSM_ISP_STATS_BG*/
+		92, /*MSM_ISP_STATS_BF*/
+		2, /*MSM_ISP_STATS_AWB*/
+		7,  /*MSM_ISP_STATS_RS*/
 		16, /*MSM_ISP_STATS_CS*/
-		16, /*MSM_ISP_STATS_IHIST*/
-		16, /*MSM_ISP_STATS_BHIST*/
+		2, /*MSM_ISP_STATS_IHIST*/
+		7, /*MSM_ISP_STATS_BHIST*/
 	};
 
 	for (i = 0; i < VFE32_NUM_STATS_TYPE; i++) {
diff --git a/drivers/media/platform/msm/camera_v2/isp/msm_isp40.c b/drivers/media/platform/msm/camera_v2/isp/msm_isp40.c
index 84b95f1..9047c40 100644
--- a/drivers/media/platform/msm/camera_v2/isp/msm_isp40.c
+++ b/drivers/media/platform/msm/camera_v2/isp/msm_isp40.c
@@ -290,6 +290,14 @@
 		goto vbif_remap_failed;
 	}
 
+	vfe_dev->tcsr_base = ioremap(vfe_dev->tcsr_mem->start,
+		resource_size(vfe_dev->tcsr_mem));
+	if (!vfe_dev->tcsr_base) {
+		rc = -ENOMEM;
+		pr_err("%s: tcsr ioremap failed\n", __func__);
+		goto tcsr_remap_failed;
+	}
+
 	rc = request_irq(vfe_dev->vfe_irq->start, msm_isp_process_irq,
 		IRQF_TRIGGER_RISING, "vfe", vfe_dev);
 	if (rc < 0) {
@@ -298,6 +306,8 @@
 	}
 	return rc;
 irq_req_failed:
+	iounmap(vfe_dev->tcsr_base);
+tcsr_remap_failed:
 	iounmap(vfe_dev->vfe_vbif_base);
 vbif_remap_failed:
 	iounmap(vfe_dev->vfe_base);
@@ -316,6 +326,7 @@
 {
 	free_irq(vfe_dev->vfe_irq->start, vfe_dev);
 	tasklet_kill(&vfe_dev->vfe_tasklet);
+	iounmap(vfe_dev->tcsr_base);
 	iounmap(vfe_dev->vfe_vbif_base);
 	iounmap(vfe_dev->vfe_base);
 	msm_cam_clk_enable(&vfe_dev->pdev->dev, msm_vfe40_clk_info,
@@ -503,15 +514,17 @@
 {
 	*irq_status0 = msm_camera_io_r(vfe_dev->vfe_base + 0x38);
 	*irq_status1 = msm_camera_io_r(vfe_dev->vfe_base + 0x3C);
-	/*Ignore composite 3 irq which is used for dual VFE only*/
+	/*
+	 * Ignore composite 2/3 irq which is used for dual VFE only
+	 */
 	if (*irq_status0 & 0x6000000)
-		*irq_status0 &= ~(0x10000000);
+		*irq_status0 &= ~(0x18000000);
 	msm_camera_io_w(*irq_status0, vfe_dev->vfe_base + 0x30);
 	msm_camera_io_w(*irq_status1, vfe_dev->vfe_base + 0x34);
 	msm_camera_io_w_mb(1, vfe_dev->vfe_base + 0x24);
-	if (*irq_status0 & 0x10000000) {
+	if (*irq_status0 & 0x18000000) {
 		pr_err_ratelimited("%s: Protection triggered\n", __func__);
-		*irq_status0 &= ~(0x10000000);
+		*irq_status0 &= ~(0x18000000);
 	}
 
 	if (*irq_status1 & (1 << 0))
@@ -597,15 +610,29 @@
 	comp_mask &= ~(0x7F << (comp_mask_index * 8));
 	comp_mask |= (axi_data->composite_info[comp_mask_index].
 		stream_composite_mask << (comp_mask_index * 8));
-	if (stream_info->plane_cfg[0].plane_addr_offset)
-		comp_mask |= (axi_data->composite_info[comp_mask_index].
-		stream_composite_mask << 24);
-	msm_camera_io_w(comp_mask, vfe_dev->vfe_base + 0x40);
 
 	irq_mask = msm_camera_io_r(vfe_dev->vfe_base + 0x28);
 	irq_mask |= 1 << (comp_mask_index + 25);
-	if (stream_info->plane_cfg[0].plane_addr_offset && (comp_mask >> 24))
+
+	/*
+	 * For dual VFE, composite 2/3 interrupt is used to trigger
+	 * microcontroller to update certain VFE registers
+	 */
+	if (stream_info->plane_cfg[0].plane_addr_offset &&
+		stream_info->stream_src == PIX_VIEWFINDER) {
+		comp_mask |= (axi_data->composite_info[comp_mask_index].
+		stream_composite_mask << 16);
+		irq_mask |= BIT(27);
+	}
+
+	if (stream_info->plane_cfg[0].plane_addr_offset &&
+		stream_info->stream_src == PIX_ENCODER) {
+		comp_mask |= (axi_data->composite_info[comp_mask_index].
+		stream_composite_mask << 24);
 		irq_mask |= BIT(28);
+	}
+
+	msm_camera_io_w(comp_mask, vfe_dev->vfe_base + 0x40);
 	msm_camera_io_w(irq_mask, vfe_dev->vfe_base + 0x28);
 }
 
@@ -618,15 +645,25 @@
 
 	comp_mask = msm_camera_io_r(vfe_dev->vfe_base + 0x40);
 	comp_mask &= ~(0x7F << (comp_mask_index * 8));
-	if (stream_info->plane_cfg[0].plane_addr_offset)
-		comp_mask &= ~(axi_data->composite_info[comp_mask_index].
-		stream_composite_mask << 24);
-	msm_camera_io_w(comp_mask, vfe_dev->vfe_base + 0x40);
 
 	irq_mask = msm_camera_io_r(vfe_dev->vfe_base + 0x28);
 	irq_mask &= ~(1 << (comp_mask_index + 25));
-	if (stream_info->plane_cfg[0].plane_addr_offset && (comp_mask >> 24))
+
+	if (stream_info->plane_cfg[0].plane_addr_offset &&
+		stream_info->stream_src == PIX_VIEWFINDER) {
+		comp_mask &= ~(axi_data->composite_info[comp_mask_index].
+		stream_composite_mask << 16);
+		irq_mask &= ~BIT(27);
+	}
+
+	if (stream_info->plane_cfg[0].plane_addr_offset &&
+		stream_info->stream_src == PIX_ENCODER) {
+		comp_mask &= ~(axi_data->composite_info[comp_mask_index].
+		stream_composite_mask << 24);
 		irq_mask &= ~BIT(28);
+	}
+
+	msm_camera_io_w(comp_mask, vfe_dev->vfe_base + 0x40);
 	msm_camera_io_w(irq_mask, vfe_dev->vfe_base + 0x28);
 }
 
@@ -690,8 +727,9 @@
 static void msm_vfe40_cfg_io_format(struct vfe_device *vfe_dev,
 	enum msm_vfe_axi_stream_src stream_src, uint32_t io_format)
 {
-	int bpp, bpp_reg = 0;
-	uint32_t io_format_reg;
+	int bpp, bpp_reg = 0, pack_reg = 0;
+	enum msm_isp_pack_fmt pack_fmt = 0;
+	uint32_t io_format_reg; /*io format register bit*/
 	bpp = msm_isp_get_bit_per_pixel(io_format);
 
 	switch (bpp) {
@@ -705,6 +743,35 @@
 		bpp_reg = 1 << 1;
 		break;
 	}
+
+	if (stream_src == IDEAL_RAW) {
+		/*use io_format(v4l2_pix_fmt) to get pack format*/
+		pack_fmt = msm_isp_get_pack_format(io_format);
+		switch (pack_fmt) {
+		case QCOM:
+			pack_reg = 0x0;
+			break;
+		case MIPI:
+			pack_reg = 0x1;
+			break;
+		case DPCM6:
+			pack_reg = 0x2;
+			break;
+		case DPCM8:
+			pack_reg = 0x3;
+			break;
+		case PLAIN8:
+			pack_reg = 0x4;
+			break;
+		case PLAIN16:
+			pack_reg = 0x5;
+			break;
+		default:
+			pr_err("%s: invalid pack fmt!\n", __func__);
+			return;
+		}
+	}
+
 	io_format_reg = msm_camera_io_r(vfe_dev->vfe_base + 0x54);
 	switch (stream_src) {
 	case PIX_ENCODER:
@@ -715,7 +782,7 @@
 		break;
 	case IDEAL_RAW:
 		io_format_reg &= 0xFFFFFFC8;
-		io_format_reg |= bpp_reg << 4;
+		io_format_reg |= bpp_reg << 4 | pack_reg;
 		break;
 	case RDI_INTF_0:
 	case RDI_INTF_1:
@@ -1262,6 +1329,14 @@
 		goto vfe_no_resource;
 	}
 
+	vfe_dev->tcsr_mem = platform_get_resource_byname(vfe_dev->pdev,
+		IORESOURCE_MEM, "tcsr");
+	if (!vfe_dev->tcsr_mem) {
+		pr_err("%s: no mem resource?\n", __func__);
+		rc = -ENODEV;
+		goto vfe_no_resource;
+	}
+
 	vfe_dev->vfe_irq = platform_get_resource_byname(vfe_dev->pdev,
 		IORESOURCE_IRQ, "vfe");
 	if (!vfe_dev->vfe_irq) {
@@ -1300,7 +1375,7 @@
 
 static struct msm_vfe_axi_hardware_info msm_vfe40_axi_hw_info = {
 	.num_wm = 5,
-	.num_comp_mask = 3,
+	.num_comp_mask = 2,
 	.num_rdi = 3,
 	.num_rdi_master = 3,
 	.min_wm_ub = 64,
diff --git a/drivers/media/platform/msm/camera_v2/isp/msm_isp_axi_util.c b/drivers/media/platform/msm/camera_v2/isp/msm_isp_axi_util.c
index 5b7658d..f547b0e 100644
--- a/drivers/media/platform/msm/camera_v2/isp/msm_isp_axi_util.c
+++ b/drivers/media/platform/msm/camera_v2/isp/msm_isp_axi_util.c
@@ -300,7 +300,16 @@
 	struct msm_vfe_axi_stream *stream_info;
 	enum msm_vfe_axi_state valid_state =
 		(stream_cfg_cmd->cmd == START_STREAM) ? INACTIVE : ACTIVE;
+
+	if (stream_cfg_cmd->num_streams > MAX_NUM_STREAM) {
+		return -EINVAL;
+	}
+
 	for (i = 0; i < stream_cfg_cmd->num_streams; i++) {
+		if (HANDLE_TO_IDX(stream_cfg_cmd->stream_handle[i])
+		> MAX_NUM_STREAM) {
+			return -EINVAL;
+		}
 		stream_info = &axi_data->stream_info[
 			HANDLE_TO_IDX(stream_cfg_cmd->stream_handle[i])];
 		spin_lock_irqsave(&stream_info->lock, flags);
@@ -407,6 +416,7 @@
 		break;
 	}
 
+	sof_event.input_intf = frame_src;
 	sof_event.frame_id = vfe_dev->axi_data.src_info[frame_src].frame_id;
 	sof_event.timestamp = ts->event_time;
 	sof_event.mono_timestamp = ts->buf_time;
@@ -594,9 +604,18 @@
 			stream_info->state == RESUME_PENDING)
 			vfe_dev->hw_info->vfe_ops.axi_ops.
 				enable_wm(vfe_dev, stream_info->wm[i], 1);
-		else
+		else {
 			vfe_dev->hw_info->vfe_ops.axi_ops.
 				enable_wm(vfe_dev, stream_info->wm[i], 0);
+			/* Issue a reg update for Raw Snapshot Case
+			 * since we dont have reg update ack
+			*/
+			if (stream_info->stream_src == CAMIF_RAW ||
+				stream_info->stream_src == IDEAL_RAW) {
+				vfe_dev->hw_info->vfe_ops.core_ops.
+				reg_update(vfe_dev);
+			}
+		}
 	}
 
 	if (stream_info->state == START_PENDING)
@@ -778,6 +797,8 @@
 			 * other ISP hardware is still processing the frame.
 			 */
 			if (rc == 0) {
+				buf_event.input_intf =
+					SRC_TO_INTF(stream_info->stream_src);
 				buf_event.frame_id = frame_id;
 				buf_event.timestamp = ts->buf_time;
 				buf_event.u.buf_done.session_id =
@@ -840,7 +861,16 @@
 	int i;
 	struct msm_vfe_axi_stream *stream_info;
 	struct msm_vfe_axi_shared_data *axi_data = &vfe_dev->axi_data;
+
+	if (stream_cfg_cmd->num_streams > MAX_NUM_STREAM) {
+		return;
+	}
+
 	for (i = 0; i < stream_cfg_cmd->num_streams; i++) {
+		if (HANDLE_TO_IDX(stream_cfg_cmd->stream_handle[i])
+		> MAX_NUM_STREAM) {
+			return;
+		}
 		stream_info =
 			&axi_data->stream_info[
 			HANDLE_TO_IDX(stream_cfg_cmd->stream_handle[i])];
@@ -1020,7 +1050,16 @@
 	uint32_t wm_reload_mask = 0x0;
 	struct msm_vfe_axi_stream *stream_info;
 	struct msm_vfe_axi_shared_data *axi_data = &vfe_dev->axi_data;
+
+	if (stream_cfg_cmd->num_streams > MAX_NUM_STREAM) {
+		return -EINVAL;
+	}
+
 	for (i = 0; i < stream_cfg_cmd->num_streams; i++) {
+		if (HANDLE_TO_IDX(stream_cfg_cmd->stream_handle[i])
+		> MAX_NUM_STREAM) {
+			return -EINVAL;
+		}
 		stream_info = &axi_data->stream_info[
 			HANDLE_TO_IDX(stream_cfg_cmd->stream_handle[i])];
 		src_state = axi_data->src_info[
@@ -1073,16 +1112,31 @@
 	uint8_t wait_for_complete = 0;
 	struct msm_vfe_axi_stream *stream_info;
 	struct msm_vfe_axi_shared_data *axi_data = &vfe_dev->axi_data;
+
+	if (stream_cfg_cmd->num_streams > MAX_NUM_STREAM) {
+		return -EINVAL;
+	}
+
 	for (i = 0; i < stream_cfg_cmd->num_streams; i++) {
+		if (HANDLE_TO_IDX(stream_cfg_cmd->stream_handle[i])
+		> MAX_NUM_STREAM) {
+			return -EINVAL;
+		}
 		stream_info = &axi_data->stream_info[
 			HANDLE_TO_IDX(stream_cfg_cmd->stream_handle[i])];
 
 		stream_info->state = STOP_PENDING;
-		if (stream_info->stream_type == BURST_STREAM &&
-			stream_info->runtime_num_burst_capture == 0) {
-			/*Configure AXI writemasters to stop immediately
-			 *since for burst case, write masters already skip
-			 *all frames.
+		if (stream_info->stream_src == CAMIF_RAW ||
+			stream_info->stream_src == IDEAL_RAW) {
+			/* We dont get reg update IRQ for raw snapshot
+			 * so frame skip cant be ocnfigured
+			*/
+			wait_for_complete = 1;
+		} else if (stream_info->stream_type == BURST_STREAM &&
+				stream_info->runtime_num_burst_capture == 0) {
+			/* Configure AXI writemasters to stop immediately
+			 * since for burst case, write masters already skip
+			 * all frames.
 			 */
 			msm_isp_axi_stream_enable_cfg(vfe_dev, stream_info);
 			stream_info->state = INACTIVE;
@@ -1090,7 +1144,6 @@
 			wait_for_complete = 1;
 		}
 	}
-
 	if (wait_for_complete) {
 		rc = msm_isp_axi_wait_for_cfg_done(vfe_dev, camif_update);
 		if (rc < 0) {
@@ -1158,8 +1211,18 @@
 		return -EBUSY;
 	}
 
+	/*num_stream is uint32 and update_info[] bound by MAX_NUM_STREAM*/
+	if (update_cmd->num_streams > MAX_NUM_STREAM) {
+		return -EINVAL;
+	}
+
 	for (i = 0; i < update_cmd->num_streams; i++) {
 		update_info = &update_cmd->update_info[i];
+		/*check array reference bounds*/
+		if (HANDLE_TO_IDX(update_info->stream_handle)
+		 > MAX_NUM_STREAM) {
+			return -EINVAL;
+		}
 		stream_info = &axi_data->stream_info[
 				HANDLE_TO_IDX(update_info->stream_handle)];
 		if (stream_info->state != ACTIVE &&
diff --git a/drivers/media/platform/msm/camera_v2/isp/msm_isp_stats_util.c b/drivers/media/platform/msm/camera_v2/isp/msm_isp_stats_util.c
index 33f63b3..b479857 100644
--- a/drivers/media/platform/msm/camera_v2/isp/msm_isp_stats_util.c
+++ b/drivers/media/platform/msm/camera_v2/isp/msm_isp_stats_util.c
@@ -23,8 +23,16 @@
 	struct msm_isp_buffer *buf;
 	uint32_t pingpong_bit = 0;
 	uint32_t bufq_handle = stream_info->bufq_handle;
-	uint32_t stats_pingpong_offset =
-		STATS_IDX(stream_info->stream_handle) +
+	uint32_t stats_pingpong_offset;
+
+	if (STATS_IDX(stream_info->stream_handle) >=
+			vfe_dev->hw_info->stats_hw_info->num_stats_type) {
+		pr_err("%s Invalid stats index %d", __func__,
+				STATS_IDX(stream_info->stream_handle));
+		return -EINVAL;
+	}
+
+	stats_pingpong_offset = STATS_IDX(stream_info->stream_handle) +
 		vfe_dev->hw_info->stats_hw_info->stats_ping_pong_offset;
 
 	pingpong_bit = (~(pingpong_status >> stats_pingpong_offset) & 0x1);
@@ -89,6 +97,7 @@
 	buf_event.timestamp = ts->event_time;
 	buf_event.frame_id =
 		vfe_dev->axi_data.src_info[VFE_PIX_0].frame_id;
+	buf_event.input_intf = VFE_PIX_0;
 	pingpong_status = vfe_dev->hw_info->
 		vfe_ops.stats_ops.get_pingpong_status(vfe_dev);
 
@@ -150,10 +159,9 @@
 	stats_idx = vfe_dev->hw_info->vfe_ops.stats_ops.
 		get_stats_idx(stream_req_cmd->stats_type);
 
-	if ((stats_idx > MSM_ISP_STATS_MAX) ||
-		(stats_idx == -EINVAL)) {
-		pr_err("%s: Stats idx Error\n", __func__);
-		return rc;
+	if (stats_idx >= vfe_dev->hw_info->stats_hw_info->num_stats_type) {
+		pr_err("%s Invalid stats index %d", __func__, stats_idx);
+		return -EINVAL;
 	}
 
 	stream_info = &stats_data->stream_info[stats_idx];
@@ -208,9 +216,10 @@
 	}
 
 	stats_idx = STATS_IDX(stream_req_cmd->stream_handle);
-	if (stats_idx > MSM_ISP_STATS_MAX) {
-		pr_err("%s: Stats idx Error\n", __func__);
-		return rc;
+
+	if (stats_idx >= vfe_dev->hw_info->stats_hw_info->num_stats_type) {
+		pr_err("%s Invalid stats index %d", __func__, stats_idx);
+		return -EINVAL;
 	}
 
 	stream_info = &stats_data->stream_info[stats_idx];
@@ -241,9 +250,9 @@
 	int stats_idx = STATS_IDX(stream_release_cmd->stream_handle);
 	struct msm_vfe_stats_stream *stream_info = NULL;
 
-	if (stats_idx > MSM_ISP_STATS_MAX) {
-		pr_err("%s: Stats idx Error\n", __func__);
-		return rc;
+	if (stats_idx >= vfe_dev->hw_info->stats_hw_info->num_stats_type) {
+		pr_err("%s Invalid stats index %d", __func__, stats_idx);
+		return -EINVAL;
 	}
 
 	stream_info = &stats_data->stream_info[stats_idx];
@@ -378,6 +387,12 @@
 	struct msm_vfe_stats_shared_data *stats_data = &vfe_dev->stats_data;
 	for (i = 0; i < stream_cfg_cmd->num_streams; i++) {
 		idx = STATS_IDX(stream_cfg_cmd->stream_handle[i]);
+
+		if (idx >= vfe_dev->hw_info->stats_hw_info->num_stats_type) {
+			pr_err("%s Invalid stats index %d", __func__, idx);
+			return -EINVAL;
+		}
+
 		stream_info = &stats_data->stream_info[idx];
 		if (stream_info->stream_handle !=
 				stream_cfg_cmd->stream_handle[i]) {
@@ -422,6 +437,12 @@
 	struct msm_vfe_stats_shared_data *stats_data = &vfe_dev->stats_data;
 	for (i = 0; i < stream_cfg_cmd->num_streams; i++) {
 		idx = STATS_IDX(stream_cfg_cmd->stream_handle[i]);
+
+		if (idx >= vfe_dev->hw_info->stats_hw_info->num_stats_type) {
+			pr_err("%s Invalid stats index %d", __func__, idx);
+			return -EINVAL;
+		}
+
 		stream_info = &stats_data->stream_info[idx];
 		if (stream_info->stream_handle !=
 				stream_cfg_cmd->stream_handle[i]) {
@@ -452,6 +473,12 @@
 
 	for (i = 0; i < stream_cfg_cmd->num_streams; i++) {
 		idx = STATS_IDX(stream_cfg_cmd->stream_handle[i]);
+
+		if (idx >= vfe_dev->hw_info->stats_hw_info->num_stats_type) {
+			pr_err("%s Invalid stats index %d", __func__, idx);
+			return -EINVAL;
+		}
+
 		stream_info = &stats_data->stream_info[idx];
 		msm_isp_deinit_stats_ping_pong_reg(vfe_dev, stream_info);
 	}
diff --git a/drivers/media/platform/msm/camera_v2/isp/msm_isp_util.c b/drivers/media/platform/msm/camera_v2/isp/msm_isp_util.c
index 590b636..b024569 100644
--- a/drivers/media/platform/msm/camera_v2/isp/msm_isp_util.c
+++ b/drivers/media/platform/msm/camera_v2/isp/msm_isp_util.c
@@ -27,6 +27,8 @@
 #define MSM_ISP_MIN_AB 300000000
 #define MSM_ISP_MIN_IB 450000000
 
+#define VFE40_8974V2_VERSION 0x1001001A
+
 static struct msm_bus_vectors msm_isp_init_vectors[] = {
 	{
 		.src = MSM_BUS_MASTER_VFE,
@@ -369,7 +371,7 @@
 		break;
 	case VIDIOC_MSM_ISP_SET_SRC_STATE:
 		mutex_lock(&vfe_dev->core_mutex);
-		msm_isp_set_src_state(vfe_dev, arg);
+		rc = msm_isp_set_src_state(vfe_dev, arg);
 		mutex_unlock(&vfe_dev->core_mutex);
 		break;
 	case VIDIOC_MSM_ISP_REQUEST_STATS_STREAM:
@@ -413,7 +415,7 @@
 		if (resource_size(vfe_dev->vfe_mem) <
 			(reg_cfg_cmd->u.rw_info.reg_offset +
 			reg_cfg_cmd->u.rw_info.len)) {
-			pr_err("%s: Invalid length\n", __func__);
+			pr_err("%s: VFE_WRITE: Invalid length\n", __func__);
 			return -EINVAL;
 		}
 		msm_camera_io_memcpy(vfe_dev->vfe_base +
@@ -425,16 +427,37 @@
 	case VFE_WRITE_MB: {
 		uint32_t *data_ptr = cfg_data +
 			reg_cfg_cmd->u.rw_info.cmd_data_offset/4;
+
+		if ((UINT_MAX - sizeof(*data_ptr) <
+					reg_cfg_cmd->u.rw_info.reg_offset) ||
+			(resource_size(vfe_dev->vfe_mem) <
+			reg_cfg_cmd->u.rw_info.reg_offset +
+			sizeof(*data_ptr))) {
+			pr_err("%s: VFE_WRITE_MB: Invalid length\n", __func__);
+			return -EINVAL;
+		}
 		msm_camera_io_w_mb(*data_ptr, vfe_dev->vfe_base +
 			reg_cfg_cmd->u.rw_info.reg_offset);
 		break;
 	}
 	case VFE_CFG_MASK: {
 		uint32_t temp;
+		if (resource_size(vfe_dev->vfe_mem) <
+				reg_cfg_cmd->u.mask_info.reg_offset)
+			return -EINVAL;
 		temp = msm_camera_io_r(vfe_dev->vfe_base +
 			reg_cfg_cmd->u.mask_info.reg_offset);
+
 		temp &= ~reg_cfg_cmd->u.mask_info.mask;
 		temp |= reg_cfg_cmd->u.mask_info.val;
+		if ((UINT_MAX - sizeof(temp) <
+					reg_cfg_cmd->u.mask_info.reg_offset) ||
+			(resource_size(vfe_dev->vfe_mem) <
+			reg_cfg_cmd->u.mask_info.reg_offset +
+			sizeof(temp))) {
+			pr_err("%s: VFE_CFG_MASK: Invalid length\n", __func__);
+			return -EINVAL;
+		}
 		msm_camera_io_w(temp, vfe_dev->vfe_base +
 			reg_cfg_cmd->u.mask_info.reg_offset);
 		break;
@@ -446,8 +469,10 @@
 		uint32_t *hi_tbl_ptr = NULL, *lo_tbl_ptr = NULL;
 		uint32_t hi_val, lo_val, lo_val1;
 		if (reg_cfg_cmd->cmd_type == VFE_WRITE_DMI_64BIT) {
-			if (reg_cfg_cmd->u.dmi_info.hi_tbl_offset +
-				reg_cfg_cmd->u.dmi_info.len > cmd_len) {
+			if ((UINT_MAX - reg_cfg_cmd->u.dmi_info.hi_tbl_offset <
+						reg_cfg_cmd->u.dmi_info.len) ||
+				(reg_cfg_cmd->u.dmi_info.hi_tbl_offset +
+				reg_cfg_cmd->u.dmi_info.len > cmd_len)) {
 				pr_err("Invalid Hi Table out of bounds\n");
 				return -EINVAL;
 			}
@@ -531,12 +556,21 @@
 		uint32_t *data_ptr = cfg_data +
 			reg_cfg_cmd->u.rw_info.cmd_data_offset/4;
 		for (i = 0; i < reg_cfg_cmd->u.rw_info.len/4; i++) {
+			if ((data_ptr < cfg_data) ||
+				(UINT_MAX / sizeof(*data_ptr) <
+				 (data_ptr - cfg_data)) ||
+				(sizeof(*data_ptr) * (data_ptr - cfg_data) >
+				 cmd_len))
+				return -EINVAL;
 			*data_ptr++ = msm_camera_io_r(vfe_dev->vfe_base +
 				reg_cfg_cmd->u.rw_info.reg_offset);
 			reg_cfg_cmd->u.rw_info.reg_offset += 4;
 		}
 		break;
 	}
+	case GET_SOC_HW_VER:
+		*cfg_data = vfe_dev->soc_hw_version;
+		break;
 	}
 	return 0;
 }
@@ -548,6 +582,11 @@
 	struct msm_vfe_reg_cfg_cmd *reg_cfg_cmd;
 	uint32_t *cfg_data;
 
+	if (!proc_cmd->num_cfg) {
+		pr_err("%s: Passed num_cfg as 0\n", __func__);
+		return -EINVAL;
+	}
+
 	reg_cfg_cmd = kzalloc(sizeof(struct msm_vfe_reg_cfg_cmd)*
 		proc_cmd->num_cfg, GFP_KERNEL);
 	if (!reg_cfg_cmd) {
@@ -668,6 +707,42 @@
 	return val;
 }
 
+enum msm_isp_pack_fmt msm_isp_get_pack_format(uint32_t output_format)
+{
+	switch (output_format) {
+	case V4L2_PIX_FMT_SBGGR8:
+	case V4L2_PIX_FMT_SGBRG8:
+	case V4L2_PIX_FMT_SGRBG8:
+	case V4L2_PIX_FMT_SRGGB8:
+	case V4L2_PIX_FMT_SBGGR10:
+	case V4L2_PIX_FMT_SGBRG10:
+	case V4L2_PIX_FMT_SGRBG10:
+	case V4L2_PIX_FMT_SRGGB10:
+	case V4L2_PIX_FMT_SBGGR12:
+	case V4L2_PIX_FMT_SGBRG12:
+	case V4L2_PIX_FMT_SGRBG12:
+	case V4L2_PIX_FMT_SRGGB12:
+		return MIPI;
+	case V4L2_PIX_FMT_QBGGR8:
+	case V4L2_PIX_FMT_QGBRG8:
+	case V4L2_PIX_FMT_QGRBG8:
+	case V4L2_PIX_FMT_QRGGB8:
+	case V4L2_PIX_FMT_QBGGR10:
+	case V4L2_PIX_FMT_QGBRG10:
+	case V4L2_PIX_FMT_QGRBG10:
+	case V4L2_PIX_FMT_QRGGB10:
+	case V4L2_PIX_FMT_QBGGR12:
+	case V4L2_PIX_FMT_QGBRG12:
+	case V4L2_PIX_FMT_QGRBG12:
+	case V4L2_PIX_FMT_QRGGB12:
+		return QCOM;
+	default:
+		pr_err("%s: Invalid output format\n", __func__);
+		break;
+	}
+	return -EINVAL;
+}
+
 int msm_isp_get_bit_per_pixel(uint32_t output_format)
 {
 	switch (output_format) {
@@ -727,6 +802,8 @@
 void msm_isp_process_error_info(struct vfe_device *vfe_dev)
 {
 	int i;
+	uint8_t num_stats_type =
+		vfe_dev->hw_info->stats_hw_info->num_stats_type;
 	struct msm_vfe_error_info *error_info = &vfe_dev->error_info;
 	static DEFINE_RATELIMIT_STATE(rs,
 		DEFAULT_RATELIMIT_INTERVAL, DEFAULT_RATELIMIT_BURST);
@@ -750,7 +827,7 @@
 				error_info->stream_framedrop_count[i] = 0;
 			}
 		}
-		for (i = 0; i < MSM_ISP_STATS_MAX; i++) {
+		for (i = 0; i < num_stats_type; i++) {
 			if (error_info->stats_framedrop_count[i] != 0 &&
 				__ratelimit(&rs_stats)) {
 				pr_err("%s: Stats stream[%d]: dropped %d frames\n",
@@ -859,11 +936,14 @@
 	}
 }
 
-void msm_isp_set_src_state(struct vfe_device *vfe_dev, void *arg)
+int msm_isp_set_src_state(struct vfe_device *vfe_dev, void *arg)
 {
 	struct msm_vfe_axi_src_state *src_state = arg;
+	if (src_state->input_src >= VFE_SRC_MAX)
+		return -EINVAL;
 	vfe_dev->axi_data.src_info[src_state->input_src].active =
 	src_state->src_active;
+	return 0;
 }
 
 int msm_isp_open_node(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh)
@@ -902,6 +982,15 @@
 
 	vfe_dev->buf_mgr->ops->buf_mgr_init(vfe_dev->buf_mgr, "msm_isp", 28);
 
+	switch (vfe_dev->vfe_hw_version) {
+	case VFE40_8974V2_VERSION:
+		vfe_dev->soc_hw_version = msm_camera_io_r(vfe_dev->tcsr_base);
+		break;
+	default:
+		/* SOC HARDWARE VERSION NOT SUPPORTED */
+		vfe_dev->soc_hw_version = 0x00;
+	}
+
 	memset(&vfe_dev->axi_data, 0, sizeof(struct msm_vfe_axi_shared_data));
 	memset(&vfe_dev->stats_data, 0,
 		sizeof(struct msm_vfe_stats_shared_data));
diff --git a/drivers/media/platform/msm/camera_v2/isp/msm_isp_util.h b/drivers/media/platform/msm/camera_v2/isp/msm_isp_util.h
index 34b9859..3364306 100644
--- a/drivers/media/platform/msm/camera_v2/isp/msm_isp_util.h
+++ b/drivers/media/platform/msm/camera_v2/isp/msm_isp_util.h
@@ -63,8 +63,9 @@
 int msm_isp_cal_word_per_line(uint32_t output_format,
 	uint32_t pixel_per_line);
 int msm_isp_get_bit_per_pixel(uint32_t output_format);
+enum msm_isp_pack_fmt msm_isp_get_pack_format(uint32_t output_format);
 irqreturn_t msm_isp_process_irq(int irq_num, void *data);
-void msm_isp_set_src_state(struct vfe_device *vfe_dev, void *arg);
+int msm_isp_set_src_state(struct vfe_device *vfe_dev, void *arg);
 void msm_isp_do_tasklet(unsigned long data);
 void msm_isp_update_error_frame_count(struct vfe_device *vfe_dev);
 void msm_isp_process_error_info(struct vfe_device *vfe_dev);
diff --git a/drivers/media/platform/msm/camera_v2/ispif/msm_ispif.c b/drivers/media/platform/msm/camera_v2/ispif/msm_ispif.c
index 2f6e6a7..2b963a4 100644
--- a/drivers/media/platform/msm/camera_v2/ispif/msm_ispif.c
+++ b/drivers/media/platform/msm/camera_v2/ispif/msm_ispif.c
@@ -40,7 +40,7 @@
 #define ISPIF_INTF_CMD_DISABLE_IMMEDIATELY    0x02
 
 #define ISPIF_TIMEOUT_SLEEP_US                1000
-#define ISPIF_TIMEOUT_ALL_US                500000
+#define ISPIF_TIMEOUT_ALL_US               1000000
 
 #undef CDBG
 #ifdef CONFIG_MSMB_CAMERA_DEBUG
@@ -86,11 +86,6 @@
 	long timeout = 0;
 	struct clk *reset_clk[ARRAY_SIZE(ispif_8974_reset_clk_info)];
 
-	if (ispif->csid_version < CSID_VERSION_V30) {
-		/* currently reset is done only for 8974 */
-		return 0;
-	}
-
 	rc = msm_cam_clk_enable(&ispif->pdev->dev,
 		ispif_8974_reset_clk_info, reset_clk,
 		ARRAY_SIZE(ispif_8974_reset_clk_info), 1);
@@ -457,6 +452,12 @@
 		rc = -EPERM;
 		return rc;
 	}
+	if (params->num > MAX_PARAM_ENTRIES) {
+		pr_err("%s: invalid param entries %d\n", __func__,
+			params->num);
+		rc = -EINVAL;
+		return rc;
+	}
 
 	for (i = 0; i < params->num; i++) {
 		vfe_intf = params->entries[i].vfe_intf;
@@ -557,6 +558,11 @@
 			pr_err("%s: invalid interface type\n", __func__);
 			return;
 		}
+		if (params->entries[i].num_cids > MAX_CID_CH) {
+			pr_err("%s: out of range of cid_num %d\n",
+				__func__, params->entries[i].num_cids);
+			return;
+		}
 	}
 
 	for (i = 0; i < params->num; i++) {
@@ -612,6 +618,12 @@
 		return rc;
 	}
 
+	if (params->num > MAX_PARAM_ENTRIES) {
+		pr_err("%s: invalid param entries %d\n", __func__,
+			params->num);
+		rc = -EINVAL;
+		return rc;
+	}
 	msm_ispif_intf_cmd(ispif, ISPIF_INTF_CMD_DISABLE_IMMEDIATELY, params);
 
 	/* after stop the interface we need to unmask the CID enable bits */
@@ -636,6 +648,12 @@
 		rc = -EPERM;
 		return rc;
 	}
+	if (params->num > MAX_PARAM_ENTRIES) {
+		pr_err("%s: invalid param entries %d\n", __func__,
+			params->num);
+		rc = -EINVAL;
+		return rc;
+	}
 
 	msm_ispif_intf_cmd(ispif, ISPIF_INTF_CMD_ENABLE_FRAME_BOUNDARY, params);
 
@@ -662,6 +680,13 @@
 		return rc;
 	}
 
+	if (params->num > MAX_PARAM_ENTRIES) {
+		pr_err("%s: invalid param entries %d\n", __func__,
+			params->num);
+		rc = -EINVAL;
+		return rc;
+	}
+
 	for (i = 0; i < params->num; i++) {
 		if (!msm_ispif_is_intf_valid(ispif->csid_version,
 				params->entries[i].vfe_intf)) {
@@ -802,7 +827,7 @@
 
 		ispif_process_irq(ispif, out, VFE0);
 	}
-	if (ispif->vfe_info.num_vfe > 1) {
+	if (ispif->hw_num_isps > 1) {
 		if (out[VFE1].ispifIrqStatus0 & RESET_DONE_IRQ)
 			complete(&ispif->reset_complete[VFE1]);
 
@@ -896,7 +921,13 @@
 		pr_err("%s: ahb_clk enable failed", __func__);
 		goto error_ahb;
 	}
-	msm_ispif_reset_hw(ispif);
+
+	if (of_device_is_compatible(ispif->pdev->dev.of_node,
+				    "qcom,ispif-v3.0")) {
+		/* currently HW reset is implemented for 8974 only */
+		msm_ispif_reset_hw(ispif);
+	}
+
 	rc = msm_ispif_reset(ispif);
 	if (rc == 0) {
 		ispif->ispif_state = ISPIF_POWER_UP;
diff --git a/drivers/media/platform/msm/camera_v2/jpeg_10/msm_jpeg_hw.c b/drivers/media/platform/msm/camera_v2/jpeg_10/msm_jpeg_hw.c
index c38771b..0a0fa04 100644
--- a/drivers/media/platform/msm/camera_v2/jpeg_10/msm_jpeg_hw.c
+++ b/drivers/media/platform/msm/camera_v2/jpeg_10/msm_jpeg_hw.c
@@ -325,7 +325,7 @@
 	}
 }
 
-int msm_jpeg_hw_exec_cmds(struct msm_jpeg_hw_cmd *hw_cmd_p, int m_cmds,
+int msm_jpeg_hw_exec_cmds(struct msm_jpeg_hw_cmd *hw_cmd_p, uint32_t m_cmds,
 	uint32_t max_size, void *base)
 {
 	int is_copy_to_user = -1;
diff --git a/drivers/media/platform/msm/camera_v2/jpeg_10/msm_jpeg_hw.h b/drivers/media/platform/msm/camera_v2/jpeg_10/msm_jpeg_hw.h
index 084e36b..4ff4292 100644
--- a/drivers/media/platform/msm/camera_v2/jpeg_10/msm_jpeg_hw.h
+++ b/drivers/media/platform/msm/camera_v2/jpeg_10/msm_jpeg_hw.h
@@ -96,7 +96,7 @@
 void msm_jpeg_hw_write(struct msm_jpeg_hw_cmd *, void *);
 int msm_jpeg_hw_wait(struct msm_jpeg_hw_cmd *, int, void *);
 void msm_jpeg_hw_delay(struct msm_jpeg_hw_cmd *, int);
-int msm_jpeg_hw_exec_cmds(struct msm_jpeg_hw_cmd *, int ,
+int msm_jpeg_hw_exec_cmds(struct msm_jpeg_hw_cmd *, uint32_t ,
 	uint32_t , void *);
 void msm_jpeg_hw_region_dump(int size);
 void msm_jpeg_io_dump(void *base, int size);
diff --git a/drivers/media/platform/msm/camera_v2/jpeg_10/msm_jpeg_sync.c b/drivers/media/platform/msm/camera_v2/jpeg_10/msm_jpeg_sync.c
index aa6f034..80ff9e5 100644
--- a/drivers/media/platform/msm/camera_v2/jpeg_10/msm_jpeg_sync.c
+++ b/drivers/media/platform/msm/camera_v2/jpeg_10/msm_jpeg_sync.c
@@ -25,6 +25,7 @@
 #define JPEG_REG_SIZE 0x308
 #define JPEG_DEV_CNT 3
 #define JPEG_DEC_ID 2
+#define UINT32_MAX (0xFFFFFFFFU)
 
 inline void msm_jpeg_q_init(char const *name, struct msm_jpeg_q *q_p)
 {
@@ -221,6 +222,7 @@
 		return -EAGAIN;
 	}
 
+	memset(&ctrl_cmd, 0, sizeof(ctrl_cmd));
 	ctrl_cmd.type = buf_p->vbuf.type;
 	kfree(buf_p);
 
@@ -501,7 +503,8 @@
 		(int) buf_cmd.vaddr, buf_cmd.y_len);
 
 	buf_p->y_buffer_addr    = msm_jpeg_platform_v2p(pgmn_dev, buf_cmd.fd,
-		buf_cmd.y_len + buf_cmd.cbcr_len + buf_cmd.pln2_len,
+		buf_cmd.y_len + buf_cmd.cbcr_len +
+		buf_cmd.pln2_len + buf_cmd.offset,
 		&buf_p->file, &buf_p->handle, pgmn_dev->domain_num) +
 		buf_cmd.offset + buf_cmd.y_off;
 	buf_p->y_len          = buf_cmd.y_len;
@@ -675,7 +678,7 @@
 	void * __user arg)
 {
 	int is_copy_to_user;
-	int len;
+	uint32_t len;
 	uint32_t m;
 	struct msm_jpeg_hw_cmds *hw_cmds_p;
 	struct msm_jpeg_hw_cmd *hw_cmd_p;
@@ -685,6 +688,12 @@
 		return -EFAULT;
 	}
 
+	if ((m == 0) || (m > ((UINT32_MAX - sizeof(struct msm_jpeg_hw_cmds)) /
+		sizeof(struct msm_jpeg_hw_cmd)))) {
+		JPEG_PR_ERR("%s:%d] m_cmds out of range\n", __func__, __LINE__);
+		return -EFAULT;
+	}
+
 	len = sizeof(struct msm_jpeg_hw_cmds) +
 		sizeof(struct msm_jpeg_hw_cmd) * (m - 1);
 	hw_cmds_p = kmalloc(len, GFP_KERNEL);
diff --git a/drivers/media/platform/msm/camera_v2/msm.c b/drivers/media/platform/msm/camera_v2/msm.c
index 07f3b40..1fd1065 100644
--- a/drivers/media/platform/msm/camera_v2/msm.c
+++ b/drivers/media/platform/msm/camera_v2/msm.c
@@ -402,12 +402,15 @@
 		list, __msm_queue_find_session, &session_id);
 	if (!session)
 		return;
+	mutex_lock(&session->lock);
 
 	cmd_ack = msm_queue_find(&session->command_ack_q,
 		struct msm_command_ack,	list, __msm_queue_find_command_ack_q,
 		&stream_id);
-	if (!cmd_ack)
+	if (!cmd_ack) {
+		mutex_unlock(&session->lock);
 		return;
+	}
 
 	msm_queue_drain(&cmd_ack->command_q, struct msm_command, list);
 
@@ -416,6 +419,7 @@
 	kzfree(cmd_ack);
 	session->command_ack_q.len--;
 	spin_unlock_irqrestore(&(session->command_ack_q.lock), flags);
+	mutex_unlock(&session->lock);
 }
 
 static inline int __msm_sd_close_subdevs(struct msm_sd_subdev *msm_sd,
@@ -468,6 +472,7 @@
 	if ((!session) || !(&session->command_ack_q))
 		return;
 
+	mutex_lock(&session->lock);
 	/* to ensure error handling purpose, it needs to detach all subdevs
 	 * which are being connected to streams */
 	msm_queue_traverse_action(&session->command_ack_q,
@@ -475,6 +480,8 @@
 		__msm_remove_session_cmd_ack_q, NULL);
 
 	msm_queue_drain(&session->command_ack_q, struct msm_command_ack, list);
+
+	mutex_unlock(&session->lock);
 }
 
 int msm_destroy_session(unsigned int session_id)
diff --git a/drivers/media/platform/msm/camera_v2/pproc/cpp/msm_cpp.c b/drivers/media/platform/msm/camera_v2/pproc/cpp/msm_cpp.c
index 822c0c8..c1f48f5 100644
--- a/drivers/media/platform/msm/camera_v2/pproc/cpp/msm_cpp.c
+++ b/drivers/media/platform/msm/camera_v2/pproc/cpp/msm_cpp.c
@@ -700,7 +700,7 @@
 	msm_cpp_create_buff_queue(cpp_dev, MSM_CPP_MAX_BUFF_QUEUE);
 	if (cpp_dev->is_firmware_loaded == 1) {
 		disable_irq(cpp_dev->irq->start);
-		cpp_load_fw(cpp_dev, NULL);
+		cpp_load_fw(cpp_dev, cpp_dev->fw_name_bin);
 		enable_irq(cpp_dev->irq->start);
 		msm_camera_io_w_mb(0x7C8, cpp_dev->base +
 			MSM_CPP_MICRO_IRQGEN_MASK);
@@ -790,6 +790,7 @@
 		}
 		if (fw)
 			release_firmware(fw);
+		msm_camera_io_w_mb(0x00, cpp_dev->cpp_hw_base + 0xC);
 		msm_cpp_poll(cpp_dev->base, MSM_CPP_MSG_ID_OK);
 		msm_cpp_poll(cpp_dev->base, MSM_CPP_MSG_ID_CMD);
 	}
@@ -856,6 +857,7 @@
 	cpp_dev->cpp_open_cnt++;
 	if (cpp_dev->cpp_open_cnt == 1) {
 		cpp_init_hardware(cpp_dev);
+		iommu_attach_device(cpp_dev->domain, cpp_dev->iommu_ctx);
 		cpp_init_mem(cpp_dev);
 		cpp_dev->state = CPP_STATE_IDLE;
 	}
@@ -922,6 +924,7 @@
 			msm_camera_io_r(cpp_dev->cpp_hw_base + 0x8C));
 		msm_camera_io_w(0x0, cpp_dev->base + MSM_CPP_MICRO_CLKEN_CTL);
 		cpp_deinit_mem(cpp_dev);
+		iommu_detach_device(cpp_dev->domain, cpp_dev->iommu_ctx);
 		cpp_release_hardware(cpp_dev);
 		cpp_dev->state = CPP_STATE_OFF;
 	}
@@ -1318,7 +1321,8 @@
 
 	fw_version_1_2_x = 0;
 	if ((cpp_dev->hw_info.cpp_hw_version == CPP_HW_VERSION_1_1_0) ||
-		(cpp_dev->hw_info.cpp_hw_version == CPP_HW_VERSION_1_1_1))
+		(cpp_dev->hw_info.cpp_hw_version == CPP_HW_VERSION_1_1_1) ||
+		(cpp_dev->hw_info.cpp_hw_version == CPP_HW_VERSION_2_0_0))
 		fw_version_1_2_x = 2;
 
 	for (i = 0; i < num_stripes; i++) {
@@ -1536,6 +1540,10 @@
 		uint32_t identity;
 		struct msm_cpp_buff_queue_info_t *buff_queue_info;
 
+		if ((ioctl_ptr->len == 0) ||
+		    (ioctl_ptr->len > sizeof(uint32_t)))
+			return -EINVAL;
+
 		rc = (copy_from_user(&identity,
 				(void __user *)ioctl_ptr->ioctl_ptr,
 				ioctl_ptr->len) ? -EFAULT : 0);
@@ -1712,6 +1720,7 @@
 	return msm_register_domain(&cpp_fw_layout);
 }
 
+
 static int __devinit cpp_probe(struct platform_device *pdev)
 {
 	struct cpp_device *cpp_dev;
@@ -1826,7 +1835,6 @@
 	cpp_dev->msm_sd.sd.entity.revision = cpp_dev->msm_sd.sd.devnode->num;
 	cpp_dev->state = CPP_STATE_BOOT;
 	cpp_init_hardware(cpp_dev);
-	iommu_attach_device(cpp_dev->domain, cpp_dev->iommu_ctx);
 
 	msm_camera_io_w(0x0, cpp_dev->base +
 					   MSM_CPP_MICRO_IRQGEN_MASK);
@@ -1854,7 +1862,6 @@
 	cpp_timers[1].used = 0;
 	cpp_dev->fw_name_bin = NULL;
 	return rc;
-
 ERROR3:
 	release_mem_region(cpp_dev->mem->start, resource_size(cpp_dev->mem));
 ERROR2:
@@ -1884,7 +1891,6 @@
 		return 0;
 	}
 
-	iommu_detach_device(cpp_dev->domain, cpp_dev->iommu_ctx);
 	msm_sd_unregister(&cpp_dev->msm_sd);
 	release_mem_region(cpp_dev->mem->start, resource_size(cpp_dev->mem));
 	release_mem_region(cpp_dev->vbif_mem->start,
diff --git a/drivers/media/platform/msm/camera_v2/pproc/cpp/msm_cpp.h b/drivers/media/platform/msm/camera_v2/pproc/cpp/msm_cpp.h
index 796bede..cf22e6c 100644
--- a/drivers/media/platform/msm/camera_v2/pproc/cpp/msm_cpp.h
+++ b/drivers/media/platform/msm/camera_v2/pproc/cpp/msm_cpp.h
@@ -28,6 +28,7 @@
 **/
 #define CPP_HW_VERSION_1_1_0  0x10010000
 #define CPP_HW_VERSION_1_1_1  0x10010001
+#define CPP_HW_VERSION_2_0_0  0x20000000
 
 #define MAX_ACTIVE_CPP_INSTANCE 8
 #define MAX_CPP_PROCESSING_FRAME 2
diff --git a/drivers/media/platform/msm/camera_v2/pproc/vpe/msm_vpe.c b/drivers/media/platform/msm/camera_v2/pproc/vpe/msm_vpe.c
index d302131..3aaff78 100644
--- a/drivers/media/platform/msm/camera_v2/pproc/vpe/msm_vpe.c
+++ b/drivers/media/platform/msm/camera_v2/pproc/vpe/msm_vpe.c
@@ -1323,6 +1323,11 @@
 		struct msm_vpe_buff_queue_info_t *buff_queue_info;
 
 		VPE_DBG("VIDIOC_MSM_VPE_DEQUEUE_STREAM_BUFF_INFO\n");
+		if (ioctl_ptr->len != sizeof(uint32_t)) {
+			pr_err("%s:%d Invalid len\n", __func__, __LINE__);
+			mutex_unlock(&vpe_dev->mutex);
+			return -EINVAL;
+		}
 
 		rc = (copy_from_user(&identity,
 				(void __user *)ioctl_ptr->ioctl_ptr,
diff --git a/drivers/media/platform/msm/camera_v2/sensor/Makefile b/drivers/media/platform/msm/camera_v2/sensor/Makefile
index bd1b10b..bbfbbdf 100644
--- a/drivers/media/platform/msm/camera_v2/sensor/Makefile
+++ b/drivers/media/platform/msm/camera_v2/sensor/Makefile
@@ -17,3 +17,4 @@
 obj-$(CONFIG_MT9M114) += mt9m114.o
 obj-$(CONFIG_SP1628) += sp1628.o
 obj-$(CONFIG_GC0339) += gc0339.o
+obj-$(CONFIG_OV8865) += ov8865.o
diff --git a/drivers/media/platform/msm/camera_v2/sensor/actuator/msm_actuator.c b/drivers/media/platform/msm/camera_v2/sensor/actuator/msm_actuator.c
index c188105..32d74ba 100644
--- a/drivers/media/platform/msm/camera_v2/sensor/actuator/msm_actuator.c
+++ b/drivers/media/platform/msm/camera_v2/sensor/actuator/msm_actuator.c
@@ -816,6 +816,7 @@
 
 	cci_client = msm_actuator_t->i2c_client.cci_client;
 	cci_client->cci_subdev = msm_cci_get_subdev();
+	cci_client->cci_i2c_master = MASTER_MAX;
 	v4l2_subdev_init(&msm_actuator_t->msm_sd.sd,
 		msm_actuator_t->act_v4l2_subdev_ops);
 	v4l2_set_subdevdata(&msm_actuator_t->msm_sd.sd, msm_actuator_t);
diff --git a/drivers/media/platform/msm/camera_v2/sensor/cci/msm_cam_cci_hwreg.h b/drivers/media/platform/msm/camera_v2/sensor/cci/msm_cam_cci_hwreg.h
index 591c464..059633b 100644
--- a/drivers/media/platform/msm/camera_v2/sensor/cci/msm_cam_cci_hwreg.h
+++ b/drivers/media/platform/msm/camera_v2/sensor/cci/msm_cam_cci_hwreg.h
@@ -15,7 +15,7 @@
 
 #define CCI_HW_VERSION_ADDR                                         0x00000000
 #define CCI_RESET_CMD_ADDR                                          0x00000004
-#define CCI_RESET_CMD_RMSK                                          0xcf73f3f7
+#define CCI_RESET_CMD_RMSK                                          0x0f73f3f7
 #define CCI_M0_RESET_RMSK                                                0x3F1
 #define CCI_M1_RESET_RMSK                                              0x3F001
 #define CCI_QUEUE_START_ADDR                                        0x00000008
diff --git a/drivers/media/platform/msm/camera_v2/sensor/cci/msm_cci.c b/drivers/media/platform/msm/camera_v2/sensor/cci/msm_cci.c
index 4fa3085..d11798e 100644
--- a/drivers/media/platform/msm/camera_v2/sensor/cci/msm_cci.c
+++ b/drivers/media/platform/msm/camera_v2/sensor/cci/msm_cci.c
@@ -41,6 +41,9 @@
 
 /* Max bytes that can be read per CCI read transaction */
 #define CCI_READ_MAX 12
+#define CCI_I2C_READ_MAX_RETRIES 3
+#define CCI_I2C_MAX_READ 8192
+#define CCI_I2C_MAX_WRITE 8192
 
 static struct v4l2_subdev *g_cci_subdev;
 
@@ -87,36 +90,6 @@
 	return;
 }
 
-static int32_t msm_cci_i2c_config_sync_timer(struct v4l2_subdev *sd,
-	struct msm_camera_cci_ctrl *c_ctrl)
-{
-	struct cci_device *cci_dev;
-	cci_dev = v4l2_get_subdevdata(sd);
-	msm_camera_io_w(c_ctrl->cci_info->cid, cci_dev->base +
-		CCI_SET_CID_SYNC_TIMER_0_ADDR + (c_ctrl->cci_info->cid * 0x4));
-	return 0;
-}
-
-static int32_t msm_cci_i2c_set_freq(struct v4l2_subdev *sd,
-	struct msm_camera_cci_ctrl *c_ctrl)
-{
-	struct cci_device *cci_dev;
-	uint32_t val;
-	cci_dev = v4l2_get_subdevdata(sd);
-	val = c_ctrl->cci_info->freq;
-	msm_camera_io_w(val, cci_dev->base + CCI_I2C_M0_SCL_CTL_ADDR +
-		c_ctrl->cci_info->cci_i2c_master*0x100);
-	msm_camera_io_w(val, cci_dev->base + CCI_I2C_M0_SDA_CTL_0_ADDR +
-		c_ctrl->cci_info->cci_i2c_master*0x100);
-	msm_camera_io_w(val, cci_dev->base + CCI_I2C_M0_SDA_CTL_1_ADDR +
-		c_ctrl->cci_info->cci_i2c_master*0x100);
-	msm_camera_io_w(val, cci_dev->base + CCI_I2C_M0_SDA_CTL_2_ADDR +
-		c_ctrl->cci_info->cci_i2c_master*0x100);
-	msm_camera_io_w(val, cci_dev->base + CCI_I2C_M0_MISC_CTL_ADDR +
-		c_ctrl->cci_info->cci_i2c_master*0x100);
-	return 0;
-}
-
 static void msm_cci_flush_queue(struct cci_device *cci_dev,
 	enum cci_i2c_master_t master)
 {
@@ -213,8 +186,29 @@
 	uint16_t cmd_size = i2c_msg->size;
 	struct msm_camera_i2c_reg_conf *i2c_cmd = i2c_msg->reg_conf_tbl;
 	enum cci_i2c_master_t master = c_ctrl->cci_info->cci_i2c_master;
+
+	if (i2c_cmd == NULL) {
+		pr_err("%s:%d Failed line\n", __func__,
+			__LINE__);
+		return -EINVAL;
+	}
+
+	if ((!cmd_size) || (cmd_size > CCI_I2C_MAX_WRITE)) {
+		pr_err("%s:%d Failed line\n", __func__, __LINE__);
+		return -EINVAL;
+	}
+
 	CDBG("%s addr type %d data type %d\n", __func__,
 		i2c_msg->addr_type, i2c_msg->data_type);
+
+	if (i2c_msg->addr_type >= MSM_CAMERA_I2C_ADDR_TYPE_MAX) {
+		pr_err("%s failed line %d\n", __func__, __LINE__);
+		return -EINVAL;
+	}
+	if (i2c_msg->data_type >= MSM_CAMERA_I2C_DATA_TYPE_MAX) {
+		pr_err("%s failed line %d\n", __func__, __LINE__);
+		return -EINVAL;
+	}
 	/* assume total size within the max queue */
 	while (cmd_size) {
 		CDBG("%s cmd_size %d addr 0x%x data 0x%x", __func__,
@@ -292,7 +286,7 @@
 static int32_t msm_cci_i2c_read(struct v4l2_subdev *sd,
 	struct msm_camera_cci_ctrl *c_ctrl)
 {
-	uint32_t rc = 0;
+	int32_t rc = 0;
 	uint32_t val = 0;
 	int32_t read_words = 0, exp_words = 0;
 	int32_t index = 0, first_byte = 0;
@@ -321,6 +315,18 @@
 		goto ERROR;
 	}
 
+	if (c_ctrl->cci_info->retries > CCI_I2C_READ_MAX_RETRIES) {
+		pr_err("%s:%d More than max retries\n", __func__,
+			__LINE__);
+		goto ERROR;
+	}
+
+	if (read_cfg->data == NULL) {
+		pr_err("%s:%d Data ptr is NULL\n", __func__,
+			__LINE__);
+		goto ERROR;
+	}
+
 	CDBG("%s master %d, queue %d\n", __func__, master, queue);
 	CDBG("%s set param sid 0x%x retries %d id_map %d\n", __func__,
 		c_ctrl->cci_info->sid, c_ctrl->cci_info->retries,
@@ -341,6 +347,11 @@
 		goto ERROR;
 	}
 
+	if (read_cfg->addr_type >= MSM_CAMERA_I2C_ADDR_TYPE_MAX) {
+		CDBG("%s failed line %d\n", __func__, __LINE__);
+		goto ERROR;
+	}
+
 	if (read_cfg->addr_type == MSM_CAMERA_I2C_BYTE_ADDR)
 		val = CCI_I2C_WRITE_DISABLE_P_CMD | (read_cfg->addr_type << 4) |
 			((read_cfg->addr & 0xFF) << 8);
@@ -454,9 +465,14 @@
 		return -EINVAL;
 	}
 
+	if (c_ctrl->cci_info->cci_i2c_master > MASTER_MAX) {
+		pr_err("%s:%d Invalid I2C master addr\n", __func__, __LINE__);
+		return -EINVAL;
+	}
+
 	master = c_ctrl->cci_info->cci_i2c_master;
 	read_cfg = &c_ctrl->cfg.cci_i2c_read_cfg;
-	if (!read_cfg->num_byte) {
+	if ((!read_cfg->num_byte) || (read_cfg->num_byte > CCI_I2C_MAX_READ)) {
 		pr_err("%s:%d read num bytes 0\n", __func__, __LINE__);
 		rc = -EINVAL;
 		goto ERROR;
@@ -494,6 +510,10 @@
 	enum cci_i2c_master_t master;
 	enum cci_i2c_queue_t queue = QUEUE_0;
 	cci_dev = v4l2_get_subdevdata(sd);
+	if (c_ctrl->cci_info->cci_i2c_master > MASTER_MAX) {
+		pr_err("%s:%d Invalid I2C master addr\n", __func__, __LINE__);
+		return -EINVAL;
+	}
 	master = c_ctrl->cci_info->cci_i2c_master;
 	CDBG("%s master %d, queue %d\n", __func__, master, queue);
 	CDBG("%s set param sid 0x%x retries %d id_map %d\n", __func__,
@@ -514,6 +534,11 @@
 			__LINE__, rc);
 		goto ERROR;
 	}
+	if (c_ctrl->cci_info->retries > CCI_I2C_READ_MAX_RETRIES) {
+		pr_err("%s:%d More than max retries\n", __func__,
+			__LINE__);
+		goto ERROR;
+	}
 
 	val = CCI_I2C_SET_PARAM_CMD | c_ctrl->cci_info->sid << 4 |
 		c_ctrl->cci_info->retries << 16 |
@@ -533,7 +558,11 @@
 		goto ERROR;
 	}
 
-	msm_cci_data_queue(cci_dev, c_ctrl, queue);
+	rc = msm_cci_data_queue(cci_dev, c_ctrl, queue);
+	if (rc < 0) {
+		CDBG("%s failed line %d\n", __func__, __LINE__);
+		goto ERROR;
+	}
 	val = CCI_I2C_UNLOCK_CMD;
 	CDBG("%s:%d CCI_I2C_UNLOCK_CMD\n", __func__, __LINE__);
 	rc = msm_cci_write_i2c_queue(cci_dev, val, master, queue);
@@ -599,21 +628,46 @@
 	{"cci_clk", -1},
 };
 
-static int32_t msm_cci_init(struct v4l2_subdev *sd)
+static int32_t msm_cci_init(struct v4l2_subdev *sd,
+	struct msm_camera_cci_ctrl *c_ctrl)
 {
 	int rc = 0;
 	struct cci_device *cci_dev;
+	enum cci_i2c_master_t master;
 	cci_dev = v4l2_get_subdevdata(sd);
-	CDBG("%s line %d\n", __func__, __LINE__);
 
-	if (!cci_dev) {
-		pr_err("%s cci device NULL\n", __func__);
+	if (!cci_dev || !c_ctrl) {
+		pr_err("%s:%d failed: invalid params %p %p\n", __func__,
+			__LINE__, cci_dev, c_ctrl);
 		rc = -ENOMEM;
 		return rc;
 	}
 
 	if (cci_dev->ref_count++) {
 		CDBG("%s ref_count %d\n", __func__, cci_dev->ref_count);
+		master = c_ctrl->cci_info->cci_i2c_master;
+		CDBG("%s:%d master %d\n", __func__, __LINE__, master);
+		if (master < MASTER_MAX) {
+			mutex_lock(&cci_dev->cci_master_info[master].mutex);
+			/* Set reset pending flag to TRUE */
+			cci_dev->cci_master_info[master].reset_pending = TRUE;
+			/* Set proper mask to RESET CMD address */
+			if (master == MASTER_0)
+				msm_camera_io_w(CCI_M0_RESET_RMSK,
+					cci_dev->base + CCI_RESET_CMD_ADDR);
+			else
+				msm_camera_io_w(CCI_M1_RESET_RMSK,
+					cci_dev->base + CCI_RESET_CMD_ADDR);
+			/* wait for reset done irq */
+			rc = wait_for_completion_interruptible_timeout(
+				&cci_dev->cci_master_info[master].
+				reset_complete,
+				CCI_TIMEOUT);
+			if (rc <= 0)
+				pr_err("%s:%d wait failed %d\n", __func__,
+					__LINE__, rc);
+			mutex_unlock(&cci_dev->cci_master_info[master].mutex);
+		}
 		return 0;
 	}
 
@@ -622,7 +676,7 @@
 	if (rc < 0) {
 		cci_dev->ref_count--;
 		CDBG("%s: request gpio failed\n", __func__);
-		goto clk_enable_failed;
+		goto request_gpio_failed;
 	}
 
 	rc = msm_cam_clk_enable(&cci_dev->pdev->dev, cci_clk_info,
@@ -647,7 +701,7 @@
 			 __func__, __LINE__);
 		if (rc == 0)
 			rc = -ETIMEDOUT;
-		return rc;
+		goto reset_complete_failed;
 	}
 	msm_cci_set_clk_param(cci_dev);
 	msm_camera_io_w(CCI_IRQ_MASK_0_RMSK,
@@ -656,9 +710,18 @@
 		cci_dev->base + CCI_IRQ_CLEAR_0_ADDR);
 	msm_camera_io_w(0x1, cci_dev->base + CCI_IRQ_GLOBAL_CLEAR_CMD_ADDR);
 	cci_dev->cci_state = CCI_STATE_ENABLED;
+
 	return 0;
 
+reset_complete_failed:
+	disable_irq(cci_dev->irq->start);
+	msm_cam_clk_enable(&cci_dev->pdev->dev, cci_clk_info,
+		cci_dev->cci_clk, ARRAY_SIZE(cci_clk_info), 0);
 clk_enable_failed:
+	msm_camera_request_gpio_table(cci_dev->cci_gpio_tbl,
+		cci_dev->cci_gpio_tbl_size, 0);
+request_gpio_failed:
+	cci_dev->ref_count--;
 	return rc;
 }
 
@@ -674,7 +737,7 @@
 	}
 
 	if (--cci_dev->ref_count) {
-		CDBG("%s ref_count %d\n", __func__, cci_dev->ref_count);
+		CDBG("%s ref_count Exit %d\n", __func__, cci_dev->ref_count);
 		return 0;
 	}
 
@@ -687,6 +750,7 @@
 		cci_dev->cci_gpio_tbl_size, 0);
 
 	cci_dev->cci_state = CCI_STATE_DISABLED;
+
 	return 0;
 }
 
@@ -698,19 +762,11 @@
 		cci_ctrl->cmd);
 	switch (cci_ctrl->cmd) {
 	case MSM_CCI_INIT:
-		rc = msm_cci_init(sd);
+		rc = msm_cci_init(sd, cci_ctrl);
 		break;
 	case MSM_CCI_RELEASE:
 		rc = msm_cci_release(sd);
 		break;
-	case MSM_CCI_SET_SID:
-		break;
-	case MSM_CCI_SET_FREQ:
-		rc = msm_cci_i2c_set_freq(sd, cci_ctrl);
-		break;
-	case MSM_CCI_SET_SYNC_CID:
-		rc = msm_cci_i2c_config_sync_timer(sd, cci_ctrl);
-		break;
 	case MSM_CCI_I2C_READ:
 		rc = msm_cci_i2c_read_bytes(sd, cci_ctrl);
 		break;
diff --git a/drivers/media/platform/msm/camera_v2/sensor/csid/msm_csid.c b/drivers/media/platform/msm/camera_v2/sensor/csid/msm_csid.c
index 9aca234..229fdb2 100644
--- a/drivers/media/platform/msm/camera_v2/sensor/csid/msm_csid.c
+++ b/drivers/media/platform/msm/camera_v2/sensor/csid/msm_csid.c
@@ -440,7 +440,7 @@
 	case CSID_CFG: {
 		struct msm_camera_csid_params csid_params;
 		struct msm_camera_csid_vc_cfg *vc_cfg = NULL;
-		int32_t i = 0;
+		int8_t i = 0;
 		if (copy_from_user(&csid_params,
 			(void *)cdata->cfg.csid_params,
 			sizeof(struct msm_camera_csid_params))) {
@@ -448,6 +448,13 @@
 			rc = -EFAULT;
 			break;
 		}
+		if (csid_params.lut_params.num_cid < 1 ||
+			csid_params.lut_params.num_cid > 16) {
+			pr_err("%s: %d num_cid outside range\n",
+				 __func__, __LINE__);
+			rc = -EINVAL;
+			break;
+		}
 		for (i = 0; i < csid_params.lut_params.num_cid; i++) {
 			vc_cfg = kzalloc(csid_params.lut_params.num_cid *
 				sizeof(struct msm_camera_csid_vc_cfg),
diff --git a/drivers/media/platform/msm/camera_v2/sensor/csiphy/msm_csiphy.c b/drivers/media/platform/msm/camera_v2/sensor/csiphy/msm_csiphy.c
index 21b9cdc..9384a5b 100644
--- a/drivers/media/platform/msm/camera_v2/sensor/csiphy/msm_csiphy.c
+++ b/drivers/media/platform/msm/camera_v2/sensor/csiphy/msm_csiphy.c
@@ -124,7 +124,6 @@
 		j++;
 		lane_mask >>= 1;
 	}
-	msleep(20);
 	return rc;
 }
 
@@ -423,7 +422,7 @@
 				__LINE__, csi_lane_params);
 			return -EINVAL;
 		}
-		csi_lane_mask = csi_lane_params->csi_lane_mask;
+		csi_lane_mask = (csi_lane_params->csi_lane_mask & 0x1F);
 
 		CDBG("%s csiphy_params, lane assign %x mask = %x\n",
 			__func__,
@@ -436,7 +435,7 @@
 		csiphy_dev->lane_mask[csiphy_dev->pdev->id] &=
 			~(csi_lane_mask);
 		i = 0;
-		while (csi_lane_mask & 0x1F) {
+		while (csi_lane_mask) {
 			if (csi_lane_mask & 0x1) {
 				msm_camera_io_w(0x0, csiphy_dev->base +
 					MIPI_CSIPHY_LNn_CFG2_ADDR + 0x40*i);
@@ -507,7 +506,7 @@
 				__LINE__, csi_lane_params);
 			return -EINVAL;
 		}
-		csi_lane_mask = csi_lane_params->csi_lane_mask;
+		csi_lane_mask = (csi_lane_params->csi_lane_mask & 0x1F);
 
 		CDBG("%s csiphy_params, lane assign %x mask = %x\n",
 			__func__,
@@ -520,7 +519,7 @@
 		csiphy_dev->lane_mask[csiphy_dev->pdev->id] &=
 			~(csi_lane_mask);
 		i = 0;
-		while (csi_lane_mask & 0x1F) {
+		while (csi_lane_mask) {
 			if (csi_lane_mask & 0x1) {
 				msm_camera_io_w(0x0, csiphy_dev->base +
 					MIPI_CSIPHY_LNn_CFG2_ADDR + 0x40*i);
diff --git a/drivers/media/platform/msm/camera_v2/sensor/eeprom/msm_eeprom.c b/drivers/media/platform/msm/camera_v2/sensor/eeprom/msm_eeprom.c
index 4ebcfdf..7f13568 100644
--- a/drivers/media/platform/msm/camera_v2/sensor/eeprom/msm_eeprom.c
+++ b/drivers/media/platform/msm/camera_v2/sensor/eeprom/msm_eeprom.c
@@ -98,6 +98,7 @@
 	.i2c_read = msm_camera_cci_i2c_read,
 	.i2c_read_seq = msm_camera_cci_i2c_read_seq,
 	.i2c_write = msm_camera_cci_i2c_write,
+	.i2c_write_seq = msm_camera_cci_i2c_write_seq,
 	.i2c_write_table = msm_camera_cci_i2c_write_table,
 	.i2c_write_seq_table = msm_camera_cci_i2c_write_seq_table,
 	.i2c_write_table_w_microdelay =
@@ -180,7 +181,17 @@
 				return rc;
 			}
 		}
-
+		if (emap[j].pageen.valid_size) {
+			e_ctrl->i2c_client.addr_type = emap[j].pageen.addr_t;
+			rc = e_ctrl->i2c_client.i2c_func_tbl->i2c_write(
+				&(e_ctrl->i2c_client), emap[j].pageen.addr,
+				emap[j].pageen.data, emap[j].pageen.data_t);
+				msleep(emap[j].pageen.delay);
+			if (rc < 0) {
+				pr_err("%s: page enable failed\n", __func__);
+				return rc;
+			}
+		}
 		if (emap[j].poll.valid_size) {
 			e_ctrl->i2c_client.addr_type = emap[j].poll.addr_t;
 			rc = e_ctrl->i2c_client.i2c_func_tbl->i2c_poll(
@@ -204,15 +215,107 @@
 			}
 			memptr += emap[j].mem.valid_size;
 		}
+		if (emap[j].pageen.valid_size) {
+			e_ctrl->i2c_client.addr_type = emap[j].pageen.addr_t;
+			rc = e_ctrl->i2c_client.i2c_func_tbl->i2c_write(
+				&(e_ctrl->i2c_client), emap[j].pageen.addr,
+				0, emap[j].pageen.data_t);
+			if (rc < 0) {
+				pr_err("%s: page disable failed\n", __func__);
+				return rc;
+			}
+		}
 	}
 	return rc;
 }
 
+static int msm_eeprom_get_dt_data(struct msm_eeprom_ctrl_t *e_ctrl)
+{
+	int rc = 0, i = 0;
+	struct msm_eeprom_board_info *eb_info;
+	struct msm_camera_power_ctrl_t *power_info =
+		&e_ctrl->eboard_info->power_info;
+	struct device_node *of_node = NULL;
+	struct msm_camera_gpio_conf *gconf = NULL;
+	uint16_t gpio_array_size = 0;
+	uint16_t *gpio_array = NULL;
+
+	eb_info = e_ctrl->eboard_info;
+	if (e_ctrl->eeprom_device_type == MSM_CAMERA_SPI_DEVICE)
+		of_node = e_ctrl->i2c_client.
+			spi_client->spi_master->dev.of_node;
+	else if (e_ctrl->eeprom_device_type == MSM_CAMERA_PLATFORM_DEVICE)
+		of_node = e_ctrl->pdev->dev.of_node;
+	else if (e_ctrl->eeprom_device_type == MSM_CAMERA_I2C_DEVICE)
+		of_node = e_ctrl->i2c_client.client->dev.of_node;
+
+	rc = msm_camera_get_dt_vreg_data(of_node, &power_info->cam_vreg,
+					     &power_info->num_vreg);
+	if (rc < 0)
+		return rc;
+
+	rc = msm_camera_get_dt_power_setting_data(of_node,
+		power_info->cam_vreg, power_info->num_vreg,
+		&power_info->power_setting, &power_info->power_setting_size);
+	if (rc < 0)
+		goto error1;
+
+	power_info->gpio_conf = kzalloc(sizeof(struct msm_camera_gpio_conf),
+					GFP_KERNEL);
+	if (!power_info->gpio_conf) {
+		rc = -ENOMEM;
+		goto error2;
+	}
+	gconf = power_info->gpio_conf;
+	gpio_array_size = of_gpio_count(of_node);
+	CDBG("%s gpio count %d\n", __func__, gpio_array_size);
+
+	if (gpio_array_size) {
+		gpio_array = kzalloc(sizeof(uint16_t) * gpio_array_size,
+			GFP_KERNEL);
+		if (!gpio_array) {
+			pr_err("%s failed %d\n", __func__, __LINE__);
+			goto error3;
+		}
+		for (i = 0; i < gpio_array_size; i++) {
+			gpio_array[i] = of_get_gpio(of_node, i);
+			CDBG("%s gpio_array[%d] = %d\n", __func__, i,
+				gpio_array[i]);
+		}
+
+		rc = msm_camera_get_dt_gpio_req_tbl(of_node, gconf,
+			gpio_array, gpio_array_size);
+		if (rc < 0) {
+			pr_err("%s failed %d\n", __func__, __LINE__);
+			goto error4;
+		}
+
+		rc = msm_camera_init_gpio_pin_tbl(of_node, gconf,
+			gpio_array, gpio_array_size);
+		if (rc < 0) {
+			pr_err("%s failed %d\n", __func__, __LINE__);
+			goto error4;
+		}
+		kfree(gpio_array);
+	}
+
+	return rc;
+error4:
+	kfree(gpio_array);
+error3:
+	kfree(power_info->gpio_conf);
+error2:
+	kfree(power_info->cam_vreg);
+error1:
+	kfree(power_info->power_setting);
+	return rc;
+}
+
 static int msm_eeprom_alloc_memory_map(struct msm_eeprom_ctrl_t *e_ctrl,
 				       struct device_node *of)
 {
 	int i, rc = 0;
-	char property[12];
+	char property[14];
 	uint32_t count = 6;
 	struct msm_eeprom_board_info *eb = e_ctrl->eboard_info;
 
@@ -240,6 +343,12 @@
 			goto out;
 		}
 
+		snprintf(property, 14, "qcom,pageen%d", i);
+		rc = of_property_read_u32_array(of, property,
+			(uint32_t *) &eb->eeprom_map[i].pageen, count);
+		if (rc < 0)
+			pr_err("%s: pageen not needed\n", __func__);
+
 		snprintf(property, 12, "qcom,poll%d", i);
 		rc = of_property_read_u32_array(of, property,
 			(uint32_t *) &eb->eeprom_map[i].poll, count);
@@ -293,10 +402,19 @@
 int32_t msm_eeprom_i2c_probe(struct i2c_client *client,
 	const struct i2c_device_id *id) {
 	int rc = 0;
+	int32_t j = 0;
+	uint32_t temp = 0;
 	struct msm_eeprom_ctrl_t *e_ctrl = NULL;
 	struct msm_camera_power_ctrl_t *power_info = NULL;
+	struct device_node *of_node = client->dev.of_node;
 	CDBG("%s E\n", __func__);
 
+
+	if (!of_node) {
+		pr_err("%s of_node NULL\n", __func__);
+		return -EINVAL;
+	}
+
 	if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) {
 		pr_err("%s i2c_check_functionality failed\n", __func__);
 		goto probe_failure;
@@ -310,13 +428,23 @@
 	e_ctrl->eeprom_v4l2_subdev_ops = &msm_eeprom_subdev_ops;
 	e_ctrl->eeprom_mutex = &msm_eeprom_mutex;
 	CDBG("%s client = %x\n", __func__, (unsigned int)client);
-	e_ctrl->eboard_info = (struct msm_eeprom_board_info *)(id->driver_data);
+	e_ctrl->eboard_info = kzalloc(sizeof(
+		struct msm_eeprom_board_info), GFP_KERNEL);
 	if (!e_ctrl->eboard_info) {
 		pr_err("%s:%d board info NULL\n", __func__, __LINE__);
 		return -EINVAL;
 	}
+
+	rc = of_property_read_u32(of_node, "qcom,slave-addr", &temp);
+	if (rc < 0) {
+		pr_err("%s failed rc %d\n", __func__, rc);
+		return rc;
+	}
+
 	power_info = &e_ctrl->eboard_info->power_info;
+	e_ctrl->eboard_info->i2c_slaveaddr = temp;
 	e_ctrl->i2c_client.client = client;
+	e_ctrl->is_supported = 0;
 
 	/* Set device type as I2C */
 	e_ctrl->eeprom_device_type = MSM_CAMERA_I2C_DEVICE;
@@ -329,6 +457,45 @@
 	power_info->clk_info_size = ARRAY_SIZE(cam_8960_clk_info);
 	power_info->dev = &client->dev;
 
+	rc = of_property_read_string(of_node, "qcom,eeprom-name",
+		&e_ctrl->eboard_info->eeprom_name);
+	CDBG("%s qcom,eeprom-name %s, rc %d\n", __func__,
+		e_ctrl->eboard_info->eeprom_name, rc);
+	if (rc < 0) {
+		pr_err("%s failed %d\n", __func__, __LINE__);
+		goto board_free;
+	}
+
+	rc = msm_eeprom_get_dt_data(e_ctrl);
+	if (rc)
+		goto board_free;
+
+	rc = msm_eeprom_alloc_memory_map(e_ctrl, of_node);
+	if (rc)
+		goto board_free;
+
+	rc = msm_camera_power_up(power_info, e_ctrl->eeprom_device_type,
+		&e_ctrl->i2c_client);
+	if (rc) {
+		pr_err("%s failed power up %d\n", __func__, __LINE__);
+		goto memdata_free;
+	}
+	rc = read_eeprom_memory(e_ctrl);
+	if (rc < 0) {
+		pr_err("%s read_eeprom_memory failed\n", __func__);
+		goto power_down;
+	}
+
+	for (j = 0; j < e_ctrl->num_bytes; j++)
+		CDBG("memory_data[%d] = 0x%X\n", j, e_ctrl->memory_data[j]);
+
+	rc = msm_camera_power_down(power_info, e_ctrl->eeprom_device_type,
+		&e_ctrl->i2c_client);
+	if (rc) {
+		pr_err("failed rc %d\n", rc);
+		goto power_down;
+	}
+
 	/*IMPLEMENT READING PART*/
 	/* Initialize sub device */
 	v4l2_i2c_subdev_init(&e_ctrl->msm_sd.sd,
@@ -341,9 +508,18 @@
 	e_ctrl->msm_sd.sd.entity.type = MEDIA_ENT_T_V4L2_SUBDEV;
 	e_ctrl->msm_sd.sd.entity.group_id = MSM_CAMERA_SUBDEV_EEPROM;
 	msm_sd_register(&e_ctrl->msm_sd);
+	e_ctrl->is_supported = 1;
 	CDBG("%s success result=%d X\n", __func__, rc);
 	return rc;
 
+power_down:
+	msm_camera_power_down(power_info, e_ctrl->eeprom_device_type,
+		&e_ctrl->i2c_client);
+memdata_free:
+	kfree(e_ctrl->memory_data);
+	kfree(e_ctrl->eboard_info->eeprom_map);
+board_free:
+	kfree(e_ctrl->eboard_info);
 probe_failure:
 	pr_err("%s failed! rc = %d\n", __func__, rc);
 	return rc;
@@ -427,86 +603,6 @@
 	return 0;
 }
 
-static int msm_eeprom_get_dt_data(struct msm_eeprom_ctrl_t *e_ctrl)
-{
-	int rc = 0, i = 0;
-	struct msm_eeprom_board_info *eb_info;
-	struct msm_camera_power_ctrl_t *power_info =
-		&e_ctrl->eboard_info->power_info;
-	struct device_node *of_node = NULL;
-	struct msm_camera_gpio_conf *gconf = NULL;
-	uint16_t gpio_array_size = 0;
-	uint16_t *gpio_array = NULL;
-
-	eb_info = e_ctrl->eboard_info;
-	if (e_ctrl->eeprom_device_type == MSM_CAMERA_SPI_DEVICE)
-		of_node = e_ctrl->i2c_client.
-			spi_client->spi_master->dev.of_node;
-	else if (e_ctrl->eeprom_device_type == MSM_CAMERA_PLATFORM_DEVICE)
-		of_node = e_ctrl->pdev->dev.of_node;
-
-	rc = msm_camera_get_dt_vreg_data(of_node, &power_info->cam_vreg,
-					     &power_info->num_vreg);
-	if (rc < 0)
-		return rc;
-
-	rc = msm_camera_get_dt_power_setting_data(of_node,
-		power_info->cam_vreg, power_info->num_vreg,
-		&power_info->power_setting, &power_info->power_setting_size);
-	if (rc < 0)
-		goto ERROR1;
-
-	power_info->gpio_conf = kzalloc(sizeof(struct msm_camera_gpio_conf),
-					GFP_KERNEL);
-	if (!power_info->gpio_conf) {
-		rc = -ENOMEM;
-		goto ERROR2;
-	}
-	gconf = power_info->gpio_conf;
-	gpio_array_size = of_gpio_count(of_node);
-	CDBG("%s gpio count %d\n", __func__, gpio_array_size);
-
-	if (gpio_array_size) {
-		gpio_array = kzalloc(sizeof(uint16_t) * gpio_array_size,
-			GFP_KERNEL);
-		if (!gpio_array) {
-			pr_err("%s failed %d\n", __func__, __LINE__);
-			goto ERROR3;
-		}
-		for (i = 0; i < gpio_array_size; i++) {
-			gpio_array[i] = of_get_gpio(of_node, i);
-			CDBG("%s gpio_array[%d] = %d\n", __func__, i,
-				gpio_array[i]);
-		}
-
-		rc = msm_camera_get_dt_gpio_req_tbl(of_node, gconf,
-			gpio_array, gpio_array_size);
-		if (rc < 0) {
-			pr_err("%s failed %d\n", __func__, __LINE__);
-			goto ERROR4;
-		}
-
-		rc = msm_camera_init_gpio_pin_tbl(of_node, gconf,
-			gpio_array, gpio_array_size);
-		if (rc < 0) {
-			pr_err("%s failed %d\n", __func__, __LINE__);
-			goto ERROR4;
-		}
-		kfree(gpio_array);
-	}
-
-	return rc;
-ERROR4:
-	kfree(gpio_array);
-ERROR3:
-	kfree(power_info->gpio_conf);
-ERROR2:
-	kfree(power_info->cam_vreg);
-ERROR1:
-	kfree(power_info->power_setting);
-	return rc;
-}
-
 static int msm_eeprom_spi_setup(struct spi_device *spi)
 {
 	struct msm_eeprom_ctrl_t *e_ctrl = NULL;
diff --git a/drivers/media/platform/msm/camera_v2/sensor/flash/Makefile b/drivers/media/platform/msm/camera_v2/sensor/flash/Makefile
index 4ce7372..9fc3817 100644
--- a/drivers/media/platform/msm/camera_v2/sensor/flash/Makefile
+++ b/drivers/media/platform/msm/camera_v2/sensor/flash/Makefile
@@ -2,3 +2,6 @@
 ccflags-y += -Idrivers/media/platform/msm/camera_v2/sensor/io
 obj-$(CONFIG_MSMB_CAMERA) += msm_led_flash.o
 obj-$(CONFIG_MSMB_CAMERA) += msm_led_trigger.o
+obj-$(CONFIG_MSMB_CAMERA) += msm_led_i2c_trigger.o
+obj-$(CONFIG_MSMB_CAMERA) += adp1660.o
+obj-$(CONFIG_MSMB_CAMERA) += msm_led_torch.o
diff --git a/drivers/media/platform/msm/camera_v2/sensor/flash/adp1660.c b/drivers/media/platform/msm/camera_v2/sensor/flash/adp1660.c
new file mode 100644
index 0000000..aad8158
--- /dev/null
+++ b/drivers/media/platform/msm/camera_v2/sensor/flash/adp1660.c
@@ -0,0 +1,182 @@
+/* Copyright (c) 2013, The Linux Foundation. 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 and
+ * only 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/export.h>
+#include "msm_led_flash.h"
+
+#define FLASH_NAME "qcom,led-flash"
+
+/*#define CONFIG_MSMB_CAMERA_DEBUG*/
+#undef CDBG
+#ifdef CONFIG_MSMB_CAMERA_DEBUG
+#define CDBG(fmt, args...) pr_err(fmt, ##args)
+#else
+#define CDBG(fmt, args...) do { } while (0)
+#endif
+
+static struct msm_led_flash_ctrl_t fctrl;
+static struct i2c_driver adp1660_i2c_driver;
+
+static struct msm_camera_i2c_reg_array adp1660_init_array[] = {
+	{0x01, 0x03},
+	{0x02, 0x0F},
+	{0x09, 0x28},
+};
+
+static struct msm_camera_i2c_reg_array adp1660_off_array[] = {
+	{0x0f, 0x00},
+};
+
+static struct msm_camera_i2c_reg_array adp1660_release_array[] = {
+	{0x0f, 0x00},
+};
+
+static struct msm_camera_i2c_reg_array adp1660_low_array[] = {
+	{0x08, 0x04},
+	{0x06, 0x1E},
+	{0x01, 0xBD},
+	{0x0f, 0x01},
+};
+
+static struct msm_camera_i2c_reg_array adp1660_high_array[] = {
+	{0x02, 0x4F},
+	{0x06, 0x3C},
+	{0x09, 0x28},
+	{0x0f, 0x01},
+	{0x01, 0xBD},
+};
+
+static void __exit msm_flash_adp1660_i2c_remove(void)
+{
+	i2c_del_driver(&adp1660_i2c_driver);
+	return;
+}
+
+static const struct of_device_id adp1660_i2c_trigger_dt_match[] = {
+	{.compatible = "qcom,led-flash"},
+	{}
+};
+
+MODULE_DEVICE_TABLE(of, adp1660_i2c_trigger_dt_match);
+
+static const struct i2c_device_id flash_i2c_id[] = {
+	{"qcom,led-flash", (kernel_ulong_t)&fctrl},
+	{ }
+};
+
+static const struct i2c_device_id adp1660_i2c_id[] = {
+	{FLASH_NAME, (kernel_ulong_t)&fctrl},
+	{ }
+};
+
+static int msm_flash_adp1660_i2c_probe(struct i2c_client *client,
+		const struct i2c_device_id *id)
+{
+	if (!id) {
+		pr_err("msm_flash_adp1660_i2c_probe: id is NULL");
+		id = adp1660_i2c_id;
+	}
+
+	return msm_flash_i2c_probe(client, id);
+}
+
+static struct i2c_driver adp1660_i2c_driver = {
+	.id_table = adp1660_i2c_id,
+	.probe  = msm_flash_adp1660_i2c_probe,
+	.remove = __exit_p(msm_flash_adp1660_i2c_remove),
+	.driver = {
+		.name = FLASH_NAME,
+		.owner = THIS_MODULE,
+		.of_match_table = adp1660_i2c_trigger_dt_match,
+	},
+};
+
+static int __init msm_flash_adp1660_i2c_add_driver(void)
+{
+	CDBG("%s called\n", __func__);
+	return i2c_add_driver(&adp1660_i2c_driver);
+}
+
+static struct msm_camera_i2c_client adp1660_i2c_client = {
+	.addr_type = MSM_CAMERA_I2C_BYTE_ADDR,
+};
+
+static struct msm_camera_i2c_reg_setting adp1660_init_setting = {
+	.reg_setting = adp1660_init_array,
+	.size = ARRAY_SIZE(adp1660_init_array),
+	.addr_type = MSM_CAMERA_I2C_BYTE_ADDR,
+	.data_type = MSM_CAMERA_I2C_BYTE_DATA,
+	.delay = 0,
+};
+
+static struct msm_camera_i2c_reg_setting adp1660_off_setting = {
+	.reg_setting = adp1660_off_array,
+	.size = ARRAY_SIZE(adp1660_off_array),
+	.addr_type = MSM_CAMERA_I2C_BYTE_ADDR,
+	.data_type = MSM_CAMERA_I2C_BYTE_DATA,
+	.delay = 0,
+};
+
+static struct msm_camera_i2c_reg_setting adp1660_release_setting = {
+	.reg_setting = adp1660_release_array,
+	.size = ARRAY_SIZE(adp1660_release_array),
+	.addr_type = MSM_CAMERA_I2C_BYTE_ADDR,
+	.data_type = MSM_CAMERA_I2C_BYTE_DATA,
+	.delay = 0,
+};
+
+static struct msm_camera_i2c_reg_setting adp1660_low_setting = {
+	.reg_setting = adp1660_low_array,
+	.size = ARRAY_SIZE(adp1660_low_array),
+	.addr_type = MSM_CAMERA_I2C_BYTE_ADDR,
+	.data_type = MSM_CAMERA_I2C_BYTE_DATA,
+	.delay = 0,
+};
+
+static struct msm_camera_i2c_reg_setting adp1660_high_setting = {
+	.reg_setting = adp1660_high_array,
+	.size = ARRAY_SIZE(adp1660_high_array),
+	.addr_type = MSM_CAMERA_I2C_BYTE_ADDR,
+	.data_type = MSM_CAMERA_I2C_BYTE_DATA,
+	.delay = 0,
+};
+
+static struct msm_led_flash_reg_t adp1660_regs = {
+	.init_setting = &adp1660_init_setting,
+	.off_setting = &adp1660_off_setting,
+	.low_setting = &adp1660_low_setting,
+	.high_setting = &adp1660_high_setting,
+	.release_setting = &adp1660_release_setting,
+};
+
+static struct msm_flash_fn_t adp1660_func_tbl = {
+	.flash_get_subdev_id = msm_led_i2c_trigger_get_subdev_id,
+	.flash_led_config = msm_led_i2c_trigger_config,
+	.flash_led_init = msm_flash_led_init,
+	.flash_led_release = msm_flash_led_release,
+	.flash_led_off = msm_flash_led_off,
+	.flash_led_low = msm_flash_led_low,
+	.flash_led_high = msm_flash_led_high,
+};
+
+static struct msm_led_flash_ctrl_t fctrl = {
+	.flash_i2c_client = &adp1660_i2c_client,
+	.reg_setting = &adp1660_regs,
+	.func_tbl = &adp1660_func_tbl,
+};
+
+/*subsys_initcall(msm_flash_i2c_add_driver);*/
+module_init(msm_flash_adp1660_i2c_add_driver);
+module_exit(msm_flash_adp1660_i2c_remove);
+MODULE_DESCRIPTION("adp1660 FLASH");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/media/platform/msm/camera_v2/sensor/flash/msm_led_flash.c b/drivers/media/platform/msm/camera_v2/sensor/flash/msm_led_flash.c
index 044fd31..2de17c9 100644
--- a/drivers/media/platform/msm/camera_v2/sensor/flash/msm_led_flash.c
+++ b/drivers/media/platform/msm/camera_v2/sensor/flash/msm_led_flash.c
@@ -42,6 +42,9 @@
 		return fctrl->func_tbl->flash_get_subdev_id(fctrl, argp);
 	case VIDIOC_MSM_FLASH_LED_DATA_CFG:
 		return fctrl->func_tbl->flash_led_config(fctrl, argp);
+	case MSM_SD_SHUTDOWN:
+		*(int *)argp = MSM_CAMERA_LED_RELEASE;
+		return fctrl->func_tbl->flash_led_config(fctrl, argp);
 	default:
 		pr_err("invalid cmd %d\n", cmd);
 		return -ENOIOCTLCMD;
@@ -87,3 +90,31 @@
 	CDBG("probe success\n");
 	return 0;
 }
+
+int32_t msm_led_i2c_flash_create_v4lsubdev(void *data)
+{
+	struct msm_led_flash_ctrl_t *fctrl =
+		(struct msm_led_flash_ctrl_t *)data;
+	CDBG("Enter\n");
+
+	if (!fctrl) {
+		pr_err("fctrl NULL\n");
+		return -EINVAL;
+	}
+
+	/* Initialize sub device */
+	v4l2_subdev_init(&fctrl->msm_sd.sd, &msm_flash_subdev_ops);
+	v4l2_set_subdevdata(&fctrl->msm_sd.sd, fctrl);
+
+	fctrl->msm_sd.sd.internal_ops = &msm_flash_internal_ops;
+	fctrl->msm_sd.sd.flags |= V4L2_SUBDEV_FL_HAS_DEVNODE;
+	snprintf(fctrl->msm_sd.sd.name, ARRAY_SIZE(fctrl->msm_sd.sd.name),
+		"msm_flash");
+	media_entity_init(&fctrl->msm_sd.sd.entity, 0, NULL, 0);
+	fctrl->msm_sd.sd.entity.type = MEDIA_ENT_T_V4L2_SUBDEV;
+	fctrl->msm_sd.sd.entity.group_id = MSM_CAMERA_SUBDEV_LED_FLASH;
+	msm_sd_register(&fctrl->msm_sd);
+
+	CDBG("probe success\n");
+	return 0;
+}
diff --git a/drivers/media/platform/msm/camera_v2/sensor/flash/msm_led_flash.h b/drivers/media/platform/msm/camera_v2/sensor/flash/msm_led_flash.h
index ac697fb..9f3a81c 100644
--- a/drivers/media/platform/msm/camera_v2/sensor/flash/msm_led_flash.h
+++ b/drivers/media/platform/msm/camera_v2/sensor/flash/msm_led_flash.h
@@ -17,9 +17,11 @@
 #include <linux/platform_device.h>
 #include <media/v4l2-subdev.h>
 #include <media/msm_cam_sensor.h>
+#include <mach/camera2.h>
+#include "msm_camera_i2c.h"
 #include "msm_sd.h"
 
-#define MAX_LED_TRIGGERS 2
+#define MAX_LED_TRIGGERS 3
 
 struct msm_led_flash_ctrl_t;
 
@@ -33,18 +35,49 @@
 	int32_t (*flash_led_high)(struct msm_led_flash_ctrl_t *);
 };
 
+struct msm_led_flash_reg_t {
+	struct msm_camera_i2c_reg_setting *init_setting;
+	struct msm_camera_i2c_reg_setting *off_setting;
+	struct msm_camera_i2c_reg_setting *release_setting;
+	struct msm_camera_i2c_reg_setting *low_setting;
+	struct msm_camera_i2c_reg_setting *high_setting;
+};
+
 struct msm_led_flash_ctrl_t {
 	struct msm_camera_i2c_client *flash_i2c_client;
 	struct msm_sd_subdev msm_sd;
 	struct platform_device *pdev;
 	struct msm_flash_fn_t *func_tbl;
-	const char *led_trigger_name[MAX_LED_TRIGGERS];
-	struct led_trigger *led_trigger[MAX_LED_TRIGGERS];
-	uint32_t op_current[MAX_LED_TRIGGERS];
+	struct msm_camera_sensor_board_info *flashdata;
+	struct msm_led_flash_reg_t *reg_setting;
+	const char *flash_trigger_name[MAX_LED_TRIGGERS];
+	struct led_trigger *flash_trigger[MAX_LED_TRIGGERS];
+	uint32_t flash_op_current[MAX_LED_TRIGGERS];
+	const char *torch_trigger_name;
+	struct led_trigger *torch_trigger;
+	uint32_t torch_op_current;
 	void *data;
+	uint32_t num_sources;
+	enum msm_camera_device_type_t flash_device_type;
+	uint32_t subdev_id;
 };
 
+int msm_flash_i2c_probe(struct i2c_client *client,
+	const struct i2c_device_id *id);
+
 int32_t msm_led_flash_create_v4lsubdev(struct platform_device *pdev,
 	void *data);
+int32_t msm_led_i2c_flash_create_v4lsubdev(void *data);
 
+int32_t msm_led_i2c_trigger_get_subdev_id(struct msm_led_flash_ctrl_t *fctrl,
+	void *arg);
+
+int32_t msm_led_i2c_trigger_config(struct msm_led_flash_ctrl_t *fctrl,
+	void *data);
+
+int msm_flash_led_init(struct msm_led_flash_ctrl_t *fctrl);
+int msm_flash_led_release(struct msm_led_flash_ctrl_t *fctrl);
+int msm_flash_led_off(struct msm_led_flash_ctrl_t *fctrl);
+int msm_flash_led_low(struct msm_led_flash_ctrl_t *fctrl);
+int msm_flash_led_high(struct msm_led_flash_ctrl_t *fctrl);
 #endif
diff --git a/drivers/media/platform/msm/camera_v2/sensor/flash/msm_led_i2c_trigger.c b/drivers/media/platform/msm/camera_v2/sensor/flash/msm_led_i2c_trigger.c
new file mode 100644
index 0000000..9caa270
--- /dev/null
+++ b/drivers/media/platform/msm/camera_v2/sensor/flash/msm_led_i2c_trigger.c
@@ -0,0 +1,577 @@
+/* Copyright (c) 2013, The Linux Foundation. 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 and
+ * only 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.
+ *
+ */
+
+#define pr_fmt(fmt) "%s:%d " fmt, __func__, __LINE__
+
+#include <mach/gpiomux.h>
+#include <linux/module.h>
+#include "msm_led_flash.h"
+#include "msm_camera_io_util.h"
+#include "../msm_sensor.h"
+#include "msm_led_flash.h"
+#include <linux/debugfs.h>
+
+#define FLASH_NAME "camera-led-flash"
+
+/*#define CONFIG_MSMB_CAMERA_DEBUG*/
+#undef CDBG
+#ifdef CONFIG_MSMB_CAMERA_DEBUG
+#define CDBG(fmt, args...) pr_err(fmt, ##args)
+#else
+#define CDBG(fmt, args...) do { } while (0)
+#endif
+
+int32_t msm_led_i2c_trigger_get_subdev_id(struct msm_led_flash_ctrl_t *fctrl,
+	void *arg)
+{
+	uint32_t *subdev_id = (uint32_t *)arg;
+	if (!subdev_id) {
+		pr_err("failed\n");
+		return -EINVAL;
+	}
+	*subdev_id = fctrl->subdev_id;
+
+	CDBG("subdev_id %d\n", *subdev_id);
+	return 0;
+}
+
+int32_t msm_led_i2c_trigger_config(struct msm_led_flash_ctrl_t *fctrl,
+	void *data)
+{
+	int rc = 0;
+	struct msm_camera_led_cfg_t *cfg = (struct msm_camera_led_cfg_t *)data;
+	CDBG("called led_state %d\n", cfg->cfgtype);
+
+	if (!fctrl->func_tbl) {
+		pr_err("failed\n");
+		return -EINVAL;
+	}
+	switch (cfg->cfgtype) {
+
+	case MSM_CAMERA_LED_INIT:
+		if (fctrl->func_tbl->flash_led_init)
+			rc = fctrl->func_tbl->flash_led_init(fctrl);
+		break;
+
+	case MSM_CAMERA_LED_RELEASE:
+		if (fctrl->func_tbl->flash_led_release)
+			rc = fctrl->func_tbl->
+				flash_led_release(fctrl);
+		break;
+
+	case MSM_CAMERA_LED_OFF:
+		if (fctrl->func_tbl->flash_led_off)
+			rc = fctrl->func_tbl->flash_led_off(fctrl);
+		break;
+
+	case MSM_CAMERA_LED_LOW:
+		if (fctrl->func_tbl->flash_led_low)
+			rc = fctrl->func_tbl->flash_led_low(fctrl);
+		break;
+
+	case MSM_CAMERA_LED_HIGH:
+		if (fctrl->func_tbl->flash_led_high)
+			rc = fctrl->func_tbl->flash_led_high(fctrl);
+		break;
+	default:
+		rc = -EFAULT;
+		break;
+	}
+	CDBG("flash_set_led_state: return %d\n", rc);
+	return rc;
+}
+
+int msm_flash_led_init(struct msm_led_flash_ctrl_t *fctrl)
+{
+	int rc = 0;
+	struct msm_camera_sensor_board_info *flashdata = NULL;
+	CDBG("%s:%d called\n", __func__, __LINE__);
+
+	flashdata = fctrl->flashdata;
+	if (flashdata->gpio_conf->cam_gpiomux_conf_tbl != NULL) {
+		pr_err("%s:%d mux install\n", __func__, __LINE__);
+		msm_gpiomux_install(
+			(struct msm_gpiomux_config *)
+			flashdata->gpio_conf->cam_gpiomux_conf_tbl,
+			flashdata->gpio_conf->cam_gpiomux_conf_tbl_size);
+	}
+
+	rc = msm_camera_request_gpio_table(
+		flashdata->gpio_conf->cam_gpio_req_tbl,
+		flashdata->gpio_conf->cam_gpio_req_tbl_size, 1);
+	if (rc < 0) {
+		pr_err("%s: request gpio failed\n", __func__);
+		return rc;
+	}
+	msleep(20);
+	gpio_set_value_cansleep(
+		flashdata->gpio_conf->gpio_num_info->gpio_num[0],
+		GPIO_OUT_HIGH);
+
+	if (fctrl->flash_i2c_client && fctrl->reg_setting) {
+		rc = fctrl->flash_i2c_client->i2c_func_tbl->i2c_write_table(
+			fctrl->flash_i2c_client,
+			fctrl->reg_setting->init_setting);
+		if (rc < 0)
+			pr_err("%s:%d failed\n", __func__, __LINE__);
+	}
+
+	return rc;
+}
+
+int msm_flash_led_release(struct msm_led_flash_ctrl_t *fctrl)
+{
+	int rc = 0;
+	struct msm_camera_sensor_board_info *flashdata = NULL;
+
+	flashdata = fctrl->flashdata;
+	CDBG("%s:%d called\n", __func__, __LINE__);
+	if (!fctrl) {
+		pr_err("%s:%d fctrl NULL\n", __func__, __LINE__);
+		return -EINVAL;
+	}
+	gpio_set_value_cansleep(
+		flashdata->gpio_conf->gpio_num_info->gpio_num[0],
+		GPIO_OUT_LOW);
+	gpio_set_value_cansleep(
+		flashdata->gpio_conf->gpio_num_info->gpio_num[1],
+		GPIO_OUT_LOW);
+	rc = msm_camera_request_gpio_table(
+		flashdata->gpio_conf->cam_gpio_req_tbl,
+		flashdata->gpio_conf->cam_gpio_req_tbl_size, 0);
+	if (rc < 0) {
+		pr_err("%s: request gpio failed\n", __func__);
+		return rc;
+	}
+	return 0;
+}
+
+int msm_flash_led_off(struct msm_led_flash_ctrl_t *fctrl)
+{
+	int rc = 0;
+	struct msm_camera_sensor_board_info *flashdata = NULL;
+
+	flashdata = fctrl->flashdata;
+	CDBG("%s:%d called\n", __func__, __LINE__);
+	if (!fctrl) {
+		pr_err("%s:%d fctrl NULL\n", __func__, __LINE__);
+		return -EINVAL;
+	}
+	if (fctrl->flash_i2c_client && fctrl->reg_setting) {
+		rc = fctrl->flash_i2c_client->i2c_func_tbl->i2c_write_table(
+			fctrl->flash_i2c_client,
+			fctrl->reg_setting->off_setting);
+		if (rc < 0)
+			pr_err("%s:%d failed\n", __func__, __LINE__);
+	}
+	gpio_set_value_cansleep(
+		flashdata->gpio_conf->gpio_num_info->gpio_num[1],
+		GPIO_OUT_LOW);
+
+	return rc;
+}
+
+int msm_flash_led_low(struct msm_led_flash_ctrl_t *fctrl)
+{
+	int rc = 0;
+	struct msm_camera_sensor_board_info *flashdata = NULL;
+	CDBG("%s:%d called\n", __func__, __LINE__);
+
+	flashdata = fctrl->flashdata;
+	gpio_set_value_cansleep(
+		flashdata->gpio_conf->gpio_num_info->gpio_num[0],
+		GPIO_OUT_HIGH);
+
+	gpio_set_value_cansleep(
+		flashdata->gpio_conf->gpio_num_info->gpio_num[1],
+		GPIO_OUT_HIGH);
+
+
+	if (fctrl->flash_i2c_client && fctrl->reg_setting) {
+		rc = fctrl->flash_i2c_client->i2c_func_tbl->i2c_write_table(
+			fctrl->flash_i2c_client,
+			fctrl->reg_setting->low_setting);
+		if (rc < 0)
+			pr_err("%s:%d failed\n", __func__, __LINE__);
+	}
+
+	return rc;
+}
+
+int msm_flash_led_high(struct msm_led_flash_ctrl_t *fctrl)
+{
+	int rc = 0;
+	struct msm_camera_sensor_board_info *flashdata = NULL;
+	CDBG("%s:%d called\n", __func__, __LINE__);
+
+	flashdata = fctrl->flashdata;
+	gpio_set_value_cansleep(
+		flashdata->gpio_conf->gpio_num_info->gpio_num[0],
+		GPIO_OUT_HIGH);
+
+	gpio_set_value_cansleep(
+		flashdata->gpio_conf->gpio_num_info->gpio_num[1],
+		GPIO_OUT_HIGH);
+
+	if (fctrl->flash_i2c_client && fctrl->reg_setting) {
+		rc = fctrl->flash_i2c_client->i2c_func_tbl->i2c_write_table(
+			fctrl->flash_i2c_client,
+			fctrl->reg_setting->high_setting);
+		if (rc < 0)
+			pr_err("%s:%d failed\n", __func__, __LINE__);
+	}
+
+	return rc;
+}
+
+static int32_t msm_flash_init_gpio_pin_tbl(struct device_node *of_node,
+	struct msm_camera_gpio_conf *gconf, uint16_t *gpio_array,
+	uint16_t gpio_array_size)
+{
+	int32_t rc = 0;
+	int32_t val = 0;
+
+	gconf->gpio_num_info = kzalloc(sizeof(struct msm_camera_gpio_num_info),
+		GFP_KERNEL);
+	if (!gconf->gpio_num_info) {
+		pr_err("%s failed %d\n", __func__, __LINE__);
+		rc = -ENOMEM;
+		return rc;
+	}
+
+	rc = of_property_read_u32(of_node, "qcom,gpio-flash-en", &val);
+	if (rc < 0) {
+		pr_err("%s:%d read qcom,gpio-flash-en failed rc %d\n",
+			__func__, __LINE__, rc);
+		goto ERROR;
+	} else if (val >= gpio_array_size) {
+		pr_err("%s:%d qcom,gpio-flash-en invalid %d\n",
+			__func__, __LINE__, val);
+		goto ERROR;
+	}
+	/*index 0 is for qcom,gpio-flash-en */
+	gconf->gpio_num_info->gpio_num[0] =
+		gpio_array[val];
+	CDBG("%s qcom,gpio-flash-en %d\n", __func__,
+		gconf->gpio_num_info->gpio_num[0]);
+
+	rc = of_property_read_u32(of_node, "qcom,gpio-flash-now", &val);
+	if (rc < 0) {
+		pr_err("%s:%d read qcom,gpio-flash-now failed rc %d\n",
+			__func__, __LINE__, rc);
+		goto ERROR;
+	} else if (val >= gpio_array_size) {
+		pr_err("%s:%d qcom,gpio-flash-now invalid %d\n",
+			__func__, __LINE__, val);
+		goto ERROR;
+	}
+	/*index 1 is for qcom,gpio-flash-now */
+	gconf->gpio_num_info->gpio_num[1] =
+		gpio_array[val];
+	CDBG("%s qcom,gpio-flash-now %d\n", __func__,
+		gconf->gpio_num_info->gpio_num[1]);
+
+	return rc;
+
+ERROR:
+	kfree(gconf->gpio_num_info);
+	gconf->gpio_num_info = NULL;
+	return rc;
+}
+
+static int32_t msm_led_get_dt_data(struct device_node *of_node,
+		struct msm_led_flash_ctrl_t *fctrl)
+{
+	int32_t rc = 0, i = 0;
+	struct msm_camera_gpio_conf *gconf = NULL;
+	struct device_node *flash_src_node = NULL;
+	struct msm_camera_sensor_board_info *flashdata = NULL;
+	uint32_t count = 0;
+	uint16_t *gpio_array = NULL;
+	uint16_t gpio_array_size = 0;
+	uint32_t id_info[3];
+
+	CDBG("called\n");
+
+	if (!of_node) {
+		pr_err("of_node NULL\n");
+		return -EINVAL;
+	}
+
+	fctrl->flashdata = kzalloc(sizeof(
+		struct msm_camera_sensor_board_info),
+		GFP_KERNEL);
+	if (!fctrl->flashdata) {
+		pr_err("%s failed %d\n", __func__, __LINE__);
+		return -ENOMEM;
+	}
+
+	flashdata = fctrl->flashdata;
+
+	flashdata->sensor_init_params = kzalloc(sizeof(
+		struct msm_sensor_init_params), GFP_KERNEL);
+	if (!flashdata->sensor_init_params) {
+		pr_err("%s failed %d\n", __func__, __LINE__);
+		return -ENOMEM;
+	}
+
+	rc = of_property_read_u32(of_node, "cell-index", &fctrl->subdev_id);
+	if (rc < 0) {
+		pr_err("failed\n");
+		return -EINVAL;
+	}
+
+	CDBG("subdev id %d\n", fctrl->subdev_id);
+
+	rc = of_property_read_string(of_node, "qcom,flash-name",
+		&flashdata->sensor_name);
+	CDBG("%s qcom,flash-name %s, rc %d\n", __func__,
+		flashdata->sensor_name, rc);
+	if (rc < 0) {
+		pr_err("%s failed %d\n", __func__, __LINE__);
+		goto ERROR1;
+	}
+
+	if (of_get_property(of_node, "qcom,flash-source", &count)) {
+		count /= sizeof(uint32_t);
+		CDBG("count %d\n", count);
+		if (count > MAX_LED_TRIGGERS) {
+			pr_err("failed\n");
+			return -EINVAL;
+		}
+		for (i = 0; i < count; i++) {
+			flash_src_node = of_parse_phandle(of_node,
+				"qcom,flash-source", i);
+			if (!flash_src_node) {
+				pr_err("flash_src_node NULL\n");
+				continue;
+			}
+
+			rc = of_property_read_string(flash_src_node,
+				"linux,default-trigger",
+				&fctrl->flash_trigger_name[i]);
+			if (rc < 0) {
+				pr_err("failed\n");
+				of_node_put(flash_src_node);
+				continue;
+			}
+
+			CDBG("default trigger %s\n",
+				 fctrl->flash_trigger_name[i]);
+
+			rc = of_property_read_u32(flash_src_node,
+				"qcom,max-current",
+				&fctrl->flash_op_current[i]);
+			if (rc < 0) {
+				pr_err("failed rc %d\n", rc);
+				of_node_put(flash_src_node);
+				continue;
+			}
+
+			of_node_put(flash_src_node);
+
+			CDBG("max_current[%d] %d\n",
+				i, fctrl->flash_op_current[i]);
+
+			led_trigger_register_simple(
+				fctrl->flash_trigger_name[i],
+				&fctrl->flash_trigger[i]);
+		}
+
+	} else { /*Handle LED Flash Ctrl by GPIO*/
+		flashdata->gpio_conf =
+			 kzalloc(sizeof(struct msm_camera_gpio_conf),
+				 GFP_KERNEL);
+		if (!flashdata->gpio_conf) {
+			pr_err("%s failed %d\n", __func__, __LINE__);
+			rc = -ENOMEM;
+			return rc;
+		}
+		gconf = flashdata->gpio_conf;
+
+		gpio_array_size = of_gpio_count(of_node);
+		CDBG("%s gpio count %d\n", __func__, gpio_array_size);
+
+		if (gpio_array_size) {
+			gpio_array = kzalloc(sizeof(uint16_t) * gpio_array_size,
+				GFP_KERNEL);
+			if (!gpio_array) {
+				pr_err("%s failed %d\n", __func__, __LINE__);
+				rc = -ENOMEM;
+				goto ERROR4;
+			}
+			for (i = 0; i < gpio_array_size; i++) {
+				gpio_array[i] = of_get_gpio(of_node, i);
+				CDBG("%s gpio_array[%d] = %d\n", __func__, i,
+					gpio_array[i]);
+			}
+
+			rc = msm_sensor_get_dt_gpio_req_tbl(of_node, gconf,
+				gpio_array, gpio_array_size);
+			if (rc < 0) {
+				pr_err("%s failed %d\n", __func__, __LINE__);
+				goto ERROR4;
+			}
+
+			rc = msm_sensor_get_dt_gpio_set_tbl(of_node, gconf,
+				gpio_array, gpio_array_size);
+			if (rc < 0) {
+				pr_err("%s failed %d\n", __func__, __LINE__);
+				goto ERROR5;
+			}
+
+			rc = msm_flash_init_gpio_pin_tbl(of_node, gconf,
+				gpio_array, gpio_array_size);
+			if (rc < 0) {
+				pr_err("%s failed %d\n", __func__, __LINE__);
+				goto ERROR6;
+			}
+		}
+
+		flashdata->slave_info =
+			kzalloc(sizeof(struct msm_camera_slave_info),
+				GFP_KERNEL);
+		if (!flashdata->slave_info) {
+			pr_err("%s failed %d\n", __func__, __LINE__);
+			rc = -ENOMEM;
+			goto ERROR8;
+		}
+
+		rc = of_property_read_u32_array(of_node, "qcom,slave-id",
+			id_info, 3);
+		if (rc < 0) {
+			pr_err("%s failed %d\n", __func__, __LINE__);
+			goto ERROR9;
+		}
+		fctrl->flashdata->slave_info->sensor_slave_addr = id_info[0];
+		fctrl->flashdata->slave_info->sensor_id_reg_addr = id_info[1];
+		fctrl->flashdata->slave_info->sensor_id = id_info[2];
+
+		kfree(gpio_array);
+		return rc;
+ERROR9:
+		kfree(fctrl->flashdata->slave_info);
+ERROR8:
+		kfree(fctrl->flashdata->gpio_conf->gpio_num_info);
+ERROR6:
+		kfree(gconf->cam_gpio_set_tbl);
+ERROR5:
+		kfree(gconf->cam_gpio_req_tbl);
+ERROR4:
+		kfree(gconf);
+ERROR1:
+		kfree(fctrl->flashdata);
+		kfree(gpio_array);
+	}
+	return rc;
+}
+
+static struct msm_camera_i2c_fn_t msm_sensor_qup_func_tbl = {
+	.i2c_read = msm_camera_qup_i2c_read,
+	.i2c_read_seq = msm_camera_qup_i2c_read_seq,
+	.i2c_write = msm_camera_qup_i2c_write,
+	.i2c_write_table = msm_camera_qup_i2c_write_table,
+	.i2c_write_seq_table = msm_camera_qup_i2c_write_seq_table,
+	.i2c_write_table_w_microdelay =
+		msm_camera_qup_i2c_write_table_w_microdelay,
+};
+
+#ifdef CONFIG_DEBUG_FS
+static int set_led_status(void *data, u64 val)
+{
+	struct msm_led_flash_ctrl_t *fctrl =
+		 (struct msm_led_flash_ctrl_t *)data;
+	int rc = -1;
+	pr_debug("set_led_status: Enter val: %llu", val);
+	if (!fctrl) {
+		pr_err("set_led_status: fctrl is NULL");
+		return rc;
+	}
+	if (!fctrl->func_tbl) {
+		pr_err("set_led_status: fctrl->func_tbl is NULL");
+		return rc;
+	}
+	if (val == 0) {
+		pr_debug("set_led_status: val is disable");
+		rc = msm_flash_led_off(fctrl);
+	} else {
+		pr_debug("set_led_status: val is enable");
+		rc = msm_flash_led_low(fctrl);
+	}
+
+	return rc;
+}
+
+DEFINE_SIMPLE_ATTRIBUTE(ledflashdbg_fops,
+	NULL, set_led_status, "%llu\n");
+#endif
+
+int msm_flash_i2c_probe(struct i2c_client *client,
+		const struct i2c_device_id *id)
+{
+	int rc = 0;
+	struct msm_led_flash_ctrl_t *fctrl = NULL;
+#ifdef CONFIG_DEBUG_FS
+	struct dentry *dentry;
+#endif
+	if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) {
+		pr_err("i2c_check_functionality failed\n");
+		goto probe_failure;
+	}
+
+	fctrl = (struct msm_led_flash_ctrl_t *)(id->driver_data);
+	if (fctrl->flash_i2c_client)
+		fctrl->flash_i2c_client->client = client;
+	/* Set device type as I2C */
+	fctrl->flash_device_type = MSM_CAMERA_I2C_DEVICE;
+
+	/* Assign name for sub device */
+	snprintf(fctrl->msm_sd.sd.name, sizeof(fctrl->msm_sd.sd.name),
+		"%s", id->name);
+
+	rc = msm_led_get_dt_data(client->dev.of_node, fctrl);
+	if (rc < 0) {
+		pr_err("%s failed line %d\n", __func__, __LINE__);
+		return rc;
+	}
+	if (fctrl->flash_i2c_client != NULL) {
+		fctrl->flash_i2c_client->client = client;
+		if (fctrl->flashdata->slave_info->sensor_slave_addr)
+			fctrl->flash_i2c_client->client->addr =
+				fctrl->flashdata->slave_info->
+				sensor_slave_addr;
+	} else {
+		pr_err("%s %s sensor_i2c_client NULL\n",
+			__func__, client->name);
+		rc = -EFAULT;
+		return rc;
+	}
+
+	if (!fctrl->flash_i2c_client->i2c_func_tbl)
+		fctrl->flash_i2c_client->i2c_func_tbl =
+			&msm_sensor_qup_func_tbl;
+
+	rc = msm_led_i2c_flash_create_v4lsubdev(fctrl);
+#ifdef CONFIG_DEBUG_FS
+	dentry = debugfs_create_file("ledflash", S_IRUGO, NULL, (void *)fctrl,
+		&ledflashdbg_fops);
+	if (!dentry)
+		pr_err("Failed to create the debugfs ledflash file");
+#endif
+	CDBG("%s:%d probe success\n", __func__, __LINE__);
+	return 0;
+
+probe_failure:
+	CDBG("%s:%d probe failed\n", __func__, __LINE__);
+	return rc;
+}
diff --git a/drivers/media/platform/msm/camera_v2/sensor/flash/msm_led_torch.c b/drivers/media/platform/msm/camera_v2/sensor/flash/msm_led_torch.c
new file mode 100644
index 0000000..ff63696
--- /dev/null
+++ b/drivers/media/platform/msm/camera_v2/sensor/flash/msm_led_torch.c
@@ -0,0 +1,60 @@
+/* Copyright (c) 2013, The Linux Foundation. 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 and
+ * only 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.
+ *
+ */
+
+#define pr_fmt(fmt) "%s:%d " fmt, __func__, __LINE__
+
+#include <linux/module.h>
+#include "msm_led_flash.h"
+
+static struct led_trigger *torch_trigger;
+
+static void msm_led_torch_brightness_set(struct led_classdev *led_cdev,
+				enum led_brightness value)
+{
+	if (!torch_trigger) {
+		pr_err("No torch trigger found, can't set brightness\n");
+		return;
+	}
+
+	led_trigger_event(torch_trigger, value);
+};
+
+static struct led_classdev msm_torch_led = {
+	.name			= "torch-light",
+	.brightness_set	= msm_led_torch_brightness_set,
+	.brightness		= LED_OFF,
+};
+
+int32_t msm_led_torch_create_classdev(struct platform_device *pdev,
+				void *data)
+{
+	int rc;
+	struct msm_led_flash_ctrl_t *fctrl =
+		(struct msm_led_flash_ctrl_t *)data;
+
+	if (!fctrl || !fctrl->torch_trigger) {
+		pr_err("Invalid fctrl or torch trigger\n");
+		return -EINVAL;
+	}
+
+	torch_trigger = fctrl->torch_trigger;
+	msm_led_torch_brightness_set(&msm_torch_led, LED_OFF);
+
+	rc = led_classdev_register(&pdev->dev, &msm_torch_led);
+	if (rc) {
+		pr_err("Failed to register led dev. rc = %d\n", rc);
+		return rc;
+	}
+
+	return 0;
+};
diff --git a/drivers/media/platform/msm/camera_v2/sensor/flash/msm_led_trigger.c b/drivers/media/platform/msm/camera_v2/sensor/flash/msm_led_trigger.c
index c6f1f72..20905c9 100644
--- a/drivers/media/platform/msm/camera_v2/sensor/flash/msm_led_trigger.c
+++ b/drivers/media/platform/msm/camera_v2/sensor/flash/msm_led_trigger.c
@@ -26,6 +26,9 @@
 #define CDBG(fmt, args...) do { } while (0)
 #endif
 
+extern int32_t msm_led_torch_create_classdev(
+				struct platform_device *pdev, void *data);
+
 static struct msm_led_flash_ctrl_t fctrl;
 
 static int32_t msm_led_trigger_get_subdev_id(struct msm_led_flash_ctrl_t *fctrl,
@@ -46,29 +49,45 @@
 {
 	int rc = 0;
 	struct msm_camera_led_cfg_t *cfg = (struct msm_camera_led_cfg_t *)data;
+	uint32_t i;
 	CDBG("called led_state %d\n", cfg->cfgtype);
 
-	if (!fctrl->led_trigger[0]) {
+	if (!fctrl) {
 		pr_err("failed\n");
 		return -EINVAL;
 	}
+
 	switch (cfg->cfgtype) {
 	case MSM_CAMERA_LED_OFF:
-		led_trigger_event(fctrl->led_trigger[0], 0);
+		for (i = 0; i < fctrl->num_sources; i++)
+			if (fctrl->flash_trigger[i])
+				led_trigger_event(fctrl->flash_trigger[i], 0);
+		if (fctrl->torch_trigger)
+			led_trigger_event(fctrl->torch_trigger, 0);
 		break;
 
 	case MSM_CAMERA_LED_LOW:
-		led_trigger_event(fctrl->led_trigger[0],
-			fctrl->op_current[0] / 2);
+		if (fctrl->torch_trigger)
+			led_trigger_event(fctrl->torch_trigger,
+				fctrl->torch_op_current);
 		break;
 
 	case MSM_CAMERA_LED_HIGH:
-		led_trigger_event(fctrl->led_trigger[0], fctrl->op_current[0]);
+		if (fctrl->torch_trigger)
+			led_trigger_event(fctrl->torch_trigger, 0);
+		for (i = 0; i < fctrl->num_sources; i++)
+			if (fctrl->flash_trigger[i])
+				led_trigger_event(fctrl->flash_trigger[i],
+					fctrl->flash_op_current[i]);
 		break;
 
 	case MSM_CAMERA_LED_INIT:
 	case MSM_CAMERA_LED_RELEASE:
-		led_trigger_event(fctrl->led_trigger[0], 0);
+		for (i = 0; i < fctrl->num_sources; i++)
+			if (fctrl->flash_trigger[i])
+				led_trigger_event(fctrl->flash_trigger[i], 0);
+		if (fctrl->torch_trigger)
+			led_trigger_event(fctrl->torch_trigger, 0);
 		break;
 
 	default:
@@ -109,6 +128,7 @@
 	}
 
 	fctrl.pdev = pdev;
+	fctrl.num_sources = 0;
 
 	rc = of_property_read_u32(of_node, "cell-index", &pdev->id);
 	if (rc < 0) {
@@ -124,6 +144,7 @@
 			pr_err("failed\n");
 			return -EINVAL;
 		}
+		fctrl.num_sources = count;
 		for (i = 0; i < count; i++) {
 			flash_src_node = of_parse_phandle(of_node,
 				"qcom,flash-source", i);
@@ -134,17 +155,18 @@
 
 			rc = of_property_read_string(flash_src_node,
 				"linux,default-trigger",
-				&fctrl.led_trigger_name[i]);
+				&fctrl.flash_trigger_name[i]);
 			if (rc < 0) {
 				pr_err("failed\n");
 				of_node_put(flash_src_node);
 				continue;
 			}
 
-			CDBG("default trigger %s\n", fctrl.led_trigger_name[i]);
+			CDBG("default trigger %s\n",
+				fctrl.flash_trigger_name[i]);
 
 			rc = of_property_read_u32(flash_src_node,
-				"qcom,current", &fctrl.op_current[i]);
+				"qcom,current", &fctrl.flash_op_current[i]);
 			if (rc < 0) {
 				pr_err("failed rc %d\n", rc);
 				of_node_put(flash_src_node);
@@ -153,13 +175,48 @@
 
 			of_node_put(flash_src_node);
 
-			CDBG("max_current[%d] %d\n", i, fctrl.op_current[i]);
+			CDBG("max_current[%d] %d\n",
+				i, fctrl.flash_op_current[i]);
 
-			led_trigger_register_simple(fctrl.led_trigger_name[i],
-				&fctrl.led_trigger[i]);
+			led_trigger_register_simple(fctrl.flash_trigger_name[i],
+				&fctrl.flash_trigger[i]);
+		}
+
+		/* Torch source */
+		flash_src_node = of_parse_phandle(of_node, "qcom,torch-source",
+			0);
+		if (flash_src_node) {
+			rc = of_property_read_string(flash_src_node,
+				"linux,default-trigger",
+				&fctrl.torch_trigger_name);
+			if (rc < 0) {
+				pr_err("failed\n");
+			} else {
+				CDBG("default trigger %s\n",
+					fctrl.torch_trigger_name);
+
+				rc = of_property_read_u32(flash_src_node,
+					"qcom,current",
+					&fctrl.torch_op_current);
+				if (rc < 0) {
+					pr_err("failed rc %d\n", rc);
+				} else {
+					CDBG("torch max_current %d\n",
+						fctrl.torch_op_current);
+
+					led_trigger_register_simple(
+						fctrl.torch_trigger_name,
+						&fctrl.torch_trigger);
+				}
+			}
+			of_node_put(flash_src_node);
 		}
 	}
+
 	rc = msm_led_flash_create_v4lsubdev(pdev, &fctrl);
+	if (!rc)
+		msm_led_torch_create_classdev(pdev, &fctrl);
+
 	return rc;
 }
 
diff --git a/drivers/media/platform/msm/camera_v2/sensor/gc0339.c b/drivers/media/platform/msm/camera_v2/sensor/gc0339.c
index cc38b56..8288ad0 100644
--- a/drivers/media/platform/msm/camera_v2/sensor/gc0339.c
+++ b/drivers/media/platform/msm/camera_v2/sensor/gc0339.c
@@ -33,6 +33,18 @@
 static struct msm_sensor_power_setting gc0339_power_setting[] = {
 
 	{
+		.seq_type = SENSOR_GPIO,
+		.seq_val = SENSOR_GPIO_RESET,
+		.config_val = GPIO_OUT_LOW,
+		.delay = 0,
+	},
+	{
+		.seq_type = SENSOR_GPIO,
+		.seq_val = SENSOR_GPIO_STANDBY,
+		.config_val = GPIO_OUT_HIGH,
+		.delay = 0,
+	},
+	{
 		.seq_type = SENSOR_VREG,
 		.seq_val = CAM_VIO,
 		.config_val = 0,
@@ -51,12 +63,6 @@
 		.delay = 0,
 	},
 	{
-		.seq_type = SENSOR_GPIO,
-		.seq_val = SENSOR_GPIO_STANDBY,
-		.config_val = GPIO_OUT_HIGH,
-		.delay = 0,
-	},
-	{
 		.seq_type = SENSOR_CLK,
 		.seq_val = SENSOR_CAM_MCLK,
 		.config_val = 24000000,
@@ -74,18 +80,6 @@
 		.config_val = GPIO_OUT_HIGH,
 		.delay = 1,
 	},
-	{
-		.seq_type = SENSOR_GPIO,
-		.seq_val = SENSOR_GPIO_RESET,
-		.config_val = GPIO_OUT_LOW,
-		.delay = 1,
-	},
-	{
-		.seq_type = SENSOR_GPIO,
-		.seq_val = SENSOR_GPIO_RESET,
-		.config_val = GPIO_OUT_HIGH,
-		.delay = 1,
-	},
 };
 
 static struct v4l2_subdev_info gc0339_subdev_info[] = {
@@ -223,6 +217,12 @@
 			goto power_up_failed;
 		}
 	}
+
+	s_ctrl->sensor_i2c_client->i2c_func_tbl->i2c_write(
+		s_ctrl->sensor_i2c_client,
+		0xfc,
+		0x10, MSM_CAMERA_I2C_BYTE_DATA);
+
 	if (s_ctrl->func_tbl->sensor_match_id)
 		rc = s_ctrl->func_tbl->sensor_match_id(s_ctrl);
 	else
@@ -254,9 +254,12 @@
 				0);
 			break;
 		case SENSOR_GPIO:
-			gpio_set_value_cansleep(
-				data->gpio_conf->gpio_num_info->gpio_num
-				[power_setting->seq_val], GPIOF_OUT_INIT_LOW);
+			if (data->gpio_conf->gpio_num_info->gpio_num
+				[power_setting->seq_val])
+				gpio_set_value_cansleep(
+					data->gpio_conf->gpio_num_info->gpio_num
+					[power_setting->seq_val],
+					GPIOF_OUT_INIT_LOW);
 			break;
 		case SENSOR_VREG:
 			msm_camera_config_single_vreg(s_ctrl->dev,
@@ -297,6 +300,11 @@
 			s_ctrl->sensor_i2c_client, MSM_CCI_RELEASE);
 	}
 
+	s_ctrl->sensor_i2c_client->i2c_func_tbl->i2c_write(
+		s_ctrl->sensor_i2c_client,
+		0xfc,
+		0x01, MSM_CAMERA_I2C_BYTE_DATA);
+
 	for (index = (power_setting_array->size - 1); index >= 0; index--) {
 		CDBG("%s index %d\n", __func__, index);
 		power_setting = &power_setting_array->power_setting[index];
@@ -317,9 +325,12 @@
 					SENSOR_GPIO_MAX);
 				continue;
 			}
-			gpio_set_value_cansleep(
-				data->gpio_conf->gpio_num_info->gpio_num
-				[power_setting->seq_val], GPIOF_OUT_INIT_LOW);
+			if (data->gpio_conf->gpio_num_info->gpio_num
+				[power_setting->seq_val])
+				gpio_set_value_cansleep(
+					data->gpio_conf->gpio_num_info->gpio_num
+					[power_setting->seq_val],
+					GPIOF_OUT_INIT_LOW);
 			break;
 		case SENSOR_VREG:
 			if (power_setting->seq_val >= CAM_VREG_MAX) {
@@ -356,10 +367,7 @@
 {
 	int32_t rc = 0;
 	uint16_t chipid = 0;
-	s_ctrl->sensor_i2c_client->i2c_func_tbl->i2c_write(
-				s_ctrl->sensor_i2c_client,
-				0xfc,
-				0x10, MSM_CAMERA_I2C_BYTE_DATA);
+
 	rc = s_ctrl->sensor_i2c_client->i2c_func_tbl->i2c_read(
 			s_ctrl->sensor_i2c_client,
 			s_ctrl->sensordata->slave_info->sensor_id_reg_addr,
diff --git a/drivers/media/platform/msm/camera_v2/sensor/hi256.c b/drivers/media/platform/msm/camera_v2/sensor/hi256.c
index de651df..835230e 100644
--- a/drivers/media/platform/msm/camera_v2/sensor/hi256.c
+++ b/drivers/media/platform/msm/camera_v2/sensor/hi256.c
@@ -122,8 +122,10 @@
 	{0x72, 0x81},
 	{0x30, 0x0c},
 	{0x31, 0x80},
-	{0x03, 0x00},
-	{0x01, 0xf0},
+	{0x03, 0x20},
+	{0x10, 0x9c},
+	{0x03, 0x22},
+	{0x10, 0xe9},
 };
 
 static struct msm_camera_i2c_reg_conf hi256_start_settings[] = {
@@ -151,7 +153,7 @@
 
 	{0x03, 0x00},
 	{0x10, 0x13},
-	{0x11, 0x93},
+	{0x11, 0x90}, /* no H/V flip */
 	{0x12, 0x00},
 	{0x0b, 0xaa},
 	{0x0c, 0xaa},
@@ -165,9 +167,9 @@
 	{0x26, 0x06},
 	{0x27, 0x40},
 	{0x40, 0x01},
-	{0x41, 0x78},
+	{0x41, 0x18},
 	{0x42, 0x00},
-	{0x43, 0x14},
+	{0x43, 0x02},
 	{0x45, 0x04},
 	{0x46, 0x18},
 	{0x47, 0xd8},
@@ -177,8 +179,8 @@
 	{0x83, 0x00},
 	{0x84, 0x0c},
 	{0x85, 0x00},
-	{0x90, 0x0c},
-	{0x91, 0x0c},
+	{0x90, 0x0a},
+	{0x91, 0x0a},
 	{0x92, 0x78},
 	{0x93, 0x70},
 	{0x94, 0xff},
@@ -186,14 +188,14 @@
 	{0x96, 0xdc},
 	{0x97, 0xfe},
 	{0x98, 0x38},
-	{0xa0, 0x45},
-	{0xa2, 0x45},
-	{0xa4, 0x45},
-	{0xa6, 0x45},
-	{0xa8, 0x45},
-	{0xaa, 0x45},
-	{0xac, 0x45},
-	{0xae, 0x45},
+	{0xa0, 0x48},
+	{0xa2, 0x48},
+	{0xa4, 0x48},
+	{0xa6, 0x48},
+	{0xa8, 0x49},
+	{0xaa, 0x49},
+	{0xac, 0x49},
+	{0xae, 0x49},
 	{0x99, 0x43},
 	{0x9a, 0x43},
 	{0x9b, 0x43},
@@ -201,7 +203,6 @@
 	{0x03, 0x02},
 	{0x12, 0x03},
 	{0x13, 0x03},
-	{0x15, 0x00},
 	{0x16, 0x00},
 	{0x17, 0x8C},
 	{0x18, 0x4c},
@@ -212,22 +213,19 @@
 	{0x1e, 0x30},
 	{0x1f, 0x10},
 	{0x20, 0x77},
-	{0x21, 0x6d},
-	{0x22, 0x77},
+	{0x21, 0xde},
+	{0x22, 0xa7},
 	{0x23, 0x30},
-	{0x24, 0x77},
 	{0x27, 0x3c},
 	{0x2b, 0x80},
-	{0x2e, 0x00},
-	{0x2f, 0x00},
+	{0x2e, 0x11},
+	{0x2f, 0xa1},
 	{0x30, 0x05},
 	{0x50, 0x20},
 	{0x52, 0x01},
 	{0x53, 0xc1},
 	{0x55, 0x1c},
 	{0x56, 0x11},
-	{0x58, 0x22},
-	{0x59, 0x20},
 	{0x5d, 0xa2},
 	{0x5e, 0x5a},
 	{0x60, 0x87},
@@ -307,8 +305,8 @@
 	{0xcf, 0x78},
 	{0xd0, 0x0a},
 	{0xd1, 0x09},
-	{0xd4, 0x0c},
-	{0xd5, 0x0c},
+	{0xd4, 0x0a},
+	{0xd5, 0x0a},
 	{0xd6, 0x78},
 	{0xd7, 0x70},
 	{0xe0, 0xc4},
@@ -319,17 +317,17 @@
 	{0xe8, 0x80},
 	{0xe9, 0x40},
 	{0xea, 0x7f},
-	{0xf0, 0xc1},
-	{0xf1, 0xc1},
-	{0xf2, 0xc1},
-	{0xf3, 0xc1},
-	{0xf4, 0xc1},
+	{0xf0, 0x01},
+	{0xf1, 0x01},
+	{0xf2, 0x01},
+	{0xf3, 0x01},
+	{0xf4, 0x01},
 	{0x03, 0x03},
 	{0x10, 0x10},
 	{0x03, 0x10},
 	{0x10, 0x03},
 	{0x12, 0x30},
-	{0x13, 0x02},
+	{0x13, 0x0a},
 	{0x20, 0x00},
 	{0x30, 0x00},
 	{0x31, 0x00},
@@ -343,18 +341,18 @@
 	{0x3f, 0x00},
 	{0x40, 0x80},
 	{0x41, 0x00},
-	{0x48, 0x95},
+	{0x48, 0x90},
 	{0x60, 0x67},
-	{0x61, 0x88},
-	{0x62, 0x90},
+	{0x61, 0x95},
+	{0x62, 0x95},
 	{0x63, 0x50},
 	{0x64, 0x41},
 	{0x66, 0x42},
 	{0x67, 0x20},
-	{0x6a, 0x71},
-	{0x6b, 0x84},
-	{0x6c, 0x72},
-	{0x6d, 0x83},
+	{0x6a, 0x80},
+	{0x6b, 0x80},
+	{0x6c, 0x80},
+	{0x6d, 0x80},
 	{0x03, 0x11},
 	{0x10, 0x7f},
 	{0x11, 0x40},
@@ -381,15 +379,15 @@
 	{0x3c, 0x80},
 	{0x3d, 0x18},
 	{0x3e, 0x80},
-	{0x3f, 0x0c},
-	{0x40, 0x05},
-	{0x41, 0x06},
+	{0x3f, 0x0D},
+	{0x40, 0x0A},
+	{0x41, 0x08},
 	{0x42, 0x80},
 	{0x43, 0x18},
 	{0x44, 0x80},
-	{0x45, 0x0c},
-	{0x46, 0x05},
-	{0x47, 0x06},
+	{0x45, 0x12},
+	{0x46, 0x10},
+	{0x47, 0x10},
 	{0x48, 0x90},
 	{0x49, 0x40},
 	{0x4a, 0x80},
@@ -408,25 +406,25 @@
 	{0x57, 0x01},
 	{0x58, 0x00},
 	{0x59, 0x00},
-	{0x5a, 0x18},
-	{0x5b, 0x00},
+	{0x5a, 0x1f},
+	{0x5b, 0x3f},
 	{0x5c, 0x00},
 	{0x60, 0x3f},
-	{0x62, 0x60},
+	{0x62, 0x10},
 	{0x70, 0x06},
 	{0x03, 0x12},
-	{0x20, 0x00},
-	{0x21, 0x00},
-	{0x25, 0x00},
+	{0x20, 0x0f},
+	{0x21, 0x0f},
+	{0x25, 0x30},
 	{0x28, 0x00},
 	{0x29, 0x00},
 	{0x2a, 0x00},
-	{0x30, 0x50},
-	{0x31, 0x18},
-	{0x32, 0x32},
-	{0x33, 0x40},
-	{0x34, 0x50},
-	{0x35, 0x70},
+	{0x30, 0x30},
+	{0x31, 0x38},
+	{0x32, 0x42},
+	{0x33, 0x60},
+	{0x34, 0x70},
+	{0x35, 0x80},
 	{0x36, 0xa0},
 	{0x40, 0xa0},
 	{0x41, 0x40},
@@ -442,22 +440,22 @@
 	{0x4b, 0x80},
 	{0x4c, 0xb0},
 	{0x4d, 0x40},
-	{0x4e, 0x90},
-	{0x4f, 0x60},
-	{0x50, 0xa0},
+	{0x4e, 0xb0},
+	{0x4f, 0xb0},
+	{0x50, 0xc0},
 	{0x51, 0x80},
 	{0x52, 0xb0},
-	{0x53, 0x40},
-	{0x54, 0x90},
-	{0x55, 0x60},
-	{0x56, 0xa0},
-	{0x57, 0x80},
+	{0x53, 0x60},
+	{0x54, 0xc0},
+	{0x55, 0xc0},
+	{0x56, 0xb0},
+	{0x57, 0x70},
 	{0x58, 0x90},
 	{0x59, 0x40},
 	{0x5a, 0xd0},
 	{0x5b, 0xd0},
-	{0x5c, 0xe0},
-	{0x5d, 0x80},
+	{0x5c, 0xc0},
+	{0x5d, 0x70},
 	{0x5e, 0x88},
 	{0x5f, 0x40},
 	{0x60, 0xe0},
@@ -479,12 +477,12 @@
 	{0x90, 0x5d},
 	{0xD0, 0x0c},
 	{0xD1, 0x80},
-	{0xD2, 0x17},
+	{0xD2, 0x67},
 	{0xD3, 0x00},
 	{0xD4, 0x00},
-	{0xD5, 0x0f},
+	{0xD5, 0x02},
 	{0xD6, 0xff},
-	{0xD7, 0xff},
+	{0xD7, 0x18},
 	{0x3b, 0x06},
 	{0x3c, 0x06},
 	{0xc5, 0x00},
@@ -615,19 +613,19 @@
 	{0x18, 0x80},
 	{0x19, 0x80},
 	{0x20, 0x80},
-	{0x21, 0x80},
-	{0x22, 0x80},
-	{0x23, 0x80},
-	{0x24, 0x80},
+	{0x21, 0x95},
+	{0x22, 0xdc},
+	{0x23, 0xcb},
+	{0x24, 0xcf},
 	{0x30, 0xc8},
 	{0x31, 0x2b},
 	{0x32, 0x00},
 	{0x33, 0x00},
 	{0x34, 0x90},
-	{0x40, 0x32},
-	{0x50, 0x21},
-	{0x60, 0x19},
-	{0x70, 0x21},
+	{0x40, 0x54},
+	{0x50, 0x4b},
+	{0x60, 0x42},
+	{0x70, 0x4b},
 	{0x03, 0x15},
 	{0x10, 0x0f},
 	{0x14, 0x46},
@@ -738,7 +736,6 @@
 	{0xC5, 0x55},
 	{0x03, 0x20},
 	{0x11, 0x1c},
-	{0x18, 0x30},
 	{0x1a, 0x08},
 	{0x20, 0x05},
 	{0x21, 0x30},
@@ -753,7 +750,7 @@
 	{0x2c, 0xc2},
 	{0x2d, 0xff},
 	{0x2e, 0x33},
-	{0x30, 0x78},
+	{0x30, 0xf8},
 	{0x32, 0x03},
 	{0x33, 0x2e},
 	{0x34, 0x30},
@@ -772,24 +769,24 @@
 	{0x58, 0x14},
 	{0x59, 0x88},
 	{0x5a, 0x04},
-	{0x60, 0xaa},
-	{0x61, 0xaa},
-	{0x62, 0xaa},
-	{0x63, 0xaa},
-	{0x64, 0xaa},
-	{0x65, 0xaa},
-	{0x66, 0xab},
-	{0x67, 0xEa},
-	{0x68, 0xab},
-	{0x69, 0xEa},
-	{0x6a, 0xaa},
-	{0x6b, 0xaa},
-	{0x6c, 0xaa},
-	{0x6d, 0xaa},
-	{0x6e, 0xaa},
-	{0x6f, 0xaa},
+	{0x60, 0x55},
+	{0x61, 0x55},
+	{0x62, 0x6A},
+	{0x63, 0xA9},
+	{0x64, 0x6A},
+	{0x65, 0xA9},
+	{0x66, 0x6B},
+	{0x67, 0xE9},
+	{0x68, 0x6B},
+	{0x69, 0xE9},
+	{0x6a, 0x6A},
+	{0x6b, 0xA9},
+	{0x6c, 0x6A},
+	{0x6d, 0xA9},
+	{0x6e, 0x55},
+	{0x6f, 0x55},
 	{0x70, 0x76},
-	{0x71, 0x80},
+	{0x71, 0x82},
 	{0x76, 0x43},
 	{0x77, 0x04},
 	{0x78, 0x23},
@@ -801,18 +798,18 @@
 	{0x84, 0x5f},
 	{0x85, 0x90},
 	{0x86, 0x01},
-	{0x87, 0x2c},
-	{0x88, 0x05},
-	{0x89, 0x7e},
-	{0x8a, 0x40},
+	{0x87, 0xe0},
+	{0x88, 0x04},
+	{0x89, 0x93},
+	{0x8a, 0xe0},
 	{0x8B, 0x75},
 	{0x8C, 0x30},
 	{0x8D, 0x61},
-	{0x8E, 0x44},
-	{0x9c, 0x08},
-	{0x9d, 0x34},
+	{0x8E, 0x80},
+	{0x9c, 0x16},
+	{0x9d, 0x80},
 	{0x9e, 0x01},
-	{0x9f, 0x2c},
+	{0x9f, 0xe0},
 	{0xb0, 0x18},
 	{0xb1, 0x14},
 	{0xb2, 0x80},
@@ -847,7 +844,7 @@
 	{0x39, 0x34},
 	{0x40, 0xfa},
 	{0x41, 0x44},
-	{0x42, 0x43},
+	{0x42, 0x33},
 	{0x43, 0xf6},
 	{0x44, 0x44},
 	{0x45, 0x33},
@@ -858,18 +855,35 @@
 	{0x80, 0x38},
 	{0x81, 0x20},
 	{0x82, 0x38},
-	{0x83, 0x5e},
-	{0x84, 0x18},
-	{0x85, 0x58},
-	{0x86, 0x20},
+	{0x83, 0x60},
+	{0x84, 0x0a},
+	{0x85, 0x60},
+	{0x86, 0x15},
 	{0x87, 0x49},
-	{0x88, 0x33},
-	{0x89, 0x37},
-	{0x8a, 0x2a},
+	{0x88, 0x10},
+	{0x89, 0x50},
+	{0x8a, 0x20},
 	{0x8b, 0x41},
 	{0x8c, 0x39},
 	{0x8d, 0x34},
-	{0x8e, 0x29},
+	{0x8e, 0x28},
+	{0x8f, 0x52},
+	{0x90, 0x50},
+	{0x91, 0x4c},
+	{0x92, 0x49},
+	{0x93, 0x44},
+	{0x94, 0x3b},
+	{0x95, 0x37},
+	{0x96, 0x31},
+	{0x97, 0x28},
+	{0x98, 0x24},
+	{0x99, 0x20},
+	{0x9a, 0x20},
+	{0x9b, 0x88},
+	{0x9c, 0x88},
+	{0x9d, 0x48},
+	{0x9e, 0x38},
+	{0x9f, 0x30},
 	{0x8f, 0x53},
 	{0x90, 0x52},
 	{0x91, 0x51},
@@ -882,11 +896,6 @@
 	{0x98, 0x22},
 	{0x99, 0x1c},
 	{0x9a, 0x18},
-	{0x9b, 0x77},
-	{0x9c, 0x77},
-	{0x9d, 0x48},
-	{0x9e, 0x38},
-	{0x9f, 0x30},
 	{0xa0, 0x60},
 	{0xa1, 0x34},
 	{0xa2, 0x6f},
@@ -958,6 +967,14 @@
 	{0x03, 0x00},
 	{0x0e, 0x03},
 	{0x0e, 0x73},
+	{0x03, 0x20},
+	{0x88, 0x01},
+	{0x89, 0x5f},
+	{0x8a, 0x90},
+	{0x03, 0x20},
+	{0x10, 0x9c},
+	{0x03, 0x22},
+	{0x10, 0xe9},
 	{0x03, 0x00},
 	{0x01, 0xf0},
 };
@@ -1000,23 +1017,478 @@
 	{0x30, 0x06},
 	{0x31, 0x40},
 	{0x03, 0x20},
-	{0x88, 0x01},
-	{0x89, 0x5f},
-	{0x8a, 0x90},
-	{0x03, 0x20},
 	{0x10, 0x9c},
 	{0x03, 0x22},
 	{0x10, 0xe9},
 };
 
 static struct msm_camera_i2c_reg_conf hi256_sleep_settings[] = {
+
 	{0x03, 0x00},
 	{0x01, 0xf1},
 	{0x03, 0x02},
 	{0x55, 0x10},
+
 	{0x01, 0xf1},
 	{0x01, 0xf3},
 	{0x01, 0xf1},
+
+};
+
+static struct msm_camera_i2c_reg_conf HI256_reg_saturation[11][3] = {
+	{
+		{0x03, 0x10},
+		{0x61, 0x1c},
+		{0x62, 0x1c},
+	},
+	{
+		{0x03, 0x10},
+		{0x61, 0x30},
+		{0x62, 0x30},
+	},
+	{
+		{0x03, 0x10},
+		{0x61, 0x44},
+		{0x62, 0x44},
+	},
+	{
+		{0x03, 0x10},
+		{0x61, 0x58},
+		{0x62, 0x58},
+	},
+	{
+		{0x03, 0x10},
+		{0x61, 0x6c},
+		{0x62, 0x6c},
+	},
+	{
+		{0x03, 0x10},
+		{0x61, 0x95},
+		{0x62, 0x95},
+	},
+	{
+		{0x03, 0x10},
+		{0x61, 0xa0},
+		{0x62, 0xa0},
+	},
+	{
+		{0x03, 0x10},
+		{0x61, 0xa8},
+		{0x62, 0xa8},
+	},
+	{
+		{0x03, 0x10},
+		{0x61, 0xbc},
+		{0x62, 0xbc},
+	},
+	{
+		{0x03, 0x10},
+		{0x61, 0xd0},
+		{0x62, 0xd0},
+	},
+	{
+		{0x03, 0x10},
+		{0x61, 0xe4},
+		{0x62, 0xe4},
+	},
+};
+
+static struct msm_camera_i2c_reg_conf HI256_reg_contrast[11][3] = {
+	{
+		{0x03, 0x10},
+		{0x13, 0x02},
+		{0x48, 0x1c},
+	},
+	{
+		{0x03, 0x10},
+		{0x13, 0x02},
+		{0x48, 0x30},
+	},
+	{
+		{0x03, 0x10},
+		{0x13, 0x02},
+		{0x48, 0x44},
+	},
+	{
+		{0x03, 0x10},
+		{0x13, 0x02},
+		{0x48, 0x58},
+	},
+	{
+		{0x03, 0x10},
+		{0x13, 0x02},
+		{0x48, 0x6c},
+	},
+	{
+		{0x03, 0x10},
+		{0x13, 0x02},
+		{0x48, 0x90},
+	},
+	{
+		{0x03, 0x10},
+		{0x13, 0x02},
+		{0x48, 0x94},
+	},
+	{
+		{0x03, 0x10},
+		{0x13, 0x02},
+		{0x48, 0xa8},
+	},
+	{
+		{0x03, 0x10},
+		{0x13, 0x02},
+		{0x48, 0xbc},
+	},
+	{
+		{0x03, 0x10},
+		{0x13, 0x02},
+		{0x48, 0xd0},
+	},
+	{
+		{0x03, 0x10},
+		{0x13, 0x02},
+		{0x48, 0xe4},
+	},
+};
+
+static struct msm_camera_i2c_reg_conf HI256_reg_sharpness[7][9] = {
+	{
+		{0x03, 0x13},
+		{0x20, 0x00},
+		{0x21, 0x00},
+		{0x23, 0x04},
+		{0x24, 0x80},
+		{0x90, 0x00},
+		{0x91, 0x00},
+		{0x94, 0x24},
+		{0x95, 0x65},
+	}, /* SHARPNESS LEVEL 0*/
+	{
+		{0x03, 0x13},
+		{0x20, 0x04},
+		{0x21, 0x03},
+		{0x23, 0x04},
+		{0x24, 0x80},
+		{0x90, 0x08},
+		{0x91, 0x08},
+		{0x94, 0x24},
+		{0x95, 0x65},
+	}, /* SHARPNESS LEVEL 1*/
+	{
+		{0x03, 0x13},
+		{0x20, 0x08},
+		{0x21, 0x07},
+		{0x23, 0x04},
+		{0x24, 0x80},
+		{0x90, 0x32},
+		{0x91, 0x32},
+		{0x94, 0x04},
+		{0x95, 0x0a},
+	}, /* SHARPNESS LEVEL 2*/
+	{
+		{0x03, 0x13},
+		{0x20, 0x15},
+		{0x21, 0x15},
+		{0x23, 0x09},
+		{0x24, 0x11},
+		{0x90, 0x05},
+		{0x91, 0x05},
+		{0x94, 0x10},
+		{0x95, 0x5a},
+	}, /* SHARPNESS LEVEL 3*/
+	{
+		{0x03, 0x13},
+		{0x20, 0x15},
+		{0x21, 0x15},
+		{0x23, 0x04},
+		{0x24, 0x80},
+		{0x90, 0xaf},
+		{0x91, 0xaf},
+		{0x94, 0x24},
+		{0x95, 0x65},
+	}, /* SHARPNESS LEVEL 4*/
+	{
+		{0x03, 0x13},
+		{0x20, 0x20},
+		{0x21, 0x20},
+		{0x23, 0x04},
+		{0x24, 0x80},
+		{0x90, 0xdf},
+		{0x91, 0xdf},
+		{0x94, 0x24},
+		{0x95, 0x65},
+	}, /* SHARPNESS LEVEL 5*/
+	{
+		{0x03, 0x13},
+		{0x20, 0x25},
+		{0x21, 0x25},
+		{0x23, 0x04},
+		{0x24, 0x80},
+		{0x90, 0xff},
+		{0x91, 0xff},
+		{0x94, 0x24},
+		{0x95, 0x65},
+	}, /* SHARPNESS LEVEL 6*/
+};
+
+static struct msm_camera_i2c_reg_conf HI256_reg_iso[7][3] = {
+	/* auto */
+	{
+		{0x03, 0x20},
+		{0x10, 0x9c},
+		{0xb0, 0x18},
+	},
+	/* auto hjt */
+	{
+		{0x03, 0x20},
+		{0x10, 0x9c},
+		{0xb0, 0x18},
+	},
+	/* iso 100 */
+	{
+		{0x03, 0x20},
+		{0x10, 0x0c},
+		{0xb0, 0x1B},
+	},
+	/* iso 200 */
+	{
+		{0x03, 0x20},
+		{0x10, 0x0c},
+		{0xb0, 0x35},
+	},
+	/* iso 400 */
+	{
+		{0x03, 0x20},
+		{0x10, 0x0c},
+		{0xb0, 0x65},
+	},
+	/* iso 800 */
+	{
+		{0x03, 0x20},
+		{0x10, 0x0c},
+		{0xb0, 0x95},
+	},
+	/* iso 1600 */
+	{
+		{0x03, 0x20},
+		{0x10, 0x0c},
+		{0xb0, 0xd0},
+	},
+};
+
+static struct msm_camera_i2c_reg_conf HI256_reg_exposure_compensation[5][2] = {
+	/* -2 */
+	{
+		{0x03, 0x10},
+		{0x40, 0x94},
+	},
+	/* -1 */
+	{
+		{0x03, 0x10},
+		{0x40, 0x80},
+	},
+	/* 0 */
+	{
+		{0x03, 0x10},
+		{0x40, 0x14},
+	},
+	/* 1 */
+	{
+		{0x03, 0x10},
+		{0x40, 0x24},
+	},
+	/* 2 */
+	{
+		{0x03, 0x10},
+		{0x40, 0x34},
+	},
+};
+
+static struct msm_camera_i2c_reg_conf HI256_reg_antibanding[][2] = {
+	/* OFF */
+	{
+		{0x03, 0x20},
+		{0x10, 0xcc},
+	},
+	/* 50Hz */
+	{
+		{0x03, 0x20},
+		{0x10, 0x9c},
+	},
+	/* 60Hz */
+	{
+		{0x03, 0x20},
+		{0x10, 0x8c},
+	},
+	/* AUTO */
+	{
+		{0x03, 0x20},
+		{0x10, 0xcc},
+	},
+};
+
+static struct msm_camera_i2c_reg_conf HI256_reg_effect_normal[] = {
+	/* normal: */
+	{0x03, 0x20},
+	{0x28, 0xe7},
+	{0x03, 0x10},
+	{0x11, 0x03},
+	{0x12, 0X30},
+	{0x13, 0x0a},
+	{0x44, 0x80},
+	{0x45, 0x80},
+};
+
+static struct msm_camera_i2c_reg_conf HI256_reg_effect_black_white[] = {
+	/* B&W: */
+	{0x03, 0x20},
+	{0x28, 0xe7},
+	{0x03, 0x10},
+	{0x11, 0x03},
+	{0x12, 0x33},
+	{0x13, 0x02},
+	{0x44, 0x80},
+	{0x45, 0x80},
+};
+
+static struct msm_camera_i2c_reg_conf HI256_reg_effect_negative[] = {
+	/* Negative: */
+	{0x03, 0x20},
+	{0x28, 0xe7},
+	{0x03, 0x10},
+	{0x11, 0x03},
+	{0x12, 0x08},
+	{0x13, 0x0a},
+	{0x14, 0x00},
+};
+
+static struct msm_camera_i2c_reg_conf HI256_reg_effect_old_movie[] = {
+	/* Sepia(antique): */
+	{0x03, 0x20},
+	{0x28, 0xe7},
+	{0x03, 0x10},
+	{0x11, 0x03},
+	{0x12, 0x33},
+	{0x13, 0x0a},
+	{0x44, 0x25},
+	{0x45, 0xa6},
+};
+
+static struct msm_camera_i2c_reg_conf HI256_reg_effect_solarize[] = {
+	{0x03, 0x20},
+	{0x28, 0xe7},
+	{0x03, 0x10},
+	{0x11, 0x0b},
+	{0x12, 0x00},
+	{0x13, 0x00},
+	{0x14, 0x00},
+};
+
+static struct msm_camera_i2c_reg_conf HI256_reg_scene_auto[] = {
+	/* <SCENE_auto> */
+	{0x03, 0x20},
+	{0x10, 0x1c},
+	{0x18, 0x38},
+	{0x88, 0x01},
+	{0x89, 0x5f},
+	{0x8a, 0x90},
+	{0x10, 0x9c},
+	{0x18, 0x30},
+};
+
+static struct msm_camera_i2c_reg_conf HI256_reg_scene_portrait[] = {
+	/* <CAMTUNING_SCENE_PORTRAIT> */
+	{0x03, 0x20},
+	{0x10, 0x1c},
+	{0x18, 0x38},
+	{0x88, 0x05},
+	{0x89, 0x7e},
+	{0x8a, 0x40},
+	{0x10, 0x9c},
+	{0x18, 0x30},
+};
+
+static struct msm_camera_i2c_reg_conf HI256_reg_scene_landscape[] = {
+	/* <CAMTUNING_SCENE_LANDSCAPE> */
+	{0x03, 0x20},
+	{0x10, 0x1c},
+	{0x18, 0x38},
+	{0x88, 0x05},
+	{0x89, 0x7e},
+	{0x8a, 0x40},
+	{0x10, 0x9c},
+	{0x18, 0x30},
+};
+
+static struct msm_camera_i2c_reg_conf HI256_reg_scene_night[] = {
+	/* <SCENE_NIGHT> */
+	{0x03, 0x20},
+	{0x10, 0x1c},
+	{0x18, 0x38},
+	{0x88, 0x09},
+	{0x89, 0x27},
+	{0x8a, 0xc0},
+	{0x10, 0x9c},
+	{0x18, 0x30},
+};
+
+static struct msm_camera_i2c_reg_conf HI256_reg_wb_auto[] = {
+	/* Auto: */
+	{0x03, 0x22},
+	{0x11, 0x2e},
+	{0x83, 0x60},
+	{0x84, 0x0a},
+	{0x85, 0x60},
+	{0x86, 0x15},
+	{0x10, 0xfd},
+};
+
+static struct msm_camera_i2c_reg_conf HI256_reg_wb_sunny[] = {
+	/* Sunny: */
+	{0x03, 0x22},
+	{0x11, 0x28},
+	{0x80, 0x33},
+	{0x82, 0x3d},
+	{0x83, 0x2e},
+	{0x84, 0x24},
+	{0x85, 0x43},
+	{0x86, 0x3d},
+};
+
+static struct msm_camera_i2c_reg_conf HI256_reg_wb_cloudy[] = {
+	/* Cloudy: */
+	{0x03, 0x22},
+	{0x11, 0x28},
+	{0x80, 0x49},
+	{0x82, 0x24},
+	{0x83, 0x50},
+	{0x84, 0x45},
+	{0x85, 0x24},
+	{0x86, 0x1E},
+};
+
+static struct msm_camera_i2c_reg_conf HI256_reg_wb_office[] = {
+	/* Office: */
+	{0x03, 0x22},
+	{0x11, 0x28},
+	{0x80, 0x20},
+	{0x82, 0x58},
+	{0x83, 0x27},
+	{0x84, 0x22},
+	{0x85, 0x58},
+	{0x86, 0x52},
+};
+
+static struct msm_camera_i2c_reg_conf HI256_reg_wb_home[] = {
+	/* Home: */
+	{0x03, 0x22},
+	{0x11, 0x28},
+	{0x80, 0x29},
+	{0x82, 0x54},
+	{0x83, 0x2e},
+	{0x84, 0x23},
+	{0x85, 0x58},
+	{0x86, 0x4f},
 };
 
 
@@ -1080,7 +1552,6 @@
 		}
 		table++;
 	}
-
 }
 
 static int32_t hi256_sensor_power_down(struct msm_sensor_ctrl_t *s_ctrl)
@@ -1144,6 +1615,153 @@
 	return rc;
 }
 
+static void hi256_set_stauration(struct msm_sensor_ctrl_t *s_ctrl, int value)
+{
+	pr_debug("%s %d", __func__, value);
+	hi256_i2c_write_table(s_ctrl, &HI256_reg_saturation[value][0],
+		ARRAY_SIZE(HI256_reg_saturation[value]));
+}
+
+static void hi256_set_contrast(struct msm_sensor_ctrl_t *s_ctrl, int value)
+{
+	pr_debug("%s %d", __func__, value);
+	hi256_i2c_write_table(s_ctrl, &HI256_reg_contrast[value][0],
+		ARRAY_SIZE(HI256_reg_contrast[value]));
+}
+
+static void hi256_set_sharpness(struct msm_sensor_ctrl_t *s_ctrl, int value)
+{
+	int val = value / 6;
+	pr_debug("%s %d", __func__, value);
+	hi256_i2c_write_table(s_ctrl, &HI256_reg_sharpness[val][0],
+		ARRAY_SIZE(HI256_reg_sharpness[val]));
+}
+
+
+static void hi256_set_iso(struct msm_sensor_ctrl_t *s_ctrl, int value)
+{
+	pr_debug("%s %d", __func__, value);
+	hi256_i2c_write_table(s_ctrl, &HI256_reg_iso[value][0],
+		ARRAY_SIZE(HI256_reg_iso[value]));
+}
+
+static void hi256_set_exposure_compensation(struct msm_sensor_ctrl_t *s_ctrl,
+	int value)
+{
+	int val = (value + 12) / 6;
+	pr_debug("%s %d", __func__, val);
+	hi256_i2c_write_table(s_ctrl, &HI256_reg_exposure_compensation[val][0],
+		ARRAY_SIZE(HI256_reg_exposure_compensation[val]));
+}
+
+static void hi256_set_effect(struct msm_sensor_ctrl_t *s_ctrl, int value)
+{
+	pr_debug("%s %d", __func__, value);
+	switch (value) {
+	case MSM_CAMERA_EFFECT_MODE_OFF: {
+		hi256_i2c_write_table(s_ctrl, &HI256_reg_effect_normal[0],
+			ARRAY_SIZE(HI256_reg_effect_normal));
+		break;
+	}
+	case MSM_CAMERA_EFFECT_MODE_MONO: {
+		hi256_i2c_write_table(s_ctrl, &HI256_reg_effect_black_white[0],
+			ARRAY_SIZE(HI256_reg_effect_black_white));
+		break;
+	}
+	case MSM_CAMERA_EFFECT_MODE_NEGATIVE: {
+		hi256_i2c_write_table(s_ctrl, &HI256_reg_effect_negative[0],
+			ARRAY_SIZE(HI256_reg_effect_negative));
+		break;
+	}
+	case MSM_CAMERA_EFFECT_MODE_SEPIA: {
+		hi256_i2c_write_table(s_ctrl, &HI256_reg_effect_old_movie[0],
+			ARRAY_SIZE(HI256_reg_effect_old_movie));
+		break;
+	}
+	case MSM_CAMERA_EFFECT_MODE_SOLARIZE: {
+		hi256_i2c_write_table(s_ctrl, &HI256_reg_effect_solarize[0],
+			ARRAY_SIZE(HI256_reg_effect_solarize));
+		break;
+	}
+	default:
+		hi256_i2c_write_table(s_ctrl, &HI256_reg_effect_normal[0],
+			ARRAY_SIZE(HI256_reg_effect_normal));
+	}
+}
+
+static void hi256_set_antibanding(struct msm_sensor_ctrl_t *s_ctrl, int value)
+{
+	pr_debug("%s %d", __func__, value);
+	hi256_i2c_write_table(s_ctrl, &HI256_reg_antibanding[value][0],
+		ARRAY_SIZE(HI256_reg_antibanding[value]));
+}
+
+static void hi256_set_scene_mode(struct msm_sensor_ctrl_t *s_ctrl, int value)
+{
+	pr_debug("%s %d", __func__, value);
+	switch (value) {
+	case MSM_CAMERA_SCENE_MODE_OFF: {
+		hi256_i2c_write_table(s_ctrl, &HI256_reg_scene_auto[0],
+			ARRAY_SIZE(HI256_reg_scene_auto));
+		break;
+	}
+	case MSM_CAMERA_SCENE_MODE_NIGHT: {
+		hi256_i2c_write_table(s_ctrl, &HI256_reg_scene_night[0],
+			ARRAY_SIZE(HI256_reg_scene_night));
+					break;
+	}
+	case MSM_CAMERA_SCENE_MODE_LANDSCAPE: {
+		hi256_i2c_write_table(s_ctrl, &HI256_reg_scene_landscape[0],
+			ARRAY_SIZE(HI256_reg_scene_landscape));
+		break;
+	}
+	case MSM_CAMERA_SCENE_MODE_PORTRAIT: {
+		hi256_i2c_write_table(s_ctrl, &HI256_reg_scene_portrait[0],
+			ARRAY_SIZE(HI256_reg_scene_portrait));
+		break;
+	}
+	default:
+		hi256_i2c_write_table(s_ctrl, &HI256_reg_scene_auto[0],
+			ARRAY_SIZE(HI256_reg_scene_auto));
+	}
+}
+
+static void hi256_set_white_balance_mode(struct msm_sensor_ctrl_t *s_ctrl,
+	int value)
+{
+	pr_debug("%s %d", __func__, value);
+	switch (value) {
+	case MSM_CAMERA_WB_MODE_AUTO: {
+		hi256_i2c_write_table(s_ctrl, &HI256_reg_wb_auto[0],
+			ARRAY_SIZE(HI256_reg_wb_auto));
+		break;
+	}
+	case MSM_CAMERA_WB_MODE_INCANDESCENT: {
+		hi256_i2c_write_table(s_ctrl, &HI256_reg_wb_home[0],
+			ARRAY_SIZE(HI256_reg_wb_home));
+		break;
+	}
+	case MSM_CAMERA_WB_MODE_DAYLIGHT: {
+		hi256_i2c_write_table(s_ctrl, &HI256_reg_wb_sunny[0],
+			ARRAY_SIZE(HI256_reg_wb_sunny));
+					break;
+	}
+	case MSM_CAMERA_WB_MODE_FLUORESCENT: {
+		hi256_i2c_write_table(s_ctrl, &HI256_reg_wb_office[0],
+			ARRAY_SIZE(HI256_reg_wb_office));
+					break;
+	}
+	case MSM_CAMERA_WB_MODE_CLOUDY_DAYLIGHT: {
+		hi256_i2c_write_table(s_ctrl, &HI256_reg_wb_cloudy[0],
+			ARRAY_SIZE(HI256_reg_wb_cloudy));
+					break;
+	}
+	default:
+		hi256_i2c_write_table(s_ctrl, &HI256_reg_wb_auto[0],
+		ARRAY_SIZE(HI256_reg_wb_auto));
+	}
+}
+
 int32_t hi256_sensor_config(struct msm_sensor_ctrl_t *s_ctrl,
 	void __user *argp)
 {
@@ -1397,6 +2015,117 @@
 		}
 		break;
 	}
+	case CFG_SET_SATURATION: {
+		int32_t sat_lev;
+		if (copy_from_user(&sat_lev, (void *)cdata->cfg.setting,
+			sizeof(int32_t))) {
+			pr_err("%s:%d failed\n", __func__, __LINE__);
+			rc = -EFAULT;
+			break;
+		}
+		pr_debug("%s: Saturation Value is %d", __func__, sat_lev);
+		hi256_set_stauration(s_ctrl, sat_lev);
+		break;
+	}
+	case CFG_SET_CONTRAST: {
+		int32_t con_lev;
+		if (copy_from_user(&con_lev, (void *)cdata->cfg.setting,
+			sizeof(int32_t))) {
+			pr_err("%s:%d failed\n", __func__, __LINE__);
+			rc = -EFAULT;
+			break;
+		}
+		pr_debug("%s: Contrast Value is %d", __func__, con_lev);
+		hi256_set_contrast(s_ctrl, con_lev);
+		break;
+	}
+	case CFG_SET_SHARPNESS: {
+		int32_t shp_lev;
+		if (copy_from_user(&shp_lev, (void *)cdata->cfg.setting,
+			sizeof(int32_t))) {
+			pr_err("%s:%d failed\n", __func__, __LINE__);
+			rc = -EFAULT;
+			break;
+		}
+		pr_debug("%s: Sharpness Value is %d", __func__, shp_lev);
+		hi256_set_sharpness(s_ctrl, shp_lev);
+		break;
+	}
+	case CFG_SET_ISO: {
+		int32_t iso_lev;
+		if (copy_from_user(&iso_lev, (void *)cdata->cfg.setting,
+			sizeof(int32_t))) {
+			pr_err("%s:%d failed\n", __func__, __LINE__);
+			rc = -EFAULT;
+			break;
+		}
+		pr_debug("%s: ISO Value is %d", __func__, iso_lev);
+		hi256_set_iso(s_ctrl, iso_lev);
+		break;
+	}
+	case CFG_SET_EXPOSURE_COMPENSATION: {
+		int32_t ec_lev;
+		if (copy_from_user(&ec_lev, (void *)cdata->cfg.setting,
+			sizeof(int32_t))) {
+			pr_err("%s:%d failed\n", __func__, __LINE__);
+			rc = -EFAULT;
+			break;
+		}
+		pr_debug("%s: Exposure compensation Value is %d",
+			__func__, ec_lev);
+		hi256_set_exposure_compensation(s_ctrl, ec_lev);
+		break;
+	}
+	case CFG_SET_EFFECT: {
+		int32_t effect_mode;
+		if (copy_from_user(&effect_mode, (void *)cdata->cfg.setting,
+			sizeof(int32_t))) {
+			pr_err("%s:%d failed\n", __func__, __LINE__);
+			rc = -EFAULT;
+			break;
+		}
+		pr_debug("%s: Effect mode is %d", __func__, effect_mode);
+		hi256_set_effect(s_ctrl, effect_mode);
+		break;
+	}
+	case CFG_SET_ANTIBANDING: {
+		int32_t antibanding_mode;
+		if (copy_from_user(&antibanding_mode,
+			(void *)cdata->cfg.setting,
+			sizeof(int32_t))) {
+			pr_err("%s:%d failed\n", __func__, __LINE__);
+			rc = -EFAULT;
+			break;
+		}
+		pr_debug("%s: anti-banding mode is %d", __func__,
+			antibanding_mode);
+		hi256_set_antibanding(s_ctrl, antibanding_mode);
+		break;
+	}
+	case CFG_SET_BESTSHOT_MODE: {
+		int32_t bs_mode;
+		if (copy_from_user(&bs_mode, (void *)cdata->cfg.setting,
+			sizeof(int32_t))) {
+			pr_err("%s:%d failed\n", __func__, __LINE__);
+			rc = -EFAULT;
+			break;
+		}
+		pr_debug("%s: best shot mode is %d", __func__, bs_mode);
+		hi256_set_scene_mode(s_ctrl, bs_mode);
+		break;
+	}
+	case CFG_SET_WHITE_BALANCE: {
+		int32_t wb_mode;
+		if (copy_from_user(&wb_mode, (void *)cdata->cfg.setting,
+			sizeof(int32_t))) {
+			pr_err("%s:%d failed\n", __func__, __LINE__);
+			rc = -EFAULT;
+			break;
+		}
+		pr_debug("%s: white balance is %d", __func__, wb_mode);
+		hi256_set_white_balance_mode(s_ctrl, wb_mode);
+		break;
+	}
 	default:
 		rc = -EFAULT;
 		break;
diff --git a/drivers/media/platform/msm/camera_v2/sensor/imx135.c b/drivers/media/platform/msm/camera_v2/sensor/imx135.c
index 8368a4d..c26e4ff 100644
--- a/drivers/media/platform/msm/camera_v2/sensor/imx135.c
+++ b/drivers/media/platform/msm/camera_v2/sensor/imx135.c
@@ -68,7 +68,7 @@
 	{
 		.seq_type = SENSOR_CLK,
 		.seq_val = SENSOR_CAM_MCLK,
-		.config_val = 0,
+		.config_val = 24000000,
 		.delay = 1,
 	},
 	{
diff --git a/drivers/media/platform/msm/camera_v2/sensor/io/msm_camera_dt_util.c b/drivers/media/platform/msm/camera_v2/sensor/io/msm_camera_dt_util.c
index 3898bd8..484dd69 100644
--- a/drivers/media/platform/msm/camera_v2/sensor/io/msm_camera_dt_util.c
+++ b/drivers/media/platform/msm/camera_v2/sensor/io/msm_camera_dt_util.c
@@ -111,6 +111,8 @@
 				ps[i].seq_val = SENSOR_GPIO_RESET;
 			else if (!strcmp(seq_name, "sensor_gpio_standby"))
 				ps[i].seq_val = SENSOR_GPIO_STANDBY;
+			else if (!strcmp(seq_name, "sensor_gpio_vdig"))
+				ps[i].seq_val = SENSOR_GPIO_VDIG;
 			else
 				rc = -EILSEQ;
 			break;
@@ -285,6 +287,23 @@
 		return rc;
 	}
 
+	if (of_property_read_bool(of_node, "qcom,gpio-vdig") == true) {
+		rc = of_property_read_u32(of_node, "qcom,gpio-vdig", &val);
+		if (rc < 0) {
+			pr_err("%s:%d read qcom,gpio-reset failed rc %d\n",
+				__func__, __LINE__, rc);
+			goto ERROR;
+		} else if (val >= gpio_array_size) {
+			pr_err("%s:%d qcom,gpio-reset invalid %d\n",
+				__func__, __LINE__, val);
+			goto ERROR;
+		}
+		gconf->gpio_num_info->gpio_num[SENSOR_GPIO_VDIG] =
+			gpio_array[val];
+		CDBG("%s qcom,gpio-reset %d\n", __func__,
+			gconf->gpio_num_info->gpio_num[SENSOR_GPIO_VDIG]);
+	}
+
 	if (of_property_read_bool(of_node, "qcom,gpio-reset") == true) {
 		rc = of_property_read_u32(of_node, "qcom,gpio-reset", &val);
 		if (rc < 0) {
diff --git a/drivers/media/platform/msm/camera_v2/sensor/io/msm_camera_io_util.c b/drivers/media/platform/msm/camera_v2/sensor/io/msm_camera_io_util.c
index 6bd7feb..46a0542 100644
--- a/drivers/media/platform/msm/camera_v2/sensor/io/msm_camera_io_util.c
+++ b/drivers/media/platform/msm/camera_v2/sensor/io/msm_camera_io_util.c
@@ -544,7 +544,7 @@
 int msm_camera_request_gpio_table(struct gpio *gpio_tbl, uint8_t size,
 	int gpio_en)
 {
-	int rc = 0, i = 0;
+	int rc = 0, i = 0, err = 0;
 
 	if (!gpio_tbl || !size) {
 		pr_err("%s:%d invalid gpio_tbl %p / size %d\n", __func__,
@@ -556,11 +556,19 @@
 			gpio_tbl[i].gpio, gpio_tbl[i].flags);
 	}
 	if (gpio_en) {
-		rc = gpio_request_array(gpio_tbl, size);
-		if (rc < 0) {
-			pr_err("%s:%d camera gpio request failed\n", __func__,
-				__LINE__);
-			return rc;
+		for (i = 0; i < size; i++) {
+			err = gpio_request_one(gpio_tbl[i].gpio,
+				gpio_tbl[i].flags, gpio_tbl[i].label);
+			if (err) {
+				/*
+				* After GPIO request fails, contine to
+				* apply new gpios, outout a error message
+				* for driver bringup debug
+				*/
+				pr_err("%s:%d gpio %d:%s request fails\n",
+					__func__, __LINE__,
+					gpio_tbl[i].gpio, gpio_tbl[i].label);
+			}
 		}
 	} else {
 		gpio_free_array(gpio_tbl, size);
diff --git a/drivers/media/platform/msm/camera_v2/sensor/msm_sensor.c b/drivers/media/platform/msm/camera_v2/sensor/msm_sensor.c
index adbfbe7..0083378 100644
--- a/drivers/media/platform/msm/camera_v2/sensor/msm_sensor.c
+++ b/drivers/media/platform/msm/camera_v2/sensor/msm_sensor.c
@@ -353,7 +353,7 @@
 	return rc;
 }
 
-static int32_t msm_sensor_get_dt_gpio_req_tbl(struct device_node *of_node,
+int32_t msm_sensor_get_dt_gpio_req_tbl(struct device_node *of_node,
 	struct msm_camera_gpio_conf *gconf, uint16_t *gpio_array,
 	uint16_t gpio_array_size)
 {
@@ -437,7 +437,7 @@
 	return rc;
 }
 
-static int32_t msm_sensor_get_dt_gpio_set_tbl(struct device_node *of_node,
+int32_t msm_sensor_get_dt_gpio_set_tbl(struct device_node *of_node,
 	struct msm_camera_gpio_conf *gconf, uint16_t *gpio_array,
 	uint16_t gpio_array_size)
 {
@@ -521,7 +521,7 @@
 	return rc;
 }
 
-static int32_t msm_sensor_init_gpio_pin_tbl(struct device_node *of_node,
+int32_t msm_sensor_init_gpio_pin_tbl(struct device_node *of_node,
 	struct msm_camera_gpio_conf *gconf, uint16_t *gpio_array,
 	uint16_t gpio_array_size)
 {
@@ -957,7 +957,7 @@
 };
 
 static struct msm_cam_clk_info cam_8974_clk_info[] = {
-	[SENSOR_CAM_MCLK] = {"cam_src_clk", 19200000},
+	[SENSOR_CAM_MCLK] = {"cam_src_clk", 24000000},
 	[SENSOR_CAM_CLK] = {"cam_clk", 0},
 };
 
@@ -967,6 +967,7 @@
 	struct msm_sensor_power_setting_array *power_setting_array = NULL;
 	struct msm_sensor_power_setting *power_setting = NULL;
 	struct msm_camera_sensor_board_info *data = s_ctrl->sensordata;
+	s_ctrl->stop_setting_valid = 0;
 
 	CDBG("%s:%d\n", __func__, __LINE__);
 	power_setting_array = &s_ctrl->power_setting_array;
@@ -1342,6 +1343,13 @@
 		s_ctrl->power_setting_array =
 			sensor_slave_info.power_setting_array;
 		power_setting_array = &s_ctrl->power_setting_array;
+
+		if (!power_setting_array->size) {
+			pr_err("%s:%d failed\n", __func__, __LINE__);
+			rc = -EFAULT;
+			break;
+		}
+
 		power_setting_array->power_setting = kzalloc(
 			power_setting_array->size *
 			sizeof(struct msm_sensor_power_setting), GFP_KERNEL);
@@ -1403,6 +1411,12 @@
 			break;
 		}
 
+		if (!conf_array.size) {
+			pr_err("%s:%d failed\n", __func__, __LINE__);
+			rc = -EFAULT;
+			break;
+		}
+
 		reg_setting = kzalloc(conf_array.size *
 			(sizeof(struct msm_camera_i2c_reg_array)), GFP_KERNEL);
 		if (!reg_setting) {
@@ -1492,6 +1506,12 @@
 		CDBG("%s:slave_addr=0x%x, array_size=%d\n", __func__,
 			write_config.slave_addr,
 			write_config.conf_array.size);
+
+		if (!write_config.conf_array.size) {
+			pr_err("%s:%d failed\n", __func__, __LINE__);
+			rc = -EFAULT;
+			break;
+		}
 		reg_setting = kzalloc(write_config.conf_array.size *
 			(sizeof(struct msm_camera_i2c_reg_array)), GFP_KERNEL);
 		if (!reg_setting) {
@@ -1565,6 +1585,11 @@
 			break;
 		}
 
+		if (!conf_array.size) {
+			pr_err("%s:%d failed\n", __func__, __LINE__);
+			rc = -EFAULT;
+			break;
+		}
 		reg_setting = kzalloc(conf_array.size *
 			(sizeof(struct msm_camera_i2c_seq_reg_array)),
 			GFP_KERNEL);
@@ -1655,8 +1680,13 @@
 			break;
 		}
 		s_ctrl->stop_setting_valid = 1;
-
 		reg_setting = stop_setting->reg_setting;
+
+		if (!stop_setting->size) {
+			pr_err("%s:%d failed\n", __func__, __LINE__);
+			rc = -EFAULT;
+			break;
+		}
 		stop_setting->reg_setting = kzalloc(stop_setting->size *
 			(sizeof(struct msm_camera_i2c_reg_array)), GFP_KERNEL);
 		if (!stop_setting->reg_setting) {
diff --git a/drivers/media/platform/msm/camera_v2/sensor/msm_sensor.h b/drivers/media/platform/msm/camera_v2/sensor/msm_sensor.h
index 80a2bd4..a53d448 100644
--- a/drivers/media/platform/msm/camera_v2/sensor/msm_sensor.h
+++ b/drivers/media/platform/msm/camera_v2/sensor/msm_sensor.h
@@ -92,4 +92,15 @@
 
 int32_t msm_sensor_free_sensor_data(struct msm_sensor_ctrl_t *s_ctrl);
 
+int32_t msm_sensor_get_dt_gpio_req_tbl(struct device_node *of_node,
+	struct msm_camera_gpio_conf *gconf, uint16_t *gpio_array,
+	uint16_t gpio_array_size);
+
+int32_t msm_sensor_get_dt_gpio_set_tbl(struct device_node *of_node,
+	struct msm_camera_gpio_conf *gconf, uint16_t *gpio_array,
+	uint16_t gpio_array_size);
+
+int32_t msm_sensor_init_gpio_pin_tbl(struct device_node *of_node,
+	struct msm_camera_gpio_conf *gconf, uint16_t *gpio_array,
+	uint16_t gpio_array_size);
 #endif
diff --git a/drivers/media/platform/msm/camera_v2/sensor/ov12830.c b/drivers/media/platform/msm/camera_v2/sensor/ov12830.c
index 593892e..fb6d548 100644
--- a/drivers/media/platform/msm/camera_v2/sensor/ov12830.c
+++ b/drivers/media/platform/msm/camera_v2/sensor/ov12830.c
@@ -21,73 +21,73 @@
 		.seq_type = SENSOR_VREG,
 		.seq_val = CAM_VIO,
 		.config_val = 0,
-		.delay = 5,
+		.delay = 1,
 	},
 	{
 		.seq_type = SENSOR_VREG,
 		.seq_val = CAM_VANA,
 		.config_val = 0,
-		.delay = 5,
+		.delay = 1,
 	},
 	{
 		.seq_type = SENSOR_GPIO,
 		.seq_val = SENSOR_GPIO_VDIG,
 		.config_val = GPIO_OUT_LOW,
-		.delay = 40,
+		.delay = 5,
 	},
 	{
 		.seq_type = SENSOR_GPIO,
 		.seq_val = SENSOR_GPIO_VDIG,
 		.config_val = GPIO_OUT_HIGH,
-		.delay = 40,
+		.delay = 5,
 	},
 	{
 		.seq_type = SENSOR_VREG,
 		.seq_val = CAM_VAF,
 		.config_val = 0,
-		.delay = 15,
+		.delay = 5,
 	},
 	{
 		.seq_type = SENSOR_GPIO,
 		.seq_val = SENSOR_GPIO_STANDBY,
 		.config_val = GPIO_OUT_LOW,
-		.delay = 15,
+		.delay = 1,
 	},
 	{
 		.seq_type = SENSOR_GPIO,
 		.seq_val = SENSOR_GPIO_RESET,
 		.config_val = GPIO_OUT_LOW,
-		.delay = 40,
+		.delay = 5,
 	},
 	{
 		.seq_type = SENSOR_GPIO,
 		.seq_val = SENSOR_GPIO_AF_PWDM,
 		.config_val = GPIO_OUT_LOW,
-		.delay = 40,
+		.delay = 5,
 	},
 	{
 		.seq_type = SENSOR_GPIO,
 		.seq_val = SENSOR_GPIO_STANDBY,
 		.config_val = GPIO_OUT_HIGH,
-		.delay = 40,
+		.delay = 5,
 	},
 	{
 		.seq_type = SENSOR_GPIO,
 		.seq_val = SENSOR_GPIO_RESET,
 		.config_val = GPIO_OUT_HIGH,
-		.delay = 40,
+		.delay = 10,
 	},
 	{
 		.seq_type = SENSOR_GPIO,
 		.seq_val = SENSOR_GPIO_AF_PWDM,
 		.config_val = GPIO_OUT_HIGH,
-		.delay = 40,
+		.delay = 5,
 	},
 	{
 		.seq_type = SENSOR_CLK,
 		.seq_val = SENSOR_CAM_MCLK,
 		.config_val = 24000000,
-		.delay = 5,
+		.delay = 10,
 	},
 	{
 		.seq_type = SENSOR_I2C_MUX,
diff --git a/drivers/media/platform/msm/camera_v2/sensor/ov5648.c b/drivers/media/platform/msm/camera_v2/sensor/ov5648.c
index 7877fcb..9922468 100644
--- a/drivers/media/platform/msm/camera_v2/sensor/ov5648.c
+++ b/drivers/media/platform/msm/camera_v2/sensor/ov5648.c
@@ -22,37 +22,37 @@
 		.seq_type = SENSOR_VREG,
 		.seq_val = CAM_VIO,
 		.config_val = 0,
-		.delay = 5,
+		.delay = 0,
 	},
 	{
 		.seq_type = SENSOR_GPIO,
 		.seq_val = SENSOR_GPIO_VDIG,
 		.config_val = GPIO_OUT_LOW,
-		.delay = 10,
+		.delay = 5,
 	},
 	{
 		.seq_type = SENSOR_GPIO,
 		.seq_val = SENSOR_GPIO_VDIG,
 		.config_val = GPIO_OUT_HIGH,
-		.delay = 10,
+		.delay = 5,
 	},
 	{
 		.seq_type = SENSOR_VREG,
 		.seq_val = CAM_VANA,
 		.config_val = 0,
-		.delay = 10,
+		.delay = 5,
 	},
 	{
 		.seq_type = SENSOR_GPIO,
 		.seq_val = SENSOR_GPIO_STANDBY,
 		.config_val = GPIO_OUT_LOW,
-		.delay = 30,
+		.delay = 5,
 	},
 	{
 		.seq_type = SENSOR_GPIO,
 		.seq_val = SENSOR_GPIO_STANDBY,
 		.config_val = GPIO_OUT_HIGH,
-		.delay = 30,
+		.delay = 10,
 	},
 	{
 		.seq_type = SENSOR_GPIO,
@@ -64,13 +64,13 @@
 		.seq_type = SENSOR_GPIO,
 		.seq_val = SENSOR_GPIO_RESET,
 		.config_val = GPIO_OUT_HIGH,
-		.delay = 30,
+		.delay = 10,
 	},
 	{
 		.seq_type = SENSOR_CLK,
 		.seq_val = SENSOR_CAM_MCLK,
 		.config_val = 24000000,
-		.delay = 5,
+		.delay = 10,
 	},
 	{
 		.seq_type = SENSOR_I2C_MUX,
@@ -126,7 +126,7 @@
 
 static const struct of_device_id ov5648_dt_match[] = {
 	{
-		.compatible = "qcom,ov5648",
+		.compatible = "ovti,ov5648",
 		.data = &ov5648_s_ctrl
 	},
 	{}
@@ -136,7 +136,7 @@
 
 static struct platform_driver ov5648_platform_driver = {
 	.driver = {
-		.name = "qcom,ov5648",
+		.name = "ovti,ov5648",
 		.owner = THIS_MODULE,
 		.of_match_table = ov5648_dt_match,
 	},
diff --git a/drivers/media/platform/msm/camera_v2/sensor/ov8825.c b/drivers/media/platform/msm/camera_v2/sensor/ov8825.c
index 3256c5c..e17c94e 100644
--- a/drivers/media/platform/msm/camera_v2/sensor/ov8825.c
+++ b/drivers/media/platform/msm/camera_v2/sensor/ov8825.c
@@ -21,55 +21,55 @@
 		.seq_type = SENSOR_VREG,
 		.seq_val = CAM_VIO,
 		.config_val = 0,
-		.delay = 5,
+		.delay = 1,
 	},
 	{
 		.seq_type = SENSOR_VREG,
 		.seq_val = CAM_VANA,
 		.config_val = 0,
-		.delay = 5,
+		.delay = 1,
 	},
 	{
 		.seq_type = SENSOR_VREG,
 		.seq_val = CAM_VDIG,
 		.config_val = 0,
-		.delay = 5,
+		.delay = 1,
 	},
 	{
 		.seq_type = SENSOR_VREG,
 		.seq_val = CAM_VAF,
 		.config_val = 0,
-		.delay = 15,
+		.delay = 5,
 	},
 	{
 		.seq_type = SENSOR_GPIO,
 		.seq_val = SENSOR_GPIO_STANDBY,
 		.config_val = GPIO_OUT_LOW,
-		.delay = 15,
+		.delay = 1,
 	},
 	{
 		.seq_type = SENSOR_GPIO,
 		.seq_val = SENSOR_GPIO_RESET,
 		.config_val = GPIO_OUT_LOW,
-		.delay = 40,
+		.delay = 5,
 	},
 	{
 		.seq_type = SENSOR_GPIO,
 		.seq_val = SENSOR_GPIO_STANDBY,
 		.config_val = GPIO_OUT_HIGH,
-		.delay = 40,
+		.delay = 5,
 	},
 	{
 		.seq_type = SENSOR_GPIO,
 		.seq_val = SENSOR_GPIO_RESET,
 		.config_val = GPIO_OUT_HIGH,
-		.delay = 40,
+		.delay = 10,
 	},
 	{
 		.seq_type = SENSOR_CLK,
 		.seq_val = SENSOR_CAM_MCLK,
 		.config_val = 24000000,
-		.delay = 5,
+		.delay = 10,
 	},
 	{
 		.seq_type = SENSOR_I2C_MUX,
diff --git a/drivers/media/platform/msm/camera_v2/sensor/ov8865.c b/drivers/media/platform/msm/camera_v2/sensor/ov8865.c
new file mode 100644
index 0000000..6d788f5
--- /dev/null
+++ b/drivers/media/platform/msm/camera_v2/sensor/ov8865.c
@@ -0,0 +1,185 @@
+/* Copyright (c) 2013, The Linux Foundation. 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 and
+ * only 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 "msm_sensor.h"
+#define OV8865_SENSOR_NAME "ov8865"
+DEFINE_MSM_MUTEX(ov8865_mut);
+
+static struct msm_sensor_ctrl_t ov8865_s_ctrl;
+
+static struct msm_sensor_power_setting ov8865_power_setting[] = {
+	{
+		.seq_type = SENSOR_VREG,
+		.seq_val = CAM_VIO,
+		.config_val = 0,
+		.delay = 1,
+	},
+	{
+		.seq_type = SENSOR_VREG,
+		.seq_val = CAM_VANA,
+		.config_val = 0,
+		.delay = 1,
+	},
+	{
+		.seq_type = SENSOR_VREG,
+		.seq_val = CAM_VDIG,
+		.config_val = 0,
+		.delay = 1,
+	},
+	{
+		.seq_type = SENSOR_VREG,
+		.seq_val = CAM_VAF,
+		.config_val = 0,
+		.delay = 5,
+	},
+	{
+		.seq_type = SENSOR_GPIO,
+		.seq_val = SENSOR_GPIO_STANDBY,
+		.config_val = GPIO_OUT_LOW,
+		.delay = 1,
+	},
+	{
+		.seq_type = SENSOR_GPIO,
+		.seq_val = SENSOR_GPIO_RESET,
+		.config_val = GPIO_OUT_LOW,
+		.delay = 5,
+	},
+	{
+		.seq_type = SENSOR_GPIO,
+		.seq_val = SENSOR_GPIO_AF_PWDM,
+		.config_val = GPIO_OUT_LOW,
+		.delay = 5,
+	},
+	{
+		.seq_type = SENSOR_GPIO,
+		.seq_val = SENSOR_GPIO_STANDBY,
+		.config_val = GPIO_OUT_HIGH,
+		.delay = 5,
+	},
+	{
+		.seq_type = SENSOR_GPIO,
+		.seq_val = SENSOR_GPIO_RESET,
+		.config_val = GPIO_OUT_HIGH,
+		.delay = 10,
+	},
+	{
+		.seq_type = SENSOR_GPIO,
+		.seq_val = SENSOR_GPIO_AF_PWDM,
+		.config_val = GPIO_OUT_HIGH,
+		.delay = 5,
+	},
+	{
+		.seq_type = SENSOR_CLK,
+		.seq_val = SENSOR_CAM_MCLK,
+		.config_val = 24000000,
+		.delay = 10,
+	},
+	{
+		.seq_type = SENSOR_I2C_MUX,
+		.seq_val = 0,
+		.config_val = 0,
+		.delay = 0,
+	},
+};
+
+static struct v4l2_subdev_info ov8865_subdev_info[] = {
+	{
+		.code   = V4L2_MBUS_FMT_SBGGR10_1X10,
+		.colorspace = V4L2_COLORSPACE_JPEG,
+		.fmt    = 1,
+		.order    = 0,
+	},
+};
+
+static const struct i2c_device_id ov8865_i2c_id[] = {
+	{OV8865_SENSOR_NAME, (kernel_ulong_t)&ov8865_s_ctrl},
+	{ }
+};
+
+static int32_t msm_ov8865_i2c_probe(struct i2c_client *client,
+	const struct i2c_device_id *id)
+{
+	return msm_sensor_i2c_probe(client, id, &ov8865_s_ctrl);
+}
+
+static struct i2c_driver ov8865_i2c_driver = {
+	.id_table = ov8865_i2c_id,
+	.probe  = msm_ov8865_i2c_probe,
+	.driver = {
+		.name = OV8865_SENSOR_NAME,
+	},
+};
+
+static struct msm_camera_i2c_client ov8865_sensor_i2c_client = {
+	.addr_type = MSM_CAMERA_I2C_WORD_ADDR,
+};
+
+static const struct of_device_id ov8865_dt_match[] = {
+	{.compatible = "ovti,ov8865", .data = &ov8865_s_ctrl},
+	{}
+};
+
+MODULE_DEVICE_TABLE(of, ov8865_dt_match);
+
+static struct platform_driver ov8865_platform_driver = {
+	.driver = {
+		.name = "ovti,ov8865",
+		.owner = THIS_MODULE,
+		.of_match_table = ov8865_dt_match,
+	},
+};
+
+static int32_t ov8865_platform_probe(struct platform_device *pdev)
+{
+	int32_t rc = 0;
+	const struct of_device_id *match;
+	match = of_match_device(ov8865_dt_match, &pdev->dev);
+	rc = msm_sensor_platform_probe(pdev, match->data);
+	return rc;
+}
+
+static int __init ov8865_init_module(void)
+{
+	int32_t rc = 0;
+	pr_info("%s:%d\n", __func__, __LINE__);
+	rc = platform_driver_probe(&ov8865_platform_driver,
+		ov8865_platform_probe);
+	if (!rc)
+		return rc;
+	pr_err("%s:%d rc %d\n", __func__, __LINE__, rc);
+	return i2c_add_driver(&ov8865_i2c_driver);
+}
+
+static void __exit ov8865_exit_module(void)
+{
+	pr_info("%s:%d\n", __func__, __LINE__);
+	if (ov8865_s_ctrl.pdev) {
+		msm_sensor_free_sensor_data(&ov8865_s_ctrl);
+		platform_driver_unregister(&ov8865_platform_driver);
+	} else
+		i2c_del_driver(&ov8865_i2c_driver);
+	return;
+}
+
+static struct msm_sensor_ctrl_t ov8865_s_ctrl = {
+	.sensor_i2c_client = &ov8865_sensor_i2c_client,
+	.power_setting_array.power_setting = ov8865_power_setting,
+	.power_setting_array.size = ARRAY_SIZE(ov8865_power_setting),
+	.msm_sensor_mutex = &ov8865_mut,
+	.sensor_v4l2_subdev_info = ov8865_subdev_info,
+	.sensor_v4l2_subdev_info_size = ARRAY_SIZE(ov8865_subdev_info),
+};
+
+module_init(ov8865_init_module);
+module_exit(ov8865_exit_module);
+MODULE_DESCRIPTION("ov8865");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/media/platform/msm/camera_v2/sensor/ov9724.c b/drivers/media/platform/msm/camera_v2/sensor/ov9724.c
index 56af02b..99bf03a 100644
--- a/drivers/media/platform/msm/camera_v2/sensor/ov9724.c
+++ b/drivers/media/platform/msm/camera_v2/sensor/ov9724.c
@@ -46,7 +46,7 @@
 		.seq_type = SENSOR_GPIO,
 		.seq_val = SENSOR_GPIO_RESET,
 		.config_val = GPIO_OUT_HIGH,
-		.delay = 30,
+		.delay = 5,
 	},
 	{
 		.seq_type = SENSOR_GPIO,
@@ -58,13 +58,13 @@
 		.seq_type = SENSOR_GPIO,
 		.seq_val = SENSOR_GPIO_STANDBY,
 		.config_val = GPIO_OUT_HIGH,
-		.delay = 30,
+		.delay = 10,
 	},
 	{
 		.seq_type = SENSOR_CLK,
 		.seq_val = SENSOR_CAM_MCLK,
 		.config_val = 24000000,
-		.delay = 5,
+		.delay = 10,
 	},
 	{
 		.seq_type = SENSOR_I2C_MUX,
diff --git a/drivers/media/platform/msm/vidc/hfi_packetization.c b/drivers/media/platform/msm/vidc/hfi_packetization.c
index 02b36f8..1dba2b6 100644
--- a/drivers/media/platform/msm/vidc/hfi_packetization.c
+++ b/drivers/media/platform/msm/vidc/hfi_packetization.c
@@ -32,6 +32,7 @@
 		HFI_H264_PROFILE_CONSTRAINED_BASE,
 	[ilog2(HAL_H264_PROFILE_CONSTRAINED_HIGH)] =
 		HFI_H264_PROFILE_CONSTRAINED_HIGH,
+	[ilog2(HAL_VPX_PROFILE_VERSION_1)] = HFI_VPX_PROFILE_VERSION_1,
 };
 
 static int entropy_mode[] = {
@@ -1160,6 +1161,19 @@
 		pkt->size += sizeof(u32) * 2;
 		break;
 	}
+	case HAL_PARAM_VDEC_CONCEAL_COLOR:
+	{
+		struct hfi_conceal_color *hfi;
+		pkt->rg_property_data[0] =
+			HFI_PROPERTY_PARAM_VDEC_CONCEAL_COLOR;
+		hfi = (struct hfi_conceal_color *) &pkt->rg_property_data[1];
+		if (hfi)
+			hfi->conceal_color =
+				((struct hfi_conceal_color *) pdata)->
+				conceal_color;
+		pkt->size += sizeof(u32) * 2;
+		break;
+	}
 	case HAL_CONFIG_VPE_OPERATIONS:
 		break;
 	case HAL_PARAM_VENC_INTRA_REFRESH:
diff --git a/drivers/media/platform/msm/vidc/hfi_response_handler.c b/drivers/media/platform/msm/vidc/hfi_response_handler.c
index 653ba46..2b6118a 100644
--- a/drivers/media/platform/msm/vidc/hfi_response_handler.c
+++ b/drivers/media/platform/msm/vidc/hfi_response_handler.c
@@ -78,6 +78,26 @@
 	return vidc_err;
 }
 
+static int validate_session_pkt(struct list_head *sessions,
+		struct hal_session *sess, struct mutex *session_lock)
+{
+	struct hal_session *session;
+	int invalid = 1;
+	if (session_lock) {
+		mutex_lock(session_lock);
+		list_for_each_entry(session, sessions, list) {
+			if (session == sess) {
+				invalid = 0;
+				break;
+			}
+		}
+		mutex_unlock(session_lock);
+	}
+	if (invalid)
+		dprintk(VIDC_WARN, "Invalid session from FW: %p\n", sess);
+	return invalid;
+}
+
 static void hfi_process_sess_evt_seq_changed(
 		msm_vidc_callback callback, u32 device_id,
 		struct hfi_msg_event_notify_packet *pkt)
@@ -164,8 +184,10 @@
 }
 static void hfi_process_event_notify(
 		msm_vidc_callback callback, u32 device_id,
-		struct hfi_msg_event_notify_packet *pkt)
+		struct hfi_msg_event_notify_packet *pkt,
+		struct list_head *sessions, struct mutex *session_lock)
 {
+	struct hal_session *sess = NULL;
 	dprintk(VIDC_DBG, "RECVD:EVENT_NOTIFY");
 
 	if (!callback || !pkt ||
@@ -173,6 +195,7 @@
 		dprintk(VIDC_ERR, "Invalid Params");
 		return;
 	}
+	sess = (struct hal_session *)pkt->session_id;
 
 	switch (pkt->event_id) {
 	case HFI_EVENT_SYS_ERROR:
@@ -182,11 +205,14 @@
 		break;
 	case HFI_EVENT_SESSION_ERROR:
 		dprintk(VIDC_ERR, "HFI_EVENT_SESSION_ERROR");
-		hfi_process_session_error(callback, device_id, pkt);
+		if (!validate_session_pkt(sessions, sess, session_lock))
+			hfi_process_session_error(callback, device_id, pkt);
 		break;
 	case HFI_EVENT_SESSION_SEQUENCE_CHANGED:
 		dprintk(VIDC_INFO, "HFI_EVENT_SESSION_SEQUENCE_CHANGED");
-		hfi_process_sess_evt_seq_changed(callback, device_id, pkt);
+		if (!validate_session_pkt(sessions, sess, session_lock))
+			hfi_process_sess_evt_seq_changed(callback,
+				device_id, pkt);
 		break;
 	case HFI_EVENT_SESSION_PROPERTY_CHANGED:
 		dprintk(VIDC_INFO, "HFI_EVENT_SESSION_PROPERTY_CHANGED");
@@ -1115,9 +1141,11 @@
 
 u32 hfi_process_msg_packet(
 		msm_vidc_callback callback, u32 device_id,
-		struct vidc_hal_msg_pkt_hdr *msg_hdr)
+		struct vidc_hal_msg_pkt_hdr *msg_hdr,
+		struct list_head *sessions, struct mutex *session_lock)
 {
 	u32 rc = 0;
+	struct hal_session *sess = NULL;
 	if (!callback || !msg_hdr || msg_hdr->size <
 		VIDC_IFACEQ_MIN_PKT_SIZE) {
 		dprintk(VIDC_ERR, "hal_process_msg_packet:bad"
@@ -1128,10 +1156,14 @@
 
 	dprintk(VIDC_INFO, "Received: 0x%x in ", msg_hdr->packet);
 	rc = (u32) msg_hdr->packet;
+	sess = (struct hal_session *)((struct
+			vidc_hal_session_cmd_pkt*) msg_hdr)->session_id;
+
 	switch (msg_hdr->packet) {
 	case HFI_MSG_EVENT_NOTIFY:
 		hfi_process_event_notify(callback, device_id,
-			(struct hfi_msg_event_notify_packet *) msg_hdr);
+			(struct hfi_msg_event_notify_packet *) msg_hdr,
+			sessions, session_lock);
 		break;
 	case  HFI_MSG_SYS_INIT_DONE:
 		hfi_process_sys_init_done(callback, device_id,
@@ -1139,11 +1171,13 @@
 					msg_hdr);
 		break;
 	case HFI_MSG_SYS_IDLE:
+	case HFI_MSG_SYS_PC_PREP_DONE:
 		break;
 	case HFI_MSG_SYS_SESSION_INIT_DONE:
-		hfi_process_session_init_done(callback, device_id,
-			(struct hfi_msg_sys_session_init_done_packet *)
-					msg_hdr);
+		if (!validate_session_pkt(sessions, sess, session_lock))
+			hfi_process_session_init_done(callback, device_id,
+				(struct hfi_msg_sys_session_init_done_packet *)
+						msg_hdr);
 		break;
 	case HFI_MSG_SYS_PROPERTY_INFO:
 		hfi_process_sys_property_info(
@@ -1151,68 +1185,81 @@
 			msg_hdr);
 		break;
 	case HFI_MSG_SYS_SESSION_END_DONE:
-		hfi_process_session_end_done(callback, device_id,
-			(struct hfi_msg_sys_session_end_done_packet *)
-					msg_hdr);
+		if (!validate_session_pkt(sessions, sess, session_lock))
+			hfi_process_session_end_done(callback, device_id,
+				(struct hfi_msg_sys_session_end_done_packet *)
+						msg_hdr);
 		break;
 	case HFI_MSG_SESSION_LOAD_RESOURCES_DONE:
-		hfi_process_session_load_res_done(callback, device_id,
+		if (!validate_session_pkt(sessions, sess, session_lock))
+			hfi_process_session_load_res_done(callback, device_id,
 			(struct hfi_msg_session_load_resources_done_packet *)
-					msg_hdr);
+						msg_hdr);
 		break;
 	case HFI_MSG_SESSION_START_DONE:
-		hfi_process_session_start_done(callback, device_id,
-			(struct hfi_msg_session_start_done_packet *)
-					msg_hdr);
+		if (!validate_session_pkt(sessions, sess, session_lock))
+			hfi_process_session_start_done(callback, device_id,
+				(struct hfi_msg_session_start_done_packet *)
+						msg_hdr);
 		break;
 	case HFI_MSG_SESSION_STOP_DONE:
-		hfi_process_session_stop_done(callback, device_id,
-			(struct hfi_msg_session_stop_done_packet *)
-					msg_hdr);
+		if (!validate_session_pkt(sessions, sess, session_lock))
+			hfi_process_session_stop_done(callback, device_id,
+				(struct hfi_msg_session_stop_done_packet *)
+						msg_hdr);
 		break;
 	case HFI_MSG_SESSION_EMPTY_BUFFER_DONE:
-		hfi_process_session_etb_done(callback, device_id,
+		if (!validate_session_pkt(sessions, sess, session_lock))
+			hfi_process_session_etb_done(callback, device_id,
 			(struct hfi_msg_session_empty_buffer_done_packet *)
-					msg_hdr);
+						msg_hdr);
 		break;
 	case HFI_MSG_SESSION_FILL_BUFFER_DONE:
-		hfi_process_session_ftb_done(callback, device_id, msg_hdr);
+		if (!validate_session_pkt(sessions, sess, session_lock))
+			hfi_process_session_ftb_done(callback, device_id,
+						msg_hdr);
 		break;
 	case HFI_MSG_SESSION_FLUSH_DONE:
-		hfi_process_session_flush_done(callback, device_id,
-			(struct hfi_msg_session_flush_done_packet *)
-					msg_hdr);
+		if (!validate_session_pkt(sessions, sess, session_lock))
+			hfi_process_session_flush_done(callback, device_id,
+				(struct hfi_msg_session_flush_done_packet *)
+						msg_hdr);
 		break;
 	case HFI_MSG_SESSION_PROPERTY_INFO:
-		hfi_process_session_prop_info(callback, device_id,
-			(struct hfi_msg_session_property_info_packet *)
-					msg_hdr);
+		if (!validate_session_pkt(sessions, sess, session_lock))
+			hfi_process_session_prop_info(callback, device_id,
+				(struct hfi_msg_session_property_info_packet *)
+						msg_hdr);
 		break;
 	case HFI_MSG_SESSION_RELEASE_RESOURCES_DONE:
-		hfi_process_session_rel_res_done(callback, device_id,
+		if (!validate_session_pkt(sessions, sess, session_lock))
+			hfi_process_session_rel_res_done(callback, device_id,
 			(struct hfi_msg_session_release_resources_done_packet *)
-					msg_hdr);
+						msg_hdr);
 		break;
 	case HFI_MSG_SYS_RELEASE_RESOURCE:
 		hfi_process_sys_rel_resource_done(callback, device_id,
 			(struct hfi_msg_sys_release_resource_done_packet *)
-			msg_hdr);
+						msg_hdr);
 		break;
 	case HFI_MSG_SESSION_GET_SEQUENCE_HEADER_DONE:
-		hfi_process_session_get_seq_hdr_done(
+		if (!validate_session_pkt(sessions, sess, session_lock))
+			hfi_process_session_get_seq_hdr_done(
 			callback, device_id, (struct
 			hfi_msg_session_get_sequence_header_done_packet*)
-			msg_hdr);
+						msg_hdr);
 		break;
 	case HFI_MSG_SESSION_RELEASE_BUFFERS_DONE:
-		hfi_process_session_rel_buf_done(
-			callback, device_id, (struct
-			hfi_msg_session_release_buffers_done_packet*)
-			msg_hdr);
+		if (!validate_session_pkt(sessions, sess, session_lock))
+			hfi_process_session_rel_buf_done(callback, device_id,
+			(struct hfi_msg_session_release_buffers_done_packet *)
+						msg_hdr);
 		break;
 	case HFI_MSG_SYS_SESSION_ABORT_DONE:
-		hfi_process_session_abort_done(callback, device_id, (struct
-			hfi_msg_sys_session_abort_done_packet*) msg_hdr);
+		if (!validate_session_pkt(sessions, sess, session_lock))
+			hfi_process_session_abort_done(callback, device_id,
+			(struct hfi_msg_sys_session_abort_done_packet *)
+						msg_hdr);
 		break;
 	default:
 		dprintk(VIDC_DBG, "UNKNOWN_MSG_TYPE : %d", msg_hdr->packet);
diff --git a/drivers/media/platform/msm/vidc/msm_v4l2_vidc.c b/drivers/media/platform/msm/vidc/msm_v4l2_vidc.c
index cf96ca2..afd7200 100644
--- a/drivers/media/platform/msm/vidc/msm_v4l2_vidc.c
+++ b/drivers/media/platform/msm/vidc/msm_v4l2_vidc.c
@@ -36,6 +36,8 @@
 
 struct msm_vidc_drv *vidc_driver;
 
+uint32_t msm_vidc_pwr_collapse_delay = 2000;
+
 struct buffer_info {
 	struct list_head list;
 	int type;
@@ -210,7 +212,8 @@
 fail_nomem:
 	return rc;
 }
-static int msm_v4l2_release_output_buffers(struct msm_v4l2_vid_inst *v4l2_inst)
+static int msm_v4l2_release_buffers(struct msm_v4l2_vid_inst *v4l2_inst,
+				int buffer_type)
 {
 	struct list_head *ptr, *next;
 	struct buffer_info *bi;
@@ -220,7 +223,7 @@
 	int i;
 	list_for_each_safe(ptr, next, &v4l2_inst->registered_bufs) {
 		bi = list_entry(ptr, struct buffer_info, list);
-		if (bi->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) {
+		if (bi->type == buffer_type) {
 			buffer_info.type = bi->type;
 			for (i = 0; (i < bi->num_planes)
 				&& (i < VIDEO_MAX_PLANES); i++) {
@@ -266,7 +269,8 @@
 	int i;
 	vidc_inst = get_vidc_inst(filp, NULL);
 	v4l2_inst = get_v4l2_inst(filp, NULL);
-	rc = msm_v4l2_release_output_buffers(v4l2_inst);
+	rc = msm_v4l2_release_buffers(v4l2_inst,
+			V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE);
 	if (rc)
 		dprintk(VIDC_WARN,
 			"Failed in %s for release output buffers\n", __func__);
@@ -339,7 +343,7 @@
 	int rc = 0;
 	v4l2_inst = get_v4l2_inst(file, NULL);
 	if (b->count == 0)
-		rc = msm_v4l2_release_output_buffers(v4l2_inst);
+		rc = msm_v4l2_release_buffers(v4l2_inst, b->type);
 	if (rc)
 		dprintk(VIDC_WARN,
 			"Failed in %s for release output buffers\n", __func__);
@@ -510,6 +514,19 @@
 		b->m.planes[i].m.userptr = binfo->device_addr[i];
 		dprintk(VIDC_DBG, "Queueing device address = 0x%x\n",
 				binfo->device_addr[i]);
+
+		if ((vidc_inst->fmts[OUTPUT_PORT]->fourcc ==
+			V4L2_PIX_FMT_HEVC_HYBRID) &&  binfo->handle[i] &&
+			(b->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE)) {
+			rc = msm_smem_cache_operations(v4l2_inst->mem_client,
+				binfo->handle[i], SMEM_CACHE_INVALIDATE);
+			if (rc) {
+				dprintk(VIDC_ERR,
+					"Failed to INV caches: %d\n", rc);
+					goto err_invalid_buff;
+			}
+		}
+
 		if (binfo->handle[i] &&
 			(b->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE)) {
 			rc = msm_smem_cache_operations(v4l2_inst->mem_client,
@@ -617,7 +634,8 @@
 	int rc = 0;
 	v4l2_inst = get_v4l2_inst(file, NULL);
 	if (dec->cmd == V4L2_DEC_CMD_STOP)
-		rc = msm_v4l2_release_output_buffers(v4l2_inst);
+		rc = msm_v4l2_release_buffers(v4l2_inst,
+				V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE);
 	if (rc)
 		dprintk(VIDC_WARN,
 			"Failed to release dec output buffers: %d\n", rc);
@@ -632,7 +650,8 @@
 	int rc = 0;
 	v4l2_inst = get_v4l2_inst(file, NULL);
 	if (enc->cmd == V4L2_ENC_CMD_STOP)
-		rc = msm_v4l2_release_output_buffers(v4l2_inst);
+		rc = msm_v4l2_release_buffers(v4l2_inst,
+				V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE);
 	if (rc)
 		dprintk(VIDC_WARN,
 			"Failed to release enc output buffers: %d\n", rc);
@@ -777,6 +796,31 @@
 
 static DEVICE_ATTR(link_name, 0644, msm_vidc_link_name_show, NULL);
 
+static ssize_t store_pwr_collapse_delay(struct device *dev,
+		struct device_attribute *attr,
+		const char *buf, size_t count)
+{
+	unsigned long val = 0;
+	int rc = 0;
+	rc = kstrtoul(buf, 0, &val);
+	if (rc)
+		return rc;
+	else if (val == 0)
+		return -EINVAL;
+	msm_vidc_pwr_collapse_delay = val;
+	return count;
+}
+
+static ssize_t show_pwr_collapse_delay(struct device *dev,
+		struct device_attribute *attr,
+		char *buf)
+{
+	return snprintf(buf, PAGE_SIZE, "%u\n", msm_vidc_pwr_collapse_delay);
+}
+
+static DEVICE_ATTR(pwr_collapse_delay, 0644, show_pwr_collapse_delay,
+		store_pwr_collapse_delay);
+
 static int __devinit msm_vidc_probe(struct platform_device *pdev)
 {
 	int rc = 0;
@@ -796,6 +840,12 @@
 		dprintk(VIDC_ERR, "Failed to init core\n");
 		goto err_v4l2_register;
 	}
+	rc = device_create_file(&pdev->dev, &dev_attr_pwr_collapse_delay);
+	if (rc) {
+		dprintk(VIDC_ERR,
+				"Failed to create pwr_collapse_delay sysfs node");
+		goto err_v4l2_register;
+	}
 	if (core->hfi_type == VIDC_HFI_Q6) {
 		dprintk(VIDC_ERR, "Q6 hfi device probe called\n");
 		nr += MSM_VIDC_MAX_DEVICES;
diff --git a/drivers/media/platform/msm/vidc/msm_vdec.c b/drivers/media/platform/msm/vidc/msm_vdec.c
index 86928f2..a3d88c5 100644
--- a/drivers/media/platform/msm/vidc/msm_vdec.c
+++ b/drivers/media/platform/msm/vidc/msm_vdec.c
@@ -22,6 +22,7 @@
 #define MSM_VDEC_DVC_NAME "msm_vdec_8974"
 #define MIN_NUM_OUTPUT_BUFFERS 4
 #define MAX_NUM_OUTPUT_BUFFERS 6
+#define DEFAULT_CONCEAL_COLOR 0x0
 
 enum msm_vdec_ctrl_cluster {
 	MSM_VDEC_CTRL_CLUSTER_MAX = 1 << 0,
@@ -362,6 +363,14 @@
 		.type = OUTPUT_PORT,
 	},
 	{
+		.name = "HEVC_HYBRID",
+		.description = "HEVC compressed format",
+		.fourcc = V4L2_PIX_FMT_HEVC_HYBRID,
+		.num_planes = 1,
+		.get_frame_size = get_frame_size_compressed,
+		.type = OUTPUT_PORT,
+	},
+	{
 		.name = "VP8",
 		.description = "VP8 compressed format",
 		.fourcc = V4L2_PIX_FMT_VP8,
@@ -1028,18 +1037,16 @@
 			mutex_unlock(&inst->lock);
 			break;
 		}
-		if (*num_buffers && *num_buffers >
+		if (*num_buffers && *num_buffers >=
 			bufreq->buffer_count_actual) {
 			property_id = HAL_PARAM_BUFFER_COUNT_ACTUAL;
 			new_buf_count.buffer_type = HAL_BUFFER_OUTPUT;
 			new_buf_count.buffer_count_actual = *num_buffers;
 			rc = call_hfi_op(hdev, session_set_property,
 				inst->session, property_id, &new_buf_count);
+		} else {
+			*num_buffers = bufreq->buffer_count_min;
 		}
-		if (bufreq->buffer_count_actual > *num_buffers)
-			*num_buffers =  bufreq->buffer_count_actual;
-		else
-			bufreq->buffer_count_actual = *num_buffers;
 		mutex_unlock(&inst->lock);
 		dprintk(VIDC_DBG, "count =  %d, size = %d, alignment = %d\n",
 				inst->buff_req.buffer[1].buffer_count_actual,
@@ -1129,17 +1136,28 @@
 {
 	struct msm_vidc_inst *inst;
 	int rc = 0;
+	int pdata = DEFAULT_CONCEAL_COLOR;
+	struct hfi_device *hdev;
 	if (!q || !q->drv_priv) {
 		dprintk(VIDC_ERR, "Invalid input, q = %p\n", q);
 		return -EINVAL;
 	}
 	inst = q->drv_priv;
+	if (!inst || !inst->core || !inst->core->device) {
+		dprintk(VIDC_ERR, "%s invalid parameters", __func__);
+		return -EINVAL;
+	}
+	hdev = inst->core->device;
 	dprintk(VIDC_DBG,
 		"Streamon called on: %d capability\n", q->type);
 	switch (q->type) {
 	case V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE:
 		if (inst->bufq[CAPTURE_PORT].vb2_bufq.streaming)
 			rc = start_streaming(inst);
+		rc = call_hfi_op(hdev, session_set_property,
+			(void *) inst->session,
+			HAL_PARAM_VDEC_CONCEAL_COLOR,
+			(void *) &pdata);
 		break;
 	case V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE:
 		if (inst->bufq[OUTPUT_PORT].vb2_bufq.streaming)
diff --git a/drivers/media/platform/msm/vidc/msm_venc.c b/drivers/media/platform/msm/vidc/msm_venc.c
index 7897068..c1a9ad0 100644
--- a/drivers/media/platform/msm/vidc/msm_venc.c
+++ b/drivers/media/platform/msm/vidc/msm_venc.c
@@ -87,6 +87,14 @@
 	"High Latency",
 };
 
+static const char *const vp8_profile_level[] = {
+	"Unused",
+	"0.0",
+	"1.0",
+	"2.0",
+	"3.0",
+};
+
 static const char *const mpeg_video_vidc_extradata[] = {
 	"Extradata none",
 	"Extradata MB Quantization",
@@ -125,7 +133,8 @@
 	MSM_VENC_CTRL_CLUSTER_INTRA_REFRESH = 1 << 7,
 	MSM_VENC_CTRL_CLUSTER_BITRATE = 1 << 8,
 	MSM_VENC_CTRL_CLUSTER_TIMING = 1 << 9,
-	MSM_VENC_CTRL_CLUSTER_MAX = 1 << 10,
+	MSM_VENC_CTRL_CLUSTER_VP8_PROFILE_LEVEL = 1 << 10,
+	MSM_VENC_CTRL_CLUSTER_MAX = 1 << 11,
 };
 
 static struct msm_vidc_ctrl msm_venc_ctrls[] = {
@@ -315,7 +324,7 @@
 		.name = "H264 Level",
 		.type = V4L2_CTRL_TYPE_MENU,
 		.minimum = V4L2_MPEG_VIDEO_H264_LEVEL_1_0,
-		.maximum = V4L2_MPEG_VIDEO_H264_LEVEL_5_1,
+		.maximum = V4L2_MPEG_VIDEO_H264_LEVEL_5_2,
 		.default_value = V4L2_MPEG_VIDEO_H264_LEVEL_1_0,
 		.step = 0,
 		.menu_skip_mask = 0,
@@ -362,6 +371,21 @@
 		.cluster = MSM_VENC_CTRL_CLUSTER_H263_PROFILE_LEVEL,
 	},
 	{
+		.id = V4L2_CID_MPEG_VIDC_VIDEO_VP8_PROFILE_LEVEL,
+		.name = "VP8 Profile Level",
+		.type = V4L2_CTRL_TYPE_MENU,
+		.minimum = V4L2_MPEG_VIDC_VIDEO_VP8_UNUSED,
+		.maximum = V4L2_MPEG_VIDC_VIDEO_VP8_VERSION_1,
+		.default_value = V4L2_MPEG_VIDC_VIDEO_VP8_VERSION_0,
+		.menu_skip_mask = ~(
+		(1 << V4L2_MPEG_VIDC_VIDEO_VP8_UNUSED) |
+		(1 << V4L2_MPEG_VIDC_VIDEO_VP8_VERSION_0) |
+		(1 << V4L2_MPEG_VIDC_VIDEO_VP8_VERSION_1)
+		),
+		.qmenu = vp8_profile_level,
+		.cluster = MSM_VENC_CTRL_CLUSTER_VP8_PROFILE_LEVEL,
+	},
+	{
 		.id = V4L2_CID_MPEG_VIDC_VIDEO_ROTATION,
 		.name = "Rotation",
 		.type = V4L2_CTRL_TYPE_MENU,
@@ -683,6 +707,18 @@
 		.qmenu = perf_level,
 		.step = 0,
 	},
+	{
+		.id = V4L2_CID_MPEG_VIDEO_CYCLIC_INTRA_REFRESH_MB,
+		.name = "Intra Refresh CIR MBS",
+		.type = V4L2_CTRL_TYPE_INTEGER,
+		.minimum = 0,
+		.maximum = MAX_INTRA_REFRESH_MBS,
+		.default_value = 0,
+		.step = 1,
+		.menu_skip_mask = 0,
+		.qmenu = NULL,
+		.cluster = MSM_VENC_CTRL_CLUSTER_INTRA_REFRESH,
+	}
 };
 
 #define NUM_CTRLS ARRAY_SIZE(msm_venc_ctrls)
@@ -1091,6 +1127,8 @@
 			return HAL_H264_LEVEL_5;
 		case V4L2_MPEG_VIDEO_H264_LEVEL_5_1:
 			return HAL_H264_LEVEL_51;
+		case V4L2_MPEG_VIDEO_H264_LEVEL_5_2:
+			return HAL_H264_LEVEL_52;
 		default:
 			goto unknown_value;
 		}
@@ -1159,6 +1197,21 @@
 		default:
 			goto unknown_value;
 		}
+	case V4L2_CID_MPEG_VIDC_VIDEO_VP8_PROFILE_LEVEL:
+		switch (value) {
+		case V4L2_MPEG_VIDC_VIDEO_VP8_VERSION_0:
+			return HAL_VPX_PROFILE_VERSION_0;
+		case V4L2_MPEG_VIDC_VIDEO_VP8_VERSION_1:
+			return HAL_VPX_PROFILE_VERSION_1;
+		case V4L2_MPEG_VIDC_VIDEO_VP8_VERSION_2:
+			return HAL_VPX_PROFILE_VERSION_2;
+		case V4L2_MPEG_VIDC_VIDEO_VP8_VERSION_3:
+			return HAL_VPX_PROFILE_VERSION_3;
+		case V4L2_MPEG_VIDC_VIDEO_VP8_UNUSED:
+			return HAL_VPX_PROFILE_UNUSED;
+		default:
+			goto unknown_value;
+		}
 	}
 
 unknown_value:
@@ -1465,6 +1518,15 @@
 				ctrl->val);
 		pdata = &profile_level;
 		break;
+	case V4L2_CID_MPEG_VIDC_VIDEO_VP8_PROFILE_LEVEL:
+		property_id =
+			HAL_PARAM_PROFILE_LEVEL_CURRENT;
+		profile_level.profile = venc_v4l2_to_hal(
+				V4L2_CID_MPEG_VIDC_VIDEO_VP8_PROFILE_LEVEL,
+				ctrl->val);
+		profile_level.level = HAL_VPX_PROFILE_UNUSED;
+		pdata = &profile_level;
+		break;
 	case V4L2_CID_MPEG_VIDC_VIDEO_ROTATION:
 		property_id =
 			HAL_CONFIG_VPE_OPERATIONS;
@@ -1641,8 +1703,8 @@
 		air_ref = TRY_GET_CTRL(V4L2_CID_MPEG_VIDC_VIDEO_AIR_REF);
 		cir_mbs = TRY_GET_CTRL(V4L2_CID_MPEG_VIDC_VIDEO_CIR_MBS);
 
-		property_id =
-			HAL_PARAM_VENC_INTRA_REFRESH;
+		property_id = HAL_PARAM_VENC_INTRA_REFRESH;
+
 		intra_refresh.air_mbs = ctrl->val;
 		intra_refresh.mode = ir_mode->val;
 		intra_refresh.air_ref = air_ref->val;
@@ -1658,8 +1720,8 @@
 		air_mbs = TRY_GET_CTRL(V4L2_CID_MPEG_VIDC_VIDEO_AIR_MBS);
 		cir_mbs = TRY_GET_CTRL(V4L2_CID_MPEG_VIDC_VIDEO_CIR_MBS);
 
-		property_id =
-			HAL_PARAM_VENC_INTRA_REFRESH;
+		property_id = HAL_PARAM_VENC_INTRA_REFRESH;
+
 		intra_refresh.air_ref = ctrl->val;
 		intra_refresh.air_mbs = air_mbs->val;
 		intra_refresh.mode = ir_mode->val;
@@ -1676,8 +1738,7 @@
 		air_mbs = TRY_GET_CTRL(V4L2_CID_MPEG_VIDC_VIDEO_AIR_MBS);
 		air_ref = TRY_GET_CTRL(V4L2_CID_MPEG_VIDC_VIDEO_AIR_REF);
 
-		property_id =
-			HAL_PARAM_VENC_INTRA_REFRESH;
+		property_id = HAL_PARAM_VENC_INTRA_REFRESH;
 
 		intra_refresh.cir_mbs = ctrl->val;
 		intra_refresh.air_mbs = air_mbs->val;
@@ -1687,6 +1748,22 @@
 		pdata = &intra_refresh;
 		break;
 	}
+	case V4L2_CID_MPEG_VIDEO_CYCLIC_INTRA_REFRESH_MB: {
+		struct v4l2_ctrl *air_mbs, *air_ref;
+
+		air_mbs = TRY_GET_CTRL(V4L2_CID_MPEG_VIDC_VIDEO_AIR_MBS);
+		air_ref = TRY_GET_CTRL(V4L2_CID_MPEG_VIDC_VIDEO_AIR_REF);
+
+		property_id = HAL_PARAM_VENC_INTRA_REFRESH;
+
+		intra_refresh.cir_mbs = ctrl->val;
+		intra_refresh.air_mbs = air_mbs->val;
+		intra_refresh.air_ref = air_ref->val;
+		intra_refresh.mode = HAL_INTRA_REFRESH_CYCLIC;
+
+		pdata = &intra_refresh;
+		break;
+	}
 	case V4L2_CID_MPEG_VIDEO_H264_LOOP_FILTER_MODE:
 		property_id =
 			HAL_PARAM_VENC_H264_DEBLOCK_CONTROL;
diff --git a/drivers/media/platform/msm/vidc/msm_vidc.c b/drivers/media/platform/msm/vidc/msm_vidc.c
index b6d031a..10a0eac 100644
--- a/drivers/media/platform/msm/vidc/msm_vidc.c
+++ b/drivers/media/platform/msm/vidc/msm_vidc.c
@@ -497,9 +497,9 @@
 
 	setup_event_queue(inst, &core->vdev[core_id].vdev);
 
-	mutex_lock(&core->lock);
+	mutex_lock(&core->sync_lock);
 	list_add_tail(&inst->list, &core->instances);
-	mutex_unlock(&core->lock);
+	mutex_unlock(&core->sync_lock);
 	return inst;
 fail_init:
 	vb2_queue_release(&inst->bufq[OUTPUT_PORT].vb2_bufq);
diff --git a/drivers/media/platform/msm/vidc/msm_vidc_common.c b/drivers/media/platform/msm/vidc/msm_vidc_common.c
index f94b6f1..fdc851c 100644
--- a/drivers/media/platform/msm/vidc/msm_vidc_common.c
+++ b/drivers/media/platform/msm/vidc/msm_vidc_common.c
@@ -22,8 +22,6 @@
 #include "msm_smem.h"
 #include "msm_vidc_debug.h"
 
-#define HW_RESPONSE_TIMEOUT 1000
-
 #define IS_ALREADY_IN_STATE(__p, __d) ({\
 	int __rc = (__p >= __d);\
 	__rc; \
@@ -362,7 +360,7 @@
 	int rc = 0;
 	rc = wait_for_completion_timeout(
 		&inst->completions[SESSION_MSG_INDEX(cmd)],
-		msecs_to_jiffies(HW_RESPONSE_TIMEOUT));
+		msecs_to_jiffies(msm_vidc_hw_rsp_timeout));
 	if (!rc) {
 		dprintk(VIDC_ERR, "Wait interrupted or timeout: %d\n", rc);
 		msm_comm_recover_from_session_error(inst);
@@ -526,8 +524,15 @@
 {
 	struct msm_vidc_cb_cmd_done *response = data;
 	struct msm_vidc_inst *inst;
-	if (response)
+	if (response) {
 		inst = (struct msm_vidc_inst *)response->session_id;
+		if (response->status) {
+			dprintk(VIDC_ERR,
+				"Load resource response from FW : 0x%x",
+				response->status);
+			msm_comm_generate_session_error(inst);
+		}
+	}
 	else
 		dprintk(VIDC_ERR,
 			"Failed to get valid response for load resource\n");
@@ -817,10 +822,21 @@
 		(u32)fill_buf_done->packet_buffer1);
 	if (vb) {
 		vb->v4l2_planes[0].bytesused = fill_buf_done->filled_len1;
+		vb->v4l2_planes[0].data_offset = fill_buf_done->offset1;
 		vb->v4l2_planes[0].reserved[2] = fill_buf_done->start_x_coord;
 		vb->v4l2_planes[0].reserved[3] = fill_buf_done->start_y_coord;
 		vb->v4l2_planes[0].reserved[4] = fill_buf_done->frame_width;
 		vb->v4l2_planes[0].reserved[5] = fill_buf_done->frame_height;
+		if (vb->v4l2_planes[0].data_offset > vb->v4l2_planes[0].length)
+			dprintk(VIDC_INFO,
+				"fbd:Overflow data_offset = %d; length = %d\n",
+				vb->v4l2_planes[0].data_offset,
+				vb->v4l2_planes[0].length);
+		if (vb->v4l2_planes[0].bytesused > vb->v4l2_planes[0].length)
+			dprintk(VIDC_INFO,
+				"fbd:Overflow bytesused = %d; length = %d\n",
+				vb->v4l2_planes[0].bytesused,
+				vb->v4l2_planes[0].length);
 		if (!(fill_buf_done->flags1 &
 			HAL_BUFFERFLAG_TIMESTAMPINVALID) &&
 			fill_buf_done->filled_len1) {
@@ -873,8 +889,9 @@
 			msm_vidc_debugfs_update(inst,
 				MSM_VIDC_DEBUGFS_EVENT_FBD);
 
-		dprintk(VIDC_DBG, "Filled length = %d; flags %x\n",
+		dprintk(VIDC_DBG, "Filled length = %d; offset = %d; flags %x\n",
 				vb->v4l2_planes[0].bytesused,
+				vb->v4l2_planes[0].data_offset,
 				vb->v4l2_buf.flags);
 		mutex_lock(&inst->bufq[CAPTURE_PORT].lock);
 		vb2_buffer_done(vb, VB2_BUF_STATE_DONE);
@@ -901,6 +918,7 @@
 				vb = list_first_entry(&q->vb2_bufq.queued_list,
 					struct vb2_buffer, queued_entry);
 				vb->v4l2_planes[0].bytesused = 0;
+				vb->v4l2_planes[0].data_offset = 0;
 				vb->v4l2_buf.flags |= V4L2_BUF_FLAG_EOS;
 				mutex_lock(&q->lock);
 				vb2_buffer_done(vb, VB2_BUF_STATE_DONE);
@@ -932,12 +950,14 @@
 	}
 
 	vb->v4l2_planes[0].bytesused = fill_buf_done->filled_len1;
+	vb->v4l2_planes[0].data_offset = fill_buf_done->offset1;
 
 	vb->v4l2_buf.flags = V4L2_QCOM_BUF_FLAG_CODECCONFIG;
 	vb->v4l2_buf.timestamp = ns_to_timeval(0);
 
-	dprintk(VIDC_DBG, "Filled length = %d; flags %x\n",
+	dprintk(VIDC_DBG, "Filled length = %d; offset = %d; flags %x\n",
 				vb->v4l2_planes[0].bytesused,
+				vb->v4l2_planes[0].data_offset,
 				vb->v4l2_buf.flags);
 	mutex_lock(&inst->bufq[CAPTURE_PORT].lock);
 	vb2_buffer_done(vb, VB2_BUF_STATE_DONE);
@@ -1106,7 +1126,7 @@
 	}
 	rc = wait_for_completion_timeout(
 		&core->completions[SYS_MSG_INDEX(RELEASE_RESOURCE_DONE)],
-		msecs_to_jiffies(HW_RESPONSE_TIMEOUT));
+		msecs_to_jiffies(msm_vidc_hw_rsp_timeout));
 	if (!rc) {
 		dprintk(VIDC_ERR, "Wait interrupted or timeout: %d\n", rc);
 		rc = -EIO;
@@ -1128,7 +1148,7 @@
 	dprintk(VIDC_DBG, "Waiting for SYS_INIT_DONE\n");
 	rc = wait_for_completion_timeout(
 		&core->completions[SYS_MSG_INDEX(SYS_INIT_DONE)],
-		msecs_to_jiffies(HW_RESPONSE_TIMEOUT));
+		msecs_to_jiffies(msm_vidc_hw_rsp_timeout));
 	if (!rc) {
 		dprintk(VIDC_ERR, "Wait interrupted or timeout: %d\n", rc);
 		rc = -EIO;
@@ -1317,7 +1337,9 @@
 	case V4L2_PIX_FMT_HEVC:
 		codec = HAL_VIDEO_CODEC_HEVC;
 		break;
-
+	case V4L2_PIX_FMT_HEVC_HYBRID:
+		codec = HAL_VIDEO_CODEC_HEVC_HYBRID;
+		break;
 	default:
 		dprintk(VIDC_ERR, "Wrong codec: %d\n", fourcc);
 		codec = HAL_UNUSED_CODEC;
@@ -1409,8 +1431,11 @@
 		return -EINVAL;
 	}
 
+	mutex_lock(&inst->core->sync_lock);
 	num_mbs_per_sec = msm_comm_get_load(inst->core, MSM_VIDC_DECODER);
 	num_mbs_per_sec += msm_comm_get_load(inst->core, MSM_VIDC_ENCODER);
+	mutex_unlock(&inst->core->sync_lock);
+
 	if (num_mbs_per_sec > inst->core->resources.max_load) {
 		dprintk(VIDC_ERR, "HW is overloaded, needed: %d max: %d\n",
 			num_mbs_per_sec, inst->core->resources.max_load);
@@ -1429,8 +1454,10 @@
 	if (inst->core->resources.has_ocmem) {
 		ocmem_sz = get_ocmem_requirement(inst->prop.height,
 						inst->prop.width);
+		mutex_lock(&inst->core->sync_lock);
 		rc = msm_comm_scale_bus(inst->core, inst->session_type,
 					OCMEM_MEM);
+		mutex_unlock(&inst->core->sync_lock);
 		if (!rc) {
 			mutex_lock(&inst->core->sync_lock);
 			rc = call_hfi_op(hdev, alloc_ocmem,
@@ -2089,7 +2116,7 @@
 	}
 	rc = wait_for_completion_timeout(
 		&inst->completions[SESSION_MSG_INDEX(SESSION_PROPERTY_INFO)],
-		msecs_to_jiffies(HW_RESPONSE_TIMEOUT));
+		msecs_to_jiffies(msm_vidc_hw_rsp_timeout));
 	if (!rc) {
 		dprintk(VIDC_ERR,
 			"Wait interrupted or timeout: %d\n", rc);
@@ -2341,6 +2368,7 @@
 					queued_entry);
 			if (vb) {
 				vb->v4l2_planes[0].bytesused = 0;
+				vb->v4l2_planes[0].data_offset = 0;
 				mutex_lock(&inst->bufq[CAPTURE_PORT].lock);
 				vb2_buffer_done(vb,
 						VB2_BUF_STATE_DONE);
@@ -2358,6 +2386,7 @@
 					queued_entry);
 			if (vb) {
 				vb->v4l2_planes[0].bytesused = 0;
+				vb->v4l2_planes[0].data_offset = 0;
 				mutex_lock(&inst->bufq[OUTPUT_PORT].lock);
 				vb2_buffer_done(vb,
 						VB2_BUF_STATE_DONE);
@@ -2436,6 +2465,7 @@
 					lock = &inst->bufq[CAPTURE_PORT].lock;
 				else
 					lock = &inst->bufq[OUTPUT_PORT].lock;
+				temp->vb->v4l2_planes[0].bytesused = 0;
 				mutex_lock(lock);
 				vb2_buffer_done(temp->vb, VB2_BUF_STATE_DONE);
 				mutex_unlock(lock);
@@ -2673,7 +2703,7 @@
 	}
 	rc = wait_for_completion_timeout(
 		&inst->completions[SESSION_MSG_INDEX(SESSION_ABORT_DONE)],
-		msecs_to_jiffies(HW_RESPONSE_TIMEOUT));
+		msecs_to_jiffies(msm_vidc_hw_rsp_timeout));
 	if (!rc) {
 		dprintk(VIDC_ERR, "%s: Wait interrupted or timeout: %d\n",
 			__func__, rc);
diff --git a/drivers/media/platform/msm/vidc/msm_vidc_debug.c b/drivers/media/platform/msm/vidc/msm_vidc_debug.c
index bea9070..03136ae 100644
--- a/drivers/media/platform/msm/vidc/msm_vidc_debug.c
+++ b/drivers/media/platform/msm/vidc/msm_vidc_debug.c
@@ -21,6 +21,7 @@
 int msm_fw_debug_mode = 0x1;
 int msm_fw_low_power_mode = 0x1;
 int msm_vp8_low_tier = 0x1;
+int msm_vidc_hw_rsp_timeout = 1000;
 
 struct debug_buffer {
 	char ptr[MAX_DBG_BUF_SIZE];
@@ -177,6 +178,11 @@
 		dprintk(VIDC_ERR, "debugfs_create_file: fail\n");
 		goto failed_create_dir;
 	}
+	if (!debugfs_create_u32("hw_rsp_timeout", S_IRUGO | S_IWUSR,
+			parent, &msm_vidc_hw_rsp_timeout)) {
+		dprintk(VIDC_ERR, "debugfs_create_file: fail\n");
+		goto failed_create_dir;
+	}
 failed_create_dir:
 	return dir;
 }
diff --git a/drivers/media/platform/msm/vidc/msm_vidc_debug.h b/drivers/media/platform/msm/vidc/msm_vidc_debug.h
index 5b572c9..c9ecc6f 100644
--- a/drivers/media/platform/msm/vidc/msm_vidc_debug.h
+++ b/drivers/media/platform/msm/vidc/msm_vidc_debug.h
@@ -53,6 +53,7 @@
 extern int msm_fw_debug_mode;
 extern int msm_fw_low_power_mode;
 extern int msm_vp8_low_tier;
+extern int msm_vidc_hw_rsp_timeout;
 
 #define dprintk(__level, __fmt, arg...)	\
 	do { \
diff --git a/drivers/media/platform/msm/vidc/msm_vidc_resources.h b/drivers/media/platform/msm/vidc/msm_vidc_resources.h
index 8176ea5..e75b410 100644
--- a/drivers/media/platform/msm/vidc/msm_vidc_resources.h
+++ b/drivers/media/platform/msm/vidc/msm_vidc_resources.h
@@ -87,5 +87,7 @@
 	return 0;
 }
 
+extern uint32_t msm_vidc_pwr_collapse_delay;
+
 #endif
 
diff --git a/drivers/media/platform/msm/vidc/q6_hfi.c b/drivers/media/platform/msm/vidc/q6_hfi.c
index bc3b93d..7c99ec3 100644
--- a/drivers/media/platform/msm/vidc/q6_hfi.c
+++ b/drivers/media/platform/msm/vidc/q6_hfi.c
@@ -184,7 +184,8 @@
 		if (!rc)
 			hfi_process_msg_packet(device->callback,
 				device->device_id,
-				(struct vidc_hal_msg_pkt_hdr *) packet);
+				(struct vidc_hal_msg_pkt_hdr *) packet,
+				&device->sess_head, &device->session_lock);
 	} while (!rc);
 
 	if (rc != -ENODATA)
@@ -381,7 +382,7 @@
 }
 
 static inline void q6_hfi_add_apr_hdr(struct q6_hfi_device *dev,
-			struct apr_hdr *hdr, u32 pkt_size, u32 opcode)
+			struct apr_hdr *hdr, u32 pkt_size)
 {
 	hdr->hdr_field = APR_HDR_FIELD(APR_MSG_TYPE_SEQ_CMD,
 				APR_HDR_LEN(sizeof(struct apr_hdr)),
@@ -394,7 +395,7 @@
 	hdr->dest_port = 0;
 	hdr->pkt_size  = pkt_size;
 	hdr->token = 0;
-	hdr->opcode = opcode;
+	hdr->opcode = VIDEO_HFI_CMD_ID;
 }
 
 static int q6_hfi_apr_callback(struct apr_client_data *data, void *priv)
@@ -483,6 +484,7 @@
 	}
 
 	INIT_LIST_HEAD(&dev->sess_head);
+	mutex_init(&dev->session_lock);
 
 	if (!dev->event_queue.buffer) {
 		rc = q6_init_event_queue(dev);
@@ -496,7 +498,7 @@
 		goto err_core_init;
 	}
 
-	q6_hfi_add_apr_hdr(dev, &apr.hdr, sizeof(apr), HFI_CMD_SYS_INIT);
+	q6_hfi_add_apr_hdr(dev, &apr.hdr, sizeof(apr));
 
 	rc = create_pkt_cmd_sys_init(&apr.pkt, HFI_VIDEO_ARCH_OX);
 	if (rc) {
@@ -529,22 +531,6 @@
 	return 0;
 }
 
-static int q6_hfi_core_pc_prep(void *device)
-{
-	(void) device;
-
-	/* Q6 does not support core_pc_prep*/
-	return 0;
-}
-
-static int q6_hfi_core_ping(void *device)
-{
-	(void) device;
-
-	/* Q6 does not support cmd_sys_ping */
-	return 0;
-}
-
 static void *q6_hfi_session_init(void *device, u32 session_id,
 	enum hal_domain session_type, enum hal_video_codec codec_type)
 {
@@ -567,8 +553,7 @@
 		new_session->is_decoder = 1;
 	new_session->device = dev;
 
-	q6_hfi_add_apr_hdr(dev, &apr.hdr, sizeof(apr),
-				   HFI_CMD_SYS_SESSION_INIT);
+	q6_hfi_add_apr_hdr(dev, &apr.hdr, sizeof(apr));
 
 	if (create_pkt_cmd_sys_session_init(&apr.pkt, (u32)new_session,
 					session_type, codec_type)) {
@@ -583,7 +568,9 @@
 		rc = -EBADE;
 		goto err_session_init;
 	}
+	mutex_lock(&dev->session_lock);
 	list_add_tail(&new_session->list, &dev->sess_head);
+	mutex_unlock(&dev->session_lock);
 	return new_session;
 
 err_session_init:
@@ -605,7 +592,7 @@
 	}
 	dev = session->device;
 
-	q6_hfi_add_apr_hdr(dev, &apr.hdr, sizeof(apr), pkt_type);
+	q6_hfi_add_apr_hdr(dev, &apr.hdr, sizeof(apr));
 
 	rc = create_pkt_cmd_session_cmd(&apr.pkt, pkt_type, (u32)session);
 	if (rc) {
@@ -646,7 +633,11 @@
 	sess_close = session;
 	dprintk(VIDC_DBG, "deleted the session: 0x%x",
 			sess_close->session_id);
+	mutex_lock(&((struct q6_hfi_device *)
+			sess_close->device)->session_lock);
 	list_del(&sess_close->list);
+	mutex_unlock(&((struct q6_hfi_device *)
+			sess_close->device)->session_lock);
 	kfree(sess_close);
 	return 0;
 }
@@ -670,8 +661,7 @@
 		return 0;
 	apr = (struct q6_apr_cmd_session_set_buffers_packet *)packet;
 
-	q6_hfi_add_apr_hdr(dev, &apr->hdr, VIDC_IFACEQ_VAR_LARGE_PKT_SIZE,
-			HFI_CMD_SESSION_SET_BUFFERS);
+	q6_hfi_add_apr_hdr(dev, &apr->hdr, VIDC_IFACEQ_VAR_LARGE_PKT_SIZE);
 
 	rc = create_pkt_cmd_session_set_buffers(&apr->pkt,
 			(u32)session, buffer_info);
@@ -713,8 +703,7 @@
 
 	apr = (struct q6_apr_cmd_session_release_buffer_packet *) packet;
 
-	q6_hfi_add_apr_hdr(dev, &apr->hdr, VIDC_IFACEQ_VAR_LARGE_PKT_SIZE,
-					   HFI_CMD_SESSION_RELEASE_BUFFERS);
+	q6_hfi_add_apr_hdr(dev, &apr->hdr, VIDC_IFACEQ_VAR_LARGE_PKT_SIZE);
 
 	rc = create_pkt_cmd_session_release_buffers(&apr->pkt,
 					(u32)session, buffer_info);
@@ -788,8 +777,7 @@
 
 	if (session->is_decoder) {
 		struct q6_apr_cmd_session_empty_buffer_compressed_packet apr;
-		q6_hfi_add_apr_hdr(dev, &apr.hdr, sizeof(apr),
-					   HFI_CMD_SESSION_EMPTY_BUFFER);
+		q6_hfi_add_apr_hdr(dev, &apr.hdr, sizeof(apr));
 
 		rc = create_pkt_cmd_session_etb_decoder(&apr.pkt,
 					(u32)session, input_frame);
@@ -811,8 +799,7 @@
 	} else {
 		struct
 		q6_apr_cmd_session_empty_buffer_uncompressed_plane0_packet apr;
-		q6_hfi_add_apr_hdr(dev, &apr.hdr, sizeof(apr),
-				   HFI_CMD_SESSION_EMPTY_BUFFER);
+		q6_hfi_add_apr_hdr(dev, &apr.hdr, sizeof(apr));
 
 		rc =  create_pkt_cmd_session_etb_encoder(&apr.pkt,
 					(u32)session, input_frame);
@@ -848,8 +835,7 @@
 	}
 	dev = session->device;
 
-	q6_hfi_add_apr_hdr(dev, &apr.hdr, sizeof(apr),
-				   HFI_CMD_SESSION_FILL_BUFFER);
+	q6_hfi_add_apr_hdr(dev, &apr.hdr, sizeof(apr));
 
 	rc = create_pkt_cmd_session_ftb(&apr.pkt, (u32)session, output_frame);
 	if (rc) {
@@ -886,8 +872,7 @@
 
 	apr = (struct q6_apr_cmd_session_parse_sequence_header_packet *) packet;
 
-	q6_hfi_add_apr_hdr(dev, &apr->hdr, VIDC_IFACEQ_VAR_SMALL_PKT_SIZE,
-			   HFI_CMD_SESSION_PARSE_SEQUENCE_HEADER);
+	q6_hfi_add_apr_hdr(dev, &apr->hdr, VIDC_IFACEQ_VAR_SMALL_PKT_SIZE);
 
 	rc = create_pkt_cmd_session_parse_seq_header(&apr->pkt,
 					(u32)session, seq_hdr);
@@ -925,8 +910,7 @@
 
 	apr = (struct q6_apr_cmd_session_get_sequence_header_packet *) packet;
 
-	q6_hfi_add_apr_hdr(dev, &apr->hdr, VIDC_IFACEQ_VAR_SMALL_PKT_SIZE,
-				   HFI_CMD_SESSION_GET_SEQUENCE_HEADER);
+	q6_hfi_add_apr_hdr(dev, &apr->hdr, VIDC_IFACEQ_VAR_SMALL_PKT_SIZE);
 
 	rc = create_pkt_cmd_session_get_seq_hdr(&apr->pkt, (u32)session,
 						seq_hdr);
@@ -960,8 +944,7 @@
 	}
 	dev = session->device;
 
-	q6_hfi_add_apr_hdr(dev, &apr.hdr, sizeof(apr),
-				   HFI_CMD_SESSION_GET_PROPERTY);
+	q6_hfi_add_apr_hdr(dev, &apr.hdr, sizeof(apr));
 
 	rc = create_pkt_cmd_session_get_buf_req(&apr.pkt, (u32)session);
 	if (rc) {
@@ -993,8 +976,7 @@
 	}
 	dev = session->device;
 
-	q6_hfi_add_apr_hdr(dev, &apr.hdr, sizeof(apr),
-				   HFI_CMD_SESSION_FLUSH);
+	q6_hfi_add_apr_hdr(dev, &apr.hdr, sizeof(apr));
 
 	rc = create_pkt_cmd_session_flush(&apr.pkt, (u32)session, flush_mode);
 	if (rc) {
@@ -1031,8 +1013,7 @@
 	dev = session->device;
 	dprintk(VIDC_DBG, "in set_prop,with prop id: 0x%x", ptype);
 
-	q6_hfi_add_apr_hdr(dev, &apr->hdr, VIDC_IFACEQ_VAR_LARGE_PKT_SIZE,
-				 HFI_CMD_SESSION_SET_PROPERTY);
+	q6_hfi_add_apr_hdr(dev, &apr->hdr, VIDC_IFACEQ_VAR_LARGE_PKT_SIZE);
 
 	rc = create_pkt_cmd_session_set_property(&apr->pkt,
 				(u32)session, ptype, pdata);
@@ -1177,28 +1158,6 @@
 	return 0;
 }
 
-static int q6_hfi_scale_clocks(void *dev, int load)
-{
-	(void)dev;
-	(void)load;
-
-	/* Q6 does not support clocks scaling */
-	return 0;
-}
-
-static int q6_hfi_scale_bus(void *dev, int load,
-			enum session_type type, enum mem_type mtype)
-{
-	(void)dev;
-	(void)load;
-	(void)type;
-	(void)mtype;
-
-	/* Q6 does not support bus scaling */
-	return 0;
-
-}
-
 static int q6_hfi_unset_ocmem(void *dev)
 {
 	(void)dev;
@@ -1207,23 +1166,6 @@
 	return -EINVAL;
 }
 
-static int q6_hfi_alloc_ocmem(void *dev, unsigned long size)
-{
-	(void)dev;
-	(void)size;
-
-	/* Q6 does not support ocmem */
-	return 0;
-}
-
-static int q6_hfi_free_ocmem(void *dev)
-{
-	(void)dev;
-
-	/* Q6 does not support ocmem */
-	return 0;
-}
-
 static int q6_hfi_iommu_get_domain_partition(void *dev, u32 flags,
 	u32 buffer_type, int *domain, int *partition)
 {
@@ -1373,14 +1315,6 @@
 	}
 }
 
-static int q6_hfi_get_fw_info(void *dev, enum fw_info info)
-{
-	(void)dev;
-	(void)info;
-
-	return 0;
-}
-
 static int q6_hfi_get_stride_scanline(int color_fmt,
 	int width, int height, int *stride, int *scanlines) {
 	*stride = VENUS_Y_STRIDE(color_fmt, width);
@@ -1392,8 +1326,6 @@
 {
 	hdev->core_init = q6_hfi_core_init;
 	hdev->core_release = q6_hfi_core_release;
-	hdev->core_pc_prep = q6_hfi_core_pc_prep;
-	hdev->core_ping = q6_hfi_core_ping;
 	hdev->session_init = q6_hfi_session_init;
 	hdev->session_end = q6_hfi_session_end;
 	hdev->session_abort = q6_hfi_session_abort;
@@ -1414,15 +1346,10 @@
 	hdev->session_flush = q6_hfi_session_flush;
 	hdev->session_set_property = q6_hfi_session_set_property;
 	hdev->session_get_property = q6_hfi_session_get_property;
-	hdev->scale_clocks = q6_hfi_scale_clocks;
-	hdev->scale_bus = q6_hfi_scale_bus;
 	hdev->unset_ocmem = q6_hfi_unset_ocmem;
-	hdev->alloc_ocmem = q6_hfi_alloc_ocmem;
-	hdev->free_ocmem = q6_hfi_free_ocmem;
 	hdev->iommu_get_domain_partition = q6_hfi_iommu_get_domain_partition;
 	hdev->load_fw = q6_hfi_load_fw;
 	hdev->unload_fw = q6_hfi_unload_fw;
-	hdev->get_fw_info = q6_hfi_get_fw_info;
 	hdev->get_stride_scanline = q6_hfi_get_stride_scanline;
 }
 
diff --git a/drivers/media/platform/msm/vidc/q6_hfi.h b/drivers/media/platform/msm/vidc/q6_hfi.h
index 3dc4607..5f48a51 100644
--- a/drivers/media/platform/msm/vidc/q6_hfi.h
+++ b/drivers/media/platform/msm/vidc/q6_hfi.h
@@ -20,6 +20,15 @@
 
 #define Q6_IFACEQ_QUEUE_SIZE (8 * 1024)
 
+/* client to Q6 communication path : forward path */
+#define VIDEO_HFI_CMD_ID  0x00012ECC
+
+/* Q6 to client ACK msg: reverse path*/
+#define VIDEO_HFI_MSG_ID  0x00012ECD
+
+/* Q6 to client event notifications */
+#define VIDEO_HFI_EVT_ID  0x00012ECE
+
 struct q6_resources {
 	struct msm_vidc_fw fw;
 };
@@ -43,6 +52,7 @@
 	struct q6_resources resources;
 	struct msm_vidc_platform_resources *res;
 	void *apr;
+	struct mutex session_lock;
 };
 
 struct q6_apr_cmd_sys_init_packet {
diff --git a/drivers/media/platform/msm/vidc/venus_hfi.c b/drivers/media/platform/msm/vidc/venus_hfi.c
index 5416210..a5aebd5 100644
--- a/drivers/media/platform/msm/vidc/venus_hfi.c
+++ b/drivers/media/platform/msm/vidc/venus_hfi.c
@@ -62,6 +62,18 @@
 	int ret;
 };
 
+#define TZBSP_VIDEO_SET_STATE 0xa
+
+enum tzbsp_video_state {
+	TZBSP_VIDEO_STATE_SUSPEND = 0,
+	TZBSP_VIDEO_STATE_RESUME
+};
+
+struct tzbsp_video_set_state_req {
+	u32 state; /*shoud be tzbsp_video_state enum value*/
+	u32 spare; /*reserved for future, should be zero*/
+};
+
 static void venus_hfi_dump_packet(u8 *packet)
 {
 	u32 c = 0, packet_size = *(u32 *)packet;
@@ -492,38 +504,320 @@
 	rmb();
 	return rc;
 }
-static inline void venus_hfi_clk_gating_on(struct venus_hfi_device *device)
+
+static int venus_hfi_core_start_cpu(struct venus_hfi_device *device)
 {
+	u32 ctrl_status = 0, count = 0, rc = 0;
+	int max_tries = 100;
+	venus_hfi_write_register(device,
+			VIDC_WRAPPER_INTR_MASK, 0x8, 0);
+	venus_hfi_write_register(device,
+			VIDC_CPU_CS_SCIACMDARG3, 1, 0);
+
+	while (!ctrl_status && count < max_tries) {
+		ctrl_status = venus_hfi_read_register(
+				device,
+				VIDC_CPU_CS_SCIACMDARG0);
+		if ((ctrl_status & 0xFE) == 0x4) {
+			dprintk(VIDC_ERR, "invalid setting for UC_REGION\n");
+			break;
+		}
+		usleep_range(500, 1000);
+		count++;
+	}
+	if (count >= max_tries)
+		rc = -ETIME;
+	return rc;
+}
+
+static int venus_hfi_iommu_attach(struct venus_hfi_device *device)
+{
+	int rc = 0;
+	struct iommu_domain *domain;
 	int i;
-	struct venus_core_clock *cl;
-	if (!device) {
-		dprintk(VIDC_ERR, "Invalid params: %p\n", device);
+	struct iommu_set *iommu_group_set;
+	struct iommu_group *group;
+	struct iommu_info *iommu_map;
+
+	if (!device || !device->res)
+		return -EINVAL;
+
+	iommu_group_set = &device->res->iommu_group_set;
+	for (i = 0; i < iommu_group_set->count; i++) {
+		iommu_map = &iommu_group_set->iommu_maps[i];
+		group = iommu_map->group;
+		domain = msm_get_iommu_domain(iommu_map->domain);
+		if (IS_ERR_OR_NULL(domain)) {
+			dprintk(VIDC_ERR,
+				"Failed to get domain: %s\n", iommu_map->name);
+			rc = PTR_ERR(domain);
+			break;
+		}
+		rc = iommu_attach_group(domain, group);
+		if (rc) {
+			dprintk(VIDC_ERR,
+				"IOMMU attach failed: %s\n", iommu_map->name);
+			break;
+		}
+	}
+	if (i < iommu_group_set->count) {
+		i--;
+		for (; i >= 0; i--) {
+			iommu_map = &iommu_group_set->iommu_maps[i];
+			group = iommu_map->group;
+			domain = msm_get_iommu_domain(iommu_map->domain);
+			if (group && domain)
+				iommu_detach_group(domain, group);
+		}
+	}
+	return rc;
+}
+
+static void venus_hfi_iommu_detach(struct venus_hfi_device *device)
+{
+	struct iommu_group *group;
+	struct iommu_domain *domain;
+	struct iommu_set *iommu_group_set;
+	struct iommu_info *iommu_map;
+	int i;
+
+	if (!device || !device->res) {
+		dprintk(VIDC_ERR, "Invalid paramter: %p\n", device);
 		return;
 	}
-	if (!device->clocks_enabled) {
-		dprintk(VIDC_DBG, "Clocks are already disabled");
-		goto already_disabled;
+
+	iommu_group_set = &device->res->iommu_group_set;
+	for (i = 0; i < iommu_group_set->count; i++) {
+		iommu_map = &iommu_group_set->iommu_maps[i];
+		group = iommu_map->group;
+		domain = msm_get_iommu_domain(iommu_map->domain);
+		if (group && domain)
+			iommu_detach_group(domain, group);
 	}
-	for (i = 0; i <= device->clk_gating_level; i++) {
-		cl = &device->resources.clock[i];
-		clk_disable(cl->clk);
-	}
-already_disabled:
-	device->clocks_enabled = 0;
 }
-static inline int venus_hfi_clk_gating_off(struct venus_hfi_device *device)
+
+static int venus_hfi_unvote_bus(void *dev,
+				enum session_type type, enum mem_type mtype)
+{
+	int rc = 0;
+	u32 handle = 0;
+	struct venus_hfi_device *device = dev;
+
+	if (!device) {
+		dprintk(VIDC_ERR, "%s invalid device handle %p",
+			__func__, device);
+		return -EINVAL;
+	}
+
+	if (mtype & DDR_MEM)
+		handle = device->resources.bus_info.ddr_handle[type];
+	if (mtype & OCMEM_MEM)
+		handle = device->resources.bus_info.ocmem_handle[type];
+
+	if (handle) {
+		rc = msm_bus_scale_client_update_request(
+				handle, 0);
+		if (rc)
+			dprintk(VIDC_ERR, "Failed to unvote bus: %d\n", rc);
+	} else {
+		dprintk(VIDC_ERR, "Failed to unvote bus, mtype: %d\n",
+				mtype);
+		rc = -EINVAL;
+	}
+	return rc;
+}
+
+static void venus_hfi_unvote_buses(void *dev, enum mem_type mtype)
 {
 	int i;
-	struct venus_core_clock *cl;
+	struct venus_hfi_device *device = dev;
+
+	if (!device) {
+		dprintk(VIDC_ERR, "%s invalid parameters", __func__);
+		return;
+	}
+
+	for (i = 0; i < MSM_VIDC_MAX_DEVICES; i++) {
+		if ((mtype & DDR_MEM) &&
+			venus_hfi_unvote_bus(device, i, DDR_MEM))
+			dprintk(VIDC_WARN,
+				"Failed to unvote for DDR accesses\n");
+
+		if ((mtype & OCMEM_MEM) &&
+			venus_hfi_unvote_bus(device, i, OCMEM_MEM))
+			dprintk(VIDC_WARN,
+				"Failed to unvote for OCMEM accesses\n");
+	}
+}
+
+static const u32 venus_hfi_bus_table[] = {
+	36000,
+	110400,
+	244800,
+	489000,
+	783360,
+	979200,
+};
+
+static int venus_hfi_get_bus_vector(struct venus_hfi_device *device, int load,
+			enum session_type type, enum mem_type mtype)
+{
+	int num_rows = sizeof(venus_hfi_bus_table)/(sizeof(u32));
+	int i, j;
+	int idx = 0;
+
+	if (!device || (mtype != DDR_MEM && mtype != OCMEM_MEM) ||
+		(type != MSM_VIDC_ENCODER && type != MSM_VIDC_DECODER)) {
+		dprintk(VIDC_ERR, "%s invalid params", __func__);
+		return -EINVAL;
+	}
+
+	for (i = 0; i < num_rows; i++) {
+		if (load <= venus_hfi_bus_table[i])
+			break;
+	}
+
+	if (type == MSM_VIDC_ENCODER)
+		idx = (mtype == DDR_MEM) ? BUS_IDX_ENC_DDR : BUS_IDX_ENC_OCMEM;
+	else
+		idx = (mtype == DDR_MEM) ? BUS_IDX_DEC_DDR : BUS_IDX_DEC_OCMEM;
+
+	j = clamp(i, 0, num_rows-1) + 1;
+
+	/* Ensure bus index remains within the supported range,
+	* as specified in the device dtsi file */
+	j = clamp(j, 0, device->res->bus_pdata[idx].num_usecases - 1);
+
+	dprintk(VIDC_DBG, "Required bus = %d\n", j);
+	return j;
+}
+
+static int venus_hfi_scale_bus(void *dev, int load,
+				enum session_type type, enum mem_type mtype)
+{
 	int rc = 0;
+	u32 handle = 0;
+	struct venus_hfi_device *device = dev;
+	int bus_vector = 0;
+
+	if (!device) {
+		dprintk(VIDC_ERR, "%s invalid device handle %p",
+			__func__, device);
+		return -EINVAL;
+	}
+
+	if (mtype & DDR_MEM)
+		handle = device->resources.bus_info.ddr_handle[type];
+	if (mtype & OCMEM_MEM)
+		handle = device->resources.bus_info.ocmem_handle[type];
+
+	if (handle) {
+		bus_vector = venus_hfi_get_bus_vector(device, load,
+				type, mtype);
+		if (bus_vector < 0) {
+			dprintk(VIDC_ERR, "Failed to get bus vector\n");
+			return -EINVAL;
+		}
+		device->bus_load[type] = load;
+		rc = msm_bus_scale_client_update_request(handle, bus_vector);
+		if (rc)
+			dprintk(VIDC_ERR, "Failed to scale bus: %d\n", rc);
+	} else {
+		dprintk(VIDC_ERR, "Failed to scale bus, mtype: %d\n",
+				mtype);
+		rc = -EINVAL;
+	}
+
+	return rc;
+}
+
+static int venus_hfi_scale_buses(void *dev, enum mem_type mtype)
+{
+	int i, rc = 0;
+	struct venus_hfi_device *device = dev;
+
+	if (!device) {
+		dprintk(VIDC_ERR, "%s invalid parameters", __func__);
+		return -EINVAL;
+	}
+	for (i = 0; i < MSM_VIDC_MAX_DEVICES; i++) {
+		if (mtype & DDR_MEM) {
+			rc = venus_hfi_scale_bus(device, device->bus_load[i],
+					i, DDR_MEM);
+			if (rc) {
+				dprintk(VIDC_ERR,
+						"Failed to scale bus for DDR accesses, session type %d, load %u\n",
+						i, device->bus_load[i]);
+				goto err_scale_bus;
+			}
+		}
+
+		if (mtype & OCMEM_MEM) {
+			rc = venus_hfi_scale_bus(device, device->bus_load[i],
+					i, OCMEM_MEM);
+			if (rc) {
+				dprintk(VIDC_ERR,
+						"Failed to scale bus for OCMEM accesses, session type %d, load %u\n",
+						i, device->bus_load[i]);
+				goto err_scale_bus;
+			}
+		}
+	}
+err_scale_bus:
+	return rc;
+}
+
+static inline int venus_hfi_tzbsp_set_video_state(enum tzbsp_video_state state)
+{
+	struct tzbsp_video_set_state_req cmd = {0};
+	int tzbsp_rsp = 0;
+	int rc = 0;
+	cmd.state = state;
+	cmd.spare = 0;
+	rc = scm_call(SCM_SVC_BOOT, TZBSP_VIDEO_SET_STATE, &cmd, sizeof(cmd),
+			&tzbsp_rsp, sizeof(tzbsp_rsp));
+	if (rc) {
+		dprintk(VIDC_ERR, "Failed scm_call %d\n", rc);
+		return rc;
+	}
+	dprintk(VIDC_DBG, "Set state %d, resp %d\n", state, tzbsp_rsp);
+	if (tzbsp_rsp) {
+		dprintk(VIDC_ERR,
+				"Failed to set video core state to suspend: %d\n",
+				tzbsp_rsp);
+		return -EINVAL;
+	}
+	return 0;
+}
+
+static inline int venus_hfi_reset_core(struct venus_hfi_device *device)
+{
+	int rc = 0;
+	venus_hfi_write_register(device,
+			VIDC_CTRL_INIT, 0x1, 0);
+	rc = venus_hfi_core_start_cpu(device);
+	if (rc)
+		dprintk(VIDC_ERR, "Failed to start core");
+	return rc;
+}
+
+
+/*Calling function is responsible to acquire device->clk_pwr_lock*/
+static inline int venus_hfi_clk_enable(struct venus_hfi_device *device)
+{
+	int rc = 0;
+	int i;
+	struct venus_core_clock *cl;
+
 	if (!device) {
 		dprintk(VIDC_ERR, "Invalid params: %p\n", device);
 		return -EINVAL;
 	}
 	if (device->clocks_enabled) {
-		dprintk(VIDC_DBG, "Clocks are already enabled");
-		goto already_enabled;
+		dprintk(VIDC_DBG, "Clocks already enabled");
+		return 0;
 	}
+
 	for (i = 0; i <= device->clk_gating_level; i++) {
 		cl = &device->resources.clock[i];
 		rc = clk_enable(cl->clk);
@@ -534,17 +828,180 @@
 			dprintk(VIDC_DBG, "Clock: %s enabled\n", cl->name);
 		}
 	}
-already_enabled:
 	device->clocks_enabled = 1;
-	return rc;
+	return 0;
 fail_clk_enable:
-	for (; i >= 0; i--) {
+	for (i--; i >= 0; i--) {
 		cl = &device->resources.clock[i];
 		clk_disable(cl->clk);
 	}
 	return rc;
 }
 
+/*Calling function is responsible to acquire device->clk_pwr_lock*/
+static inline void venus_hfi_clk_disable(struct venus_hfi_device *device)
+{
+	int i;
+	struct venus_core_clock *cl;
+
+	if (!device) {
+		dprintk(VIDC_ERR, "Invalid params: %p\n", device);
+		return;
+	}
+	if (!device->clocks_enabled) {
+		dprintk(VIDC_DBG, "Clocks already disabled");
+		return;
+	}
+
+	for (i = 0; i <= device->clk_gating_level; i++) {
+		cl = &device->resources.clock[i];
+		clk_disable(cl->clk);
+	}
+	device->clocks_enabled = 0;
+}
+
+static DECLARE_COMPLETION(pc_prep_done);
+
+static inline int venus_hfi_power_off(struct venus_hfi_device *device)
+{
+	int rc = 0;
+	if (!device) {
+		dprintk(VIDC_ERR, "Invalid params: %p\n", device);
+		return -EINVAL;
+	}
+	if (!device->power_enabled) {
+		dprintk(VIDC_DBG, "Power already disabled");
+		goto already_disabled;
+	}
+
+	/*Temporarily enable clocks to make TZ call.*/
+	rc = venus_hfi_clk_enable(device);
+	if (rc) {
+		dprintk(VIDC_ERR, "Failed to enable clocks before TZ call");
+		return rc;
+	}
+	rc = venus_hfi_tzbsp_set_video_state(TZBSP_VIDEO_STATE_SUSPEND);
+	if (rc) {
+		dprintk(VIDC_ERR, "Failed to suspend video core %d\n", rc);
+		venus_hfi_clk_disable(device);
+		return rc;
+	}
+	venus_hfi_clk_disable(device);
+	venus_hfi_iommu_detach(device);
+	rc = regulator_disable(device->gdsc);
+	if (rc) {
+		dprintk(VIDC_ERR, "Failed to disable GDSC, %d", rc);
+		return rc;
+	}
+	if (device->res->has_ocmem)
+		venus_hfi_unvote_buses(device, DDR_MEM|OCMEM_MEM);
+	else
+		venus_hfi_unvote_buses(device, DDR_MEM);
+
+	device->power_enabled = 0;
+already_disabled:
+	return rc;
+}
+
+static inline int venus_hfi_power_on(struct venus_hfi_device *device)
+{
+	int rc = 0;
+	if (!device) {
+		dprintk(VIDC_ERR, "Invalid params: %p\n", device);
+		return -EINVAL;
+	}
+
+	if (device->res->has_ocmem)
+		rc = venus_hfi_scale_buses(device, DDR_MEM|OCMEM_MEM);
+	else
+		rc = venus_hfi_scale_buses(device, DDR_MEM);
+	if (rc) {
+		dprintk(VIDC_ERR, "Failed to scale buses");
+		goto err_scale_buses;
+	}
+
+	rc = regulator_enable(device->gdsc);
+	if (rc) {
+		dprintk(VIDC_ERR, "Failed to enable GDSC %d", rc);
+		goto err_enable_gdsc;
+	}
+
+	rc = venus_hfi_iommu_attach(device);
+	if (rc) {
+		dprintk(VIDC_ERR, "Failed to attach iommu after power on");
+		goto err_iommu_attach;
+	}
+
+	rc = venus_hfi_clk_enable(device);
+	if (rc) {
+		dprintk(VIDC_ERR, "Failed to enable clocks");
+		goto err_enable_clk;
+	}
+
+	rc = venus_hfi_tzbsp_set_video_state(TZBSP_VIDEO_STATE_RESUME);
+	if (rc) {
+		dprintk(VIDC_ERR, "Failed to resume video core %d\n", rc);
+		goto err_set_video_state;
+	}
+	rc = venus_hfi_reset_core(device);
+	if (rc) {
+		dprintk(VIDC_ERR, "Failed to reset venus core");
+		goto err_reset_core;
+	}
+	device->power_enabled = 1;
+	return rc;
+err_reset_core:
+	venus_hfi_tzbsp_set_video_state(TZBSP_VIDEO_STATE_SUSPEND);
+err_set_video_state:
+	venus_hfi_clk_disable(device);
+err_enable_clk:
+	venus_hfi_iommu_detach(device);
+err_iommu_attach:
+	regulator_disable(device->gdsc);
+err_enable_gdsc:
+	if (device->res->has_ocmem)
+		venus_hfi_unvote_buses(device, DDR_MEM|OCMEM_MEM);
+	else
+		venus_hfi_unvote_buses(device, DDR_MEM);
+err_scale_buses:
+	return rc;
+}
+
+static void venus_hfi_pm_hndlr(struct work_struct *work);
+static DECLARE_DELAYED_WORK(venus_hfi_pm_work, venus_hfi_pm_hndlr);
+
+static inline int venus_hfi_clk_gating_off(struct venus_hfi_device *device)
+{
+	int rc = 0;
+	if (!device) {
+		dprintk(VIDC_ERR, "Invalid params: %p\n", device);
+		return -EINVAL;
+	}
+	if (device->clocks_enabled) {
+		dprintk(VIDC_DBG, "Clocks are already enabled");
+		goto already_enabled;
+	}
+	cancel_delayed_work(&venus_hfi_pm_work);
+	if (!device->power_enabled) {
+		/*This will enable clocks as well*/
+		rc = venus_hfi_power_on(device);
+		if (rc) {
+			dprintk(VIDC_ERR, "Failed venus power on");
+			goto fail_clk_power_on;
+		}
+	} else {
+		rc = venus_hfi_clk_enable(device);
+		if (rc) {
+			dprintk(VIDC_ERR, "Failed venus clock enable");
+			goto fail_clk_power_on;
+		}
+	}
+already_enabled:
+	device->clocks_enabled = 1;
+fail_clk_power_on:
+	return rc;
+}
+
 static unsigned long venus_hfi_get_clock_rate(struct venus_core_clock *clock,
 	int num_mbs_per_sec)
 {
@@ -569,7 +1026,7 @@
 		dprintk(VIDC_ERR, "Invalid args: %p\n", device);
 		return -EINVAL;
 	}
-	device->load = load;
+	device->clk_load = load;
 	rc = clk_set_rate(device->resources.clock[VCODEC_CLK].clk,
 		venus_hfi_get_clock_rate(&device->resources.clock[VCODEC_CLK],
 			load));
@@ -595,14 +1052,14 @@
 		dprintk(VIDC_ERR, "cannot write to shared Q's");
 		goto err_q_null;
 	}
-	mutex_lock(&device->clock_lock);
+	mutex_lock(&device->clk_pwr_lock);
 	result = venus_hfi_clk_gating_off(device);
 	if (result) {
 		dprintk(VIDC_ERR, "%s : Clock enable failed\n",
 			__func__);
 		goto err_q_write;
 	}
-	result = venus_hfi_scale_clocks(device, device->load);
+	result = venus_hfi_scale_clocks(device, device->clk_load);
 	if (result) {
 		dprintk(VIDC_ERR, "Clock scaling failed\n");
 		goto err_q_write;
@@ -618,7 +1075,7 @@
 		dprintk(VIDC_ERR, "venus_hfi_iface_cmdq_write:queue_full");
 	}
 err_q_write:
-	mutex_unlock(&device->clock_lock);
+	mutex_unlock(&device->clk_pwr_lock);
 err_q_null:
 	mutex_unlock(&device->write_lock);
 	return result;
@@ -642,7 +1099,7 @@
 		goto read_error_null;
 	}
 	q_info = &device->iface_queues[VIDC_IFACEQ_MSGQ_IDX];
-	mutex_lock(&device->clock_lock);
+	mutex_lock(&device->clk_pwr_lock);
 	rc = venus_hfi_clk_gating_off(device);
 	if (rc) {
 		dprintk(VIDC_ERR,
@@ -661,7 +1118,7 @@
 		rc = -ENODATA;
 	}
 read_error:
-	mutex_unlock(&device->clock_lock);
+	mutex_unlock(&device->clk_pwr_lock);
 read_error_null:
 	mutex_unlock(&device->read_lock);
 	return rc;
@@ -684,7 +1141,7 @@
 		rc = -ENODATA;
 		goto dbg_error_null;
 	}
-	mutex_lock(&device->clock_lock);
+	mutex_lock(&device->clk_pwr_lock);
 	rc = venus_hfi_clk_gating_off(device);
 	if (rc) {
 		dprintk(VIDC_ERR,
@@ -704,7 +1161,7 @@
 		rc = -ENODATA;
 	}
 dbg_error:
-	mutex_unlock(&device->clock_lock);
+	mutex_unlock(&device->clk_pwr_lock);
 dbg_error_null:
 	mutex_unlock(&device->read_lock);
 	return rc;
@@ -954,31 +1411,6 @@
 	return -ENOMEM;
 }
 
-static int venus_hfi_core_start_cpu(struct venus_hfi_device *device)
-{
-	u32 ctrl_status = 0, count = 0, rc = 0;
-	int max_tries = 100;
-	venus_hfi_write_register(device,
-			VIDC_WRAPPER_INTR_MASK, 0x8, 0);
-	venus_hfi_write_register(device,
-			VIDC_CPU_CS_SCIACMDARG3, 1, 0);
-
-	while (!ctrl_status && count < max_tries) {
-		ctrl_status = venus_hfi_read_register(
-				device,
-				VIDC_CPU_CS_SCIACMDARG0);
-		if ((ctrl_status & 0xFE) == 0x4) {
-			dprintk(VIDC_ERR, "invalid setting for UC_REGION\n");
-			break;
-		}
-		usleep_range(500, 1000);
-		count++;
-	}
-	if (count >= max_tries)
-		rc = -ETIME;
-	return rc;
-}
-
 static void venus_hfi_set_registers(struct venus_hfi_device *device)
 {
 	struct reg_set *reg_set;
@@ -1045,6 +1477,7 @@
 	INIT_LIST_HEAD(&dev->sess_head);
 	mutex_init(&dev->read_lock);
 	mutex_init(&dev->write_lock);
+	mutex_init(&dev->session_lock);
 	venus_hfi_set_registers(dev);
 
 	if (!dev->hal_client) {
@@ -1110,12 +1543,12 @@
 		return -ENODEV;
 	}
 	if (dev->hal_client) {
-		mutex_lock(&dev->clock_lock);
+		mutex_lock(&dev->clk_pwr_lock);
 		rc = venus_hfi_clk_gating_off(device);
 		if (rc) {
 			dprintk(VIDC_ERR,
 				"%s : Clock enable failed\n", __func__);
-			mutex_unlock(&dev->clock_lock);
+			mutex_unlock(&dev->clk_pwr_lock);
 			return -EIO;
 		}
 		venus_hfi_write_register(dev,
@@ -1123,38 +1556,12 @@
 		if (!(dev->intr_status & VIDC_WRAPPER_INTR_STATUS_A2HWD_BMSK))
 			disable_irq_nosync(dev->hal_data->irq);
 		dev->intr_status = 0;
-		mutex_unlock(&dev->clock_lock);
+		mutex_unlock(&dev->clk_pwr_lock);
 	}
 	dprintk(VIDC_INFO, "HAL exited\n");
 	return 0;
 }
 
-int venus_hfi_core_pc_prep(void *device)
-{
-	struct hfi_cmd_sys_pc_prep_packet pkt;
-	int rc = 0;
-	struct venus_hfi_device *dev;
-
-	if (device) {
-		dev = device;
-	} else {
-		dprintk(VIDC_ERR, "invalid device");
-		return -ENODEV;
-	}
-
-	rc = create_pkt_cmd_sys_pc_prep(&pkt);
-	if (rc) {
-		dprintk(VIDC_ERR, "Failed to create sys pc prep pkt");
-		goto err_create_pkt;
-	}
-
-	if (venus_hfi_iface_cmdq_write(dev, &pkt))
-		rc = -ENOTEMPTY;
-
-err_create_pkt:
-	return rc;
-}
-
 static void venus_hfi_core_clear_interrupt(struct venus_hfi_device *device)
 {
 	u32 intr_status = 0;
@@ -1162,12 +1569,12 @@
 
 	if (!device->callback)
 		return;
-	mutex_lock(&device->clock_lock);
+	mutex_lock(&device->clk_pwr_lock);
 	rc = venus_hfi_clk_gating_off(device);
 	if (rc) {
 		dprintk(VIDC_ERR,
 			"%s : Clock enable failed\n", __func__);
-		mutex_unlock(&device->clock_lock);
+		mutex_unlock(&device->clk_pwr_lock);
 		return;
 	}
 	intr_status = venus_hfi_read_register(
@@ -1191,7 +1598,7 @@
 			VIDC_CPU_CS_A2HSOFTINTCLR, 1, 0);
 	venus_hfi_write_register(device,
 			VIDC_WRAPPER_INTR_CLEAR, intr_status, 0);
-	mutex_unlock(&device->clock_lock);
+	mutex_unlock(&device->clk_pwr_lock);
 	dprintk(VIDC_DBG, "Cleared WRAPPER/A2H interrupt");
 }
 
@@ -1484,7 +1891,10 @@
 	else if (session_type == 2)
 		new_session->is_decoder = 1;
 	new_session->device = dev;
+
+	mutex_lock(&dev->session_lock);
 	list_add_tail(&new_session->list, &dev->sess_head);
+	mutex_unlock(&dev->session_lock);
 
 	if (create_pkt_cmd_sys_session_init(&pkt, (u32)new_session,
 			session_type, codec_type)) {
@@ -1554,7 +1964,11 @@
 	sess_close = session;
 	dprintk(VIDC_DBG, "deleted the session: 0x%p",
 			sess_close);
+	mutex_lock(&((struct venus_hfi_device *)
+			sess_close->device)->session_lock);
 	list_del(&sess_close->list);
+	mutex_unlock(&((struct venus_hfi_device *)
+			sess_close->device)->session_lock);
 	kfree(sess_close);
 	return 0;
 }
@@ -1922,6 +2336,91 @@
 	return rc;
 }
 
+static int venus_hfi_core_pc_prep(void *device)
+{
+	struct hfi_cmd_sys_pc_prep_packet pkt;
+	int rc = 0;
+	struct venus_hfi_device *dev;
+
+	if (device) {
+		dev = device;
+	} else {
+		dprintk(VIDC_ERR, "invalid device");
+		return -ENODEV;
+	}
+
+	rc = create_pkt_cmd_sys_pc_prep(&pkt);
+	if (rc) {
+		dprintk(VIDC_ERR, "Failed to create sys pc prep pkt");
+		goto err_create_pkt;
+	}
+
+	if (venus_hfi_iface_cmdq_write(dev, &pkt))
+		rc = -ENOTEMPTY;
+
+err_create_pkt:
+	return rc;
+}
+
+
+static void venus_hfi_pm_hndlr(struct work_struct *work)
+{
+	int rc = 0;
+	struct venus_hfi_device *device = list_first_entry(
+			&hal_ctxt.dev_head, struct venus_hfi_device, list);
+	mutex_lock(&device->clk_pwr_lock);
+	if (device->clocks_enabled || !device->power_enabled) {
+		dprintk(VIDC_DBG,
+				"Clocks status: %d, Power status: %d, ignore power off\n",
+				device->clocks_enabled, device->power_enabled);
+		goto clks_enabled;
+	}
+	mutex_unlock(&device->clk_pwr_lock);
+	init_completion(&pc_prep_done);
+	rc = venus_hfi_core_pc_prep(device);
+	if (rc) {
+		dprintk(VIDC_ERR, "Failed to prepare venus for power off");
+		return;
+	}
+	rc = wait_for_completion_timeout(&pc_prep_done,
+			msecs_to_jiffies(msm_vidc_hw_rsp_timeout));
+	if (!rc) {
+		dprintk(VIDC_ERR, "Wait interrupted or timeout: %d", rc);
+		return;
+	}
+
+	mutex_lock(&device->clk_pwr_lock);
+	if (device->clocks_enabled) {
+		dprintk(VIDC_ERR,
+				"Clocks are still enabled after PC_PREP_DONE, ignore power off");
+		goto clks_enabled;
+	}
+
+	rc = venus_hfi_power_off(device);
+	if (rc)
+		dprintk(VIDC_ERR, "Failed venus power off");
+clks_enabled:
+	mutex_unlock(&device->clk_pwr_lock);
+}
+
+static inline void venus_hfi_clk_gating_on(struct venus_hfi_device *device)
+{
+	if (!device) {
+		dprintk(VIDC_ERR, "Invalid params: %p\n", device);
+		return;
+	}
+	if (!device->clocks_enabled) {
+		dprintk(VIDC_DBG, "Clocks are already disabled");
+		goto already_disabled;
+	}
+	venus_hfi_clk_disable(device);
+	if (!queue_delayed_work(device->venus_pm_workq, &venus_hfi_pm_work,
+			msecs_to_jiffies(msm_vidc_pwr_collapse_delay)))
+		dprintk(VIDC_DBG, "PM work already scheduled\n");
+already_disabled:
+	device->clocks_enabled = 0;
+}
+
 static int venus_hfi_try_clk_gating(struct venus_hfi_device *device)
 {
 	int rc = 0;
@@ -1931,15 +2430,21 @@
 		return -ENODEV;
 	}
 	mutex_lock(&device->write_lock);
-	mutex_lock(&device->clock_lock);
+	mutex_lock(&device->clk_pwr_lock);
 	rc = venus_hfi_is_cmd_pending(device);
 	ctrl_status = venus_hfi_read_register(
 		device,
 		VIDC_CPU_CS_SCIACMDARG0);
+	dprintk(VIDC_DBG,
+			"venus_hfi_try_clk_gating - rc %d, ctrl_status 0x%x",
+			rc, ctrl_status);
 	if (((ctrl_status & VIDC_CPU_CS_SCIACMDARG0_HFI_CTRL_INIT_IDLE_MSG_BMSK)
-		!= 0) && !rc)
+		|| (ctrl_status & VIDC_CPU_CS_SCIACMDARG0_HFI_CTRL_PC_READY))
+			&& !rc)
 		venus_hfi_clk_gating_on(device);
-	mutex_unlock(&device->clock_lock);
+	else
+		dprintk(VIDC_DBG, "Ignore clock gating");
+	mutex_unlock(&device->clk_pwr_lock);
 	mutex_unlock(&device->write_lock);
 	return rc;
 }
@@ -1985,7 +2490,8 @@
 		while (!venus_hfi_iface_msgq_read(device, packet)) {
 			rc = hfi_process_msg_packet(device->callback,
 				device->device_id,
-				(struct vidc_hal_msg_pkt_hdr *) packet);
+				(struct vidc_hal_msg_pkt_hdr *) packet,
+				&device->sess_head, &device->session_lock);
 			if (rc == HFI_MSG_EVENT_NOTIFY)
 				venus_hfi_process_msg_event_notify(
 					device, (void *)packet);
@@ -1997,6 +2503,14 @@
 		}
 		if (rc == HFI_MSG_SYS_IDLE)
 			rc = venus_hfi_try_clk_gating(device);
+		else if (rc == HFI_MSG_SYS_PC_PREP_DONE) {
+			dprintk(VIDC_DBG, "Received HFI_MSG_SYS_PC_PREP_DONE");
+			rc = venus_hfi_try_clk_gating(device);
+			if (rc)
+				dprintk(VIDC_ERR,
+					"Failed clk gating after PC_PREP_DONE");
+			complete(&pc_prep_done);
+		}
 	} else {
 		dprintk(VIDC_ERR, "SPURIOUS_INTERRUPT");
 	}
@@ -2177,6 +2691,7 @@
 		dprintk(VIDC_ERR, "Invalid params: %p\n", device);
 		return;
 	}
+	mutex_lock(&device->clk_pwr_lock);
 	if (device->clocks_enabled) {
 		for (i = VCODEC_CLK; i < VCODEC_MAX_CLKS; i++) {
 			cl = &device->resources.clock[i];
@@ -2196,6 +2711,7 @@
 		clk_unprepare(cl->clk);
 	}
 	device->clocks_enabled = 0;
+	mutex_unlock(&device->clk_pwr_lock);
 }
 static inline int venus_hfi_enable_clks(struct venus_hfi_device *device)
 {
@@ -2206,7 +2722,7 @@
 		dprintk(VIDC_ERR, "Invalid params: %p\n", device);
 		return -EINVAL;
 	}
-
+	mutex_lock(&device->clk_pwr_lock);
 	for (i = VCODEC_CLK; i < VCODEC_MAX_CLKS; i++) {
 		if (i == VCODEC_OCMEM_CLK && !device->res->has_ocmem)
 			continue;
@@ -2220,12 +2736,14 @@
 		}
 	}
 	device->clocks_enabled = 1;
+	mutex_unlock(&device->clk_pwr_lock);
 	return rc;
 fail_clk_enable:
 	for (; i >= 0; i--) {
 		cl = &device->resources.clock[i];
 		clk_disable_unprepare(cl->clk);
 	}
+	mutex_unlock(&device->clk_pwr_lock);
 	return rc;
 }
 static int venus_hfi_register_iommu_domains(struct venus_hfi_device *device,
@@ -2371,118 +2889,6 @@
 	return -EINVAL;
 }
 
-
-static const u32 venus_hfi_bus_table[] = {
-	36000,
-	110400,
-	244800,
-	489000,
-	783360,
-	979200,
-};
-
-static int venus_hfi_get_bus_vector(struct venus_hfi_device *device, int load,
-			enum session_type type, enum mem_type mtype)
-{
-	int num_rows = sizeof(venus_hfi_bus_table)/(sizeof(u32));
-	int i, j;
-	int idx = 0;
-
-	if (!device || (mtype != DDR_MEM && mtype != OCMEM_MEM) ||
-		(type != MSM_VIDC_ENCODER && type != MSM_VIDC_DECODER)) {
-		dprintk(VIDC_ERR, "%s invalid params", __func__);
-		return -EINVAL;
-	}
-
-	for (i = 0; i < num_rows; i++) {
-		if (load <= venus_hfi_bus_table[i])
-			break;
-	}
-
-	if (type == MSM_VIDC_ENCODER)
-		idx = (mtype == DDR_MEM) ? BUS_IDX_ENC_DDR : BUS_IDX_ENC_OCMEM;
-	else
-		idx = (mtype == DDR_MEM) ? BUS_IDX_DEC_DDR : BUS_IDX_DEC_OCMEM;
-
-	j = clamp(i, 0, num_rows-1) + 1;
-
-	/* Ensure bus index remains within the supported range,
-	* as specified in the device dtsi file */
-	j = clamp(j, 0, device->res->bus_pdata[idx].num_usecases - 1);
-
-	dprintk(VIDC_DBG, "Required bus = %d\n", j);
-	return j;
-}
-
-static int venus_hfi_scale_bus(void *dev, int load,
-				enum session_type type, enum mem_type mtype)
-{
-	int rc = 0;
-	u32 handle = 0;
-	struct venus_hfi_device *device = dev;
-	int bus_vector = 0;
-
-	if (!device) {
-		dprintk(VIDC_ERR, "%s invalid device handle %p",
-			__func__, device);
-		return -EINVAL;
-	}
-
-	if (mtype & DDR_MEM)
-		handle = device->resources.bus_info.ddr_handle[type];
-	if (mtype & OCMEM_MEM)
-		handle = device->resources.bus_info.ocmem_handle[type];
-
-	if (handle) {
-		bus_vector = venus_hfi_get_bus_vector(device, load,
-				type, mtype);
-		if (bus_vector < 0) {
-			dprintk(VIDC_ERR, "Failed to get bus vector\n");
-			return -EINVAL;
-		}
-		rc = msm_bus_scale_client_update_request(handle, bus_vector);
-		if (rc)
-			dprintk(VIDC_ERR, "Failed to scale bus: %d\n", rc);
-	} else {
-		dprintk(VIDC_ERR, "Failed to scale bus, mtype: %d\n",
-				mtype);
-		rc = -EINVAL;
-	}
-
-	return rc;
-}
-
-static int venus_hfi_unvote_bus(void *dev,
-				enum session_type type, enum mem_type mtype)
-{
-	int rc = 0;
-	u32 handle = 0;
-	struct venus_hfi_device *device = dev;
-
-	if (!device) {
-		dprintk(VIDC_ERR, "%s invalid device handle %p",
-			__func__, device);
-		return -EINVAL;
-	}
-
-	if (mtype & DDR_MEM)
-		handle = device->resources.bus_info.ddr_handle[type];
-	if (mtype & OCMEM_MEM)
-		handle = device->resources.bus_info.ocmem_handle[type];
-
-	if (handle) {
-		rc = msm_bus_scale_client_update_request(
-				handle, 0);
-		if (rc)
-			dprintk(VIDC_ERR, "Failed to unvote bus: %d\n", rc);
-	} else {
-		dprintk(VIDC_ERR, "Failed to unvote bus, mtype: %d\n",
-				mtype);
-		rc = -EINVAL;
-	}
-	return rc;
-}
-
 static int venus_hfi_set_ocmem(void *dev, struct ocmem_buf *ocmem)
 {
 	struct vidc_resource_hdr rhdr;
@@ -2648,6 +3054,15 @@
 	int rc = 0;
 
 	device->res = res;
+	if (!res) {
+		dprintk(VIDC_ERR, "Invalid params: %p\n", res);
+		return -ENODEV;
+	}
+	device->gdsc = devm_regulator_get(&res->pdev->dev, "vdd");
+	if (IS_ERR(device->gdsc)) {
+		dprintk(VIDC_ERR, "Failed to get Venus GDSC\n");
+		return -ENODEV;
+	}
 	rc = venus_hfi_init_clocks(res, device);
 	if (rc) {
 		dprintk(VIDC_ERR, "Failed to init clocks\n");
@@ -2677,6 +3092,7 @@
 err_init_bus:
 	venus_hfi_deinit_clocks(device);
 err_init_clocks:
+	device->gdsc = NULL;
 	return rc;
 }
 
@@ -2687,72 +3103,7 @@
 	venus_hfi_deregister_iommu_domains(device);
 	venus_hfi_deinit_bus(device);
 	venus_hfi_deinit_clocks(device);
-}
-
-static int venus_hfi_iommu_attach(struct venus_hfi_device *device)
-{
-	int rc = 0;
-	struct iommu_domain *domain;
-	int i;
-	struct iommu_set *iommu_group_set;
-	struct iommu_group *group;
-	struct iommu_info *iommu_map;
-
-	if (!device || !device->res)
-		return -EINVAL;
-
-	iommu_group_set = &device->res->iommu_group_set;
-	for (i = 0; i < iommu_group_set->count; i++) {
-		iommu_map = &iommu_group_set->iommu_maps[i];
-		group = iommu_map->group;
-		domain = msm_get_iommu_domain(iommu_map->domain);
-		if (IS_ERR_OR_NULL(domain)) {
-			dprintk(VIDC_ERR,
-				"Failed to get domain: %s\n", iommu_map->name);
-			rc = PTR_ERR(domain);
-			break;
-		}
-		rc = iommu_attach_group(domain, group);
-		if (rc) {
-			dprintk(VIDC_ERR,
-				"IOMMU attach failed: %s\n", iommu_map->name);
-			break;
-		}
-	}
-	if (i < iommu_group_set->count) {
-		i--;
-		for (; i >= 0; i--) {
-			iommu_map = &iommu_group_set->iommu_maps[i];
-			group = iommu_map->group;
-			domain = msm_get_iommu_domain(iommu_map->domain);
-			if (group && domain)
-				iommu_detach_group(domain, group);
-		}
-	}
-	return rc;
-}
-
-static void venus_hfi_iommu_detach(struct venus_hfi_device *device)
-{
-	struct iommu_group *group;
-	struct iommu_domain *domain;
-	struct iommu_set *iommu_group_set;
-	struct iommu_info *iommu_map;
-	int i;
-
-	if (!device || !device->res) {
-		dprintk(VIDC_ERR, "Invalid paramter: %p\n", device);
-		return;
-	}
-
-	iommu_group_set = &device->res->iommu_group_set;
-	for (i = 0; i < iommu_group_set->count; i++) {
-		iommu_map = &iommu_group_set->iommu_maps[i];
-		group = iommu_map->group;
-		domain = msm_get_iommu_domain(iommu_map->domain);
-		if (group && domain)
-			iommu_detach_group(domain, group);
-	}
+	device->gdsc = NULL;
 }
 
 static int venus_hfi_iommu_get_domain_partition(void *dev, u32 flags,
@@ -2824,12 +3175,12 @@
 	int rc = 0;
 	struct venus_hfi_device *device = dev;
 
-	if (!device) {
+	if (!device || !device->gdsc) {
 		dprintk(VIDC_ERR, "%s Invalid paramter: %p\n",
 			__func__, device);
 		return -EINVAL;
 	}
-	mutex_init(&device->clock_lock);
+	mutex_init(&device->clk_pwr_lock);
 	device->clk_gating_level = VCODEC_CLK;
 	rc = venus_hfi_iommu_attach(device);
 	if (rc) {
@@ -2837,14 +3188,25 @@
 		goto fail_iommu_attach;
 	}
 
-	if (!device->resources.fw.cookie)
+	mutex_lock(&device->clk_pwr_lock);
+	if (!device->resources.fw.cookie) {
+		rc = regulator_enable(device->gdsc);
+		if (rc) {
+			dprintk(VIDC_ERR, "Failed to enable GDSC %d", rc);
+			mutex_unlock(&device->clk_pwr_lock);
+			goto fail_enable_gdsc;
+		}
 		device->resources.fw.cookie = subsystem_get("venus");
+	}
 
 	if (IS_ERR_OR_NULL(device->resources.fw.cookie)) {
 		dprintk(VIDC_ERR, "Failed to download firmware\n");
 		rc = -ENOMEM;
+		mutex_unlock(&device->clk_pwr_lock);
 		goto fail_load_fw;
 	}
+	device->power_enabled = 1;
+	mutex_unlock(&device->clk_pwr_lock);
 	/*Clocks can be enabled only after pil_get since
 	 * gdsc is turned-on in pil_get*/
 	rc = venus_hfi_enable_clks(device);
@@ -2865,7 +3227,12 @@
 fail_enable_clks:
 	subsystem_put(device->resources.fw.cookie);
 fail_load_fw:
+	mutex_lock(&device->clk_pwr_lock);
 	device->resources.fw.cookie = NULL;
+	regulator_disable(device->gdsc);
+	device->power_enabled = 0;
+	mutex_unlock(&device->clk_pwr_lock);
+fail_enable_gdsc:
 	venus_hfi_iommu_detach(device);
 fail_iommu_attach:
 	return rc;
@@ -2881,8 +3248,13 @@
 	}
 	if (device->resources.fw.cookie) {
 		flush_workqueue(device->vidc_workq);
+		flush_workqueue(device->venus_pm_workq);
 		venus_hfi_disable_clks(device);
+		mutex_lock(&device->clk_pwr_lock);
 		subsystem_put(device->resources.fw.cookie);
+		regulator_disable(device->gdsc);
+		device->power_enabled = 0;
+		mutex_unlock(&device->clk_pwr_lock);
 		venus_hfi_interface_queues_release(dev);
 		venus_hfi_iommu_detach(device);
 		device->resources.fw.cookie = NULL;
@@ -2983,9 +3355,15 @@
 	hdevice->vidc_workq = create_singlethread_workqueue(
 		"msm_vidc_workerq_venus");
 	if (!hdevice->vidc_workq) {
-		dprintk(VIDC_ERR, ": create workq failed\n");
+		dprintk(VIDC_ERR, ": create vidc workq failed\n");
 		goto error_createq;
 	}
+	hdevice->venus_pm_workq = create_singlethread_workqueue(
+			"pm_workerq_venus");
+	if (!hdevice->venus_pm_workq) {
+		dprintk(VIDC_ERR, ": create pm workq failed\n");
+		goto error_createq_pm;
+	}
 
 	if (hal_ctxt.dev_count == 0)
 		INIT_LIST_HEAD(&hal_ctxt.dev_head);
@@ -2995,6 +3373,8 @@
 	hal_ctxt.dev_count++;
 
 	return (void *) hdevice;
+error_createq_pm:
+	destroy_workqueue(hdevice->vidc_workq);
 error_createq:
 err_init_regs:
 	kfree(hdevice);
@@ -3045,6 +3425,7 @@
 				free_irq(dev->hal_data->irq, close);
 				list_del(&close->list);
 				destroy_workqueue(close->vidc_workq);
+				destroy_workqueue(close->venus_pm_workq);
 				kfree(close->hal_data);
 				kfree(close);
 				break;
diff --git a/drivers/media/platform/msm/vidc/venus_hfi.h b/drivers/media/platform/msm/vidc/venus_hfi.h
index a59a053..f1d8694 100644
--- a/drivers/media/platform/msm/vidc/venus_hfi.h
+++ b/drivers/media/platform/msm/vidc/venus_hfi.h
@@ -182,12 +182,15 @@
 	struct list_head sess_head;
 	u32 intr_status;
 	u32 device_id;
-	u32 load;
+	u32 clk_load;
+	u32 bus_load[MSM_VIDC_MAX_DEVICES];
 	u32 clocks_enabled;
+	u32 power_enabled;
 	enum vidc_clocks clk_gating_level;
 	struct mutex read_lock;
 	struct mutex write_lock;
-	struct mutex clock_lock;
+	struct mutex clk_pwr_lock;
+	struct mutex session_lock;
 	msm_vidc_callback callback;
 	struct vidc_mem_addr iface_q_table;
 	struct vidc_mem_addr qdss;
@@ -197,6 +200,7 @@
 	struct smem_client *hal_client;
 	struct hal_data *hal_data;
 	struct workqueue_struct *vidc_workq;
+	struct workqueue_struct *venus_pm_workq;
 	int spur_count;
 	int reg_count;
 	u32 base_addr;
@@ -205,6 +209,7 @@
 	u32 irq;
 	struct venus_resources resources;
 	struct msm_vidc_platform_resources *res;
+	struct regulator *gdsc;
 };
 
 void venus_hfi_delete_device(void *device);
diff --git a/drivers/media/platform/msm/vidc/vidc_hfi.h b/drivers/media/platform/msm/vidc/vidc_hfi.h
index 874738b..5059273 100644
--- a/drivers/media/platform/msm/vidc/vidc_hfi.h
+++ b/drivers/media/platform/msm/vidc/vidc_hfi.h
@@ -832,6 +832,7 @@
 };
 
 u32 hfi_process_msg_packet(msm_vidc_callback callback,
-		u32 device_id, struct vidc_hal_msg_pkt_hdr *msg_hdr);
+		u32 device_id, struct vidc_hal_msg_pkt_hdr *msg_hdr,
+		struct list_head *sessions, struct mutex *session_lock);
 #endif
 
diff --git a/drivers/media/platform/msm/vidc/vidc_hfi_api.h b/drivers/media/platform/msm/vidc/vidc_hfi_api.h
index 010f15d..b600d64 100644
--- a/drivers/media/platform/msm/vidc/vidc_hfi_api.h
+++ b/drivers/media/platform/msm/vidc/vidc_hfi_api.h
@@ -176,6 +176,7 @@
 	HAL_PARAM_VENC_MAX_NUM_B_FRAMES,
 	HAL_PARAM_BUFFER_ALLOC_MODE,
 	HAL_PARAM_VDEC_FRAME_ASSEMBLY,
+	HAL_PARAM_VDEC_CONCEAL_COLOR,
 };
 
 enum hal_domain {
@@ -200,7 +201,8 @@
 	HAL_VIDEO_CODEC_VP6      = 0x00000400,
 	HAL_VIDEO_CODEC_VP7      = 0x00000800,
 	HAL_VIDEO_CODEC_VP8      = 0x00001000,
-	HAL_VIDEO_CODEC_HEVC     = 0x00010000,
+	HAL_VIDEO_CODEC_HEVC     = 0x00002000,
+	HAL_VIDEO_CODEC_HEVC_HYBRID     = 0x00004000,
 	HAL_UNUSED_CODEC = 0x10000000,
 };
 
@@ -315,6 +317,7 @@
 	HAL_H264_LEVEL_42 = 0x00002000,
 	HAL_H264_LEVEL_5  = 0x00004000,
 	HAL_H264_LEVEL_51 = 0x00008000,
+	HAL_H264_LEVEL_52 = 0x00010000,
 	HAL_UNUSED_H264_LEVEL = 0x10000000,
 };
 
diff --git a/drivers/media/platform/msm/vidc/vidc_hfi_helper.h b/drivers/media/platform/msm/vidc/vidc_hfi_helper.h
index 0f1e896..b5c431e 100644
--- a/drivers/media/platform/msm/vidc/vidc_hfi_helper.h
+++ b/drivers/media/platform/msm/vidc/vidc_hfi_helper.h
@@ -79,7 +79,8 @@
 #define HFI_VIDEO_CODEC_VC1				0x00000100
 #define HFI_VIDEO_CODEC_SPARK				0x00000200
 #define HFI_VIDEO_CODEC_VP8				0x00001000
-#define HFI_VIDEO_CODEC_HEVC				0x00010000
+#define HFI_VIDEO_CODEC_HEVC				0x00002000
+#define HFI_VIDEO_CODEC_HEVC_HYBRID			0x00004000
 
 #define HFI_H264_PROFILE_BASELINE			0x00000001
 #define HFI_H264_PROFILE_MAIN				0x00000002
@@ -105,6 +106,7 @@
 #define HFI_H264_LEVEL_42					0x00002000
 #define HFI_H264_LEVEL_5					0x00004000
 #define HFI_H264_LEVEL_51					0x00008000
+#define HFI_H264_LEVEL_52                                       0x00010000
 
 #define HFI_H263_PROFILE_BASELINE			0x00000001
 
@@ -435,6 +437,10 @@
 	u32 max_num_b_frames;
 };
 
+struct hfi_conceal_color {
+	u32 conceal_color;
+};
+
 struct hfi_intra_period {
 	u32 pframes;
 	u32 bframes;
diff --git a/drivers/media/platform/msm/vidc/vidc_hfi_io.h b/drivers/media/platform/msm/vidc/vidc_hfi_io.h
index eeffe35..6377fbf 100644
--- a/drivers/media/platform/msm/vidc/vidc_hfi_io.h
+++ b/drivers/media/platform/msm/vidc/vidc_hfi_io.h
@@ -49,6 +49,7 @@
 #define VIDC_CPU_CS_SCIACMDARG0_HFI_CTRL_ERROR_STATUS_SHFT	0x1
 #define VIDC_CPU_CS_SCIACMDARG0_HFI_CTRL_INIT_STATUS_BMSK	0x1
 #define VIDC_CPU_CS_SCIACMDARG0_HFI_CTRL_INIT_STATUS_SHFT	0x0
+#define VIDC_CPU_CS_SCIACMDARG0_HFI_CTRL_PC_READY           0x100
 #define VIDC_CPU_CS_SCIACMDARG0_HFI_CTRL_INIT_IDLE_MSG_BMSK     0x40000000
 
 /* HFI_QTBL_INFO */
diff --git a/drivers/media/platform/msm/wfd/wfd-ioctl.c b/drivers/media/platform/msm/wfd/wfd-ioctl.c
index 58e008d..e3c9b2a 100644
--- a/drivers/media/platform/msm/wfd/wfd-ioctl.c
+++ b/drivers/media/platform/msm/wfd/wfd-ioctl.c
@@ -134,10 +134,18 @@
 
 static void wfd_vidbuf_wait_prepare(struct vb2_queue *q)
 {
+	struct file *priv_data = (struct file *)(q->drv_priv);
+	struct wfd_inst *inst = file_to_inst(priv_data);
+
+	mutex_unlock(&inst->vb2_lock);
 }
 
 static void wfd_vidbuf_wait_finish(struct vb2_queue *q)
 {
+	struct file *priv_data = (struct file *)(q->drv_priv);
+	struct wfd_inst *inst = file_to_inst(priv_data);
+
+	mutex_lock(&inst->vb2_lock);
 }
 
 static unsigned long wfd_enc_addr_to_mdp_addr(struct wfd_inst *inst,
@@ -1026,10 +1034,9 @@
 
 	WFD_MSG_DBG("Waiting to dequeue buffer\n");
 
-	/* XXX: If we switch to non-blocking mode in the future,
-	 * we'll need to lock this with vb2_lock */
-	rc = vb2_dqbuf(&inst->vid_bufq, b, false /* blocking */);
-
+	mutex_lock(&inst->vb2_lock);
+	rc = vb2_dqbuf(&inst->vid_bufq, b, false);
+	mutex_unlock(&inst->vb2_lock);
 	if (rc)
 		WFD_MSG_ERR("Failed to dequeue buffer\n");
 	else
diff --git a/drivers/media/radio/radio-iris.c b/drivers/media/radio/radio-iris.c
index b9eb8f9..5e056be 100644
--- a/drivers/media/radio/radio-iris.c
+++ b/drivers/media/radio/radio-iris.c
@@ -126,6 +126,11 @@
 		struct rds_grp_data rds_buf);
 static void hci_ev_ert(struct iris_device *radio);
 static int update_spur_table(struct iris_device *radio);
+static int initialise_recv(struct iris_device *radio);
+static int initialise_trans(struct iris_device *radio);
+static int is_enable_rx_possible(struct iris_device *radio);
+static int is_enable_tx_possible(struct iris_device *radio);
+
 static struct v4l2_queryctrl iris_v4l2_queryctrl[] = {
 	{
 	.id	= V4L2_CID_AUDIO_VOLUME,
@@ -1633,13 +1638,16 @@
 	__u8 status = *((__u8 *) skb->data);
 	struct iris_device *radio = video_get_drvdata(video_get_dev());
 
-	if (status)
-		return;
-	if ((radio->mode != FM_CALIB) && (radio->mode != FM_OFF))
+	if ((radio->mode == FM_TURNING_OFF) && (status == 0)) {
 		iris_q_event(radio, IRIS_EVT_RADIO_DISABLED);
-	radio->mode = FM_OFF;
-
-	radio_hci_req_complete(hdev, status);
+		radio_hci_req_complete(hdev, status);
+		radio->mode = FM_OFF;
+	} else if (radio->mode == FM_CALIB) {
+		radio_hci_req_complete(hdev, status);
+	} else if ((radio->mode == FM_RECV) || (radio->mode == FM_TRANS)) {
+		iris_q_event(radio, IRIS_EVT_RADIO_DISABLED);
+		radio->mode = FM_OFF;
+	}
 }
 
 static void hci_cc_conf_rsp(struct radio_hci_dev *hdev, struct sk_buff *skb)
@@ -1673,11 +1681,18 @@
 	struct hci_fm_conf_rsp  *rsp = (void *)skb->data;
 	struct iris_device *radio = video_get_drvdata(video_get_dev());
 
-	if (rsp->status)
+	if (rsp->status) {
+		radio_hci_req_complete(hdev, rsp->status);
 		return;
-	if (radio->mode != FM_CALIB)
-		iris_q_event(radio, IRIS_EVT_RADIO_READY);
+	}
 
+	if (radio->mode == FM_RECV_TURNING_ON) {
+		radio->mode = FM_RECV;
+		iris_q_event(radio, IRIS_EVT_RADIO_READY);
+	} else if (radio->mode == FM_TRANS_TURNING_ON) {
+		radio->mode = FM_TRANS;
+		iris_q_event(radio, IRIS_EVT_RADIO_READY);
+	}
 	radio_hci_req_complete(hdev, rsp->status);
 }
 
@@ -2046,8 +2061,7 @@
 
 	if (radio->fm_st_rsp.station_rsp.stereo_prg)
 		iris_q_event(radio, IRIS_EVT_STEREO);
-
-	if (radio->fm_st_rsp.station_rsp.mute_mode)
+	else if (radio->fm_st_rsp.station_rsp.stereo_prg == 0)
 		iris_q_event(radio, IRIS_EVT_MONO);
 
 	if (radio->fm_st_rsp.station_rsp.rds_sync_status)
@@ -2695,7 +2709,9 @@
 			radio->fm_hdev);
 	if (retval < 0)
 		FMDERR("Disable Failed after calibration %d", retval);
-	radio->mode = FM_TURNING_OFF;
+	else
+		radio->mode = FM_OFF;
+
 	return retval;
 }
 static int iris_vidioc_g_ctrl(struct file *file, void *priv,
@@ -3177,82 +3193,60 @@
 	case V4L2_CID_PRIVATE_IRIS_STATE:
 		switch (ctrl->value) {
 		case FM_RECV:
+			if (is_enable_rx_possible(radio) != 0)
+				return -EINVAL;
+			radio->mode = FM_RECV_TURNING_ON;
 			retval = hci_cmd(HCI_FM_ENABLE_RECV_CMD,
 							 radio->fm_hdev);
 			if (retval < 0) {
 				FMDERR("Error while enabling RECV FM"
 							" %d\n", retval);
+				radio->mode = FM_OFF;
 				return retval;
+			} else {
+				initialise_recv(radio);
 			}
-			radio->mode = FM_RECV;
-			radio->mute_mode.soft_mute = CTRL_ON;
-			retval = hci_set_fm_mute_mode(
-						&radio->mute_mode,
-							radio->fm_hdev);
-			if (retval < 0) {
-				FMDERR("Failed to enable Smute\n");
-				return retval;
-			}
-			radio->stereo_mode.stereo_mode = CTRL_OFF;
-			radio->stereo_mode.sig_blend = CTRL_ON;
-			radio->stereo_mode.intf_blend = CTRL_ON;
-			radio->stereo_mode.most_switch = CTRL_ON;
-			retval = hci_set_fm_stereo_mode(
-						&radio->stereo_mode,
-							radio->fm_hdev);
-			if (retval < 0) {
-				FMDERR("Failed to set stereo mode\n");
-				return retval;
-			}
-			radio->event_mask = SIG_LEVEL_INTR |
-						RDS_SYNC_INTR | AUDIO_CTRL_INTR;
-			retval = hci_conf_event_mask(&radio->event_mask,
-							radio->fm_hdev);
-			if (retval < 0) {
-				FMDERR("Enable Async events failed");
-				return retval;
-			}
-			retval = hci_cmd(HCI_FM_GET_RECV_CONF_CMD,
-						radio->fm_hdev);
-			if (retval < 0)
-				FMDERR("Failed to get the Recv Config\n");
 			break;
 		case FM_TRANS:
+			if (is_enable_tx_possible(radio) != 0)
+				return -EINVAL;
+			radio->mode = FM_TRANS_TURNING_ON;
 			retval = hci_cmd(HCI_FM_ENABLE_TRANS_CMD,
 							 radio->fm_hdev);
 			if (retval < 0) {
 				FMDERR("Error while enabling TRANS FM"
 							" %d\n", retval);
+				radio->mode = FM_OFF;
 				return retval;
+			} else {
+				initialise_trans(radio);
 			}
-			radio->mode = FM_TRANS;
-			retval = hci_cmd(HCI_FM_GET_TX_CONFIG, radio->fm_hdev);
-			if (retval < 0)
-				FMDERR("get frequency failed %d\n", retval);
 			break;
 		case FM_OFF:
 			radio->spur_table_size = 0;
 			switch (radio->mode) {
 			case FM_RECV:
+				radio->mode = FM_TURNING_OFF;
 				retval = hci_cmd(HCI_FM_DISABLE_RECV_CMD,
 						radio->fm_hdev);
 				if (retval < 0) {
 					FMDERR("Err on disable recv FM"
 						   " %d\n", retval);
+					radio->mode = FM_RECV;
 					return retval;
 				}
-				radio->mode = FM_TURNING_OFF;
 				break;
 			case FM_TRANS:
+				radio->mode = FM_TURNING_OFF;
 				retval = hci_cmd(HCI_FM_DISABLE_TRANS_CMD,
 						radio->fm_hdev);
 
 				if (retval < 0) {
 					FMDERR("Err disabling trans FM"
 						" %d\n", retval);
+					radio->mode = FM_TRANS;
 					return retval;
 				}
-				radio->mode = FM_TURNING_OFF;
 				break;
 			default:
 				retval = -EINVAL;
@@ -4128,10 +4122,78 @@
 	radio = video_get_drvdata(video_devdata(file));
 	strlcpy(capability->driver, DRIVER_NAME, sizeof(capability->driver));
 	strlcpy(capability->card, DRIVER_CARD, sizeof(capability->card));
+	capability->capabilities = V4L2_CAP_TUNER | V4L2_CAP_RADIO;
 	radio->g_cap = capability;
 	return 0;
 }
 
+static int initialise_recv(struct iris_device *radio)
+{
+	int retval;
+
+	radio->mute_mode.soft_mute = CTRL_ON;
+	retval = hci_set_fm_mute_mode(&radio->mute_mode,
+					radio->fm_hdev);
+
+	if (retval < 0) {
+		FMDERR("Failed to enable Smute\n");
+		return retval;
+	}
+
+	radio->stereo_mode.stereo_mode = CTRL_OFF;
+	radio->stereo_mode.sig_blend = CTRL_ON;
+	radio->stereo_mode.intf_blend = CTRL_ON;
+	radio->stereo_mode.most_switch = CTRL_ON;
+	retval = hci_set_fm_stereo_mode(&radio->stereo_mode,
+						radio->fm_hdev);
+
+	if (retval < 0) {
+		FMDERR("Failed to set stereo mode\n");
+		return retval;
+	}
+
+	radio->event_mask = SIG_LEVEL_INTR | RDS_SYNC_INTR | AUDIO_CTRL_INTR;
+	retval = hci_conf_event_mask(&radio->event_mask, radio->fm_hdev);
+	if (retval < 0) {
+		FMDERR("Enable Async events failed");
+		return retval;
+	}
+
+	retval = hci_cmd(HCI_FM_GET_RECV_CONF_CMD, radio->fm_hdev);
+	if (retval < 0)
+		FMDERR("Failed to get the Recv Config\n");
+	return retval;
+}
+
+static int initialise_trans(struct iris_device *radio)
+{
+
+	int retval = hci_cmd(HCI_FM_GET_TX_CONFIG, radio->fm_hdev);
+	if (retval < 0)
+		FMDERR("get frequency failed %d\n", retval);
+
+	return retval;
+}
+
+static int is_enable_rx_possible(struct iris_device *radio)
+{
+	int retval = 1;
+
+	if (radio->mode == FM_OFF || radio->mode == FM_RECV)
+		retval = 0;
+
+	return retval;
+}
+
+static int is_enable_tx_possible(struct iris_device *radio)
+{
+	int retval = 1;
+
+	if (radio->mode == FM_OFF || radio->mode == FM_TRANS)
+		retval = 0;
+
+	return retval;
+}
 
 static const struct v4l2_ioctl_ops iris_ioctl_ops = {
 	.vidioc_querycap              = iris_vidioc_querycap,
diff --git a/drivers/media/video/v4l2-ctrls.c b/drivers/media/video/v4l2-ctrls.c
index 3222ea0..4a8d974 100644
--- a/drivers/media/video/v4l2-ctrls.c
+++ b/drivers/media/video/v4l2-ctrls.c
@@ -595,6 +595,8 @@
 	case V4L2_CID_MPEG_VIDC_VIDEO_AIR_MBS: return "Intra Refresh AIR MBS";
 	case V4L2_CID_MPEG_VIDC_VIDEO_AIR_REF: return "Intra Refresh AIR REF";
 	case V4L2_CID_MPEG_VIDC_VIDEO_CIR_MBS: return "Intra Refresh CIR MBS";
+	case V4L2_CID_MPEG_VIDC_VIDEO_VP8_PROFILE_LEVEL:
+		return "VP8 Profile Level";
 
 	/* CAMERA controls */
 	/* Keep the order of the 'case's the same as in videodev2.h! */
diff --git a/drivers/mfd/Makefile b/drivers/mfd/Makefile
index c99bed1..75a76c0 100644
--- a/drivers/mfd/Makefile
+++ b/drivers/mfd/Makefile
@@ -75,11 +75,14 @@
 obj-$(CONFIG_MCP_UCB1200)	+= ucb1x00-core.o
 obj-$(CONFIG_MCP_UCB1200_TS)	+= ucb1x00-ts.o
 
-obj-$(CONFIG_WCD9310_CODEC)       += wcd9xxx-core.o wcd9xxx-irq.o wcd9xxx-slimslave.o
-obj-$(CONFIG_WCD9304_CODEC)       += wcd9xxx-core.o wcd9xxx-irq.o wcd9xxx-slimslave.o
-obj-$(CONFIG_WCD9320_CODEC)       += wcd9xxx-core.o wcd9xxx-irq.o wcd9xxx-slimslave.o
-obj-$(CONFIG_WCD9306_CODEC)       += wcd9xxx-core.o wcd9xxx-irq.o wcd9xxx-slimslave.o
-
+obj-$(CONFIG_WCD9310_CODEC)	+= wcd9xxx-core.o wcd9xxx-irq.o \
+						wcd9xxx-slimslave.o wcd9xxx-core-resource.o
+obj-$(CONFIG_WCD9304_CODEC)	+= wcd9xxx-core.o wcd9xxx-irq.o \
+						wcd9xxx-slimslave.o wcd9xxx-core-resource.o
+obj-$(CONFIG_WCD9320_CODEC)	+= wcd9xxx-core.o wcd9xxx-irq.o wcd9xxx-slimslave.o\
+						wcd9xxx-core-resource.o
+obj-$(CONFIG_WCD9306_CODEC)	+= wcd9xxx-core.o wcd9xxx-irq.o\
+						wcd9xxx-slimslave.o wcd9xxx-core-resource.o
 
 ifeq ($(CONFIG_SA1100_ASSABET),y)
 obj-$(CONFIG_MCP_UCB1200)	+= ucb1x00-assabet.o
diff --git a/drivers/mfd/wcd9xxx-core-resource.c b/drivers/mfd/wcd9xxx-core-resource.c
new file mode 100644
index 0000000..1791d72
--- /dev/null
+++ b/drivers/mfd/wcd9xxx-core-resource.c
@@ -0,0 +1,194 @@
+/* Copyright (c) 2013, The Linux Foundation. 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 and
+ * only 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/kernel.h>
+#include <linux/module.h>
+#include <linux/types.h>
+#include <linux/delay.h>
+#include <linux/slab.h>
+#include <linux/wait.h>
+#include <linux/sched.h>
+#include <linux/mfd/wcd9xxx/core-resource.h>
+
+
+static enum wcd9xxx_intf_status wcd9xxx_intf = -1;
+
+int wcd9xxx_core_irq_init(
+	struct wcd9xxx_core_resource *wcd9xxx_core_res)
+{
+	int ret = 0;
+
+	if (wcd9xxx_core_res->irq != 1) {
+		ret = wcd9xxx_irq_init(wcd9xxx_core_res);
+		if (ret)
+			pr_err("IRQ initialization failed\n");
+	}
+
+	return ret;
+}
+EXPORT_SYMBOL(wcd9xxx_core_irq_init);
+
+int wcd9xxx_initialize_irq(
+	struct wcd9xxx_core_resource *wcd9xxx_core_res,
+	unsigned int irq,
+	unsigned int irq_base)
+{
+	wcd9xxx_core_res->irq = irq;
+	wcd9xxx_core_res->irq_base = irq_base;
+
+	return 0;
+}
+EXPORT_SYMBOL(wcd9xxx_initialize_irq);
+
+int wcd9xxx_core_res_init(
+	struct wcd9xxx_core_resource *wcd9xxx_core_res,
+	int num_irqs, int num_irq_regs,
+	int (*codec_read)(struct wcd9xxx_core_resource*, unsigned short),
+	int (*codec_write)(struct wcd9xxx_core_resource*, unsigned short, u8),
+	int (*codec_bulk_read) (struct wcd9xxx_core_resource*, unsigned short,
+							int, u8*))
+{
+	mutex_init(&wcd9xxx_core_res->pm_lock);
+	wcd9xxx_core_res->wlock_holders = 0;
+	wcd9xxx_core_res->pm_state = WCD9XXX_PM_SLEEPABLE;
+	init_waitqueue_head(&wcd9xxx_core_res->pm_wq);
+	pm_qos_add_request(&wcd9xxx_core_res->pm_qos_req,
+				PM_QOS_CPU_DMA_LATENCY,
+				PM_QOS_DEFAULT_VALUE);
+
+	wcd9xxx_core_res->codec_reg_read = codec_read;
+	wcd9xxx_core_res->codec_reg_write = codec_write;
+	wcd9xxx_core_res->codec_bulk_read = codec_bulk_read;
+	wcd9xxx_core_res->num_irqs = num_irqs;
+	wcd9xxx_core_res->num_irq_regs = num_irq_regs;
+
+	pr_info("%s: num_irqs = %d, num_irq_regs = %d\n",
+			__func__, wcd9xxx_core_res->num_irqs,
+			wcd9xxx_core_res->num_irq_regs);
+
+	return 0;
+}
+EXPORT_SYMBOL(wcd9xxx_core_res_init);
+
+void wcd9xxx_core_res_deinit(struct wcd9xxx_core_resource *wcd9xxx_core_res)
+{
+	pm_qos_remove_request(&wcd9xxx_core_res->pm_qos_req);
+	mutex_destroy(&wcd9xxx_core_res->pm_lock);
+	wcd9xxx_core_res->codec_reg_read = NULL;
+	wcd9xxx_core_res->codec_reg_write = NULL;
+	wcd9xxx_core_res->codec_bulk_read = NULL;
+}
+EXPORT_SYMBOL(wcd9xxx_core_res_deinit);
+
+enum wcd9xxx_pm_state wcd9xxx_pm_cmpxchg(
+		struct wcd9xxx_core_resource *wcd9xxx_core_res,
+		enum wcd9xxx_pm_state o,
+		enum wcd9xxx_pm_state n)
+{
+	enum wcd9xxx_pm_state old;
+	mutex_lock(&wcd9xxx_core_res->pm_lock);
+	old = wcd9xxx_core_res->pm_state;
+	if (old == o)
+		wcd9xxx_core_res->pm_state = n;
+	mutex_unlock(&wcd9xxx_core_res->pm_lock);
+	return old;
+}
+EXPORT_SYMBOL(wcd9xxx_pm_cmpxchg);
+
+int wcd9xxx_core_res_suspend(
+	struct wcd9xxx_core_resource *wcd9xxx_core_res,
+	pm_message_t pmesg)
+{
+	int ret = 0;
+
+	pr_debug("%s: enter\n", __func__);
+	/*
+	 * pm_qos_update_request() can be called after this suspend chain call
+	 * started. thus suspend can be called while lock is being held
+	 */
+	mutex_lock(&wcd9xxx_core_res->pm_lock);
+	if (wcd9xxx_core_res->pm_state == WCD9XXX_PM_SLEEPABLE) {
+		pr_debug("%s: suspending system, state %d, wlock %d\n",
+			 __func__, wcd9xxx_core_res->pm_state,
+			 wcd9xxx_core_res->wlock_holders);
+		wcd9xxx_core_res->pm_state = WCD9XXX_PM_ASLEEP;
+	} else if (wcd9xxx_core_res->pm_state == WCD9XXX_PM_AWAKE) {
+		/*
+		 * unlock to wait for pm_state == WCD9XXX_PM_SLEEPABLE
+		 * then set to WCD9XXX_PM_ASLEEP
+		 */
+		pr_debug("%s: waiting to suspend system, state %d, wlock %d\n",
+			 __func__, wcd9xxx_core_res->pm_state,
+			 wcd9xxx_core_res->wlock_holders);
+		mutex_unlock(&wcd9xxx_core_res->pm_lock);
+		if (!(wait_event_timeout(wcd9xxx_core_res->pm_wq,
+					 wcd9xxx_pm_cmpxchg(wcd9xxx_core_res,
+						  WCD9XXX_PM_SLEEPABLE,
+						  WCD9XXX_PM_ASLEEP) ==
+							WCD9XXX_PM_SLEEPABLE,
+					 HZ))) {
+			pr_debug("%s: suspend failed state %d, wlock %d\n",
+				 __func__, wcd9xxx_core_res->pm_state,
+				 wcd9xxx_core_res->wlock_holders);
+			ret = -EBUSY;
+		} else {
+			pr_debug("%s: done, state %d, wlock %d\n", __func__,
+				 wcd9xxx_core_res->pm_state,
+				 wcd9xxx_core_res->wlock_holders);
+		}
+		mutex_lock(&wcd9xxx_core_res->pm_lock);
+	} else if (wcd9xxx_core_res->pm_state == WCD9XXX_PM_ASLEEP) {
+		pr_warn("%s: system is already suspended, state %d, wlock %dn",
+			__func__, wcd9xxx_core_res->pm_state,
+			wcd9xxx_core_res->wlock_holders);
+	}
+	mutex_unlock(&wcd9xxx_core_res->pm_lock);
+
+	return ret;
+}
+EXPORT_SYMBOL(wcd9xxx_core_res_suspend);
+
+int wcd9xxx_core_res_resume(
+	struct wcd9xxx_core_resource *wcd9xxx_core_res)
+{
+	int ret = 0;
+
+	pr_debug("%s: enter\n", __func__);
+	mutex_lock(&wcd9xxx_core_res->pm_lock);
+	if (wcd9xxx_core_res->pm_state == WCD9XXX_PM_ASLEEP) {
+		pr_debug("%s: resuming system, state %d, wlock %d\n", __func__,
+				wcd9xxx_core_res->pm_state,
+				wcd9xxx_core_res->wlock_holders);
+		wcd9xxx_core_res->pm_state = WCD9XXX_PM_SLEEPABLE;
+	} else {
+		pr_warn("%s: system is already awake, state %d wlock %d\n",
+				__func__, wcd9xxx_core_res->pm_state,
+				wcd9xxx_core_res->wlock_holders);
+	}
+	mutex_unlock(&wcd9xxx_core_res->pm_lock);
+	wake_up_all(&wcd9xxx_core_res->pm_wq);
+
+	return ret;
+}
+EXPORT_SYMBOL(wcd9xxx_core_res_resume);
+
+enum wcd9xxx_intf_status wcd9xxx_get_intf_type(void)
+{
+	return wcd9xxx_intf;
+}
+EXPORT_SYMBOL(wcd9xxx_get_intf_type);
+
+void wcd9xxx_set_intf_type(enum wcd9xxx_intf_status intf_status)
+{
+	wcd9xxx_intf = intf_status;
+}
+EXPORT_SYMBOL(wcd9xxx_set_intf_type);
diff --git a/drivers/mfd/wcd9xxx-core.c b/drivers/mfd/wcd9xxx-core.c
index 3d0abce..317c6a9 100644
--- a/drivers/mfd/wcd9xxx-core.c
+++ b/drivers/mfd/wcd9xxx-core.c
@@ -19,6 +19,7 @@
 #include <linux/mfd/core.h>
 #include <linux/mfd/wcd9xxx/wcd9xxx-slimslave.h>
 #include <linux/mfd/wcd9xxx/core.h>
+#include <linux/mfd/wcd9xxx/core-resource.h>
 #include <linux/mfd/wcd9xxx/pdata.h>
 #include <linux/mfd/wcd9xxx/wcd9xxx_registers.h>
 
@@ -45,6 +46,9 @@
 #define WCD9XXX_I2C_DIGITAL_1	2
 #define WCD9XXX_I2C_DIGITAL_2	3
 
+#define ONDEMAND_REGULATOR true
+#define STATIC_REGULATOR (!ONDEMAND_REGULATOR)
+
 /* Number of return values needs to be checked for each
  * registration of Slimbus of I2C bus for each codec
  */
@@ -65,7 +69,6 @@
 static struct wcd9xxx_pdata *wcd9xxx_populate_dt_pdata(struct device *dev);
 
 struct wcd9xxx_i2c wcd9xxx_modules[MAX_WCD9XXX_DEVICE];
-static int wcd9xxx_intf = -1;
 
 static int wcd9xxx_read(struct wcd9xxx *wcd9xxx, unsigned short reg,
 		       int bytes, void *dest, bool interface_reg)
@@ -89,7 +92,9 @@
 
 	return 0;
 }
-int wcd9xxx_reg_read(struct wcd9xxx *wcd9xxx, unsigned short reg)
+static int __wcd9xxx_reg_read(
+	struct wcd9xxx *wcd9xxx,
+	unsigned short reg)
 {
 	u8 val;
 	int ret;
@@ -103,7 +108,16 @@
 	else
 		return val;
 }
-EXPORT_SYMBOL_GPL(wcd9xxx_reg_read);
+
+int wcd9xxx_reg_read(
+	struct wcd9xxx_core_resource *core_res,
+	unsigned short reg)
+{
+	struct wcd9xxx *wcd9xxx = (struct wcd9xxx *) core_res->parent;
+	return __wcd9xxx_reg_read(wcd9xxx, reg);
+
+}
+EXPORT_SYMBOL(wcd9xxx_reg_read);
 
 static int wcd9xxx_write(struct wcd9xxx *wcd9xxx, unsigned short reg,
 			int bytes, void *src, bool interface_reg)
@@ -122,8 +136,9 @@
 	return wcd9xxx->write_dev(wcd9xxx, reg, bytes, src, interface_reg);
 }
 
-int wcd9xxx_reg_write(struct wcd9xxx *wcd9xxx, unsigned short reg,
-		     u8 val)
+static int __wcd9xxx_reg_write(
+	struct wcd9xxx *wcd9xxx,
+	unsigned short reg, u8 val)
 {
 	int ret;
 
@@ -133,7 +148,15 @@
 
 	return ret;
 }
-EXPORT_SYMBOL_GPL(wcd9xxx_reg_write);
+
+int wcd9xxx_reg_write(
+	struct wcd9xxx_core_resource *core_res,
+	unsigned short reg, u8 val)
+{
+	struct wcd9xxx *wcd9xxx = (struct wcd9xxx *) core_res->parent;
+	return __wcd9xxx_reg_write(wcd9xxx, reg, val);
+}
+EXPORT_SYMBOL(wcd9xxx_reg_write);
 
 static u8 wcd9xxx_pgd_la;
 static u8 wcd9xxx_inf_la;
@@ -152,7 +175,7 @@
 	else
 		return val;
 }
-EXPORT_SYMBOL_GPL(wcd9xxx_interface_reg_read);
+EXPORT_SYMBOL(wcd9xxx_interface_reg_read);
 
 int wcd9xxx_interface_reg_write(struct wcd9xxx *wcd9xxx, unsigned short reg,
 		     u8 val)
@@ -165,37 +188,54 @@
 
 	return ret;
 }
-EXPORT_SYMBOL_GPL(wcd9xxx_interface_reg_write);
+EXPORT_SYMBOL(wcd9xxx_interface_reg_write);
 
-int wcd9xxx_bulk_read(struct wcd9xxx *wcd9xxx, unsigned short reg,
-		     int count, u8 *buf)
+static int __wcd9xxx_bulk_read(
+	struct wcd9xxx *wcd9xxx,
+	unsigned short reg,
+	int count, u8 *buf)
 {
 	int ret;
 
 	mutex_lock(&wcd9xxx->io_lock);
-
 	ret = wcd9xxx_read(wcd9xxx, reg, count, buf, false);
-
 	mutex_unlock(&wcd9xxx->io_lock);
 
 	return ret;
 }
-EXPORT_SYMBOL_GPL(wcd9xxx_bulk_read);
 
-int wcd9xxx_bulk_write(struct wcd9xxx *wcd9xxx, unsigned short reg,
+int wcd9xxx_bulk_read(
+	struct wcd9xxx_core_resource *core_res,
+	unsigned short reg,
+	int count, u8 *buf)
+{
+	struct wcd9xxx *wcd9xxx =
+			(struct wcd9xxx *) core_res->parent;
+	return __wcd9xxx_bulk_read(wcd9xxx, reg, count, buf);
+}
+EXPORT_SYMBOL(wcd9xxx_bulk_read);
+
+static int __wcd9xxx_bulk_write(struct wcd9xxx *wcd9xxx, unsigned short reg,
 		     int count, u8 *buf)
 {
 	int ret;
 
 	mutex_lock(&wcd9xxx->io_lock);
-
 	ret = wcd9xxx_write(wcd9xxx, reg, count, buf, false);
-
 	mutex_unlock(&wcd9xxx->io_lock);
 
 	return ret;
 }
-EXPORT_SYMBOL_GPL(wcd9xxx_bulk_write);
+
+int wcd9xxx_bulk_write(
+	struct wcd9xxx_core_resource *core_res,
+	unsigned short reg, int count, u8 *buf)
+{
+	struct wcd9xxx *wcd9xxx =
+			(struct wcd9xxx *) core_res->parent;
+	return __wcd9xxx_bulk_write(wcd9xxx, reg, count, buf);
+}
+EXPORT_SYMBOL(wcd9xxx_bulk_write);
 
 static int wcd9xxx_slim_read_device(struct wcd9xxx *wcd9xxx, unsigned short reg,
 				int bytes, void *dest, bool interface)
@@ -334,19 +374,19 @@
 
 static void wcd9xxx_bring_up(struct wcd9xxx *wcd9xxx)
 {
-	wcd9xxx_reg_write(wcd9xxx, WCD9XXX_A_LEAKAGE_CTL, 0x4);
-	wcd9xxx_reg_write(wcd9xxx, WCD9XXX_A_CDC_CTL, 0);
+	__wcd9xxx_reg_write(wcd9xxx, WCD9XXX_A_LEAKAGE_CTL, 0x4);
+	__wcd9xxx_reg_write(wcd9xxx, WCD9XXX_A_CDC_CTL, 0);
 	usleep_range(5000, 5000);
-	wcd9xxx_reg_write(wcd9xxx, WCD9XXX_A_CDC_CTL, 3);
-	wcd9xxx_reg_write(wcd9xxx, WCD9XXX_A_LEAKAGE_CTL, 3);
+	__wcd9xxx_reg_write(wcd9xxx, WCD9XXX_A_CDC_CTL, 3);
+	__wcd9xxx_reg_write(wcd9xxx, WCD9XXX_A_LEAKAGE_CTL, 3);
 }
 
 static void wcd9xxx_bring_down(struct wcd9xxx *wcd9xxx)
 {
-	wcd9xxx_reg_write(wcd9xxx, WCD9XXX_A_LEAKAGE_CTL, 0x7);
-	wcd9xxx_reg_write(wcd9xxx, WCD9XXX_A_LEAKAGE_CTL, 0x6);
-	wcd9xxx_reg_write(wcd9xxx, WCD9XXX_A_LEAKAGE_CTL, 0xe);
-	wcd9xxx_reg_write(wcd9xxx, WCD9XXX_A_LEAKAGE_CTL, 0x8);
+	__wcd9xxx_reg_write(wcd9xxx, WCD9XXX_A_LEAKAGE_CTL, 0x7);
+	__wcd9xxx_reg_write(wcd9xxx, WCD9XXX_A_LEAKAGE_CTL, 0x6);
+	__wcd9xxx_reg_write(wcd9xxx, WCD9XXX_A_LEAKAGE_CTL, 0xe);
+	__wcd9xxx_reg_write(wcd9xxx, WCD9XXX_A_LEAKAGE_CTL, 0x8);
 }
 
 static int wcd9xxx_reset(struct wcd9xxx *wcd9xxx)
@@ -385,13 +425,13 @@
 	int i, rc;
 	const struct wcd9xxx_codec_type *c, *d = NULL;
 
-	rc = wcd9xxx_bulk_read(wcd9xxx, WCD9XXX_A_CHIP_ID_BYTE_0,
+	rc = __wcd9xxx_bulk_read(wcd9xxx, WCD9XXX_A_CHIP_ID_BYTE_0,
 			       sizeof(wcd9xxx->id_minor),
 			       (u8 *)&wcd9xxx->id_minor);
 	if (rc < 0)
 		goto exit;
 
-	rc = wcd9xxx_bulk_read(wcd9xxx, WCD9XXX_A_CHIP_ID_BYTE_2,
+	rc = __wcd9xxx_bulk_read(wcd9xxx, WCD9XXX_A_CHIP_ID_BYTE_2,
 			       sizeof(wcd9xxx->id_major),
 			       (u8 *)&wcd9xxx->id_major);
 	if (rc < 0)
@@ -431,7 +471,8 @@
 		if (d->version > -1) {
 			*version = d->version;
 		} else {
-			rc = wcd9xxx_reg_read(wcd9xxx, WCD9XXX_A_CHIP_VERSION);
+			rc = __wcd9xxx_reg_read(wcd9xxx,
+							WCD9XXX_A_CHIP_VERSION);
 			if (rc < 0) {
 				d = NULL;
 				goto exit;
@@ -447,56 +488,145 @@
 	return d;
 }
 
+static int wcd9xxx_num_irq_regs(const struct wcd9xxx *wcd9xxx)
+{
+	return (wcd9xxx->codec_type->num_irqs / 8) +
+		((wcd9xxx->codec_type->num_irqs % 8) ? 1 : 0);
+}
+
+/*
+ * Interrupt table for v1 corresponds to newer version
+ * codecs (wcd9304 and wcd9310)
+ */
+static const struct intr_data intr_tbl_v1[] = {
+	{WCD9XXX_IRQ_SLIMBUS, false},
+	{WCD9XXX_IRQ_MBHC_INSERTION, true},
+	{WCD9XXX_IRQ_MBHC_POTENTIAL, true},
+	{WCD9XXX_IRQ_MBHC_RELEASE, true},
+	{WCD9XXX_IRQ_MBHC_PRESS, true},
+	{WCD9XXX_IRQ_MBHC_SHORT_TERM, true},
+	{WCD9XXX_IRQ_MBHC_REMOVAL, true},
+	{WCD9XXX_IRQ_BG_PRECHARGE, false},
+	{WCD9XXX_IRQ_PA1_STARTUP, false},
+	{WCD9XXX_IRQ_PA2_STARTUP, false},
+	{WCD9XXX_IRQ_PA3_STARTUP, false},
+	{WCD9XXX_IRQ_PA4_STARTUP, false},
+	{WCD9XXX_IRQ_PA5_STARTUP, false},
+	{WCD9XXX_IRQ_MICBIAS1_PRECHARGE, false},
+	{WCD9XXX_IRQ_MICBIAS2_PRECHARGE, false},
+	{WCD9XXX_IRQ_MICBIAS3_PRECHARGE, false},
+	{WCD9XXX_IRQ_HPH_PA_OCPL_FAULT, false},
+	{WCD9XXX_IRQ_HPH_PA_OCPR_FAULT, false},
+	{WCD9XXX_IRQ_EAR_PA_OCPL_FAULT, false},
+	{WCD9XXX_IRQ_HPH_L_PA_STARTUP, false},
+	{WCD9XXX_IRQ_HPH_R_PA_STARTUP, false},
+	{WCD9320_IRQ_EAR_PA_STARTUP, false},
+	{WCD9XXX_IRQ_RESERVED_0, false},
+	{WCD9XXX_IRQ_RESERVED_1, false},
+};
+
+/*
+ * Interrupt table for v2 corresponds to newer version
+ * codecs (wcd9320 and wcd9306)
+ */
+static const struct intr_data intr_tbl_v2[] = {
+	{WCD9XXX_IRQ_SLIMBUS, false},
+	{WCD9XXX_IRQ_MBHC_INSERTION, true},
+	{WCD9XXX_IRQ_MBHC_POTENTIAL, true},
+	{WCD9XXX_IRQ_MBHC_RELEASE, true},
+	{WCD9XXX_IRQ_MBHC_PRESS, true},
+	{WCD9XXX_IRQ_MBHC_SHORT_TERM, true},
+	{WCD9XXX_IRQ_MBHC_REMOVAL, true},
+	{WCD9320_IRQ_MBHC_JACK_SWITCH, true},
+	{WCD9306_IRQ_MBHC_JACK_SWITCH, true},
+	{WCD9XXX_IRQ_BG_PRECHARGE, false},
+	{WCD9XXX_IRQ_PA1_STARTUP, false},
+	{WCD9XXX_IRQ_PA2_STARTUP, false},
+	{WCD9XXX_IRQ_PA3_STARTUP, false},
+	{WCD9XXX_IRQ_PA4_STARTUP, false},
+	{WCD9XXX_IRQ_PA5_STARTUP, false},
+	{WCD9XXX_IRQ_MICBIAS1_PRECHARGE, false},
+	{WCD9XXX_IRQ_MICBIAS2_PRECHARGE, false},
+	{WCD9XXX_IRQ_MICBIAS3_PRECHARGE, false},
+	{WCD9XXX_IRQ_HPH_PA_OCPL_FAULT, false},
+	{WCD9XXX_IRQ_HPH_PA_OCPR_FAULT, false},
+	{WCD9XXX_IRQ_EAR_PA_OCPL_FAULT, false},
+	{WCD9XXX_IRQ_HPH_L_PA_STARTUP, false},
+	{WCD9XXX_IRQ_HPH_R_PA_STARTUP, false},
+	{WCD9320_IRQ_EAR_PA_STARTUP, false},
+	{WCD9XXX_IRQ_RESERVED_0, false},
+	{WCD9XXX_IRQ_RESERVED_1, false},
+	{WCD9XXX_IRQ_MAD_AUDIO, false},
+	{WCD9XXX_IRQ_MAD_BEACON, false},
+	{WCD9XXX_IRQ_MAD_ULTRASOUND, false},
+	{WCD9XXX_IRQ_SPEAKER_CLIPPING, false},
+	{WCD9XXX_IRQ_VBAT_MONITOR_ATTACK, false},
+	{WCD9XXX_IRQ_VBAT_MONITOR_RELEASE, false},
+	{WCD9XXX_IRQ_RESERVED_2, false},
+};
+
 static int wcd9xxx_device_init(struct wcd9xxx *wcd9xxx)
 {
-	int ret;
+	int ret = 0;
 	u8 version;
 	const struct wcd9xxx_codec_type *found;
+	struct wcd9xxx_core_resource *core_res = &wcd9xxx->core_res;
 
 	mutex_init(&wcd9xxx->io_lock);
 	mutex_init(&wcd9xxx->xfer_lock);
 
-	mutex_init(&wcd9xxx->pm_lock);
-	wcd9xxx->wlock_holders = 0;
-	wcd9xxx->pm_state = WCD9XXX_PM_SLEEPABLE;
-	init_waitqueue_head(&wcd9xxx->pm_wq);
-	pm_qos_add_request(&wcd9xxx->pm_qos_req, PM_QOS_CPU_DMA_LATENCY,
-				PM_QOS_DEFAULT_VALUE);
-
 	dev_set_drvdata(wcd9xxx->dev, wcd9xxx);
-
 	wcd9xxx_bring_up(wcd9xxx);
 
 	found = wcd9xxx_check_codec_type(wcd9xxx, &version);
 	if (!found) {
 		ret = -ENODEV;
-		goto err_irq;
+		goto err;
 	} else {
 		wcd9xxx->codec_type = found;
 		wcd9xxx->version = version;
 	}
 
-	if (wcd9xxx->irq != -1) {
-		ret = wcd9xxx_irq_init(wcd9xxx);
-		if (ret) {
-			pr_err("IRQ initialization failed\n");
-			goto err;
-		}
+	core_res->parent = wcd9xxx;
+	core_res->dev = wcd9xxx->dev;
+
+	if (wcd9xxx->codec_type->id_major == TABLA_MAJOR
+		|| wcd9xxx->codec_type->id_major == SITAR_MAJOR) {
+		core_res->intr_table = intr_tbl_v1;
+		core_res->intr_table_size = ARRAY_SIZE(intr_tbl_v1);
+	} else {
+		core_res->intr_table = intr_tbl_v2;
+		core_res->intr_table_size = ARRAY_SIZE(intr_tbl_v2);
 	}
 
+	wcd9xxx_core_res_init(&wcd9xxx->core_res,
+				wcd9xxx->codec_type->num_irqs,
+				wcd9xxx_num_irq_regs(wcd9xxx),
+				wcd9xxx_reg_read, wcd9xxx_reg_write,
+				wcd9xxx_bulk_read);
+
+	if (wcd9xxx_core_irq_init(&wcd9xxx->core_res))
+		goto err;
+
 	ret = mfd_add_devices(wcd9xxx->dev, -1, found->dev, found->size,
 			      NULL, 0);
 	if (ret != 0) {
 		dev_err(wcd9xxx->dev, "Failed to add children: %d\n", ret);
 		goto err_irq;
 	}
+
+	ret = device_init_wakeup(wcd9xxx->dev, true);
+	if (ret) {
+		dev_err(wcd9xxx->dev, "Device wakeup init failed: %d\n", ret);
+		goto err_irq;
+	}
+
 	return ret;
 err_irq:
-	wcd9xxx_irq_exit(wcd9xxx);
+	wcd9xxx_irq_exit(&wcd9xxx->core_res);
 err:
 	wcd9xxx_bring_down(wcd9xxx);
-	pm_qos_remove_request(&wcd9xxx->pm_qos_req);
-	mutex_destroy(&wcd9xxx->pm_lock);
+	wcd9xxx_core_res_deinit(&wcd9xxx->core_res);
 	mutex_destroy(&wcd9xxx->io_lock);
 	mutex_destroy(&wcd9xxx->xfer_lock);
 	return ret;
@@ -504,14 +634,14 @@
 
 static void wcd9xxx_device_exit(struct wcd9xxx *wcd9xxx)
 {
-	wcd9xxx_irq_exit(wcd9xxx);
+	device_init_wakeup(wcd9xxx->dev, false);
+	wcd9xxx_irq_exit(&wcd9xxx->core_res);
 	wcd9xxx_bring_down(wcd9xxx);
 	wcd9xxx_free_reset(wcd9xxx);
-	mutex_destroy(&wcd9xxx->pm_lock);
-	pm_qos_remove_request(&wcd9xxx->pm_qos_req);
+	wcd9xxx_core_res_deinit(&wcd9xxx->core_res);
 	mutex_destroy(&wcd9xxx->io_lock);
 	mutex_destroy(&wcd9xxx->xfer_lock);
-	if (wcd9xxx_intf == WCD9XXX_INTERFACE_TYPE_SLIMBUS)
+	if (wcd9xxx_get_intf_type() == WCD9XXX_INTERFACE_TYPE_SLIMBUS)
 		slim_remove_device(wcd9xxx->slim_slave);
 	kfree(wcd9xxx);
 }
@@ -736,13 +866,6 @@
 	kfree(wcd9xxx->supplies);
 }
 
-enum wcd9xxx_intf_status wcd9xxx_get_intf_type(void)
-{
-	return wcd9xxx_intf;
-}
-
-EXPORT_SYMBOL_GPL(wcd9xxx_get_intf_type);
-
 struct wcd9xxx_i2c *get_i2c_wcd9xxx_device_info(u16 reg)
 {
 	u16 mask = 0x0f00;
@@ -894,13 +1017,16 @@
 	int ret = 0;
 	int wcd9xx_index = 0;
 	struct device *dev;
+	int intf_type;
 
-	pr_debug("%s: interface status %d\n", __func__, wcd9xxx_intf);
-	if (wcd9xxx_intf == WCD9XXX_INTERFACE_TYPE_SLIMBUS) {
+	intf_type = wcd9xxx_get_intf_type();
+
+	pr_debug("%s: interface status %d\n", __func__, intf_type);
+	if (intf_type == WCD9XXX_INTERFACE_TYPE_SLIMBUS) {
 		dev_dbg(&client->dev, "%s:Codec is detected in slimbus mode\n",
 			__func__);
 		return -ENODEV;
-	} else if (wcd9xxx_intf == WCD9XXX_INTERFACE_TYPE_I2C) {
+	} else if (intf_type == WCD9XXX_INTERFACE_TYPE_I2C) {
 		ret = wcd9xxx_i2c_get_client_index(client, &wcd9xx_index);
 		if (ret != 0)
 			dev_err(&client->dev, "%s: I2C set codec I2C\n"
@@ -912,7 +1038,7 @@
 			wcd9xxx_modules[wcd9xx_index].client = client;
 		}
 		return ret;
-	} else if (wcd9xxx_intf == WCD9XXX_INTERFACE_TYPE_PROBING) {
+	} else if (intf_type == WCD9XXX_INTERFACE_TYPE_PROBING) {
 		dev = &client->dev;
 		if (client->dev.of_node) {
 			dev_dbg(&client->dev, "%s:Platform data\n"
@@ -979,10 +1105,9 @@
 		wcd9xxx_modules[wcd9xx_index].client = client;
 		wcd9xxx->read_dev = wcd9xxx_i2c_read;
 		wcd9xxx->write_dev = wcd9xxx_i2c_write;
-		if (!wcd9xxx->dev->of_node) {
-			wcd9xxx->irq = pdata->irq;
-			wcd9xxx->irq_base = pdata->irq_base;
-		}
+		if (!wcd9xxx->dev->of_node)
+			wcd9xxx_initialize_irq(&wcd9xxx->core_res,
+					pdata->irq, pdata->irq_base);
 
 		ret = wcd9xxx_device_init(wcd9xxx);
 		if (ret) {
@@ -998,7 +1123,7 @@
 		if (val != wcd9xxx->codec_type->i2c_chip_status)
 			pr_err("%s: unknown chip status 0x%x\n", __func__, val);
 
-		wcd9xxx_intf = WCD9XXX_INTERFACE_TYPE_I2C;
+		wcd9xxx_set_intf_type(WCD9XXX_INTERFACE_TYPE_I2C);
 
 		return ret;
 	} else
@@ -1195,15 +1320,54 @@
 	return 0;
 }
 
+static int wcd9xxx_process_supplies(struct device *dev,
+		struct wcd9xxx_pdata *pdata, const char *supply_list,
+		int supply_cnt, bool is_ondemand, int index)
+{
+	int idx, ret = 0;
+	const char *name;
+
+	if (supply_cnt == 0) {
+		dev_dbg(dev, "%s: no supplies defined for %s\n", __func__,
+				supply_list);
+		return 0;
+	}
+
+	for (idx = 0; idx < supply_cnt; idx++) {
+		ret = of_property_read_string_index(dev->of_node,
+						    supply_list, idx,
+						    &name);
+		if (ret) {
+			dev_err(dev, "%s: of read string %s idx %d error %d\n",
+				__func__, supply_list, idx, ret);
+			goto err;
+		}
+
+		dev_dbg(dev, "%s: Found cdc supply %s as part of %s\n",
+				__func__, name, supply_list);
+		ret = wcd9xxx_dt_parse_vreg_info(dev,
+					&pdata->regulator[index + idx],
+					name, is_ondemand);
+		if (ret)
+			goto err;
+	}
+
+	return 0;
+
+err:
+	return ret;
+
+}
+
 static struct wcd9xxx_pdata *wcd9xxx_populate_dt_pdata(struct device *dev)
 {
 	struct wcd9xxx_pdata *pdata;
-	int ret, static_cnt, ond_cnt, idx, i;
-	const char *name = NULL;
+	int ret, static_cnt, ond_cnt, cp_supplies_cnt;
 	u32 mclk_rate = 0;
 	u32 dmic_sample_rate = 0;
 	const char *static_prop_name = "qcom,cdc-static-supplies";
 	const char *ond_prop_name = "qcom,cdc-on-demand-supplies";
+	const char *cp_supplies_name = "qcom,cdc-cp-supplies";
 
 	pdata = devm_kzalloc(dev, sizeof(*pdata), GFP_KERNEL);
 	if (!pdata) {
@@ -1223,44 +1387,35 @@
 	if (IS_ERR_VALUE(ond_cnt))
 		ond_cnt = 0;
 
-	BUG_ON(static_cnt <= 0 || ond_cnt < 0);
-	if ((static_cnt + ond_cnt) > ARRAY_SIZE(pdata->regulator)) {
+	/* cp-supplies list is an optional property */
+	cp_supplies_cnt = of_property_count_strings(dev->of_node,
+							cp_supplies_name);
+	if (IS_ERR_VALUE(cp_supplies_cnt))
+		cp_supplies_cnt = 0;
+
+	BUG_ON(static_cnt <= 0 || ond_cnt < 0 || cp_supplies_cnt < 0);
+	if ((static_cnt + ond_cnt + cp_supplies_cnt)
+			> ARRAY_SIZE(pdata->regulator)) {
 		dev_err(dev, "%s: Num of supplies %u > max supported %u\n",
 			__func__, static_cnt, ARRAY_SIZE(pdata->regulator));
 		goto err;
 	}
 
-	for (idx = 0; idx < static_cnt; idx++) {
-		ret = of_property_read_string_index(dev->of_node,
-						    static_prop_name, idx,
-						    &name);
-		if (ret) {
-			dev_err(dev, "%s: of read string %s idx %d error %d\n",
-				__func__, static_prop_name, idx, ret);
-			goto err;
-		}
+	ret = wcd9xxx_process_supplies(dev, pdata, static_prop_name,
+				static_cnt, STATIC_REGULATOR, 0);
+	if (ret)
+		goto err;
 
-		dev_dbg(dev, "%s: Found static cdc supply %s\n", __func__,
-			name);
-		ret = wcd9xxx_dt_parse_vreg_info(dev, &pdata->regulator[idx],
-						 name, false);
-		if (ret)
-			goto err;
-	}
+	ret = wcd9xxx_process_supplies(dev, pdata, ond_prop_name,
+				ond_cnt, ONDEMAND_REGULATOR, static_cnt);
+	if (ret)
+		goto err;
 
-	for (i = 0; i < ond_cnt; i++, idx++) {
-		ret = of_property_read_string_index(dev->of_node, ond_prop_name,
-						    i, &name);
-		if (ret)
-			goto err;
-
-		dev_dbg(dev, "%s: Found on-demand cdc supply %s\n", __func__,
-			name);
-		ret = wcd9xxx_dt_parse_vreg_info(dev, &pdata->regulator[idx],
-						 name, true);
-		if (ret)
-			goto err;
-	}
+	ret = wcd9xxx_process_supplies(dev, pdata, cp_supplies_name,
+				cp_supplies_cnt, ONDEMAND_REGULATOR,
+				static_cnt + ond_cnt);
+	if (ret)
+		goto err;
 
 	ret = wcd9xxx_dt_parse_micbias_info(dev, &pdata->micbias);
 	if (ret)
@@ -1351,8 +1506,11 @@
 	struct wcd9xxx *wcd9xxx;
 	struct wcd9xxx_pdata *pdata;
 	int ret = 0;
+	int intf_type;
 
-	if (wcd9xxx_intf == WCD9XXX_INTERFACE_TYPE_I2C) {
+	intf_type = wcd9xxx_get_intf_type();
+
+	if (intf_type == WCD9XXX_INTERFACE_TYPE_I2C) {
 		dev_dbg(&slim->dev, "%s:Codec is detected in I2C mode\n",
 			__func__);
 		return -ENODEV;
@@ -1430,10 +1588,9 @@
 	wcd9xxx->write_dev = wcd9xxx_slim_write_device;
 	wcd9xxx_pgd_la = wcd9xxx->slim->laddr;
 	wcd9xxx->slim_slave = &pdata->slimbus_slave_device;
-	if (!wcd9xxx->dev->of_node) {
-		wcd9xxx->irq = pdata->irq;
-		wcd9xxx->irq_base = pdata->irq_base;
-	}
+	if (!wcd9xxx->dev->of_node)
+		wcd9xxx_initialize_irq(&wcd9xxx->core_res,
+					pdata->irq, pdata->irq_base);
 
 	ret = slim_add_device(slim->ctrl, wcd9xxx->slim_slave);
 	if (ret) {
@@ -1451,7 +1608,7 @@
 		goto err_slim_add;
 	}
 	wcd9xxx_inf_la = wcd9xxx->slim_slave->laddr;
-	wcd9xxx_intf = WCD9XXX_INTERFACE_TYPE_SLIMBUS;
+	wcd9xxx_set_intf_type(WCD9XXX_INTERFACE_TYPE_SLIMBUS);
 
 	ret = wcd9xxx_device_init(wcd9xxx);
 	if (ret) {
@@ -1505,29 +1662,10 @@
 	return 0;
 }
 
-static int wcd9xxx_resume(struct wcd9xxx *wcd9xxx)
-{
-	int ret = 0;
-
-	pr_debug("%s: enter\n", __func__);
-	mutex_lock(&wcd9xxx->pm_lock);
-	if (wcd9xxx->pm_state == WCD9XXX_PM_ASLEEP) {
-		pr_debug("%s: resuming system, state %d, wlock %d\n", __func__,
-			 wcd9xxx->pm_state, wcd9xxx->wlock_holders);
-		wcd9xxx->pm_state = WCD9XXX_PM_SLEEPABLE;
-	} else {
-		pr_warn("%s: system is already awake, state %d wlock %d\n",
-			__func__, wcd9xxx->pm_state, wcd9xxx->wlock_holders);
-	}
-	mutex_unlock(&wcd9xxx->pm_lock);
-	wake_up_all(&wcd9xxx->pm_wq);
-
-	return ret;
-}
-
 static int wcd9xxx_device_up(struct wcd9xxx *wcd9xxx)
 {
 	int ret = 0;
+	struct wcd9xxx_core_resource *wcd9xxx_res = &wcd9xxx->core_res;
 
 	if (wcd9xxx->slim_device_bootup) {
 		wcd9xxx->slim_device_bootup = false;
@@ -1538,86 +1676,68 @@
 		pr_err("%s: Resetting Codec failed\n", __func__);
 
 	wcd9xxx_bring_up(wcd9xxx);
-	wcd9xxx->post_reset(wcd9xxx);
+	ret = wcd9xxx_irq_init(wcd9xxx_res);
+	if (ret) {
+		pr_err("%s: wcd9xx_irq_init failed : %d\n", __func__, ret);
+	} else {
+		if (wcd9xxx->post_reset)
+			ret = wcd9xxx->post_reset(wcd9xxx);
+	}
 	return ret;
 }
 
 static int wcd9xxx_slim_device_up(struct slim_device *sldev)
 {
 	struct wcd9xxx *wcd9xxx = slim_get_devicedata(sldev);
+	if (!wcd9xxx) {
+		pr_err("%s: wcd9xxx is NULL\n", __func__);
+		return -EINVAL;
+	}
+	dev_dbg(wcd9xxx->dev, "%s: device up\n", __func__);
 	return wcd9xxx_device_up(wcd9xxx);
 }
 
+static int wcd9xxx_slim_device_down(struct slim_device *sldev)
+{
+	struct wcd9xxx *wcd9xxx = slim_get_devicedata(sldev);
+
+	if (!wcd9xxx) {
+		pr_err("%s: wcd9xxx is NULL\n", __func__);
+		return -EINVAL;
+	}
+	wcd9xxx_irq_exit(&wcd9xxx->core_res);
+	if (wcd9xxx->dev_down)
+		wcd9xxx->dev_down(wcd9xxx);
+	dev_dbg(wcd9xxx->dev, "%s: device down\n", __func__);
+	return 0;
+}
+
 static int wcd9xxx_slim_resume(struct slim_device *sldev)
 {
 	struct wcd9xxx *wcd9xxx = slim_get_devicedata(sldev);
-	return wcd9xxx_resume(wcd9xxx);
+	return wcd9xxx_core_res_resume(&wcd9xxx->core_res);
 }
 
 static int wcd9xxx_i2c_resume(struct i2c_client *i2cdev)
 {
 	struct wcd9xxx *wcd9xxx = dev_get_drvdata(&i2cdev->dev);
 	if (wcd9xxx)
-		return wcd9xxx_resume(wcd9xxx);
+		return wcd9xxx_core_res_resume(&wcd9xxx->core_res);
 	else
 		return 0;
 }
 
-static int wcd9xxx_suspend(struct wcd9xxx *wcd9xxx, pm_message_t pmesg)
-{
-	int ret = 0;
-
-	pr_debug("%s: enter\n", __func__);
-	/*
-	 * pm_qos_update_request() can be called after this suspend chain call
-	 * started. thus suspend can be called while lock is being held
-	 */
-	mutex_lock(&wcd9xxx->pm_lock);
-	if (wcd9xxx->pm_state == WCD9XXX_PM_SLEEPABLE) {
-		pr_debug("%s: suspending system, state %d, wlock %d\n",
-			 __func__, wcd9xxx->pm_state, wcd9xxx->wlock_holders);
-		wcd9xxx->pm_state = WCD9XXX_PM_ASLEEP;
-	} else if (wcd9xxx->pm_state == WCD9XXX_PM_AWAKE) {
-		/* unlock to wait for pm_state == WCD9XXX_PM_SLEEPABLE
-		 * then set to WCD9XXX_PM_ASLEEP */
-		pr_debug("%s: waiting to suspend system, state %d, wlock %d\n",
-			 __func__, wcd9xxx->pm_state, wcd9xxx->wlock_holders);
-		mutex_unlock(&wcd9xxx->pm_lock);
-		if (!(wait_event_timeout(wcd9xxx->pm_wq,
-					 wcd9xxx_pm_cmpxchg(wcd9xxx,
-						  WCD9XXX_PM_SLEEPABLE,
-						  WCD9XXX_PM_ASLEEP) ==
-							WCD9XXX_PM_SLEEPABLE,
-					 HZ))) {
-			pr_debug("%s: suspend failed state %d, wlock %d\n",
-				 __func__, wcd9xxx->pm_state,
-				 wcd9xxx->wlock_holders);
-			ret = -EBUSY;
-		} else {
-			pr_debug("%s: done, state %d, wlock %d\n", __func__,
-				 wcd9xxx->pm_state, wcd9xxx->wlock_holders);
-		}
-		mutex_lock(&wcd9xxx->pm_lock);
-	} else if (wcd9xxx->pm_state == WCD9XXX_PM_ASLEEP) {
-		pr_warn("%s: system is already suspended, state %d, wlock %dn",
-			__func__, wcd9xxx->pm_state, wcd9xxx->wlock_holders);
-	}
-	mutex_unlock(&wcd9xxx->pm_lock);
-
-	return ret;
-}
-
 static int wcd9xxx_slim_suspend(struct slim_device *sldev, pm_message_t pmesg)
 {
 	struct wcd9xxx *wcd9xxx = slim_get_devicedata(sldev);
-	return wcd9xxx_suspend(wcd9xxx, pmesg);
+	return wcd9xxx_core_res_suspend(&wcd9xxx->core_res, pmesg);
 }
 
 static int wcd9xxx_i2c_suspend(struct i2c_client *i2cdev, pm_message_t pmesg)
 {
 	struct wcd9xxx *wcd9xxx = dev_get_drvdata(&i2cdev->dev);
 	if (wcd9xxx)
-		return wcd9xxx_suspend(wcd9xxx, pmesg);
+		return wcd9xxx_core_res_suspend(&wcd9xxx->core_res, pmesg);
 	else
 		return 0;
 }
@@ -1704,6 +1824,7 @@
 	.resume = wcd9xxx_slim_resume,
 	.suspend = wcd9xxx_slim_suspend,
 	.device_up = wcd9xxx_slim_device_up,
+	.device_down = wcd9xxx_slim_device_down,
 };
 
 static const struct slim_device_id tapan_slimtest_id[] = {
@@ -1722,6 +1843,7 @@
 	.resume = wcd9xxx_slim_resume,
 	.suspend = wcd9xxx_slim_suspend,
 	.device_up = wcd9xxx_slim_device_up,
+	.device_down = wcd9xxx_slim_device_down,
 };
 
 static struct i2c_device_id wcd9xxx_id_table[] = {
@@ -1771,7 +1893,7 @@
 	int ret[NUM_WCD9XXX_REG_RET];
 	int i = 0;
 
-	wcd9xxx_intf = WCD9XXX_INTERFACE_TYPE_PROBING;
+	wcd9xxx_set_intf_type(WCD9XXX_INTERFACE_TYPE_PROBING);
 
 	ret[0] = slim_driver_register(&tabla_slim_driver);
 	if (ret[0])
@@ -1815,6 +1937,7 @@
 
 static void __exit wcd9xxx_exit(void)
 {
+	wcd9xxx_set_intf_type(WCD9XXX_INTERFACE_TYPE_PROBING);
 }
 module_exit(wcd9xxx_exit);
 
diff --git a/drivers/mfd/wcd9xxx-irq.c b/drivers/mfd/wcd9xxx-irq.c
index 062351d..dc32efd 100644
--- a/drivers/mfd/wcd9xxx-irq.c
+++ b/drivers/mfd/wcd9xxx-irq.c
@@ -15,10 +15,9 @@
 #include <linux/sched.h>
 #include <linux/irq.h>
 #include <linux/mfd/core.h>
-#include <linux/mfd/wcd9xxx/core.h>
+#include <linux/mfd/wcd9xxx/core-resource.h>
 #include <linux/mfd/wcd9xxx/wcd9xxx_registers.h>
 #include <linux/mfd/wcd9xxx/wcd9310_registers.h>
-#include <linux/mfd/wcd9xxx/wcd9xxx-slimslave.h>
 #include <linux/delay.h>
 #include <linux/irqdomain.h>
 #include <linux/interrupt.h>
@@ -40,57 +39,76 @@
 };
 #endif
 
-static int virq_to_phyirq(struct wcd9xxx *wcd9xxx, int virq);
-static int phyirq_to_virq(struct wcd9xxx *wcd9xxx, int irq);
-static unsigned int wcd9xxx_irq_get_upstream_irq(struct wcd9xxx *wcd9xxx);
-static void wcd9xxx_irq_put_upstream_irq(struct wcd9xxx *wcd9xxx);
-static int wcd9xxx_map_irq(struct wcd9xxx *wcd9xxx, int irq);
+static int virq_to_phyirq(
+	struct wcd9xxx_core_resource *wcd9xxx_res, int virq);
+static int phyirq_to_virq(
+	struct wcd9xxx_core_resource *wcd9xxx_res, int irq);
+static unsigned int wcd9xxx_irq_get_upstream_irq(
+	struct wcd9xxx_core_resource *wcd9xxx_res);
+static void wcd9xxx_irq_put_upstream_irq(
+	struct wcd9xxx_core_resource *wcd9xxx_res);
+static int wcd9xxx_map_irq(
+	struct wcd9xxx_core_resource *wcd9xxx_res, int irq);
 
 static void wcd9xxx_irq_lock(struct irq_data *data)
 {
-	struct wcd9xxx *wcd9xxx = irq_data_get_irq_chip_data(data);
-	mutex_lock(&wcd9xxx->irq_lock);
+	struct wcd9xxx_core_resource *wcd9xxx_res =
+			irq_data_get_irq_chip_data(data);
+	mutex_lock(&wcd9xxx_res->irq_lock);
 }
 
 static void wcd9xxx_irq_sync_unlock(struct irq_data *data)
 {
-	struct wcd9xxx *wcd9xxx = irq_data_get_irq_chip_data(data);
+	struct wcd9xxx_core_resource *wcd9xxx_res =
+			irq_data_get_irq_chip_data(data);
 	int i;
 
-	if (ARRAY_SIZE(wcd9xxx->irq_masks_cur) > WCD9XXX_NUM_IRQ_REGS ||
-		ARRAY_SIZE(wcd9xxx->irq_masks_cache) > WCD9XXX_NUM_IRQ_REGS) {
+	if ((ARRAY_SIZE(wcd9xxx_res->irq_masks_cur) >
+			WCD9XXX_MAX_IRQ_REGS) ||
+		(ARRAY_SIZE(wcd9xxx_res->irq_masks_cache) >
+			WCD9XXX_MAX_IRQ_REGS)) {
 			pr_err("%s: Array Size out of bound\n", __func__);
 			 return;
 	}
+	if (!wcd9xxx_res->codec_reg_write) {
+		pr_err("%s: Codec reg write callback function not defined\n",
+				__func__);
+		return;
+	}
 
-	for (i = 0; i < ARRAY_SIZE(wcd9xxx->irq_masks_cur); i++) {
+	for (i = 0; i < ARRAY_SIZE(wcd9xxx_res->irq_masks_cur); i++) {
 		/* If there's been a change in the mask write it back
 		 * to the hardware.
 		 */
-		if (wcd9xxx->irq_masks_cur[i] != wcd9xxx->irq_masks_cache[i]) {
-			wcd9xxx->irq_masks_cache[i] = wcd9xxx->irq_masks_cur[i];
-			wcd9xxx_reg_write(wcd9xxx,
+		if (wcd9xxx_res->irq_masks_cur[i] !=
+					wcd9xxx_res->irq_masks_cache[i]) {
+
+			wcd9xxx_res->irq_masks_cache[i] =
+					wcd9xxx_res->irq_masks_cur[i];
+			wcd9xxx_res->codec_reg_write(wcd9xxx_res,
 					  WCD9XXX_A_INTR_MASK0 + i,
-					  wcd9xxx->irq_masks_cur[i]);
+					  wcd9xxx_res->irq_masks_cur[i]);
 		}
 	}
 
-	mutex_unlock(&wcd9xxx->irq_lock);
+	mutex_unlock(&wcd9xxx_res->irq_lock);
 }
 
 static void wcd9xxx_irq_enable(struct irq_data *data)
 {
-	struct wcd9xxx *wcd9xxx = irq_data_get_irq_chip_data(data);
-	int wcd9xxx_irq = virq_to_phyirq(wcd9xxx, data->irq);
-	wcd9xxx->irq_masks_cur[BIT_BYTE(wcd9xxx_irq)] &=
+	struct wcd9xxx_core_resource *wcd9xxx_res =
+			irq_data_get_irq_chip_data(data);
+	int wcd9xxx_irq = virq_to_phyirq(wcd9xxx_res, data->irq);
+	wcd9xxx_res->irq_masks_cur[BIT_BYTE(wcd9xxx_irq)] &=
 		~(BYTE_BIT_MASK(wcd9xxx_irq));
 }
 
 static void wcd9xxx_irq_disable(struct irq_data *data)
 {
-	struct wcd9xxx *wcd9xxx = irq_data_get_irq_chip_data(data);
-	int wcd9xxx_irq = virq_to_phyirq(wcd9xxx, data->irq);
-	wcd9xxx->irq_masks_cur[BIT_BYTE(wcd9xxx_irq)]
+	struct wcd9xxx_core_resource *wcd9xxx_res =
+			irq_data_get_irq_chip_data(data);
+	int wcd9xxx_irq = virq_to_phyirq(wcd9xxx_res, data->irq);
+	wcd9xxx_res->irq_masks_cur[BIT_BYTE(wcd9xxx_irq)]
 		|= BYTE_BIT_MASK(wcd9xxx_irq);
 }
 
@@ -108,21 +126,8 @@
 	.irq_mask = wcd9xxx_irq_mask,
 };
 
-enum wcd9xxx_pm_state wcd9xxx_pm_cmpxchg(struct wcd9xxx *wcd9xxx,
-		enum wcd9xxx_pm_state o,
-		enum wcd9xxx_pm_state n)
-{
-	enum wcd9xxx_pm_state old;
-	mutex_lock(&wcd9xxx->pm_lock);
-	old = wcd9xxx->pm_state;
-	if (old == o)
-		wcd9xxx->pm_state = n;
-	mutex_unlock(&wcd9xxx->pm_lock);
-	return old;
-}
-EXPORT_SYMBOL_GPL(wcd9xxx_pm_cmpxchg);
-
-bool wcd9xxx_lock_sleep(struct wcd9xxx *wcd9xxx)
+bool wcd9xxx_lock_sleep(
+	struct wcd9xxx_core_resource *wcd9xxx_res)
 {
 	enum wcd9xxx_pm_state os;
 
@@ -138,164 +143,154 @@
 	 * As interrupt line is still active, codec will have another IRQ to
 	 * retry shortly.
 	 */
-	mutex_lock(&wcd9xxx->pm_lock);
-	if (wcd9xxx->wlock_holders++ == 0) {
+	mutex_lock(&wcd9xxx_res->pm_lock);
+	if (wcd9xxx_res->wlock_holders++ == 0) {
 		pr_debug("%s: holding wake lock\n", __func__);
-		pm_qos_update_request(&wcd9xxx->pm_qos_req,
+		pm_qos_update_request(&wcd9xxx_res->pm_qos_req,
 				      msm_cpuidle_get_deep_idle_latency());
 	}
-	mutex_unlock(&wcd9xxx->pm_lock);
-	if (!wait_event_timeout(wcd9xxx->pm_wq,
-			((os = wcd9xxx_pm_cmpxchg(wcd9xxx, WCD9XXX_PM_SLEEPABLE,
-						WCD9XXX_PM_AWAKE)) ==
-						    WCD9XXX_PM_SLEEPABLE ||
-			 (os == WCD9XXX_PM_AWAKE)),
+	mutex_unlock(&wcd9xxx_res->pm_lock);
+	os = wcd9xxx_pm_cmpxchg(wcd9xxx_res,
+					WCD9XXX_PM_SLEEPABLE,
+					WCD9XXX_PM_AWAKE);
+	if (!wait_event_timeout(wcd9xxx_res->pm_wq,
+			(os  == WCD9XXX_PM_SLEEPABLE ||
+			 os == WCD9XXX_PM_AWAKE),
 			msecs_to_jiffies(WCD9XXX_SYSTEM_RESUME_TIMEOUT_MS))) {
 		pr_warn("%s: system didn't resume within %dms, s %d, w %d\n",
 			__func__,
-			WCD9XXX_SYSTEM_RESUME_TIMEOUT_MS, wcd9xxx->pm_state,
-			wcd9xxx->wlock_holders);
-		wcd9xxx_unlock_sleep(wcd9xxx);
+			WCD9XXX_SYSTEM_RESUME_TIMEOUT_MS, wcd9xxx_res->pm_state,
+			wcd9xxx_res->wlock_holders);
+		wcd9xxx_unlock_sleep(wcd9xxx_res);
 		return false;
 	}
-	wake_up_all(&wcd9xxx->pm_wq);
+	wake_up_all(&wcd9xxx_res->pm_wq);
 	return true;
 }
-EXPORT_SYMBOL_GPL(wcd9xxx_lock_sleep);
+EXPORT_SYMBOL(wcd9xxx_lock_sleep);
 
-void wcd9xxx_unlock_sleep(struct wcd9xxx *wcd9xxx)
+void wcd9xxx_unlock_sleep(
+	struct wcd9xxx_core_resource *wcd9xxx_res)
 {
-	mutex_lock(&wcd9xxx->pm_lock);
-	if (--wcd9xxx->wlock_holders == 0) {
+	mutex_lock(&wcd9xxx_res->pm_lock);
+	if (--wcd9xxx_res->wlock_holders == 0) {
 		pr_debug("%s: releasing wake lock pm_state %d -> %d\n",
-			 __func__, wcd9xxx->pm_state, WCD9XXX_PM_SLEEPABLE);
+			 __func__, wcd9xxx_res->pm_state, WCD9XXX_PM_SLEEPABLE);
 		/*
 		 * if wcd9xxx_lock_sleep failed, pm_state would be still
 		 * WCD9XXX_PM_ASLEEP, don't overwrite
 		 */
-		if (likely(wcd9xxx->pm_state == WCD9XXX_PM_AWAKE))
-			wcd9xxx->pm_state = WCD9XXX_PM_SLEEPABLE;
-		pm_qos_update_request(&wcd9xxx->pm_qos_req,
+		if (likely(wcd9xxx_res->pm_state == WCD9XXX_PM_AWAKE))
+			wcd9xxx_res->pm_state = WCD9XXX_PM_SLEEPABLE;
+		pm_qos_update_request(&wcd9xxx_res->pm_qos_req,
 				PM_QOS_DEFAULT_VALUE);
 	}
-	mutex_unlock(&wcd9xxx->pm_lock);
-	wake_up_all(&wcd9xxx->pm_wq);
+	mutex_unlock(&wcd9xxx_res->pm_lock);
+	wake_up_all(&wcd9xxx_res->pm_wq);
 }
-EXPORT_SYMBOL_GPL(wcd9xxx_unlock_sleep);
+EXPORT_SYMBOL(wcd9xxx_unlock_sleep);
 
-void wcd9xxx_nested_irq_lock(struct wcd9xxx *wcd9xxx)
+void wcd9xxx_nested_irq_lock(struct wcd9xxx_core_resource *wcd9xxx_res)
 {
-	mutex_lock(&wcd9xxx->nested_irq_lock);
+	mutex_lock(&wcd9xxx_res->nested_irq_lock);
 }
 
-void wcd9xxx_nested_irq_unlock(struct wcd9xxx *wcd9xxx)
+void wcd9xxx_nested_irq_unlock(struct wcd9xxx_core_resource *wcd9xxx_res)
 {
-	mutex_unlock(&wcd9xxx->nested_irq_lock);
+	mutex_unlock(&wcd9xxx_res->nested_irq_lock);
 }
 
-static bool wcd9xxx_is_mbhc_irq(struct wcd9xxx *wcd9xxx, int irqbit)
-{
-	if ((irqbit <= WCD9XXX_IRQ_MBHC_INSERTION) &&
-	    (irqbit >= WCD9XXX_IRQ_MBHC_REMOVAL))
-		return true;
-	else if (wcd9xxx->codec_type->id_major == TAIKO_MAJOR &&
-		 irqbit == WCD9320_IRQ_MBHC_JACK_SWITCH)
-		return true;
-	else if (wcd9xxx->codec_type->id_major == TAPAN_MAJOR &&
-		 irqbit == WCD9306_IRQ_MBHC_JACK_SWITCH)
-		return true;
-	else
-		return false;
-}
 
-static void wcd9xxx_irq_dispatch(struct wcd9xxx *wcd9xxx, int irqbit)
+static void wcd9xxx_irq_dispatch(struct wcd9xxx_core_resource *wcd9xxx_res,
+			struct intr_data *irqdata)
 {
-	if (wcd9xxx_is_mbhc_irq(wcd9xxx, irqbit)) {
-		wcd9xxx_nested_irq_lock(wcd9xxx);
-		wcd9xxx_reg_write(wcd9xxx, WCD9XXX_A_INTR_CLEAR0 +
-					   BIT_BYTE(irqbit),
-				  BYTE_BIT_MASK(irqbit));
-		if (wcd9xxx_get_intf_type() == WCD9XXX_INTERFACE_TYPE_I2C)
-			wcd9xxx_reg_write(wcd9xxx, WCD9XXX_A_INTR_MODE, 0x02);
-		handle_nested_irq(phyirq_to_virq(wcd9xxx, irqbit));
-		wcd9xxx_nested_irq_unlock(wcd9xxx);
-	} else {
-		wcd9xxx_nested_irq_lock(wcd9xxx);
-		handle_nested_irq(phyirq_to_virq(wcd9xxx, irqbit));
-		wcd9xxx_reg_write(wcd9xxx, WCD9XXX_A_INTR_CLEAR0 +
-					   BIT_BYTE(irqbit),
-				  BYTE_BIT_MASK(irqbit));
-		if (wcd9xxx_get_intf_type() == WCD9XXX_INTERFACE_TYPE_I2C)
-			wcd9xxx_reg_write(wcd9xxx, WCD9XXX_A_INTR_MODE, 0x02);
-		wcd9xxx_nested_irq_unlock(wcd9xxx);
+	int irqbit = irqdata->intr_num;
+	if (!wcd9xxx_res->codec_reg_write) {
+		pr_err("%s: codec read/write callback not defined\n",
+			   __func__);
+		return;
 	}
-}
 
-static int wcd9xxx_num_irq_regs(const struct wcd9xxx *wcd9xxx)
-{
-	return (wcd9xxx->codec_type->num_irqs / 8) +
-		((wcd9xxx->codec_type->num_irqs % 8) ? 1 : 0);
+	if (irqdata->clear_first) {
+		wcd9xxx_nested_irq_lock(wcd9xxx_res);
+		wcd9xxx_res->codec_reg_write(wcd9xxx_res,
+				WCD9XXX_A_INTR_CLEAR0 + BIT_BYTE(irqbit),
+				BYTE_BIT_MASK(irqbit));
+
+		if (wcd9xxx_get_intf_type() == WCD9XXX_INTERFACE_TYPE_I2C)
+			wcd9xxx_res->codec_reg_write(wcd9xxx_res,
+						WCD9XXX_A_INTR_MODE, 0x02);
+		handle_nested_irq(phyirq_to_virq(wcd9xxx_res, irqbit));
+		wcd9xxx_nested_irq_unlock(wcd9xxx_res);
+	} else {
+		wcd9xxx_nested_irq_lock(wcd9xxx_res);
+		handle_nested_irq(phyirq_to_virq(wcd9xxx_res, irqbit));
+		wcd9xxx_res->codec_reg_write(wcd9xxx_res,
+				WCD9XXX_A_INTR_CLEAR0 + BIT_BYTE(irqbit),
+				BYTE_BIT_MASK(irqbit));
+		if (wcd9xxx_get_intf_type() == WCD9XXX_INTERFACE_TYPE_I2C)
+			wcd9xxx_res->codec_reg_write(wcd9xxx_res,
+						WCD9XXX_A_INTR_MODE, 0x02);
+
+		wcd9xxx_nested_irq_unlock(wcd9xxx_res);
+	}
 }
 
 static irqreturn_t wcd9xxx_irq_thread(int irq, void *data)
 {
 	int ret;
 	int i;
+	struct intr_data irqdata;
 	char linebuf[128];
-	struct wcd9xxx *wcd9xxx = data;
-	int num_irq_regs = wcd9xxx_num_irq_regs(wcd9xxx);
-	u8 status[num_irq_regs], status1[num_irq_regs];
 	static DEFINE_RATELIMIT_STATE(ratelimit, 5 * HZ, 1);
+	struct wcd9xxx_core_resource *wcd9xxx_res = data;
+	int num_irq_regs = wcd9xxx_res->num_irq_regs;
+	u8 status[num_irq_regs], status1[num_irq_regs];
 
-	if (unlikely(wcd9xxx_lock_sleep(wcd9xxx) == false)) {
-		dev_err(wcd9xxx->dev, "Failed to hold suspend\n");
+	if (unlikely(wcd9xxx_lock_sleep(wcd9xxx_res) == false)) {
+		dev_err(wcd9xxx_res->dev, "Failed to hold suspend\n");
 		return IRQ_NONE;
 	}
-	ret = wcd9xxx_bulk_read(wcd9xxx, WCD9XXX_A_INTR_STATUS0,
+
+	if (!wcd9xxx_res->codec_bulk_read) {
+		dev_err(wcd9xxx_res->dev,
+				"%s: Codec Bulk Register read callback not supplied\n",
+			   __func__);
+		goto err_disable_irq;
+	}
+
+	ret = wcd9xxx_res->codec_bulk_read(wcd9xxx_res,
+				WCD9XXX_A_INTR_STATUS0,
 				num_irq_regs, status);
+
 	if (ret < 0) {
-		dev_err(wcd9xxx->dev, "Failed to read interrupt status: %d\n",
-			ret);
-		dev_err(wcd9xxx->dev, "Disable irq %d\n", wcd9xxx->irq);
-		disable_irq_wake(wcd9xxx->irq);
-		disable_irq_nosync(wcd9xxx->irq);
-		wcd9xxx_unlock_sleep(wcd9xxx);
-		return IRQ_NONE;
+		dev_err(wcd9xxx_res->dev,
+				"Failed to read interrupt status: %d\n", ret);
+		goto err_disable_irq;
 	}
 
 	/* Apply masking */
 	for (i = 0; i < num_irq_regs; i++)
-		status[i] &= ~wcd9xxx->irq_masks_cur[i];
+		status[i] &= ~wcd9xxx_res->irq_masks_cur[i];
 
 	memcpy(status1, status, sizeof(status1));
 
 	/* Find out which interrupt was triggered and call that interrupt's
 	 * handler function
-	 */
-	if (status[BIT_BYTE(WCD9XXX_IRQ_SLIMBUS)] &
-	    BYTE_BIT_MASK(WCD9XXX_IRQ_SLIMBUS)) {
-		wcd9xxx_irq_dispatch(wcd9xxx, WCD9XXX_IRQ_SLIMBUS);
-		status1[BIT_BYTE(WCD9XXX_IRQ_SLIMBUS)] &=
-		    ~BYTE_BIT_MASK(WCD9XXX_IRQ_SLIMBUS);
-	}
-
-	/* Since codec has only one hardware irq line which is shared by
+	 *
+	 * Since codec has only one hardware irq line which is shared by
 	 * codec's different internal interrupts, so it's possible master irq
 	 * handler dispatches multiple nested irq handlers after breaking
-	 * order.  Dispatch MBHC interrupts order to follow MBHC state
-	 * machine's order */
-	for (i = WCD9XXX_IRQ_MBHC_INSERTION;
-	     i >= WCD9XXX_IRQ_MBHC_REMOVAL; i--) {
-		if (status[BIT_BYTE(i)] & BYTE_BIT_MASK(i)) {
-			wcd9xxx_irq_dispatch(wcd9xxx, i);
-			status1[BIT_BYTE(i)] &= ~BYTE_BIT_MASK(i);
-		}
-	}
-	for (i = WCD9XXX_IRQ_BG_PRECHARGE; i < wcd9xxx->codec_type->num_irqs;
-	     i++) {
-		if (status[BIT_BYTE(i)] & BYTE_BIT_MASK(i)) {
-			wcd9xxx_irq_dispatch(wcd9xxx, i);
-			status1[BIT_BYTE(i)] &= ~BYTE_BIT_MASK(i);
+	 * order.  Dispatch interrupts in the order that is maintained by
+	 * the interrupt table.
+	 */
+	for (i = 0; i < wcd9xxx_res->intr_table_size; i++) {
+		irqdata = wcd9xxx_res->intr_table[i];
+		if (status[BIT_BYTE(irqdata.intr_num)] &
+			BYTE_BIT_MASK(irqdata.intr_num)) {
+			wcd9xxx_irq_dispatch(wcd9xxx_res, &irqdata);
+			status1[BIT_BYTE(irqdata.intr_num)] &=
+					~BYTE_BIT_MASK(irqdata.intr_num);
 		}
 	}
 
@@ -319,45 +314,58 @@
 		}
 
 		memset(status, 0xff, num_irq_regs);
-		wcd9xxx_bulk_write(wcd9xxx, WCD9XXX_A_INTR_CLEAR0,
+		wcd9xxx_bulk_write(wcd9xxx_res, WCD9XXX_A_INTR_CLEAR0,
 				   num_irq_regs, status);
 		if (wcd9xxx_get_intf_type() == WCD9XXX_INTERFACE_TYPE_I2C)
-			wcd9xxx_reg_write(wcd9xxx, WCD9XXX_A_INTR_MODE, 0x02);
+			wcd9xxx_reg_write(wcd9xxx_res,
+					WCD9XXX_A_INTR_MODE, 0x02);
 	}
-	wcd9xxx_unlock_sleep(wcd9xxx);
+	wcd9xxx_unlock_sleep(wcd9xxx_res);
 
 	return IRQ_HANDLED;
+
+err_disable_irq:
+		dev_err(wcd9xxx_res->dev,
+				"Disable irq %d\n", wcd9xxx_res->irq);
+
+		disable_irq_wake(wcd9xxx_res->irq);
+		disable_irq_nosync(wcd9xxx_res->irq);
+		wcd9xxx_unlock_sleep(wcd9xxx_res);
+		return IRQ_NONE;
 }
 
-void wcd9xxx_free_irq(struct wcd9xxx *wcd9xxx, int irq, void *data)
+void wcd9xxx_free_irq(struct wcd9xxx_core_resource *wcd9xxx_res,
+			int irq, void *data)
 {
-	free_irq(phyirq_to_virq(wcd9xxx, irq), data);
+	free_irq(phyirq_to_virq(wcd9xxx_res, irq), data);
 }
 
-void wcd9xxx_enable_irq(struct wcd9xxx *wcd9xxx, int irq)
+void wcd9xxx_enable_irq(struct wcd9xxx_core_resource *wcd9xxx_res, int irq)
 {
-	enable_irq(phyirq_to_virq(wcd9xxx, irq));
+	enable_irq(phyirq_to_virq(wcd9xxx_res, irq));
 }
 
-void wcd9xxx_disable_irq(struct wcd9xxx *wcd9xxx, int irq)
+void wcd9xxx_disable_irq(struct wcd9xxx_core_resource *wcd9xxx_res, int irq)
 {
-	disable_irq_nosync(phyirq_to_virq(wcd9xxx, irq));
+	disable_irq_nosync(phyirq_to_virq(wcd9xxx_res, irq));
 }
 
-void wcd9xxx_disable_irq_sync(struct wcd9xxx *wcd9xxx, int irq)
+void wcd9xxx_disable_irq_sync(
+			struct wcd9xxx_core_resource *wcd9xxx_res, int irq)
 {
-	disable_irq(phyirq_to_virq(wcd9xxx, irq));
+	disable_irq(phyirq_to_virq(wcd9xxx_res, irq));
 }
 
-static int wcd9xxx_irq_setup_downstream_irq(struct wcd9xxx *wcd9xxx)
+static int wcd9xxx_irq_setup_downstream_irq(
+			struct wcd9xxx_core_resource *wcd9xxx_res)
 {
 	int irq, virq, ret;
 
 	pr_debug("%s: enter\n", __func__);
 
-	for (irq = 0; irq < wcd9xxx->codec_type->num_irqs; irq++) {
+	for (irq = 0; irq < wcd9xxx_res->num_irqs; irq++) {
 		/* Map OF irq */
-		virq = wcd9xxx_map_irq(wcd9xxx, irq);
+		virq = wcd9xxx_map_irq(wcd9xxx_res, irq);
 		pr_debug("%s: irq %d -> %d\n", __func__, irq, virq);
 		if (virq == NO_IRQ) {
 			pr_err("%s, No interrupt specifier for irq %d\n",
@@ -365,14 +373,14 @@
 			return NO_IRQ;
 		}
 
-		ret = irq_set_chip_data(virq, wcd9xxx);
+		ret = irq_set_chip_data(virq, wcd9xxx_res);
 		if (ret) {
 			pr_err("%s: Failed to configure irq %d (%d)\n",
 			       __func__, irq, ret);
 			return ret;
 		}
 
-		if (wcd9xxx->irq_level_high[irq])
+		if (wcd9xxx_res->irq_level_high[irq])
 			irq_set_chip_and_handler(virq, &wcd9xxx_irq_chip,
 						 handle_level_irq);
 		else
@@ -387,91 +395,100 @@
 	return 0;
 }
 
-int wcd9xxx_irq_init(struct wcd9xxx *wcd9xxx)
+int wcd9xxx_irq_init(struct wcd9xxx_core_resource *wcd9xxx_res)
 {
 	int i, ret;
-	u8 irq_level[wcd9xxx_num_irq_regs(wcd9xxx)];
+	u8 irq_level[wcd9xxx_res->num_irq_regs];
 
-	mutex_init(&wcd9xxx->irq_lock);
-	mutex_init(&wcd9xxx->nested_irq_lock);
+	mutex_init(&wcd9xxx_res->irq_lock);
+	mutex_init(&wcd9xxx_res->nested_irq_lock);
 
-	wcd9xxx->irq = wcd9xxx_irq_get_upstream_irq(wcd9xxx);
-	if (!wcd9xxx->irq) {
+	wcd9xxx_res->irq = wcd9xxx_irq_get_upstream_irq(wcd9xxx_res);
+	if (!wcd9xxx_res->irq) {
 		pr_warn("%s: irq driver is not yet initialized\n", __func__);
-		mutex_destroy(&wcd9xxx->irq_lock);
-		mutex_destroy(&wcd9xxx->nested_irq_lock);
+		mutex_destroy(&wcd9xxx_res->irq_lock);
+		mutex_destroy(&wcd9xxx_res->nested_irq_lock);
 		return -EPROBE_DEFER;
 	}
-	pr_debug("%s: probed irq %d\n", __func__, wcd9xxx->irq);
+	pr_debug("%s: probed irq %d\n", __func__, wcd9xxx_res->irq);
 
 	/* Setup downstream IRQs */
-	ret = wcd9xxx_irq_setup_downstream_irq(wcd9xxx);
+	ret = wcd9xxx_irq_setup_downstream_irq(wcd9xxx_res);
 	if (ret) {
 		pr_err("%s: Failed to setup downstream IRQ\n", __func__);
-		wcd9xxx_irq_put_upstream_irq(wcd9xxx);
-		mutex_destroy(&wcd9xxx->irq_lock);
-		mutex_destroy(&wcd9xxx->nested_irq_lock);
+		wcd9xxx_irq_put_upstream_irq(wcd9xxx_res);
+		mutex_destroy(&wcd9xxx_res->irq_lock);
+		mutex_destroy(&wcd9xxx_res->nested_irq_lock);
 		return ret;
 	}
 
 	/* All other wcd9xxx interrupts are edge triggered */
-	wcd9xxx->irq_level_high[0] = true;
+	wcd9xxx_res->irq_level_high[0] = true;
 
 	/* mask all the interrupts */
-	memset(irq_level, 0, wcd9xxx_num_irq_regs(wcd9xxx));
-	for (i = 0; i < wcd9xxx->codec_type->num_irqs; i++) {
-		wcd9xxx->irq_masks_cur[BIT_BYTE(i)] |= BYTE_BIT_MASK(i);
-		wcd9xxx->irq_masks_cache[BIT_BYTE(i)] |= BYTE_BIT_MASK(i);
+	memset(irq_level, 0, wcd9xxx_res->num_irq_regs);
+	for (i = 0; i < wcd9xxx_res->num_irqs; i++) {
+		wcd9xxx_res->irq_masks_cur[BIT_BYTE(i)] |= BYTE_BIT_MASK(i);
+		wcd9xxx_res->irq_masks_cache[BIT_BYTE(i)] |= BYTE_BIT_MASK(i);
 		irq_level[BIT_BYTE(i)] |=
-		    wcd9xxx->irq_level_high[i] << (i % BITS_PER_BYTE);
+		    wcd9xxx_res->irq_level_high[i] << (i % BITS_PER_BYTE);
 	}
 
-	for (i = 0; i < wcd9xxx_num_irq_regs(wcd9xxx); i++) {
+	if (!wcd9xxx_res->codec_reg_write) {
+		dev_err(wcd9xxx_res->dev,
+				"%s: Codec Register write callback not defined\n",
+			   __func__);
+		ret = -EINVAL;
+		goto fail_irq_init;
+	}
+
+	for (i = 0; i < wcd9xxx_res->num_irq_regs; i++) {
 		/* Initialize interrupt mask and level registers */
-		wcd9xxx_reg_write(wcd9xxx, WCD9XXX_A_INTR_LEVEL0 + i,
-				  irq_level[i]);
-		wcd9xxx_reg_write(wcd9xxx, WCD9XXX_A_INTR_MASK0 + i,
-				  wcd9xxx->irq_masks_cur[i]);
+		wcd9xxx_res->codec_reg_write(wcd9xxx_res,
+					WCD9XXX_A_INTR_LEVEL0 + i,
+					irq_level[i]);
+		wcd9xxx_res->codec_reg_write(wcd9xxx_res,
+					WCD9XXX_A_INTR_MASK0 + i,
+					wcd9xxx_res->irq_masks_cur[i]);
 	}
 
-	ret = request_threaded_irq(wcd9xxx->irq, NULL, wcd9xxx_irq_thread,
+	ret = request_threaded_irq(wcd9xxx_res->irq, NULL, wcd9xxx_irq_thread,
 				   IRQF_TRIGGER_HIGH | IRQF_ONESHOT,
-				   "wcd9xxx", wcd9xxx);
+				   "wcd9xxx", wcd9xxx_res);
 	if (ret != 0)
-		dev_err(wcd9xxx->dev, "Failed to request IRQ %d: %d\n",
-			wcd9xxx->irq, ret);
+		dev_err(wcd9xxx_res->dev, "Failed to request IRQ %d: %d\n",
+			wcd9xxx_res->irq, ret);
 	else {
-		ret = enable_irq_wake(wcd9xxx->irq);
-		if (ret == 0) {
-			ret = device_init_wakeup(wcd9xxx->dev, 1);
-			if (ret) {
-				dev_err(wcd9xxx->dev, "Failed to init device"
-					"wakeup : %d\n", ret);
-				disable_irq_wake(wcd9xxx->irq);
-			}
-		} else
-			dev_err(wcd9xxx->dev, "Failed to set wake interrupt on"
-				" IRQ %d: %d\n", wcd9xxx->irq, ret);
+		ret = enable_irq_wake(wcd9xxx_res->irq);
 		if (ret)
-			free_irq(wcd9xxx->irq, wcd9xxx);
+			dev_err(wcd9xxx_res->dev,
+				"Failed to set wake interrupt on IRQ %d: %d\n",
+				wcd9xxx_res->irq, ret);
+		if (ret)
+			free_irq(wcd9xxx_res->irq, wcd9xxx_res);
 	}
 
-	if (ret) {
-		pr_err("%s: Failed to init wcd9xxx irq\n", __func__);
-		wcd9xxx_irq_put_upstream_irq(wcd9xxx);
-		mutex_destroy(&wcd9xxx->irq_lock);
-		mutex_destroy(&wcd9xxx->nested_irq_lock);
-	}
+	if (ret)
+		goto fail_irq_init;
 
 	return ret;
+
+fail_irq_init:
+	dev_err(wcd9xxx_res->dev,
+			"%s: Failed to init wcd9xxx irq\n", __func__);
+	wcd9xxx_irq_put_upstream_irq(wcd9xxx_res);
+	mutex_destroy(&wcd9xxx_res->irq_lock);
+	mutex_destroy(&wcd9xxx_res->nested_irq_lock);
+	return ret;
 }
 
-int wcd9xxx_request_irq(struct wcd9xxx *wcd9xxx, int irq, irq_handler_t handler,
+int wcd9xxx_request_irq(struct wcd9xxx_core_resource *wcd9xxx_res,
+			int irq, irq_handler_t handler,
 			const char *name, void *data)
 {
 	int virq;
 
-	virq = phyirq_to_virq(wcd9xxx, irq);
+	virq = phyirq_to_virq(wcd9xxx_res, irq);
 
 	/*
 	 * ARM needs us to explicitly flag the IRQ as valid
@@ -487,43 +504,52 @@
 				    name, data);
 }
 
-void wcd9xxx_irq_exit(struct wcd9xxx *wcd9xxx)
+void wcd9xxx_irq_exit(struct wcd9xxx_core_resource *wcd9xxx_res)
 {
-	if (wcd9xxx->irq) {
-		disable_irq_wake(wcd9xxx->irq);
-		free_irq(wcd9xxx->irq, wcd9xxx);
+	dev_dbg(wcd9xxx_res->dev, "%s: Cleaning up irq %d\n", __func__,
+		wcd9xxx_res->irq);
+
+	if (wcd9xxx_res->irq) {
+		disable_irq_wake(wcd9xxx_res->irq);
+		free_irq(wcd9xxx_res->irq, wcd9xxx_res);
 		/* Release parent's of node */
-		wcd9xxx_irq_put_upstream_irq(wcd9xxx);
-		device_init_wakeup(wcd9xxx->dev, 0);
+		wcd9xxx_irq_put_upstream_irq(wcd9xxx_res);
 	}
-	mutex_destroy(&wcd9xxx->irq_lock);
-	mutex_destroy(&wcd9xxx->nested_irq_lock);
+	mutex_destroy(&wcd9xxx_res->irq_lock);
+	mutex_destroy(&wcd9xxx_res->nested_irq_lock);
 }
 
 #ifndef CONFIG_OF
-static int phyirq_to_virq(struct wcd9xxx *wcd9xxx, int offset)
+static int phyirq_to_virq(
+	struct wcd9xxx_core_resource *wcd9xxx_res,
+	int offset)
 {
-	return wcd9xxx->irq_base + offset;
+	return wcd9xxx_res->irq_base + offset;
 }
 
-static int virq_to_phyirq(struct wcd9xxx *wcd9xxx, int virq)
+static int virq_to_phyirq(
+	struct wcd9xxx_core_resource *wcd9xxx_res,
+	int virq)
 {
-	return virq - wcd9xxx->irq_base;
+	return virq - wcd9xxx_res->irq_base;
 }
 
-static unsigned int wcd9xxx_irq_get_upstream_irq(struct wcd9xxx *wcd9xxx)
+static unsigned int wcd9xxx_irq_get_upstream_irq(
+	struct wcd9xxx_core_resource *wcd9xxx_res)
 {
-	return wcd9xxx->irq;
+	return wcd9xxx_res->irq;
 }
 
-static void wcd9xxx_irq_put_upstream_irq(struct wcd9xxx *wcd9xxx)
+static void wcd9xxx_irq_put_upstream_irq(
+	struct wcd9xxx_core_resource *wcd9xxx_res)
 {
 	/* Do nothing */
 }
 
-static int wcd9xxx_map_irq(struct wcd9xxx *wcd9xxx, int irq)
+static int wcd9xxx_map_irq(
+	struct wcd9xxx_core_resource *wcd9xxx_core_res, int irq)
 {
-	return phyirq_to_virq(wcd9xxx, irq);
+	return phyirq_to_virq(wcd9xxx_core_res, irq);
 }
 #else
 int __init wcd9xxx_irq_of_init(struct device_node *node,
@@ -555,12 +581,12 @@
 }
 
 static struct wcd9xxx_irq_drv_data *
-wcd9xxx_get_irq_drv_d(const struct wcd9xxx *wcd9xxx)
+wcd9xxx_get_irq_drv_d(const struct wcd9xxx_core_resource *wcd9xxx_res)
 {
 	struct device_node *pnode;
 	struct irq_domain *domain;
 
-	pnode = of_irq_find_parent(wcd9xxx->dev->of_node);
+	pnode = of_irq_find_parent(wcd9xxx_res->dev->of_node);
 	/* Shouldn't happen */
 	if (unlikely(!pnode))
 		return NULL;
@@ -569,11 +595,11 @@
 	return (struct wcd9xxx_irq_drv_data *)domain->host_data;
 }
 
-static int phyirq_to_virq(struct wcd9xxx *wcd9xxx, int offset)
+static int phyirq_to_virq(struct wcd9xxx_core_resource *wcd9xxx_res, int offset)
 {
 	struct wcd9xxx_irq_drv_data *data;
 
-	data = wcd9xxx_get_irq_drv_d(wcd9xxx);
+	data = wcd9xxx_get_irq_drv_d(wcd9xxx_res);
 	if (!data) {
 		pr_warn("%s: not registered to interrupt controller\n",
 			__func__);
@@ -582,21 +608,22 @@
 	return irq_linear_revmap(data->domain, offset);
 }
 
-static int virq_to_phyirq(struct wcd9xxx *wcd9xxx, int virq)
+static int virq_to_phyirq(struct wcd9xxx_core_resource *wcd9xxx_res, int virq)
 {
 	struct irq_data *irq_data = irq_get_irq_data(virq);
 	return irq_data->hwirq;
 }
 
-static unsigned int wcd9xxx_irq_get_upstream_irq(struct wcd9xxx *wcd9xxx)
+static unsigned int wcd9xxx_irq_get_upstream_irq(
+				struct wcd9xxx_core_resource *wcd9xxx_res)
 {
 	struct wcd9xxx_irq_drv_data *data;
 
 	/* Hold parent's of node */
-	if (!of_node_get(of_irq_find_parent(wcd9xxx->dev->of_node)))
+	if (!of_node_get(of_irq_find_parent(wcd9xxx_res->dev->of_node)))
 		return -EINVAL;
 
-	data = wcd9xxx_get_irq_drv_d(wcd9xxx);
+	data = wcd9xxx_get_irq_drv_d(wcd9xxx_res);
 	if (!data) {
 		pr_err("%s: interrupt controller is not registerd\n", __func__);
 		return 0;
@@ -606,15 +633,16 @@
 	return data->irq;
 }
 
-static void wcd9xxx_irq_put_upstream_irq(struct wcd9xxx *wcd9xxx)
+static void wcd9xxx_irq_put_upstream_irq(
+			struct wcd9xxx_core_resource *wcd9xxx_res)
 {
 	/* Hold parent's of node */
-	of_node_put(of_irq_find_parent(wcd9xxx->dev->of_node));
+	of_node_put(of_irq_find_parent(wcd9xxx_res->dev->of_node));
 }
 
-static int wcd9xxx_map_irq(struct wcd9xxx *wcd9xxx, int irq)
+static int wcd9xxx_map_irq(struct wcd9xxx_core_resource *wcd9xxx_res, int irq)
 {
-	return of_irq_to_resource(wcd9xxx->dev->of_node, irq, NULL);
+	return of_irq_to_resource(wcd9xxx_res->dev->of_node, irq, NULL);
 }
 
 static int __devinit wcd9xxx_irq_probe(struct platform_device *pdev)
diff --git a/drivers/misc/isa1200.c b/drivers/misc/isa1200.c
index c6d08d1..8090b95 100644
--- a/drivers/misc/isa1200.c
+++ b/drivers/misc/isa1200.c
@@ -44,6 +44,7 @@
 	struct timed_output_dev dev;
 	struct work_struct work;
 	struct mutex lock;
+	struct mutex lock_clk;
 	unsigned int enable;
 	unsigned int period_ns;
 	bool is_len_gpio_valid;
@@ -120,16 +121,19 @@
 				}
 			}
 
+			mutex_lock(&haptic->lock_clk);
 			/* vote for clock */
 			if (haptic->pdata->need_pwm_clk && !haptic->clk_on) {
 				rc = clk_prepare_enable(haptic->pwm_clk);
 				if (rc < 0) {
 					pr_err("%s: clk enable failed\n",
 								__func__);
+					mutex_unlock(&haptic->lock_clk);
 					goto dis_clk_cb;
 				}
 				haptic->clk_on = true;
 			}
+			mutex_unlock(&haptic->lock_clk);
 
 			rc = isa1200_write_reg(haptic->client,
 						ISA1200_HCTRL5,
@@ -162,11 +166,13 @@
 			if (rc < 0)
 				pr_err("%s: stop vibartion fail\n", __func__);
 
+			mutex_lock(&haptic->lock_clk);
 			/* de-vote clock */
 			if (haptic->pdata->need_pwm_clk && haptic->clk_on) {
 				clk_disable_unprepare(haptic->pwm_clk);
 				haptic->clk_on = false;
 			}
+			mutex_unlock(&haptic->lock_clk);
 			/* check for board specific clk callback */
 			if (haptic->pdata->clk_enable) {
 				rc = haptic->pdata->clk_enable(false);
@@ -180,10 +186,12 @@
 	return;
 
 dis_clk:
+	mutex_lock(&haptic->lock_clk);
 	if (haptic->pdata->need_pwm_clk && haptic->clk_on) {
 		clk_disable_unprepare(haptic->pwm_clk);
 		haptic->clk_on = false;
 	}
+	mutex_unlock(&haptic->lock_clk);
 
 dis_clk_cb:
 	if (haptic->pdata->clk_enable) {
@@ -649,6 +657,7 @@
 	}
 
 	mutex_init(&haptic->lock);
+	mutex_init(&haptic->lock_clk);
 	INIT_WORK(&haptic->work, isa1200_chip_work);
 	haptic->clk_on = false;
 
@@ -787,6 +796,7 @@
 
 	/* destroy mutex */
 	mutex_destroy(&haptic->lock);
+	mutex_destroy(&haptic->lock_clk);
 
 	/* power-off the chip */
 	if (haptic->pdata->regulator_info) {
diff --git a/drivers/misc/qseecom.c b/drivers/misc/qseecom.c
index b750602..58703cf 100644
--- a/drivers/misc/qseecom.c
+++ b/drivers/misc/qseecom.c
@@ -77,10 +77,11 @@
 };
 
 enum qseecom_client_handle_type {
-	QSEECOM_CLIENT_APP = 0,
+	QSEECOM_CLIENT_APP = 1,
 	QSEECOM_LISTENER_SERVICE,
 	QSEECOM_SECURE_SERVICE,
 	QSEECOM_GENERIC,
+	QSEECOM_UNAVAILABLE_CLIENT_APP,
 };
 
 enum qseecom_ce_hw_instance {
@@ -890,8 +891,8 @@
 	data->type = QSEECOM_SECURE_SERVICE;
 
 	switch (req.cmd_id) {
-	case QSEE_RPMB_PROVISION_KEY_COMMAND:
-	case QSEE_RPMB_ERASE_COMMAND:
+	case QSEOS_RPMB_PROVISION_KEY_COMMAND:
+	case QSEOS_RPMB_ERASE_COMMAND:
 		if (__qseecom_process_rpmb_svc_cmd(data, &req,
 				&send_svc_ireq))
 			return -EINVAL;
@@ -2171,6 +2172,9 @@
 	struct qseecom_unload_app_ireq req;
 	struct cpumask mask;
 
+	/* unavailable client app */
+	data->type = QSEECOM_UNAVAILABLE_CLIENT_APP;
+
 	/* Populate the structure for sending scm call to unload image */
 	req.qsee_cmd_id = QSEOS_UNLOAD_EXTERNAL_ELF_COMMAND;
 
@@ -2943,6 +2947,8 @@
 				return ret;
 			}
 			break;
+		case QSEECOM_UNAVAILABLE_CLIENT_APP:
+			break;
 		default:
 			pr_err("Unsupported clnt_handle_type %d",
 				data->type);
diff --git a/drivers/misc/smsc_hub.c b/drivers/misc/smsc_hub.c
index 41d9ff8..0147e66 100644
--- a/drivers/misc/smsc_hub.c
+++ b/drivers/misc/smsc_hub.c
@@ -21,14 +21,12 @@
 #include <linux/clk.h>
 #include <linux/slab.h>
 #include <linux/delay.h>
-#include <linux/smsc3503.h>
+#include <linux/smsc_hub.h>
 #include <linux/module.h>
 #include <mach/msm_xo.h>
 
-#define SMSC3503_I2C_ADDR 0x08
-#define SMSC_GSBI_I2C_BUS_ID 10
-static const unsigned short normal_i2c[] = {
-SMSC3503_I2C_ADDR, I2C_CLIENT_END };
+static unsigned short normal_i2c[] = {
+0, I2C_CLIENT_END };
 
 struct hsic_hub {
 	struct device *dev;
@@ -111,6 +109,22 @@
 	return i2c_smbus_write_byte_data(client, reg, (ret & ~value));
 }
 
+static int smsc4604_send_connect_cmd(struct i2c_client *client)
+{
+	u8 buf[3];
+
+	buf[0] = 0xAA;
+	buf[1] = 0x55;
+	buf[2] = 0x00;
+
+	if (i2c_master_send(client, buf, 3) != 3) {
+		dev_err(&client->dev, "%s: i2c send failed\n", __func__);
+		return -EIO;
+	}
+
+	return 0;
+}
+
 static int i2c_hsic_hub_probe(struct i2c_client *client,
 				const struct i2c_device_id *id)
 {
@@ -118,21 +132,37 @@
 				     I2C_FUNC_SMBUS_WORD_DATA))
 		return -EIO;
 
-	/* CONFIG_N bit in SP_ILOCK register has to be set before changing
-	 * other registers to change default configuration of hsic hub.
-	 */
-	hsic_hub_set_bits(client, SMSC3503_SP_ILOCK, CONFIG_N);
+	switch (smsc_hub->pdata->model_id) {
+	case SMSC3503_ID:
+		/*
+		 * CONFIG_N bit in SP_ILOCK register has to be set before
+		 * changing other registers to change default configuration
+		 * of hsic hub.
+		 */
+		hsic_hub_set_bits(client, SMSC3503_SP_ILOCK, CONFIG_N);
 
-	/* Can change default configuartion like VID,PID, strings etc
-	 * by writing new values to hsic hub registers.
-	 */
-	hsic_hub_write_word_data(client, SMSC3503_VENDORID, 0x05C6);
+		/*
+		 * Can change default configuartion like VID,PID,
+		 * strings etc by writing new values to hsic hub registers
+		 */
+		hsic_hub_write_word_data(client, SMSC3503_VENDORID, 0x05C6);
 
-	/* CONFIG_N bit in SP_ILOCK register has to be cleared for new
-	 * values in registers to be effective after writing to
-	 * other registers.
-	 */
-	hsic_hub_clear_bits(client, SMSC3503_SP_ILOCK, CONFIG_N);
+		/*
+		 * CONFIG_N bit in SP_ILOCK register has to be cleared
+		 * for new values in registers to be effective after
+		 * writing to other registers.
+		 */
+		hsic_hub_clear_bits(client, SMSC3503_SP_ILOCK, CONFIG_N);
+		break;
+	case SMSC4604_ID:
+		/*
+		 * SMSC4604 requires an I2C attach command to be issued
+		 * if I2C bus is connected
+		 */
+		return smsc4604_send_connect_cmd(client);
+	default:
+		return -EINVAL;
+	}
 
 	return 0;
 }
@@ -318,6 +348,8 @@
 struct smsc_hub_platform_data *msm_hub_dt_to_pdata(
 				struct platform_device *pdev)
 {
+	int rc;
+	u32 temp_val;
 	struct device_node *node = pdev->dev.of_node;
 	struct smsc_hub_platform_data *pdata;
 
@@ -327,6 +359,14 @@
 		return ERR_PTR(-ENOMEM);
 	}
 
+	rc = of_property_read_u32(node, "smsc,model-id", &temp_val);
+	if (rc) {
+		dev_err(&pdev->dev, "Unable to read smsc,model-id\n");
+		return ERR_PTR(rc);
+	} else {
+		pdata->model_id = temp_val;
+	}
+
 	pdata->hub_reset = of_get_named_gpio(node, "smsc,reset-gpio", 0);
 	if (pdata->hub_reset < 0)
 		return ERR_PTR(pdata->hub_reset);
@@ -399,18 +439,13 @@
 	}
 
 	gpio_direction_output(pdata->hub_reset, 0);
-	/* Hub reset should be asserted for minimum 2microsec
+	/*
+	 * Hub reset should be asserted for minimum 2microsec
 	 * before deasserting.
 	 */
 	udelay(5);
 	gpio_direction_output(pdata->hub_reset, 1);
 
-	ret = of_platform_populate(node, NULL, NULL, &pdev->dev);
-	if (ret) {
-		dev_err(&pdev->dev, "failed to add child node, ret=%d\n", ret);
-		goto uninit_gpio;
-	}
-
 	if (!IS_ERR(smsc_hub->hub_vbus_reg)) {
 		ret = regulator_enable(smsc_hub->hub_vbus_reg);
 		if (ret) {
@@ -436,14 +471,39 @@
 	memset(&i2c_info, 0, sizeof(struct i2c_board_info));
 	strlcpy(i2c_info.type, "i2c_hsic_hub", I2C_NAME_SIZE);
 
+	/* 250ms delay is required for SMSC4604 HUB to get I2C up */
+	msleep(250);
+
+	/* Assign I2C slave address per SMSC model */
+	switch (pdata->model_id) {
+	case SMSC3503_ID:
+		normal_i2c[0] = SMSC3503_I2C_ADDR;
+		break;
+	case SMSC4604_ID:
+		normal_i2c[0] = SMSC4604_I2C_ADDR;
+		break;
+	default:
+		dev_err(&pdev->dev, "unsupported SMSC model-id\n");
+		i2c_put_adapter(i2c_adap);
+		i2c_del_driver(&hsic_hub_driver);
+		goto uninit_gpio;
+	}
+
 	smsc_hub->client = i2c_new_probed_device(i2c_adap, &i2c_info,
 						   normal_i2c, NULL);
 	i2c_put_adapter(i2c_adap);
-	if (!smsc_hub->client)
-		dev_err(&pdev->dev, "failed to connect to smsc_hub"
-			 "through I2C\n");
 
 i2c_add_fail:
+	ret = of_platform_populate(node, NULL, NULL, &pdev->dev);
+	if (ret) {
+		dev_err(&pdev->dev, "failed to add child node, ret=%d\n", ret);
+		goto uninit_gpio;
+	}
+
+	if (!smsc_hub->client)
+		dev_err(&pdev->dev,
+			"failed to connect to smsc_hub through I2C\n");
+
 	pm_runtime_set_active(&pdev->dev);
 	pm_runtime_enable(&pdev->dev);
 
diff --git a/drivers/mmc/card/block.c b/drivers/mmc/card/block.c
index da07947..6ef389c 100644
--- a/drivers/mmc/card/block.c
+++ b/drivers/mmc/card/block.c
@@ -1640,6 +1640,13 @@
 		 ext_csd[EXT_CSD_CORRECTLY_PRG_SECTORS_NUM + 2] << 16 |
 		 ext_csd[EXT_CSD_CORRECTLY_PRG_SECTORS_NUM + 3] << 24);
 
+	/*
+	 * skip packed command header (1 sector) included by the counter but not
+	 * actually written to the NAND
+	 */
+	if (correctly_done >= card->ext_csd.data_sector_size)
+		correctly_done -= card->ext_csd.data_sector_size;
+
 	list_for_each_entry(prq, &mq_rq->packed_list, queuelist) {
 		if ((correctly_done - (int)blk_rq_bytes(prq)) < 0) {
 			/* prq is not successfull */
@@ -2993,11 +3000,6 @@
 	return ret;
 }
 
-#define CID_MANFID_SANDISK	0x2
-#define CID_MANFID_TOSHIBA	0x11
-#define CID_MANFID_MICRON	0x13
-#define CID_MANFID_SAMSUNG	0x15
-
 static const struct mmc_fixup blk_fixups[] =
 {
 	MMC_FIXUP("SEM02G", CID_MANFID_SANDISK, 0x100, add_quirk,
diff --git a/drivers/mmc/card/mmc_block_test.c b/drivers/mmc/card/mmc_block_test.c
index e9ac2fc..39296ef 100644
--- a/drivers/mmc/card/mmc_block_test.c
+++ b/drivers/mmc/card/mmc_block_test.c
@@ -2867,6 +2867,7 @@
 {
 	int ret = 0;
 	int i;
+	int num_requests = TEST_MAX_REQUESTS / 2;
 
 	td->test_count = 0;
 	mbtd->completed_req_count = 0;
@@ -2876,15 +2877,15 @@
 		     td->wr_rd_next_req_id);
 
 	do {
-		for (i = 0; i < TEST_MAX_REQUESTS; i++) {
+		for (i = 0; i < num_requests; i++) {
 			/*
 			 * since our requests come from a pool containing 128
 			 * requests, we don't want to exhaust this quantity,
-			 * therefore we add up to TEST_MAX_REQUESTS (which
+			 * therefore we add up to num_requests (which
 			 * includes a safety margin) and then call the mmc layer
 			 * to fetch them
 			 */
-			if (td->test_count > TEST_MAX_REQUESTS)
+			if (td->test_count > num_requests)
 				break;
 
 			ret = test_iosched_add_wr_rd_test_req(0, WRITE,
diff --git a/drivers/mmc/card/queue.c b/drivers/mmc/card/queue.c
index 507cd5b..8986829 100644
--- a/drivers/mmc/card/queue.c
+++ b/drivers/mmc/card/queue.c
@@ -264,7 +264,7 @@
 
 	if ((host->caps2 & MMC_CAP2_STOP_REQUEST) &&
 			host->ops->stop_request &&
-			mq->card->ext_csd.hpi)
+			mq->card->ext_csd.hpi_en)
 		blk_urgent_request(mq->queue, mmc_urgent_request);
 
 	memset(&mq->mqrq_cur, 0, sizeof(mq->mqrq_cur));
@@ -285,7 +285,9 @@
 	if (mmc_can_erase(card))
 		mmc_queue_setup_discard(mq->queue, card);
 
-	if ((mmc_can_sanitize(card) && (host->caps2 & MMC_CAP2_SANITIZE)))
+	/* Don't enable Sanitize if HPI is not supported */
+	if ((mmc_can_sanitize(card) && (host->caps2 & MMC_CAP2_SANITIZE) &&
+	    card->ext_csd.hpi_en))
 		mmc_queue_setup_sanitize(mq->queue);
 
 #ifdef CONFIG_MMC_BLOCK_BOUNCE
diff --git a/drivers/mmc/core/bus.c b/drivers/mmc/core/bus.c
index a990f43..eb5d365 100644
--- a/drivers/mmc/core/bus.c
+++ b/drivers/mmc/core/bus.c
@@ -204,9 +204,11 @@
 
 	if (mmc_use_core_runtime_pm(card->host)) {
 		ret = pm_schedule_suspend(dev, card->idle_timeout);
-		if (ret) {
-			pr_err("%s: %s: pm_schedule_suspend failed: err: %d\n",
-			       mmc_hostname(host), __func__, ret);
+		if ((ret < 0) && (dev->power.runtime_error ||
+				  dev->power.disable_depth > 0)) {
+			pr_err("%s: %s: %s: pm_schedule_suspend failed: err: %d\n",
+			       mmc_hostname(host), __func__, dev_name(dev),
+			       ret);
 			return ret;
 		}
 	}
@@ -397,10 +399,11 @@
 			mmc_card_ddr_mode(card) ? "DDR " : "",
 			type);
 	} else {
-		pr_info("%s: new %s%s%s%s%s card at address %04x\n",
+		pr_info("%s: new %s%s%s%s%s%s card at address %04x\n",
 			mmc_hostname(card->host),
 			mmc_card_uhs(card) ? "ultra high speed " :
 			(mmc_card_highspeed(card) ? "high speed " : ""),
+			(mmc_card_hs400(card) ? "HS400 " : ""),
 			(mmc_card_hs200(card) ? "HS200 " : ""),
 			mmc_card_ddr_mode(card) ? "DDR " : "",
 			uhs_bus_speed_mode, type, card->rca);
@@ -416,7 +419,7 @@
 		if (ret)
 			pr_err("%s: %s: failed setting runtime active: ret: %d\n",
 			       mmc_hostname(card->host), __func__, ret);
-		else
+		else if (!mmc_card_sdio(card))
 			pm_runtime_enable(&card->dev);
 	}
 
@@ -424,7 +427,7 @@
 	if (ret)
 		return ret;
 
-	if (mmc_use_core_runtime_pm(card->host)) {
+	if (mmc_use_core_runtime_pm(card->host) && !mmc_card_sdio(card)) {
 		card->rpm_attrib.show = show_rpm_delay;
 		card->rpm_attrib.store = store_rpm_delay;
 		sysfs_attr_init(&card->rpm_attrib.attr);
diff --git a/drivers/mmc/core/core.c b/drivers/mmc/core/core.c
index 064d5ec..91efb12 100644
--- a/drivers/mmc/core/core.c
+++ b/drivers/mmc/core/core.c
@@ -607,7 +607,7 @@
 	int err = 0;
 	u32 status;
 
-	if (!host->ops->stop_request || !card->ext_csd.hpi) {
+	if (!host->ops->stop_request || !card->ext_csd.hpi_en) {
 		pr_warn("%s: host ops stop_request() or HPI not supported\n",
 				mmc_hostname(host));
 		return -ENOTSUPP;
@@ -731,7 +731,8 @@
 			 * notification before it receives end_io on
 			 * the current
 			 */
-			BUG_ON(pending_is_urgent == true);
+			if (pending_is_urgent)
+				continue; /* wait for done/new/urgent event */
 
 			context_info->is_urgent = false;
 			context_info->is_new_req = false;
diff --git a/drivers/mmc/core/mmc.c b/drivers/mmc/core/mmc.c
index 90d9826..e1609cf 100644
--- a/drivers/mmc/core/mmc.c
+++ b/drivers/mmc/core/mmc.c
@@ -58,6 +58,17 @@
 		__res & __mask;						\
 	})
 
+static const struct mmc_fixup mmc_fixups[] = {
+	/*
+	 * Certain Hynix eMMC 4.41 cards might get broken when HPI feature
+	 * is used so disable the HPI feature for such buggy cards.
+	 */
+	MMC_FIXUP_EXT_CSD_REV(CID_NAME_ANY, CID_MANFID_HYNIX,
+			      0x014a, add_quirk, MMC_QUIRK_BROKEN_HPI, 5),
+
+	END_FIXUP
+};
+
 /*
  * Given the decoded CSD structure, decode the raw CID to our CID structure.
  */
@@ -263,6 +274,12 @@
 			card_type & EXT_CSD_CARD_TYPE_SDR_1_2V))
 		hs_max_dtr = MMC_HS200_MAX_DTR;
 
+	if ((caps2 & MMC_CAP2_HS400_1_8V &&
+			card_type & EXT_CSD_CARD_TYPE_HS400_1_8V) ||
+	    (caps2 & MMC_CAP2_HS400_1_2V &&
+			card_type & EXT_CSD_CARD_TYPE_HS400_1_2V))
+		hs_max_dtr = MMC_HS400_MAX_DTR;
+
 	card->ext_csd.hs_max_dtr = hs_max_dtr;
 	card->ext_csd.card_type = card_type;
 }
@@ -301,6 +318,9 @@
 		goto out;
 	}
 
+	/* fixup device after ext_csd revision field is updated */
+	mmc_fixup_device(card, mmc_fixups);
+
 	card->ext_csd.raw_sectors[0] = ext_csd[EXT_CSD_SEC_CNT + 0];
 	card->ext_csd.raw_sectors[1] = ext_csd[EXT_CSD_SEC_CNT + 1];
 	card->ext_csd.raw_sectors[2] = ext_csd[EXT_CSD_SEC_CNT + 2];
@@ -465,8 +485,28 @@
 	}
 
 	if (card->ext_csd.rev >= 5) {
-		/* check whether the eMMC card supports BKOPS */
-		if (ext_csd[EXT_CSD_BKOPS_SUPPORT] & 0x1) {
+		/* check whether the eMMC card supports HPI */
+		if ((ext_csd[EXT_CSD_HPI_FEATURES] & 0x1) &&
+				!(card->quirks & MMC_QUIRK_BROKEN_HPI)) {
+			card->ext_csd.hpi = 1;
+			if (ext_csd[EXT_CSD_HPI_FEATURES] & 0x2)
+				card->ext_csd.hpi_cmd = MMC_STOP_TRANSMISSION;
+			else
+				card->ext_csd.hpi_cmd = MMC_SEND_STATUS;
+			/*
+			 * Indicate the maximum timeout to close
+			 * a command interrupted by HPI
+			 */
+			card->ext_csd.out_of_int_time =
+				ext_csd[EXT_CSD_OUT_OF_INTERRUPT_TIME] * 10;
+		}
+
+		/*
+		 * check whether the eMMC card supports BKOPS.
+		 * If HPI is not supported then BKOPs shouldn't be enabled.
+		 */
+		if ((ext_csd[EXT_CSD_BKOPS_SUPPORT] & 0x1) &&
+		    card->ext_csd.hpi) {
 			card->ext_csd.bkops = 1;
 			card->ext_csd.bkops_en = ext_csd[EXT_CSD_BKOPS_EN];
 			card->ext_csd.raw_bkops_status =
@@ -486,21 +526,6 @@
 		pr_info("%s: BKOPS_EN bit = %d\n",
 			mmc_hostname(card->host), card->ext_csd.bkops_en);
 
-		/* check whether the eMMC card supports HPI */
-		if (ext_csd[EXT_CSD_HPI_FEATURES] & 0x1) {
-			card->ext_csd.hpi = 1;
-			if (ext_csd[EXT_CSD_HPI_FEATURES] & 0x2)
-				card->ext_csd.hpi_cmd =	MMC_STOP_TRANSMISSION;
-			else
-				card->ext_csd.hpi_cmd = MMC_SEND_STATUS;
-			/*
-			 * Indicate the maximum timeout to close
-			 * a command interrupted by HPI
-			 */
-			card->ext_csd.out_of_int_time =
-				ext_csd[EXT_CSD_OUT_OF_INTERRUPT_TIME] * 10;
-		}
-
 		card->ext_csd.rel_param = ext_csd[EXT_CSD_WR_REL_PARAM];
 		card->ext_csd.rst_n_function = ext_csd[EXT_CSD_RST_N_FUNCTION];
 
@@ -719,7 +744,9 @@
 				EXT_CSD_PWR_CL_52_195 :
 				EXT_CSD_PWR_CL_DDR_52_195;
 		else if (host->ios.clock <= 200000000)
-			index = EXT_CSD_PWR_CL_200_195;
+			index = (bus_width <= EXT_CSD_BUS_WIDTH_8) ?
+				EXT_CSD_PWR_CL_200_195 :
+				EXT_CSD_PWR_CL_DDR_200_195;
 		break;
 	case MMC_VDD_27_28:
 	case MMC_VDD_28_29:
@@ -737,7 +764,9 @@
 				EXT_CSD_PWR_CL_52_360 :
 				EXT_CSD_PWR_CL_DDR_52_360;
 		else if (host->ios.clock <= 200000000)
-			index = EXT_CSD_PWR_CL_200_360;
+			index = (bus_width <= EXT_CSD_BUS_WIDTH_8) ?
+				EXT_CSD_PWR_CL_200_360 :
+				EXT_CSD_PWR_CL_DDR_200_360;
 		break;
 	default:
 		pr_warning("%s: Voltage range not supported "
@@ -766,75 +795,385 @@
 }
 
 /*
- * Selects the desired buswidth and switch to the HS200 mode
- * if bus width set without error
+ * Select the correct bus width supported by both host and card
  */
-static int mmc_select_hs200(struct mmc_card *card)
+static int mmc_select_bus_width(struct mmc_card *card, int ddr, u8 *ext_csd)
 {
-	int idx, err = 0;
 	struct mmc_host *host;
-	static unsigned ext_csd_bits[] = {
-		EXT_CSD_BUS_WIDTH_4,
-		EXT_CSD_BUS_WIDTH_8,
+	static unsigned ext_csd_bits[][2] = {
+		{ EXT_CSD_BUS_WIDTH_8, EXT_CSD_DDR_BUS_WIDTH_8 },
+		{ EXT_CSD_BUS_WIDTH_4, EXT_CSD_DDR_BUS_WIDTH_4 },
+		{ EXT_CSD_BUS_WIDTH_1, EXT_CSD_BUS_WIDTH_1 },
 	};
 	static unsigned bus_widths[] = {
-		MMC_BUS_WIDTH_4,
 		MMC_BUS_WIDTH_8,
+		MMC_BUS_WIDTH_4,
+		MMC_BUS_WIDTH_1
 	};
-
-	BUG_ON(!card);
+	unsigned idx, bus_width = 0;
+	int err = 0;
 
 	host = card->host;
 
+	if ((card->csd.mmca_vsn < CSD_SPEC_VER_4) ||
+	    !(host->caps & (MMC_CAP_4_BIT_DATA | MMC_CAP_8_BIT_DATA)))
+		goto out;
+
+	if (host->caps & MMC_CAP_8_BIT_DATA)
+		idx = 0;
+	else
+		idx = 1;
+
+	for (; idx < ARRAY_SIZE(bus_widths); idx++) {
+		bus_width = bus_widths[idx];
+		if (bus_width == MMC_BUS_WIDTH_1)
+			ddr = 0; /* no DDR for 1-bit width */
+		err = mmc_select_powerclass(card, ext_csd_bits[idx][0],
+					    ext_csd);
+		if (err)
+			pr_warning("%s: power class selection to " \
+				   "bus width %d failed\n",
+				   mmc_hostname(host),
+				   1 << bus_width);
+
+		err = mmc_switch(card, EXT_CSD_CMD_SET_NORMAL,
+				 EXT_CSD_BUS_WIDTH,
+				 ext_csd_bits[idx][0],
+				 card->ext_csd.generic_cmd6_time);
+		if (!err) {
+			mmc_set_bus_width(host, bus_width);
+
+			/*
+			 * If controller can't handle bus width test,
+			 * compare ext_csd previously read in 1 bit mode
+			 * against ext_csd at new bus width
+			 */
+			if (!(host->caps & MMC_CAP_BUS_WIDTH_TEST))
+				err = mmc_compare_ext_csds(card, bus_width);
+			else
+				err = mmc_bus_test(card, bus_width);
+			if (!err)
+				break;
+		}
+	}
+
+	if (!err && ddr) {
+		err = mmc_select_powerclass(card, ext_csd_bits[idx][1],
+					    ext_csd);
+		if (err)
+			pr_warning("%s: power class selection to " \
+				   "bus width %d ddr %d failed\n",
+				   mmc_hostname(host),
+				   1 << bus_width, ddr);
+			err = mmc_switch(card, EXT_CSD_CMD_SET_NORMAL,
+					 EXT_CSD_BUS_WIDTH,
+					 ext_csd_bits[idx][1],
+					 card->ext_csd.generic_cmd6_time);
+	}
+
+out:
+	return err;
+}
+
+/*
+ * Switch to HighSpeed mode and select wide bus if supported
+ */
+static int mmc_select_hs(struct mmc_card *card, u8 *ext_csd)
+{
+	int err = 0;
+	struct mmc_host *host;
+
+	host = card->host;
+
+	if (!(host->caps & MMC_CAP_MMC_HIGHSPEED) ||
+		!(card->ext_csd.card_type & EXT_CSD_CARD_TYPE_52)) {
+		err = -EOPNOTSUPP;
+		goto out;
+	}
+
+	err = mmc_switch(card, EXT_CSD_CMD_SET_NORMAL,
+				EXT_CSD_HS_TIMING, 1,
+				card->ext_csd.generic_cmd6_time);
+
+	if (err && err != -EBADMSG)
+		goto out;
+
+	mmc_card_set_highspeed(card);
+	mmc_set_timing(host, MMC_TIMING_MMC_HS);
+	mmc_set_clock(host, MMC_HIGH_52_MAX_DTR);
+
+	err = mmc_select_bus_width(card, 0, ext_csd);
+
+out:
+	if (err && err != -EOPNOTSUPP)
+		pr_warning("%s: Switch to HighSpeed mode failed (err:%d)\n",
+				mmc_hostname(host), err);
+	return err;
+}
+
+/*
+ * Select the desired buswidth and switch to HighSpeed DDR mode
+ * if bus width set without error
+ */
+static int mmc_select_hsddr(struct mmc_card *card, u8 *ext_csd)
+{
+	int ddr = 0, err = 0;
+	struct mmc_host *host;
+
+	host = card->host;
+
+	if (!(host->caps & MMC_CAP_HSDDR) ||
+		!(card->ext_csd.card_type & EXT_CSD_CARD_TYPE_DDR_52)) {
+		err = -EOPNOTSUPP;
+		goto out;
+	}
+
+	err = mmc_select_hs(card, ext_csd);
+	if (err)
+		goto out;
+	mmc_card_clr_highspeed(card);
+
+	if ((card->ext_csd.card_type & EXT_CSD_CARD_TYPE_DDR_1_8V)
+		&& ((host->caps & (MMC_CAP_1_8V_DDR |
+		     MMC_CAP_UHS_DDR50))
+			== (MMC_CAP_1_8V_DDR | MMC_CAP_UHS_DDR50)))
+			ddr = MMC_1_8V_DDR_MODE;
+	else if ((card->ext_csd.card_type & EXT_CSD_CARD_TYPE_DDR_1_2V)
+		&& ((host->caps & (MMC_CAP_1_2V_DDR |
+		     MMC_CAP_UHS_DDR50))
+			== (MMC_CAP_1_2V_DDR | MMC_CAP_UHS_DDR50)))
+			ddr = MMC_1_2V_DDR_MODE;
+
+	err = mmc_select_bus_width(card, ddr, ext_csd);
+	if (err)
+		goto out;
+
+	if (host->ios.bus_width == MMC_BUS_WIDTH_1) {
+		pr_err("%s: failed to switch to wide bus\n",
+			mmc_hostname(host));
+		goto out;
+	}
+
+	/*
+	 * eMMC cards can support 3.3V to 1.2V i/o (vccq)
+	 * signaling.
+	 *
+	 * EXT_CSD_CARD_TYPE_DDR_1_8V means 3.3V or 1.8V vccq.
+	 *
+	 * 1.8V vccq at 3.3V core voltage (vcc) is not required
+	 * in the JEDEC spec for DDR.
+	 *
+	 * Do not force change in vccq since we are obviously
+	 * working and no change to vccq is needed.
+	 *
+	 * WARNING: eMMC rules are NOT the same as SD DDR
+	 */
+	if (ddr == MMC_1_2V_DDR_MODE) {
+		err = mmc_set_signal_voltage(host,
+			MMC_SIGNAL_VOLTAGE_120, 0);
+		if (err)
+			goto out;
+	}
+	mmc_card_set_ddr_mode(card);
+	mmc_set_timing(host, MMC_TIMING_UHS_DDR50);
+	mmc_set_bus_width(host, host->ios.bus_width);
+
+out:
+	if (err && err != -EOPNOTSUPP)
+		pr_warning("%s: Switch to HighSpeed DDR mode failed (err:%d)\n",
+				mmc_hostname(host), err);
+	return err;
+}
+
+/*
+ * Select the desired buswidth and switch to HS200 mode
+ * if bus width set without error
+ */
+static int mmc_select_hs200(struct mmc_card *card, u8 *ext_csd)
+{
+	int err = 0;
+	struct mmc_host *host;
+
+	host = card->host;
+
+	if (!(host->caps2 & MMC_CAP2_HS200) ||
+		!(card->ext_csd.card_type & EXT_CSD_CARD_TYPE_HS200)) {
+		err = -EOPNOTSUPP;
+		goto out;
+	}
+
 	if (card->ext_csd.card_type & EXT_CSD_CARD_TYPE_SDR_1_2V &&
 	    host->caps2 & MMC_CAP2_HS200_1_2V_SDR)
 		if (mmc_set_signal_voltage(host, MMC_SIGNAL_VOLTAGE_120, 0))
 			err = mmc_set_signal_voltage(host,
 						     MMC_SIGNAL_VOLTAGE_180, 0);
-
 	/* If fails try again during next card power cycle */
 	if (err)
-		goto err;
-
-	idx = (host->caps & MMC_CAP_8_BIT_DATA) ? 1 : 0;
+		goto out;
 
 	/*
-	 * Unlike SD, MMC cards dont have a configuration register to notify
-	 * supported bus width. So bus test command should be run to identify
-	 * the supported bus width or compare the ext csd values of current
-	 * bus width and ext csd values of 1 bit mode read earlier.
+	 * For devices supporting HS200 mode, the bus width has
+	 * to be set before executing the tuning function. If
+	 * set before tuning, then device will respond with CRC
+	 * errors for responses on CMD line. So for HS200 the
+	 * sequence will be
+	 * 1. set bus width 4bit / 8 bit (1 bit not supported)
+	 * 2. switch to HS200 mode
+	 * 3. set the clock to > 52Mhz <=200MHz and
+	 * 4. execute tuning for HS200
 	 */
-	for (; idx >= 0; idx--) {
+	err = mmc_select_bus_width(card, 0, ext_csd);
+	if (err) {
+		pr_err("%s: select bus width failed\n",
+			mmc_hostname(host));
+		goto out;
+	}
 
-		/*
-		 * Host is capable of 8bit transfer, then switch
-		 * the device to work in 8bit transfer mode. If the
-		 * mmc switch command returns error then switch to
-		 * 4bit transfer mode. On success set the corresponding
-		 * bus width on the host.
-		 */
-		err = mmc_switch(card, EXT_CSD_CMD_SET_NORMAL,
-				 EXT_CSD_BUS_WIDTH,
-				 ext_csd_bits[idx],
-				 card->ext_csd.generic_cmd6_time);
-		if (err)
-			continue;
-
-		mmc_set_bus_width(card->host, bus_widths[idx]);
-
-		if (!(host->caps & MMC_CAP_BUS_WIDTH_TEST))
-			err = mmc_compare_ext_csds(card, bus_widths[idx]);
-		else
-			err = mmc_bus_test(card, bus_widths[idx]);
-		if (!err)
-			break;
+	if (host->ios.bus_width == MMC_BUS_WIDTH_1) {
+		pr_err("%s: failed to switch to wide bus\n",
+			mmc_hostname(host));
+		goto out;
 	}
 
 	/* switch to HS200 mode if bus width set successfully */
-	if (!err)
-		err = mmc_switch(card, EXT_CSD_CMD_SET_NORMAL,
-				 EXT_CSD_HS_TIMING, 2, 0);
-err:
+	err = mmc_switch(card, EXT_CSD_CMD_SET_NORMAL,
+				EXT_CSD_HS_TIMING, 2, 0);
+
+	if (err && err != -EBADMSG) {
+		pr_err("%s: HS200 switch failed\n",
+			mmc_hostname(host));
+		goto out;
+	}
+
+	/*
+	 * When HS200 activation is performed as part of HS400 selection
+	 * set the timing appropriately
+	 */
+	if (mmc_card_hs400(card))
+		mmc_set_timing(host, MMC_TIMING_MMC_HS400);
+	else
+		mmc_set_timing(host, MMC_TIMING_MMC_HS200);
+
+	mmc_set_clock(host, MMC_HS200_MAX_DTR);
+
+	if (host->ops->execute_tuning) {
+		mmc_host_clk_hold(host);
+		err = host->ops->execute_tuning(host,
+				MMC_SEND_TUNING_BLOCK_HS200);
+		mmc_host_clk_release(host);
+	}
+	if (err) {
+		pr_warning("%s: tuning execution failed\n",
+			   mmc_hostname(host));
+		goto out;
+	}
+	mmc_card_set_hs200(card);
+
+out:
+	if (err && err != -EOPNOTSUPP)
+		pr_warning("%s: Switch to HS200 mode failed (err:%d)\n",
+				mmc_hostname(host), err);
+	return err;
+}
+
+static int mmc_select_hs400(struct mmc_card *card, u8 *ext_csd)
+{
+	int err = 0;
+	struct mmc_host *host;
+
+	host = card->host;
+
+	if (!(host->caps2 & MMC_CAP2_HS400) ||
+		!(card->ext_csd.card_type & EXT_CSD_CARD_TYPE_HS400)) {
+		err = -EOPNOTSUPP;
+		goto out;
+	}
+
+	/*
+	 * eMMC5.0 spec doesn't allow switching to HS400 mode from
+	 * HS200 mode directly. Hence follow these steps to switch
+	 * to HS400 mode:
+	 *	Enable HS200 mode
+	 *	Enable HighSpeed mode (The clk should be low enough
+	 *		to enable HighSpeed mode) - HS_TIMING is 0x1
+	 *	Enable DDR mode (Set bus width to 8-bit DDR)
+	 *	Enable HS400 mode (Set HS_TIMING to 0x3 and change
+	 *		frequency to <= 200MHz)
+	 *	Perform tuning if required
+	 */
+	mmc_card_set_hs400(card);
+	err = mmc_select_hs200(card, ext_csd);
+	if (err)
+		goto out;
+	mmc_card_clr_hs200(card);
+
+	if ((card->ext_csd.card_type & EXT_CSD_CARD_TYPE_HS400_1_2V)
+	    && (host->caps2 & MMC_CAP2_HS400_1_2V))
+		if (mmc_set_signal_voltage(host, MMC_SIGNAL_VOLTAGE_120, 0))
+				err = mmc_set_signal_voltage(host,
+						MMC_SIGNAL_VOLTAGE_180, 0);
+	/* If fails try again during next card power cycle */
+	if (err)
+		goto out;
+
+	/*
+	 * Lower the clock and adjust the timing to be able
+	 * to switch to HighSpeed mode
+	 */
+	mmc_set_timing(host, MMC_TIMING_LEGACY);
+	mmc_set_clock(host, MMC_HIGH_26_MAX_DTR);
+
+	err = mmc_select_hs(card, ext_csd);
+	if (err)
+		goto out;
+	mmc_card_clr_highspeed(card);
+
+	/* Switch to 8-bit DDR mode */
+	err = mmc_select_hsddr(card, ext_csd);
+	if (err)
+		goto out;
+	mmc_card_clr_ddr_mode(card);
+
+	/*
+	 * In HS400 mode only DDR 8-bit bus width is allowed.
+	 */
+	if (host->ios.bus_width != MMC_BUS_WIDTH_8) {
+		pr_err("%s: failed to switch to 8-bit bus width\n",
+			mmc_hostname(host));
+		goto out;
+	}
+
+	/* Switch to HS400 mode if bus width set successfully */
+	err = mmc_switch(card, EXT_CSD_CMD_SET_NORMAL,
+				 EXT_CSD_HS_TIMING, 3, 0);
+	if (err && err != -EBADMSG) {
+		pr_err("%s: Setting HS_TIMING to HS400 failed (err:%d)\n",
+			mmc_hostname(host), err);
+		goto out;
+	}
+
+	mmc_set_timing(host, MMC_TIMING_MMC_HS400);
+	mmc_set_clock(host, MMC_HS400_MAX_DTR);
+
+	if (host->ops->execute_tuning) {
+		mmc_host_clk_hold(host);
+		err = host->ops->execute_tuning(host,
+				MMC_SEND_TUNING_BLOCK_HS400);
+		mmc_host_clk_release(host);
+	}
+	if (err) {
+		pr_err("%s: tuning execution failed (err:%d)\n",
+			   mmc_hostname(host), err);
+		goto out;
+	}
+	mmc_card_set_hs400(card);
+
+out:
+	if (err && err != -EOPNOTSUPP) {
+		pr_warning("%s: Switch to HS400 mode failed (err:%d)\n",
+				mmc_hostname(host), err);
+		mmc_card_clr_hs400(card);
+	}
 	return err;
 }
 
@@ -869,7 +1208,8 @@
 	}
 
 	if (mmc_card_highspeed(card) || mmc_card_hs200(card)
-			|| mmc_card_ddr_mode(card)) {
+			|| mmc_card_ddr_mode(card)
+			|| mmc_card_hs400(card)) {
 		if (*freq > card->ext_csd.hs_max_dtr)
 			*freq = card->ext_csd.hs_max_dtr;
 	} else if (*freq > card->csd.max_dtr) {
@@ -881,7 +1221,8 @@
 
 	mmc_set_clock(host, (unsigned int) (*freq));
 
-	if (mmc_card_hs200(card) && card->host->ops->execute_tuning) {
+	if ((mmc_card_hs400(card) || mmc_card_hs200(card))
+		&& card->host->ops->execute_tuning) {
 		/*
 		 * We try to probe host driver for tuning for any
 		 * frequency, it is host driver responsibility to
@@ -919,6 +1260,35 @@
 }
 
 /*
+ * Activate highest bus speed mode supported by both host and card.
+ * On failure activate the next supported highest bus speed mode.
+ */
+static int mmc_select_bus_speed(struct mmc_card *card, u8 *ext_csd)
+{
+	int err = 0;
+
+	BUG_ON(!card);
+
+	if (!mmc_select_hs400(card, ext_csd))
+		goto out;
+	if (!mmc_select_hs200(card, ext_csd))
+		goto out;
+	if (!mmc_select_hsddr(card, ext_csd))
+		goto out;
+	if (!mmc_select_hs(card, ext_csd))
+		goto out;
+
+	/*
+	 * Select the default speed and wide bus if supported
+	 */
+	mmc_set_clock(card->host, card->csd.max_dtr);
+	err = mmc_select_bus_width(card, 0, ext_csd);
+
+out:
+	return err;
+}
+
+/*
  * Handle the detection and initialisation of a card.
  *
  * In the case of a resume, "oldcard" will contain the card
@@ -928,9 +1298,8 @@
 	struct mmc_card *oldcard)
 {
 	struct mmc_card *card;
-	int err, ddr = 0;
+	int err = 0;
 	u32 cid[4];
-	unsigned int max_dtr;
 	u32 rocr;
 	u8 *ext_csd = NULL;
 
@@ -1132,209 +1501,11 @@
 	}
 
 	/*
-	 * Activate high speed (if supported)
+	 * Activate highest bus speed mode supported by both host and card.
 	 */
-	if (card->ext_csd.hs_max_dtr != 0) {
-		err = 0;
-		if (card->ext_csd.hs_max_dtr > 52000000 &&
-		    host->caps2 & MMC_CAP2_HS200)
-			err = mmc_select_hs200(card);
-		else if	(host->caps & MMC_CAP_MMC_HIGHSPEED)
-			err = mmc_switch(card, EXT_CSD_CMD_SET_NORMAL,
-					 EXT_CSD_HS_TIMING, 1,
-					 card->ext_csd.generic_cmd6_time);
-
-		if (err && err != -EBADMSG)
-			goto free_card;
-
-		if (err) {
-			pr_warning("%s: switch to highspeed failed\n",
-			       mmc_hostname(card->host));
-			err = 0;
-		} else {
-			if (card->ext_csd.hs_max_dtr > 52000000 &&
-			    host->caps2 & MMC_CAP2_HS200) {
-				mmc_card_set_hs200(card);
-				mmc_set_timing(card->host,
-					       MMC_TIMING_MMC_HS200);
-			} else {
-				mmc_card_set_highspeed(card);
-				mmc_set_timing(card->host, MMC_TIMING_MMC_HS);
-			}
-		}
-	}
-
-	/*
-	 * Compute bus speed.
-	 */
-	max_dtr = (unsigned int)-1;
-
-	if (mmc_card_highspeed(card) || mmc_card_hs200(card)) {
-		if (max_dtr > card->ext_csd.hs_max_dtr)
-			max_dtr = card->ext_csd.hs_max_dtr;
-	} else if (max_dtr > card->csd.max_dtr) {
-		max_dtr = card->csd.max_dtr;
-	}
-
-	mmc_set_clock(host, max_dtr);
-
-	/*
-	 * Indicate DDR mode (if supported).
-	 */
-	if (mmc_card_highspeed(card)) {
-		if ((card->ext_csd.card_type & EXT_CSD_CARD_TYPE_DDR_1_8V)
-			&& ((host->caps & (MMC_CAP_1_8V_DDR |
-			     MMC_CAP_UHS_DDR50))
-				== (MMC_CAP_1_8V_DDR | MMC_CAP_UHS_DDR50)))
-				ddr = MMC_1_8V_DDR_MODE;
-		else if ((card->ext_csd.card_type & EXT_CSD_CARD_TYPE_DDR_1_2V)
-			&& ((host->caps & (MMC_CAP_1_2V_DDR |
-			     MMC_CAP_UHS_DDR50))
-				== (MMC_CAP_1_2V_DDR | MMC_CAP_UHS_DDR50)))
-				ddr = MMC_1_2V_DDR_MODE;
-	}
-
-	/*
-	 * Indicate HS200 SDR mode (if supported).
-	 */
-	if (mmc_card_hs200(card)) {
-		u32 ext_csd_bits;
-		u32 bus_width = card->host->ios.bus_width;
-
-		/*
-		 * For devices supporting HS200 mode, the bus width has
-		 * to be set before executing the tuning function. If
-		 * set before tuning, then device will respond with CRC
-		 * errors for responses on CMD line. So for HS200 the
-		 * sequence will be
-		 * 1. set bus width 4bit / 8 bit (1 bit not supported)
-		 * 2. switch to HS200 mode
-		 * 3. set the clock to > 52Mhz <=200MHz and
-		 * 4. execute tuning for HS200
-		 */
-		if ((host->caps2 & MMC_CAP2_HS200) &&
-		    card->host->ops->execute_tuning) {
-			mmc_host_clk_hold(card->host);
-			err = card->host->ops->execute_tuning(card->host,
-				MMC_SEND_TUNING_BLOCK_HS200);
-			mmc_host_clk_release(card->host);
-		}
-		if (err) {
-			pr_warning("%s: tuning execution failed\n",
-				   mmc_hostname(card->host));
-			goto err;
-		}
-
-		ext_csd_bits = (bus_width == MMC_BUS_WIDTH_8) ?
-				EXT_CSD_BUS_WIDTH_8 : EXT_CSD_BUS_WIDTH_4;
-		err = mmc_select_powerclass(card, ext_csd_bits, ext_csd);
-		if (err)
-			pr_warning("%s: power class selection to bus width %d"
-				   " failed\n", mmc_hostname(card->host),
-				   1 << bus_width);
-	}
-
-	/*
-	 * Activate wide bus and DDR (if supported).
-	 */
-	if (!mmc_card_hs200(card) &&
-	    (card->csd.mmca_vsn >= CSD_SPEC_VER_4) &&
-	    (host->caps & (MMC_CAP_4_BIT_DATA | MMC_CAP_8_BIT_DATA))) {
-		static unsigned ext_csd_bits[][2] = {
-			{ EXT_CSD_BUS_WIDTH_8, EXT_CSD_DDR_BUS_WIDTH_8 },
-			{ EXT_CSD_BUS_WIDTH_4, EXT_CSD_DDR_BUS_WIDTH_4 },
-			{ EXT_CSD_BUS_WIDTH_1, EXT_CSD_BUS_WIDTH_1 },
-		};
-		static unsigned bus_widths[] = {
-			MMC_BUS_WIDTH_8,
-			MMC_BUS_WIDTH_4,
-			MMC_BUS_WIDTH_1
-		};
-		unsigned idx, bus_width = 0;
-
-		if (host->caps & MMC_CAP_8_BIT_DATA)
-			idx = 0;
-		else
-			idx = 1;
-		for (; idx < ARRAY_SIZE(bus_widths); idx++) {
-			bus_width = bus_widths[idx];
-			if (bus_width == MMC_BUS_WIDTH_1)
-				ddr = 0; /* no DDR for 1-bit width */
-			err = mmc_select_powerclass(card, ext_csd_bits[idx][0],
-						    ext_csd);
-			if (err)
-				pr_warning("%s: power class selection to "
-					   "bus width %d failed\n",
-					   mmc_hostname(card->host),
-					   1 << bus_width);
-
-			err = mmc_switch(card, EXT_CSD_CMD_SET_NORMAL,
-					 EXT_CSD_BUS_WIDTH,
-					 ext_csd_bits[idx][0],
-					 card->ext_csd.generic_cmd6_time);
-			if (!err) {
-				mmc_set_bus_width(card->host, bus_width);
-
-				/*
-				 * If controller can't handle bus width test,
-				 * compare ext_csd previously read in 1 bit mode
-				 * against ext_csd at new bus width
-				 */
-				if (!(host->caps & MMC_CAP_BUS_WIDTH_TEST))
-					err = mmc_compare_ext_csds(card,
-						bus_width);
-				else
-					err = mmc_bus_test(card, bus_width);
-				if (!err)
-					break;
-			}
-		}
-
-		if (!err && ddr) {
-			err = mmc_select_powerclass(card, ext_csd_bits[idx][1],
-						    ext_csd);
-			if (err)
-				pr_warning("%s: power class selection to "
-					   "bus width %d ddr %d failed\n",
-					   mmc_hostname(card->host),
-					   1 << bus_width, ddr);
-
-			err = mmc_switch(card, EXT_CSD_CMD_SET_NORMAL,
-					 EXT_CSD_BUS_WIDTH,
-					 ext_csd_bits[idx][1],
-					 card->ext_csd.generic_cmd6_time);
-		}
-		if (err) {
-			pr_warning("%s: switch to bus width %d ddr %d "
-				"failed\n", mmc_hostname(card->host),
-				1 << bus_width, ddr);
-			goto free_card;
-		} else if (ddr) {
-			/*
-			 * eMMC cards can support 3.3V to 1.2V i/o (vccq)
-			 * signaling.
-			 *
-			 * EXT_CSD_CARD_TYPE_DDR_1_8V means 3.3V or 1.8V vccq.
-			 *
-			 * 1.8V vccq at 3.3V core voltage (vcc) is not required
-			 * in the JEDEC spec for DDR.
-			 *
-			 * Do not force change in vccq since we are obviously
-			 * working and no change to vccq is needed.
-			 *
-			 * WARNING: eMMC rules are NOT the same as SD DDR
-			 */
-			if (ddr == MMC_1_2V_DDR_MODE) {
-				err = mmc_set_signal_voltage(host,
-					MMC_SIGNAL_VOLTAGE_120, 0);
-				if (err)
-					goto err;
-			}
-			mmc_card_set_ddr_mode(card);
-			mmc_set_timing(card->host, MMC_TIMING_UHS_DDR50);
-			mmc_set_bus_width(card->host, bus_width);
-		}
-	}
+	err = mmc_select_bus_speed(card, ext_csd);
+	if (err)
+		goto free_card;
 
 	/*
 	 * Enable HPI feature (if supported)
@@ -1356,9 +1527,10 @@
 	/*
 	 * If cache size is higher than 0, this indicates
 	 * the existence of cache and it can be turned on.
+	 * If HPI is not supported then cache shouldn't be enabled.
 	 */
 	if ((host->caps2 & MMC_CAP2_CACHE_CTRL) &&
-			card->ext_csd.cache_size > 0) {
+	    (card->ext_csd.cache_size > 0) && card->ext_csd.hpi_en) {
 		err = mmc_switch(card, EXT_CSD_CMD_SET_NORMAL,
 				EXT_CSD_CACHE_CTRL, 1,
 				card->ext_csd.generic_cmd6_time);
diff --git a/drivers/mmc/core/mmc_ops.c b/drivers/mmc/core/mmc_ops.c
index 164c418..32e126b 100644
--- a/drivers/mmc/core/mmc_ops.c
+++ b/drivers/mmc/core/mmc_ops.c
@@ -598,7 +598,7 @@
 	unsigned int opcode;
 	int err;
 
-	if (!card->ext_csd.hpi) {
+	if (!card->ext_csd.hpi_en) {
 		pr_warning("%s: Card didn't support HPI command\n",
 			   mmc_hostname(card->host));
 		return -EINVAL;
diff --git a/drivers/mmc/core/quirks.c b/drivers/mmc/core/quirks.c
index 59f0340..4407d91 100644
--- a/drivers/mmc/core/quirks.c
+++ b/drivers/mmc/core/quirks.c
@@ -107,6 +107,8 @@
 		    (f->name == CID_NAME_ANY ||
 		     !strncmp(f->name, card->cid.prod_name,
 			      sizeof(card->cid.prod_name))) &&
+		    (f->ext_csd_rev == EXT_CSD_REV_ANY ||
+		     f->ext_csd_rev == card->ext_csd.rev) &&
 		    (f->cis_vendor == card->cis.vendor ||
 		     f->cis_vendor == (u16) SDIO_ANY_ID) &&
 		    (f->cis_device == card->cis.device ||
diff --git a/drivers/mmc/core/sd.c b/drivers/mmc/core/sd.c
index a4498d2..3648d88 100644
--- a/drivers/mmc/core/sd.c
+++ b/drivers/mmc/core/sd.c
@@ -26,6 +26,12 @@
 #include "sd.h"
 #include "sd_ops.h"
 
+#define UHS_SDR104_MIN_DTR	(100 * 1000 * 1000)
+#define UHS_DDR50_MIN_DTR	(50 * 1000 * 1000)
+#define UHS_SDR50_MIN_DTR	(50 * 1000 * 1000)
+#define UHS_SDR25_MIN_DTR	(25 * 1000 * 1000)
+#define UHS_SDR12_MIN_DTR	(12.5 * 1000 * 1000)
+
 static const unsigned int tran_exp[] = {
 	10000,		100000,		1000000,	10000000,
 	0,		0,		0,		0
@@ -486,18 +492,22 @@
 	}
 
 	if ((card->host->caps & MMC_CAP_UHS_SDR104) &&
-	    (card->sw_caps.sd3_bus_mode & SD_MODE_UHS_SDR104)) {
+	    (card->sw_caps.sd3_bus_mode & SD_MODE_UHS_SDR104) &&
+	    (card->host->f_max > UHS_SDR104_MIN_DTR)) {
 			card->sd_bus_speed = UHS_SDR104_BUS_SPEED;
 	} else if ((card->host->caps & MMC_CAP_UHS_DDR50) &&
-		   (card->sw_caps.sd3_bus_mode & SD_MODE_UHS_DDR50)) {
+		   (card->sw_caps.sd3_bus_mode & SD_MODE_UHS_DDR50) &&
+		    (card->host->f_max > UHS_DDR50_MIN_DTR)) {
 			card->sd_bus_speed = UHS_DDR50_BUS_SPEED;
 	} else if ((card->host->caps & (MMC_CAP_UHS_SDR104 |
 		    MMC_CAP_UHS_SDR50)) && (card->sw_caps.sd3_bus_mode &
-		    SD_MODE_UHS_SDR50)) {
+		    SD_MODE_UHS_SDR50) &&
+		    (card->host->f_max > UHS_SDR50_MIN_DTR)) {
 			card->sd_bus_speed = UHS_SDR50_BUS_SPEED;
 	} else if ((card->host->caps & (MMC_CAP_UHS_SDR104 |
 		    MMC_CAP_UHS_SDR50 | MMC_CAP_UHS_SDR25)) &&
-		   (card->sw_caps.sd3_bus_mode & SD_MODE_UHS_SDR25)) {
+		   (card->sw_caps.sd3_bus_mode & SD_MODE_UHS_SDR25) &&
+		 (card->host->f_max > UHS_SDR25_MIN_DTR)) {
 			card->sd_bus_speed = UHS_SDR25_BUS_SPEED;
 	} else if ((card->host->caps & (MMC_CAP_UHS_SDR104 |
 		    MMC_CAP_UHS_SDR50 | MMC_CAP_UHS_SDR25 |
diff --git a/drivers/mmc/host/sdhci-msm.c b/drivers/mmc/host/sdhci-msm.c
index 3495f4d..a7ce6ae 100644
--- a/drivers/mmc/host/sdhci-msm.c
+++ b/drivers/mmc/host/sdhci-msm.c
@@ -45,6 +45,7 @@
 #define SDHCI_VER_100		0x2B
 #define CORE_HC_MODE		0x78
 #define HC_MODE_EN		0x1
+#define FF_CLK_SW_RST_DIS	(1 << 13)
 
 #define CORE_POWER		0x0
 #define CORE_SW_RST		(1 << 7)
@@ -67,20 +68,57 @@
 #define INT_MASK		0xF
 #define MAX_PHASES		16
 
-#define CORE_DLL_LOCK		(1 << 7)
+#define CORE_DLL_CONFIG		0x100
+#define CORE_CMD_DAT_TRACK_SEL	(1 << 0)
 #define CORE_DLL_EN		(1 << 16)
 #define CORE_CDR_EN		(1 << 17)
 #define CORE_CK_OUT_EN		(1 << 18)
 #define CORE_CDR_EXT_EN		(1 << 19)
 #define CORE_DLL_PDN		(1 << 29)
 #define CORE_DLL_RST		(1 << 30)
-#define CORE_DLL_CONFIG		0x100
-#define CORE_DLL_TEST_CTL	0x104
+
 #define CORE_DLL_STATUS		0x108
+#define CORE_DLL_LOCK		(1 << 7)
 
 #define CORE_VENDOR_SPEC	0x10C
 #define CORE_CLK_PWRSAVE	(1 << 1)
+#define CORE_HC_MCLK_SEL_DFLT	(2 << 8)
+#define CORE_HC_MCLK_SEL_HS400	(3 << 8)
+#define CORE_HC_MCLK_SEL_MASK	(3 << 8)
 #define CORE_IO_PAD_PWR_SWITCH	(1 << 16)
+#define CORE_HC_SELECT_IN_EN	(1 << 18)
+#define CORE_HC_SELECT_IN_HS400	(6 << 19)
+#define CORE_HC_SELECT_IN_MASK	(7 << 19)
+
+#define CORE_VENDOR_SPEC_ADMA_ERR_ADDR0	0x114
+#define CORE_VENDOR_SPEC_ADMA_ERR_ADDR1	0x118
+
+#define CORE_CSR_CDC_CTLR_CFG0		0x130
+#define CORE_SW_TRIG_FULL_CALIB		(1 << 16)
+#define CORE_HW_AUTOCAL_ENA		(1 << 17)
+
+#define CORE_CSR_CDC_CTLR_CFG1		0x134
+#define CORE_CSR_CDC_CAL_TIMER_CFG0	0x138
+#define CORE_TIMER_ENA			(1 << 16)
+
+#define CORE_CSR_CDC_CAL_TIMER_CFG1	0x13C
+#define CORE_CSR_CDC_REFCOUNT_CFG	0x140
+#define CORE_CSR_CDC_COARSE_CAL_CFG	0x144
+#define CORE_CDC_OFFSET_CFG		0x14C
+#define CORE_CSR_CDC_DELAY_CFG		0x150
+#define CORE_CDC_SLAVE_DDA_CFG		0x160
+#define CORE_CSR_CDC_STATUS0		0x164
+#define CORE_CALIBRATION_DONE		(1 << 0)
+
+#define CORE_CDC_ERROR_CODE_MASK	0x7000000
+
+#define CORE_CSR_CDC_GEN_CFG		0x178
+#define CORE_CDC_SWITCH_BYPASS_OFF	(1 << 0)
+#define CORE_CDC_SWITCH_RC_EN		(1 << 1)
+
+#define CORE_DDR_200_CFG		0x184
+#define CORE_CDC_T4_DLY_SEL		(1 << 0)
+#define CORE_START_CDC_TRAFFIC		(1 << 6)
 
 #define CORE_MCI_DATA_CTRL	0x2C
 #define CORE_MCI_DPSM_ENABLE	(1 << 0)
@@ -114,6 +152,10 @@
 #define SDHCI_MSM_MAX_SEGMENTS  (1 << 13)
 #define SDHCI_MSM_MMC_CLK_GATE_DELAY	200 /* msecs */
 
+#define CORE_FREQ_100MHZ	(100 * 1000 * 1000)
+
+#define INVALID_TUNING_PHASE	-1
+
 static const u32 tuning_block_64[] = {
 	0x00FF0FFF, 0xCCC3CCFF, 0xFFCC3CC3, 0xEFFEFFFE,
 	0xDDFFDFFF, 0xFBFFFBFF, 0xFF7FFFBF, 0xEFBDF777,
@@ -155,6 +197,7 @@
 	bool is_always_on;
 	/* is low power mode setting required for this regulator? */
 	bool lpm_sup;
+	bool set_voltage_sup;
 };
 
 /*
@@ -259,6 +302,8 @@
 	struct clk	 *clk;     /* main SD/MMC bus clock */
 	struct clk	 *pclk;    /* SDHC peripheral bus clock */
 	struct clk	 *bus_clk; /* SDHC bus voter clock */
+	struct clk	 *ff_clk; /* CDC calibration fixed feedback clock */
+	struct clk	 *sleep_clk; /* CDC calibration sleep clock */
 	atomic_t clks_on; /* Set if clocks are enabled */
 	struct sdhci_msm_pltfm_data *pdata;
 	struct mmc_host  *mmc;
@@ -269,6 +314,9 @@
 	struct sdhci_msm_bus_vote msm_bus_vote;
 	struct device_attribute	polling;
 	u32 clk_rate; /* Keeps track of current clock rate that is set */
+	bool tuning_done;
+	bool calibration_done;
+	u8 saved_tuning_phase;
 };
 
 enum vdd_io_level {
@@ -372,8 +420,8 @@
  * Find out the greatest range of consecuitive selected
  * DLL clock output phases that can be used as sampling
  * setting for SD3.0 UHS-I card read operation (in SDR104
- * timing mode) or for eMMC4.5 card read operation (in HS200
- * timing mode).
+ * timing mode) or for eMMC4.5 card read operation (in
+ * HS400/HS200 timing mode).
  * Select the 3/4 of the range and configure the DLL with the
  * selected DLL clock output phase.
  */
@@ -594,6 +642,137 @@
 	return rc;
 }
 
+static int sdhci_msm_cdclp533_calibration(struct sdhci_host *host)
+{
+	u32 wait_cnt;
+	int ret = 0;
+	int cdc_err = 0;
+	struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
+	struct sdhci_msm_host *msm_host = pltfm_host->priv;
+
+	pr_debug("%s: Enter %s\n", mmc_hostname(host->mmc), __func__);
+
+	/*
+	 * Retuning in HS400 (DDR mode) will fail, just reset the
+	 * tuning block and restore the saved tuning phase.
+	 */
+	ret = msm_init_cm_dll(host);
+	if (ret)
+		goto out;
+
+	/* Set the selected phase in delay line hw block */
+	ret = msm_config_cm_dll_phase(host, msm_host->saved_tuning_phase);
+	if (ret)
+		goto out;
+
+	/* Write 1 to CMD_DAT_TRACK_SEL field in DLL_CONFIG */
+	writel_relaxed((readl_relaxed(host->ioaddr + CORE_DLL_CONFIG)
+			| CORE_CMD_DAT_TRACK_SEL),
+			host->ioaddr + CORE_DLL_CONFIG);
+
+	/* Write 0 to CDC_T4_DLY_SEL field in VENDOR_SPEC_DDR200_CFG */
+	writel_relaxed((readl_relaxed(host->ioaddr + CORE_DDR_200_CFG)
+			& ~CORE_CDC_T4_DLY_SEL),
+			host->ioaddr + CORE_DDR_200_CFG);
+
+	/* Write 0 to CDC_SWITCH_BYPASS_OFF field in CORE_CSR_CDC_GEN_CFG */
+	writel_relaxed((readl_relaxed(host->ioaddr + CORE_CSR_CDC_GEN_CFG)
+			& ~CORE_CDC_SWITCH_BYPASS_OFF),
+			host->ioaddr + CORE_CSR_CDC_GEN_CFG);
+
+	/* Write 1 to CDC_SWITCH_RC_EN field in CORE_CSR_CDC_GEN_CFG */
+	writel_relaxed((readl_relaxed(host->ioaddr + CORE_CSR_CDC_GEN_CFG)
+			| CORE_CDC_SWITCH_RC_EN),
+			host->ioaddr + CORE_CSR_CDC_GEN_CFG);
+
+	/* Write 0 to START_CDC_TRAFFIC field in CORE_DDR200_CFG */
+	writel_relaxed((readl_relaxed(host->ioaddr + CORE_DDR_200_CFG)
+			& ~CORE_START_CDC_TRAFFIC),
+			host->ioaddr + CORE_DDR_200_CFG);
+
+	/*
+	 * Perform CDC Register Initialization Sequence
+	 *
+	 * CORE_CSR_CDC_CTLR_CFG0	0x11800EC
+	 * CORE_CSR_CDC_CTLR_CFG1	0x3011111
+	 * CORE_CSR_CDC_CAL_TIMER_CFG0	0x1201000
+	 * CORE_CSR_CDC_CAL_TIMER_CFG1	0x4
+	 * CORE_CSR_CDC_REFCOUNT_CFG	0xCB732020
+	 * CORE_CSR_CDC_COARSE_CAL_CFG	0xB19
+	 * CORE_CSR_CDC_DELAY_CFG	0x3AC
+	 * CORE_CDC_OFFSET_CFG		0x0
+	 * CORE_CDC_SLAVE_DDA_CFG	0x16334
+	 */
+
+	writel_relaxed(0x11800EC, host->ioaddr + CORE_CSR_CDC_CTLR_CFG0);
+	writel_relaxed(0x3011111, host->ioaddr + CORE_CSR_CDC_CTLR_CFG1);
+	writel_relaxed(0x1201000, host->ioaddr + CORE_CSR_CDC_CAL_TIMER_CFG0);
+	writel_relaxed(0x4, host->ioaddr + CORE_CSR_CDC_CAL_TIMER_CFG1);
+	writel_relaxed(0xCB732020, host->ioaddr + CORE_CSR_CDC_REFCOUNT_CFG);
+	writel_relaxed(0xB19, host->ioaddr + CORE_CSR_CDC_COARSE_CAL_CFG);
+	writel_relaxed(0x3AC, host->ioaddr + CORE_CSR_CDC_DELAY_CFG);
+	writel_relaxed(0x0, host->ioaddr + CORE_CDC_OFFSET_CFG);
+	writel_relaxed(0x16334, host->ioaddr + CORE_CDC_SLAVE_DDA_CFG);
+
+	/* CDC HW Calibration */
+
+	/* Write 1 to SW_TRIG_FULL_CALIB field in CORE_CSR_CDC_CTLR_CFG0 */
+	writel_relaxed((readl_relaxed(host->ioaddr + CORE_CSR_CDC_CTLR_CFG0)
+			| CORE_SW_TRIG_FULL_CALIB),
+			host->ioaddr + CORE_CSR_CDC_CTLR_CFG0);
+
+	/* Write 0 to SW_TRIG_FULL_CALIB field in CORE_CSR_CDC_CTLR_CFG0 */
+	writel_relaxed((readl_relaxed(host->ioaddr + CORE_CSR_CDC_CTLR_CFG0)
+			& ~CORE_SW_TRIG_FULL_CALIB),
+			host->ioaddr + CORE_CSR_CDC_CTLR_CFG0);
+
+	/* Write 1 to HW_AUTOCAL_ENA field in CORE_CSR_CDC_CTLR_CFG0 */
+	writel_relaxed((readl_relaxed(host->ioaddr + CORE_CSR_CDC_CTLR_CFG0)
+			| CORE_HW_AUTOCAL_ENA),
+			host->ioaddr + CORE_CSR_CDC_CTLR_CFG0);
+
+	/* Write 1 to TIMER_ENA field in CORE_CSR_CDC_CAL_TIMER_CFG0 */
+	writel_relaxed((readl_relaxed(host->ioaddr +
+			CORE_CSR_CDC_CAL_TIMER_CFG0) | CORE_TIMER_ENA),
+			host->ioaddr + CORE_CSR_CDC_CAL_TIMER_CFG0);
+
+	mb();
+
+	/* Poll on CALIBRATION_DONE field in CORE_CSR_CDC_STATUS0 to be 1 */
+	wait_cnt = 50;
+	while (!(readl_relaxed(host->ioaddr + CORE_CSR_CDC_STATUS0)
+			& CORE_CALIBRATION_DONE)) {
+		/* max. wait for 50us sec for CALIBRATION_DONE bit to be set */
+		if (--wait_cnt == 0) {
+			pr_err("%s: %s: CDC Calibration was not completed\n",
+				mmc_hostname(host->mmc), __func__);
+			ret = -ETIMEDOUT;
+			goto out;
+		}
+		/* wait for 1us before polling again */
+		udelay(1);
+	}
+
+	/* Verify CDC_ERROR_CODE field in CORE_CSR_CDC_STATUS0 is 0 */
+	cdc_err = readl_relaxed(host->ioaddr + CORE_CSR_CDC_STATUS0)
+			& CORE_CDC_ERROR_CODE_MASK;
+	if (cdc_err) {
+		pr_err("%s: %s: CDC Error Code %d\n",
+			mmc_hostname(host->mmc), __func__, cdc_err);
+		ret = -EINVAL;
+		goto out;
+	}
+
+	/* Write 1 to START_CDC_TRAFFIC field in CORE_DDR200_CFG */
+	writel_relaxed((readl_relaxed(host->ioaddr + CORE_DDR_200_CFG)
+			| CORE_START_CDC_TRAFFIC),
+			host->ioaddr + CORE_DDR_200_CFG);
+out:
+	pr_debug("%s: Exit %s, ret:%d\n", mmc_hostname(host->mmc),
+			__func__, ret);
+	return ret;
+}
+
 int sdhci_msm_execute_tuning(struct sdhci_host *host, u32 opcode)
 {
 	unsigned long flags;
@@ -604,20 +783,36 @@
 	int rc;
 	struct mmc_host *mmc = host->mmc;
 	struct mmc_ios	ios = host->mmc->ios;
+	struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
+	struct sdhci_msm_host *msm_host = pltfm_host->priv;
 
 	/*
-	 * Tuning is required for SDR104 and HS200 cards and if clock frequency
-	 * is greater than 100MHz in these modes.
+	 * Tuning is required for SDR104, HS200 and HS400 cards and
+	 * if clock frequency is greater than 100MHz in these modes.
 	 */
-	if (host->clock <= (100 * 1000 * 1000) ||
-		!(ios.timing == MMC_TIMING_MMC_HS200 ||
-		ios.timing == MMC_TIMING_UHS_SDR104))
+	if (host->clock <= CORE_FREQ_100MHZ ||
+		!((ios.timing == MMC_TIMING_MMC_HS400) ||
+		(ios.timing == MMC_TIMING_MMC_HS200) ||
+		(ios.timing == MMC_TIMING_UHS_SDR104)))
 		return 0;
 
 	pr_debug("%s: Enter %s\n", mmc_hostname(mmc), __func__);
+
+	/* CDCLP533 HW calibration is only required for HS400 mode*/
+	if (msm_host->tuning_done && !msm_host->calibration_done &&
+		(mmc->ios.timing == MMC_TIMING_MMC_HS400)) {
+		rc = sdhci_msm_cdclp533_calibration(host);
+		spin_lock_irqsave(&host->lock, flags);
+		if (!rc)
+			msm_host->calibration_done = true;
+		spin_unlock_irqrestore(&host->lock, flags);
+		goto out;
+	}
+
 	spin_lock_irqsave(&host->lock, flags);
 
-	if ((opcode == MMC_SEND_TUNING_BLOCK_HS200) &&
+	if (((opcode == MMC_SEND_TUNING_BLOCK_HS400) ||
+		(opcode == MMC_SEND_TUNING_BLOCK_HS200)) &&
 		(mmc->ios.bus_width == MMC_BUS_WIDTH_8)) {
 		tuning_block_pattern = tuning_block_128;
 		size = sizeof(tuning_block_128);
@@ -689,6 +884,7 @@
 		rc = msm_config_cm_dll_phase(host, phase);
 		if (rc)
 			goto kfree;
+		msm_host->saved_tuning_phase = phase;
 		pr_debug("%s: %s: finally setting the tuning phase to %d\n",
 				mmc_hostname(mmc), __func__, phase);
 	} else {
@@ -703,7 +899,11 @@
 kfree:
 	kfree(data_buf);
 out:
-	pr_debug("%s: Exit %s\n", mmc_hostname(mmc), __func__);
+	spin_lock_irqsave(&host->lock, flags);
+	if (!rc)
+		msm_host->tuning_done = true;
+	spin_unlock_irqrestore(&host->lock, flags);
+	pr_debug("%s: Exit %s, err(%d)\n", mmc_hostname(mmc), __func__, rc);
 	return rc;
 }
 
@@ -802,7 +1002,7 @@
 		goto out;
 	}
 	sz = *len = *len / sizeof(*arr);
-	if (sz <= 0 || (size > 0 && (sz != size))) {
+	if (sz <= 0 || (size > 0 && (sz > size))) {
 		dev_err(dev, "%s invalid size\n", prop_name);
 		ret = -EINVAL;
 		goto out;
@@ -839,8 +1039,7 @@
 
 	snprintf(prop_name, MAX_PROP_SIZE, "%s-supply", vreg_name);
 	if (!of_parse_phandle(np, prop_name, 0)) {
-		dev_err(dev, "No vreg data found for %s\n", vreg_name);
-		ret = -EINVAL;
+		dev_info(dev, "No vreg data found for %s\n", vreg_name);
 		return ret;
 	}
 
@@ -929,9 +1128,9 @@
 		ret = -ENOMEM;
 		goto out;
 	}
-	pull_data->size = 3; /* array size for clk, cmd, data */
+	pull_data->size = 4; /* array size for clk, cmd, data and rclk */
 
-	/* Allocate on, off configs for clk, cmd, data */
+	/* Allocate on, off configs for clk, cmd, data and rclk */
 	pull = devm_kzalloc(dev, 2 * pull_data->size *\
 			sizeof(struct sdhci_msm_pad_pull), GFP_KERNEL);
 	if (!pull) {
@@ -1214,7 +1413,11 @@
 		if (!name)
 			continue;
 
-		if (!strncmp(name, "HS200_1p8v", sizeof("HS200_1p8v")))
+		if (!strncmp(name, "HS400_1p8v", sizeof("HS400_1p8v")))
+			pdata->caps2 |= MMC_CAP2_HS400_1_8V;
+		else if (!strncmp(name, "HS400_1p2v", sizeof("HS400_1p2v")))
+			pdata->caps2 |= MMC_CAP2_HS400_1_2V;
+		else if (!strncmp(name, "HS200_1p8v", sizeof("HS200_1p8v")))
 			pdata->caps2 |= MMC_CAP2_HS200_1_8V_SDR;
 		else if (!strncmp(name, "HS200_1p2v", sizeof("HS200_1p2v")))
 			pdata->caps2 |= MMC_CAP2_HS200_1_2V_SDR;
@@ -1478,11 +1681,14 @@
 		goto out;
 	}
 
-	/* sanity check */
-	if (!vreg->high_vol_level || !vreg->hpm_uA) {
-		pr_err("%s: %s invalid constraints specified\n",
-		       __func__, vreg->name);
-		ret = -EINVAL;
+	if (regulator_count_voltages(vreg->reg) > 0) {
+		vreg->set_voltage_sup = true;
+		/* sanity check */
+		if (!vreg->high_vol_level || !vreg->hpm_uA) {
+			pr_err("%s: %s invalid constraints specified\n",
+			       __func__, vreg->name);
+			ret = -EINVAL;
+		}
 	}
 
 out:
@@ -1504,9 +1710,10 @@
 	 * regulators that do not support regulator_set_voltage also
 	 * do not support regulator_set_optimum_mode
 	 */
-	ret = regulator_set_optimum_mode(vreg->reg, uA_load);
-	if (ret < 0)
-		pr_err("%s: regulator_set_optimum_mode(reg=%s,uA_load=%d) failed. ret=%d\n",
+	if (vreg->set_voltage_sup) {
+		ret = regulator_set_optimum_mode(vreg->reg, uA_load);
+		if (ret < 0)
+			pr_err("%s: regulator_set_optimum_mode(reg=%s,uA_load=%d) failed. ret=%d\n",
 			       __func__, vreg->name, uA_load, ret);
 		else
 			/*
@@ -1514,6 +1721,7 @@
 			 * value even for success case.
 			 */
 			ret = 0;
+	}
 	return ret;
 }
 
@@ -1521,12 +1729,13 @@
 					int min_uV, int max_uV)
 {
 	int ret = 0;
-
-	ret = regulator_set_voltage(vreg->reg, min_uV, max_uV);
-	if (ret) {
-		pr_err("%s: regulator_set_voltage(%s)failed. min_uV=%d,max_uV=%d,ret=%d\n",
+	if (vreg->set_voltage_sup) {
+		ret = regulator_set_voltage(vreg->reg, min_uV, max_uV);
+		if (ret) {
+			pr_err("%s: regulator_set_voltage(%s)failed. min_uV=%d,max_uV=%d,ret=%d\n",
 			       __func__, vreg->name, min_uV, max_uV, ret);
 		}
+	}
 
 	return ret;
 }
@@ -2038,6 +2247,22 @@
 				mmc_hostname(host->mmc), __func__, rc);
 			goto disable_pclk;
 		}
+		if (!IS_ERR(msm_host->ff_clk)) {
+			rc = clk_prepare_enable(msm_host->ff_clk);
+			if (rc) {
+				pr_err("%s: %s: failed to enable the ff_clk with error %d\n",
+					mmc_hostname(host->mmc), __func__, rc);
+				goto disable_clk;
+			}
+		}
+		if (!IS_ERR(msm_host->sleep_clk)) {
+			rc = clk_prepare_enable(msm_host->sleep_clk);
+			if (rc) {
+				pr_err("%s: %s: failed to enable the sleep_clk with error %d\n",
+					mmc_hostname(host->mmc), __func__, rc);
+				goto disable_ff_clk;
+			}
+		}
 		mb();
 
 	} else if (!enable && atomic_read(&msm_host->clks_on)) {
@@ -2045,6 +2270,10 @@
 				mmc_hostname(host->mmc));
 		sdhci_writew(host, 0, SDHCI_CLOCK_CONTROL);
 		mb();
+		if (!IS_ERR_OR_NULL(msm_host->sleep_clk))
+			clk_disable_unprepare(msm_host->sleep_clk);
+		if (!IS_ERR_OR_NULL(msm_host->ff_clk))
+			clk_disable_unprepare(msm_host->ff_clk);
 		clk_disable_unprepare(msm_host->clk);
 		if (!IS_ERR(msm_host->pclk))
 			clk_disable_unprepare(msm_host->pclk);
@@ -2055,6 +2284,12 @@
 	}
 	atomic_set(&msm_host->clks_on, enable);
 	goto out;
+disable_ff_clk:
+	if (!IS_ERR_OR_NULL(msm_host->ff_clk))
+		clk_disable_unprepare(msm_host->ff_clk);
+disable_clk:
+	if (!IS_ERR_OR_NULL(msm_host->clk))
+		clk_disable_unprepare(msm_host->clk);
 disable_pclk:
 	if (!IS_ERR_OR_NULL(msm_host->pclk))
 		clk_disable_unprepare(msm_host->pclk);
@@ -2087,17 +2322,79 @@
 		return;
 
 	sup_clock = sdhci_msm_get_sup_clk_rate(host, clock);
-	if (curr_ios.timing == MMC_TIMING_UHS_DDR50) {
+	if ((curr_ios.timing == MMC_TIMING_UHS_DDR50) ||
+		(curr_ios.timing == MMC_TIMING_MMC_HS400)) {
 		/*
 		 * The SDHC requires internal clock frequency to be double the
 		 * actual clock that will be set for DDR mode. The controller
-		 * uses the faster clock(100MHz) for some of its parts and send
-		 * the actual required clock (50MHz) to the card.
+		 * uses the faster clock(100/400MHz) for some of its parts and
+		 * send the actual required clock (50/200MHz) to the card.
 		 */
 		ddr_clock = clock * 2;
 		sup_clock = sdhci_msm_get_sup_clk_rate(host,
 				ddr_clock);
 	}
+
+	/*
+	 * In general all timing modes are controlled via UHS mode select in
+	 * Host Control2 register. eMMC specific HS200/HS400 doesn't have
+	 * their respective modes defined here, hence we use these values.
+	 *
+	 * HS200 - SDR104 (Since they both are equivalent in functionality)
+	 * HS400 - This involves multiple configurations
+	 *		Initially SDR104 - when tuning is required as HS200
+	 *		Then when switching to DDR @ 400MHz (HS400) we use
+	 *		the vendor specific HC_SELECT_IN to control the mode.
+	 *
+	 * In addition to controlling the modes we also need to select the
+	 * correct input clock for DLL depending on the mode.
+	 *
+	 * HS400 - divided clock (free running MCLK/2)
+	 * All other modes - default (free running MCLK)
+	 */
+	if (curr_ios.timing == MMC_TIMING_MMC_HS400) {
+		/* Select the divided clock (free running MCLK/2) */
+		writel_relaxed(((readl_relaxed(host->ioaddr + CORE_VENDOR_SPEC)
+					& ~CORE_HC_MCLK_SEL_MASK)
+					| CORE_HC_MCLK_SEL_HS400),
+					host->ioaddr + CORE_VENDOR_SPEC);
+		/*
+		 * Select HS400 mode using the HC_SELECT_IN from VENDOR SPEC
+		 * register
+		 */
+		if (msm_host->tuning_done && !msm_host->calibration_done) {
+			/*
+			 * Write 0x6 to HC_SELECT_IN and 1 to HC_SELECT_IN_EN
+			 * field in VENDOR_SPEC_FUNC
+			 */
+			writel_relaxed((readl_relaxed(host->ioaddr + \
+					CORE_VENDOR_SPEC)
+					| CORE_HC_SELECT_IN_HS400
+					| CORE_HC_SELECT_IN_EN),
+					host->ioaddr + CORE_VENDOR_SPEC);
+		}
+	} else {
+		/* Select the default clock (free running MCLK) */
+		writel_relaxed(((readl_relaxed(host->ioaddr + CORE_VENDOR_SPEC)
+					& ~CORE_HC_MCLK_SEL_MASK)
+					| CORE_HC_MCLK_SEL_DFLT),
+					host->ioaddr + CORE_VENDOR_SPEC);
+
+		/*
+		 * Disable HC_SELECT_IN to be able to use the UHS mode select
+		 * configuration from Host Control2 register for all other
+		 * modes.
+		 *
+		 * Write 0 to HC_SELECT_IN and HC_SELECT_IN_EN field
+		 * in VENDOR_SPEC_FUNC
+		 */
+		writel_relaxed((readl_relaxed(host->ioaddr + CORE_VENDOR_SPEC)
+				& ~CORE_HC_SELECT_IN_EN
+				& ~CORE_HC_SELECT_IN_MASK),
+				host->ioaddr + CORE_VENDOR_SPEC);
+	}
+	mb();
+
 	if (sup_clock != msm_host->clk_rate) {
 		pr_debug("%s: %s: setting clk rate to %u\n",
 				mmc_hostname(host->mmc), __func__, sup_clock);
@@ -2121,12 +2418,16 @@
 static int sdhci_msm_set_uhs_signaling(struct sdhci_host *host,
 					unsigned int uhs)
 {
+	struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
+	struct sdhci_msm_host *msm_host = pltfm_host->priv;
 	u16 ctrl_2;
 
 	ctrl_2 = sdhci_readw(host, SDHCI_HOST_CONTROL2);
 	/* Select Bus Speed Mode for host */
 	ctrl_2 &= ~SDHCI_CTRL_UHS_MASK;
-	if (uhs == MMC_TIMING_MMC_HS200)
+	if (uhs == MMC_TIMING_MMC_HS400)
+		ctrl_2 |= SDHCI_CTRL_UHS_SDR104;
+	else if (uhs == MMC_TIMING_MMC_HS200)
 		ctrl_2 |= SDHCI_CTRL_UHS_SDR104;
 	else if (uhs == MMC_TIMING_UHS_SDR12)
 		ctrl_2 |= SDHCI_CTRL_UHS_SDR12;
@@ -2144,11 +2445,36 @@
 	 * provide feedback clock, the mode selection can be any value less
 	 * than 3'b011 in bits [2:0] of HOST CONTROL2 register.
 	 */
-	if (host->clock <= (100 * 1000 * 1000) &&
-			(uhs == MMC_TIMING_MMC_HS200 ||
-			uhs == MMC_TIMING_UHS_SDR104))
-		ctrl_2 &= ~SDHCI_CTRL_UHS_MASK;
+	if (host->clock <= CORE_FREQ_100MHZ) {
+		if ((uhs == MMC_TIMING_MMC_HS400) ||
+		    (uhs == MMC_TIMING_MMC_HS200) ||
+		    (uhs == MMC_TIMING_UHS_SDR104))
+			ctrl_2 &= ~SDHCI_CTRL_UHS_MASK;
 
+		/*
+		 * Make sure DLL is disabled when not required
+		 *
+		 * Write 1 to DLL_RST bit of DLL_CONFIG register
+		 */
+		writel_relaxed((readl_relaxed(host->ioaddr + CORE_DLL_CONFIG)
+				| CORE_DLL_RST),
+				host->ioaddr + CORE_DLL_CONFIG);
+
+		/* Write 1 to DLL_PDN bit of DLL_CONFIG register */
+		writel_relaxed((readl_relaxed(host->ioaddr + CORE_DLL_CONFIG)
+				| CORE_DLL_PDN),
+				host->ioaddr + CORE_DLL_CONFIG);
+		mb();
+
+		/*
+		 * The DLL needs to be restored and CDCLP533 recalibrated
+		 * when the clock frequency is set back to 400MHz.
+		 */
+		msm_host->calibration_done = false;
+	}
+
+	pr_debug("%s: %s-clock:%u uhs mode:%u ctrl_2:0x%x\n",
+		mmc_hostname(host->mmc), __func__, host->clock, uhs, ctrl_2);
 	sdhci_writew(host, ctrl_2, SDHCI_HOST_CONTROL2);
 
 	return 0;
@@ -2315,9 +2641,27 @@
 	msm_host->clk_rate = sdhci_msm_get_min_clock(host);
 	atomic_set(&msm_host->clks_on, 1);
 
+	/* Setup CDC calibration fixed feedback clock */
+	msm_host->ff_clk = devm_clk_get(&pdev->dev, "cal_clk");
+	if (!IS_ERR(msm_host->ff_clk)) {
+		ret = clk_prepare_enable(msm_host->ff_clk);
+		if (ret)
+			goto clk_disable;
+	}
+
+	/* Setup CDC calibration sleep clock */
+	msm_host->sleep_clk = devm_clk_get(&pdev->dev, "sleep_clk");
+	if (!IS_ERR(msm_host->sleep_clk)) {
+		ret = clk_prepare_enable(msm_host->sleep_clk);
+		if (ret)
+			goto ff_clk_disable;
+	}
+
+	msm_host->saved_tuning_phase = INVALID_TUNING_PHASE;
+
 	ret = sdhci_msm_bus_register(msm_host, pdev);
 	if (ret)
-		goto clk_disable;
+		goto sleep_clk_disable;
 
 	if (msm_host->msm_bus_vote.client_handle)
 		INIT_DELAYED_WORK(&msm_host->msm_bus_vote.vote_work,
@@ -2362,6 +2706,10 @@
 	/* Set HC_MODE_EN bit in HC_MODE register */
 	writel_relaxed(HC_MODE_EN, (msm_host->core_mem + CORE_HC_MODE));
 
+	/* Set FF_CLK_SW_RST_DIS bit in HC_MODE register */
+	writel_relaxed(readl_relaxed(msm_host->core_mem + CORE_HC_MODE) |
+			FF_CLK_SW_RST_DIS, msm_host->core_mem + CORE_HC_MODE);
+
 	/*
 	 * CORE_SW_RST above may trigger power irq if previous status of PWRCTL
 	 * was either BUS_ON or IO_HIGH_V. So before we enable the power irq
@@ -2472,6 +2820,7 @@
 	msm_host->mmc->caps2 |= MMC_CAP2_CLK_SCALE;
 	msm_host->mmc->caps2 |= MMC_CAP2_STOP_REQUEST;
 	msm_host->mmc->caps2 |= MMC_CAP2_ASYNC_SDIO_IRQ_4BIT_MODE;
+	msm_host->mmc->pm_caps |= MMC_PM_KEEP_POWER;
 
 	if (msm_host->pdata->nonremovable)
 		msm_host->mmc->caps |= MMC_CAP_NONREMOVABLE;
@@ -2547,6 +2896,12 @@
 	if (msm_host->msm_bus_vote.client_handle)
 		sdhci_msm_bus_cancel_work_and_set_vote(host, 0);
 	sdhci_msm_bus_unregister(msm_host);
+sleep_clk_disable:
+	if (!IS_ERR(msm_host->sleep_clk))
+		clk_disable_unprepare(msm_host->sleep_clk);
+ff_clk_disable:
+	if (!IS_ERR(msm_host->ff_clk))
+		clk_disable_unprepare(msm_host->ff_clk);
 clk_disable:
 	if (!IS_ERR(msm_host->clk))
 		clk_disable_unprepare(msm_host->clk);
diff --git a/drivers/mmc/host/sdhci.c b/drivers/mmc/host/sdhci.c
index 578cc14..f9f3802 100644
--- a/drivers/mmc/host/sdhci.c
+++ b/drivers/mmc/host/sdhci.c
@@ -1129,6 +1129,7 @@
 
 	/* CMD19 is special in that the Data Present Select should be set */
 	if (cmd->data || cmd->opcode == MMC_SEND_TUNING_BLOCK ||
+	    cmd->opcode == MMC_SEND_TUNING_BLOCK_HS400 ||
 	    cmd->opcode == MMC_SEND_TUNING_BLOCK_HS200)
 		flags |= SDHCI_CMD_DATA;
 
@@ -1631,7 +1632,8 @@
 		unsigned int clock;
 
 		/* In case of UHS-I modes, set High Speed Enable */
-		if ((ios->timing == MMC_TIMING_MMC_HS200) ||
+		if ((ios->timing == MMC_TIMING_MMC_HS400) ||
+		    (ios->timing == MMC_TIMING_MMC_HS200) ||
 		    (ios->timing == MMC_TIMING_UHS_SDR50) ||
 		    (ios->timing == MMC_TIMING_UHS_SDR104) ||
 		    (ios->timing == MMC_TIMING_UHS_DDR50) ||
@@ -1686,7 +1688,9 @@
 			ctrl_2 = sdhci_readw(host, SDHCI_HOST_CONTROL2);
 			/* Select Bus Speed Mode for host */
 			ctrl_2 &= ~SDHCI_CTRL_UHS_MASK;
-			if (ios->timing == MMC_TIMING_MMC_HS200)
+			if (ios->timing == MMC_TIMING_MMC_HS400)
+				ctrl_2 |= SDHCI_CTRL_HS_SDR200;
+			else if (ios->timing == MMC_TIMING_MMC_HS200)
 				ctrl_2 |= SDHCI_CTRL_HS_SDR200;
 			else if (ios->timing == MMC_TIMING_UHS_SDR12)
 				ctrl_2 |= SDHCI_CTRL_UHS_SDR12;
@@ -1982,12 +1986,13 @@
 	 * The Host Controller needs tuning only in case of SDR104 mode
 	 * and for SDR50 mode when Use Tuning for SDR50 is set in the
 	 * Capabilities register.
-	 * If the Host Controller supports the HS200 mode then the
+	 * If the Host Controller supports the HS400/HS200 mode then the
 	 * tuning function has to be executed.
 	 */
 	if ((((ctrl & SDHCI_CTRL_UHS_MASK) == SDHCI_CTRL_UHS_SDR50) &&
 	    (host->flags & SDHCI_SDR50_NEEDS_TUNING)) ||
-	     (host->flags & SDHCI_HS200_NEEDS_TUNING))
+	     (host->flags & SDHCI_HS200_NEEDS_TUNING) ||
+	     (host->flags & SDHCI_HS400_NEEDS_TUNING))
 		requires_tuning_nonuhs = true;
 
 	if (((ctrl & SDHCI_CTRL_UHS_MASK) == SDHCI_CTRL_UHS_SDR104) ||
@@ -2050,7 +2055,8 @@
 		 * block to the Host Controller. So we set the block size
 		 * to 64 here.
 		 */
-		if (cmd.opcode == MMC_SEND_TUNING_BLOCK_HS200) {
+		if ((cmd.opcode == MMC_SEND_TUNING_BLOCK_HS400) ||
+		    (cmd.opcode == MMC_SEND_TUNING_BLOCK_HS200)) {
 			if (mmc->ios.bus_width == MMC_BUS_WIDTH_8)
 				sdhci_writew(host, SDHCI_MAKE_BLKSZ(7, 128),
 					     SDHCI_BLOCK_SIZE);
@@ -2451,7 +2457,8 @@
 		host->cmd->error = -EILSEQ;
 
 	if (host->quirks2 & SDHCI_QUIRK2_IGNORE_CMDCRC_FOR_TUNING) {
-		if ((host->cmd->opcode == MMC_SEND_TUNING_BLOCK_HS200) ||
+		if ((host->cmd->opcode == MMC_SEND_TUNING_BLOCK_HS400) ||
+			(host->cmd->opcode == MMC_SEND_TUNING_BLOCK_HS200) ||
 			(host->cmd->opcode == MMC_SEND_TUNING_BLOCK)) {
 			if (intmask & SDHCI_INT_CRC) {
 				sdhci_reset(host, SDHCI_RESET_CMD);
@@ -2488,7 +2495,8 @@
 	}
 
 	if (host->quirks2 & SDHCI_QUIRK2_IGNORE_CMDCRC_FOR_TUNING) {
-		if ((host->cmd->opcode == MMC_SEND_TUNING_BLOCK_HS200) ||
+		if ((host->cmd->opcode == MMC_SEND_TUNING_BLOCK_HS400) ||
+			(host->cmd->opcode == MMC_SEND_TUNING_BLOCK_HS200) ||
 			(host->cmd->opcode == MMC_SEND_TUNING_BLOCK)) {
 			if (intmask & SDHCI_INT_CRC) {
 				sdhci_finish_command(host);
@@ -2536,7 +2544,8 @@
 	if (intmask & SDHCI_INT_DATA_AVAIL) {
 		command = SDHCI_GET_CMD(sdhci_readw(host, SDHCI_COMMAND));
 		if (command == MMC_SEND_TUNING_BLOCK ||
-		    command == MMC_SEND_TUNING_BLOCK_HS200) {
+		    command == MMC_SEND_TUNING_BLOCK_HS200 ||
+		    command == MMC_SEND_TUNING_BLOCK_HS400) {
 			host->tuning_done = 1;
 			wake_up(&host->buf_ready_int);
 			return;
@@ -2585,7 +2594,8 @@
 		    (host->quirks2 & SDHCI_QUIRK2_IGNORE_CMDCRC_FOR_TUNING)) {
 			command = SDHCI_GET_CMD(sdhci_readw(host,
 							    SDHCI_COMMAND));
-			if ((command != MMC_SEND_TUNING_BLOCK_HS200) &&
+			if ((command != MMC_SEND_TUNING_BLOCK_HS400) &&
+			    (command != MMC_SEND_TUNING_BLOCK_HS200) &&
 			    (command != MMC_SEND_TUNING_BLOCK))
 				pr_msg = true;
 		} else {
@@ -3217,6 +3227,10 @@
 	if (mmc->caps2 & MMC_CAP2_HS200)
 		host->flags |= SDHCI_HS200_NEEDS_TUNING;
 
+	/* Does the host need tuning for HS400? */
+	if (mmc->caps2 & MMC_CAP2_HS400)
+		host->flags |= SDHCI_HS400_NEEDS_TUNING;
+
 	/* Driver Type(s) (A, C, D) supported by the host */
 	if (caps[1] & SDHCI_DRIVER_TYPE_A)
 		mmc->caps |= MMC_CAP_DRIVER_TYPE_A;
diff --git a/drivers/net/ethernet/msm/msm_rmnet_bam.c b/drivers/net/ethernet/msm/msm_rmnet_bam.c
index 3f3d76a..9f06258 100644
--- a/drivers/net/ethernet/msm/msm_rmnet_bam.c
+++ b/drivers/net/ethernet/msm/msm_rmnet_bam.c
@@ -42,6 +42,11 @@
 module_param_named(debug_enable, msm_rmnet_bam_debug_mask,
 			int, S_IRUGO | S_IWUSR | S_IWGRP);
 
+static unsigned long int msm_rmnet_bam_headroom_check_failure;
+module_param(msm_rmnet_bam_headroom_check_failure, ulong, S_IRUGO);
+MODULE_PARM_DESC(msm_rmnet_bam_headroom_check_failure,
+		 "Number of packets with insufficient headroom");
+
 #define DEBUG_MASK_LVL0 (1U << 0)
 #define DEBUG_MASK_LVL1 (1U << 1)
 #define DEBUG_MASK_LVL2 (1U << 2)
@@ -62,8 +67,9 @@
 
 #define DEVICE_ID_INVALID   -1
 
-#define DEVICE_INACTIVE      0
+#define DEVICE_INACTIVE      2
 #define DEVICE_ACTIVE        1
+#define DEVICE_UNINITIALIZED 0
 
 #define HEADROOM_FOR_BAM   8 /* for mux header */
 #define HEADROOM_FOR_QOS    8
@@ -286,6 +292,23 @@
 			((struct net_device *)dev)->name, __func__);
 }
 
+static struct sk_buff *_rmnet_add_headroom(struct sk_buff **skb,
+					   struct net_device *dev)
+{
+	struct sk_buff *skbn;
+
+	if (skb_headroom(*skb) < dev->needed_headroom) {
+		msm_rmnet_bam_headroom_check_failure++;
+		skbn = skb_realloc_headroom(*skb, dev->needed_headroom);
+		kfree_skb(*skb);
+		*skb = skbn;
+	} else {
+		skbn = *skb;
+	}
+
+	return skbn;
+}
+
 static int _rmnet_xmit(struct sk_buff *skb, struct net_device *dev)
 {
 	struct rmnet_private *p = netdev_priv(dev);
@@ -294,6 +317,10 @@
 	u32 opmode;
 	unsigned long flags;
 
+	if (unlikely(!_rmnet_add_headroom(&skb, dev))) {
+		dev->stats.tx_dropped++;
+		return NETDEV_TX_OK;
+	}
 	/* For QoS mode, prepend QMI header and assign flow ID from skb->mark */
 	spin_lock_irqsave(&p->lock, flags);
 	opmode = p->operation_mode;
@@ -394,7 +421,7 @@
 
 	DBG0("[%s] __rmnet_open()\n", dev->name);
 
-	if (!p->device_up) {
+	if (p->device_up == DEVICE_UNINITIALIZED) {
 		r = msm_bam_dmux_open(p->ch_id, dev, bam_notify);
 
 		if (r < 0) {
@@ -436,7 +463,7 @@
 	struct rmnet_private *p = netdev_priv(dev);
 	int rc = 0;
 
-	if (p->device_up) {
+	if (p->device_up == DEVICE_ACTIVE) {
 		/* do not close rmnet port once up,  this causes
 		   remote side to hang if tried to open again */
 		p->device_up = DEVICE_INACTIVE;
@@ -906,6 +933,7 @@
 		p->ch_id = n;
 		p->waiting_for_ul_skb = NULL;
 		p->in_reset = 0;
+		p->device_up = DEVICE_UNINITIALIZED;
 		spin_lock_init(&p->lock);
 		spin_lock_init(&p->tx_queue_lock);
 #ifdef CONFIG_MSM_RMNET_DEBUG
@@ -971,6 +999,7 @@
 		p->ch_id = n+BAM_DMUX_DATA_REV_RMNET_0;
 		p->waiting_for_ul_skb = NULL;
 		p->in_reset = 0;
+		p->device_up = DEVICE_UNINITIALIZED;
 		spin_lock_init(&p->lock);
 		spin_lock_init(&p->tx_queue_lock);
 
diff --git a/drivers/net/wireless/wcnss/wcnss_wlan.c b/drivers/net/wireless/wcnss/wcnss_wlan.c
index 657fc2f..d35bdaa 100644
--- a/drivers/net/wireless/wcnss/wcnss_wlan.c
+++ b/drivers/net/wireless/wcnss/wcnss_wlan.c
@@ -31,7 +31,10 @@
 #include <linux/kthread.h>
 #include <linux/wait.h>
 #include <linux/uaccess.h>
+#include <linux/suspend.h>
+#include <linux/rwsem.h>
 #include <linux/mfd/pm8xxx/misc.h>
+#include <linux/qpnp/qpnp-adc.h>
 
 #include <mach/msm_smd.h>
 #include <mach/msm_iomap.h>
@@ -81,9 +84,16 @@
 
 #define PRONTO_PMU_SPARE_OFFSET       0x1088
 
-#define PRONTO_PMU_GDSCR_OFFSET       0x0024
-#define PRONTO_PMU_GDSCR_SW_COLLAPSE  BIT(0)
-#define PRONTO_PMU_GDSCR_HW_CTRL      BIT(1)
+#define PRONTO_PMU_COM_GDSCR_OFFSET       0x0024
+#define PRONTO_PMU_COM_GDSCR_SW_COLLAPSE  BIT(0)
+#define PRONTO_PMU_COM_GDSCR_HW_CTRL      BIT(1)
+
+#define PRONTO_PMU_WLAN_BCR_OFFSET         0x0050
+#define PRONTO_PMU_WLAN_BCR_BLK_ARES       BIT(0)
+
+#define PRONTO_PMU_WLAN_GDSCR_OFFSET       0x0054
+#define PRONTO_PMU_WLAN_GDSCR_SW_COLLAPSE  BIT(0)
+
 
 #define PRONTO_PMU_CBCR_OFFSET        0x0008
 #define PRONTO_PMU_CBCR_CLK_EN        BIT(0)
@@ -118,7 +128,14 @@
 #define MSM_PRONTO_PLL_BASE				0xfb21b1c0
 #define PRONTO_PLL_STATUS_OFFSET		0x1c
 
+#define MSM_PRONTO_TXP_PHY_ABORT        0xfb080488
+#define MSM_PRONTO_BRDG_ERR_SRC         0xfb080fb0
+
 #define WCNSS_DEF_WLAN_RX_BUFF_COUNT		1024
+#define WCNSS_VBATT_THRESHOLD		3500000
+#define WCNSS_VBATT_GUARD		200
+#define WCNSS_VBATT_HIGH		3700000
+#define WCNSS_VBATT_LOW			3300000
 
 #define WCNSS_CTRL_CHANNEL			"WCNSS_CTRL"
 #define WCNSS_MAX_FRAME_SIZE		(4*1024)
@@ -134,6 +151,7 @@
 #define	WCNSS_CALDATA_UPLD_RSP        (WCNSS_CTRL_MSG_START + 5)
 #define	WCNSS_CALDATA_DNLD_REQ        (WCNSS_CTRL_MSG_START + 6)
 #define	WCNSS_CALDATA_DNLD_RSP        (WCNSS_CTRL_MSG_START + 7)
+#define	WCNSS_VBATT_LEVEL_IND         (WCNSS_CTRL_MSG_START + 8)
 
 
 #define VALID_VERSION(version) \
@@ -265,6 +283,16 @@
 	struct cal_data_params cal_params;
 };
 
+struct vbatt_level {
+	u32 curr_volt;
+	u32 threshold;
+};
+
+struct vbatt_message {
+	struct smd_msg_hdr hdr;
+	struct vbatt_level vbatt;
+};
+
 static struct {
 	struct platform_device *pdev;
 	void		*pil;
@@ -286,6 +314,7 @@
 	void		(*tm_notify)(struct device *, int);
 	struct wcnss_wlan_config wlan_config;
 	struct delayed_work wcnss_work;
+	struct delayed_work vbatt_work;
 	struct work_struct wcnssctrl_version_work;
 	struct work_struct wcnssctrl_nvbin_dnld_work;
 	struct work_struct wcnssctrl_rx_work;
@@ -296,6 +325,8 @@
 	void __iomem *pronto_ccpu_base;
 	void __iomem *pronto_saw2_base;
 	void __iomem *pronto_pll_base;
+	void __iomem *wlan_tx_phy_aborts;
+	void __iomem *wlan_brdg_err_source;
 	void __iomem *fiq_reg;
 	int	ssr_boot;
 	int	nv_downloaded;
@@ -310,8 +341,12 @@
 	int	user_cal_exp_size;
 	int	device_opened;
 	int	iris_xo_mode_set;
+	int	fw_vbatt_state;
 	struct mutex dev_lock;
 	wait_queue_head_t read_wait;
+	struct qpnp_adc_tm_btm_param vbat_monitor_params;
+	struct qpnp_adc_tm_chip *adc_tm_dev;
+	struct mutex vbat_monitor_mutex;
 } *penv = NULL;
 
 static ssize_t wcnss_serial_number_show(struct device *dev,
@@ -435,14 +470,14 @@
 void wcnss_pronto_log_debug_regs(void)
 {
 	void __iomem *reg_addr, *tst_addr, *tst_ctrl_addr;
-	u32 reg = 0;
+	u32 reg = 0, reg2 = 0;
 
 
 	reg_addr = penv->msm_wcnss_base + PRONTO_PMU_SPARE_OFFSET;
 	reg = readl_relaxed(reg_addr);
 	pr_info_ratelimited("%s:  PRONTO_PMU_SPARE %08x\n", __func__, reg);
 
-	reg_addr = penv->msm_wcnss_base + PRONTO_PMU_GDSCR_OFFSET;
+	reg_addr = penv->msm_wcnss_base + PRONTO_PMU_COM_GDSCR_OFFSET;
 	reg = readl_relaxed(reg_addr);
 	reg >>= 31;
 
@@ -451,7 +486,8 @@
 				__func__);
 		return;
 	}
-	reg &= ~(PRONTO_PMU_GDSCR_SW_COLLAPSE | PRONTO_PMU_GDSCR_HW_CTRL);
+	reg &= ~(PRONTO_PMU_COM_GDSCR_SW_COLLAPSE
+			| PRONTO_PMU_COM_GDSCR_HW_CTRL);
 	writel_relaxed(reg, reg_addr);
 
 	reg_addr = penv->msm_wcnss_base + PRONTO_PMU_CBCR_OFFSET;
@@ -557,6 +593,26 @@
 	reg = readl_relaxed(tst_addr);
 	pr_info_ratelimited("%s:  CTRL SEL CFG1 testbus %08x\n", __func__, reg);
 
+
+	reg_addr = penv->msm_wcnss_base + PRONTO_PMU_WLAN_BCR_OFFSET;
+	reg = readl_relaxed(reg_addr);
+
+	reg_addr = penv->msm_wcnss_base + PRONTO_PMU_WLAN_GDSCR_OFFSET;
+	reg2 = readl_relaxed(reg_addr);
+
+	if ((reg & PRONTO_PMU_WLAN_BCR_BLK_ARES) ||
+			(reg2 & PRONTO_PMU_WLAN_GDSCR_SW_COLLAPSE)) {
+		pr_info_ratelimited("%s:  Cannot log, wlan domain is power collapsed\n",
+				__func__);
+		return;
+	}
+
+	reg = readl_relaxed(penv->wlan_tx_phy_aborts);
+	pr_info_ratelimited("%s: WLAN_TX_PHY_ABORTS %08x\n", __func__, reg);
+
+	reg = readl_relaxed(penv->wlan_brdg_err_source);
+	pr_info_ratelimited("%s: WLAN_BRDG_ERR_SOURCE %08x\n", __func__, reg);
+
 }
 EXPORT_SYMBOL(wcnss_pronto_log_debug_regs);
 
@@ -1046,7 +1102,6 @@
 }
 EXPORT_SYMBOL(wcnss_get_wlan_rx_buff_count);
 
-
 static int wcnss_smd_tx(void *data, int len)
 {
 	int ret = 0;
@@ -1064,6 +1119,102 @@
 	return ret;
 }
 
+static void wcnss_notify_vbat(enum qpnp_tm_state state, void *ctx)
+{
+	mutex_lock(&penv->vbat_monitor_mutex);
+	cancel_delayed_work_sync(&penv->vbatt_work);
+
+	if (state == ADC_TM_LOW_STATE) {
+		pr_debug("wcnss: low voltage notification triggered\n");
+		penv->vbat_monitor_params.state_request =
+			ADC_TM_HIGH_THR_ENABLE;
+		penv->vbat_monitor_params.high_thr = WCNSS_VBATT_THRESHOLD +
+		WCNSS_VBATT_GUARD;
+		penv->vbat_monitor_params.low_thr = 0;
+	} else if (state == ADC_TM_HIGH_STATE) {
+		penv->vbat_monitor_params.state_request =
+			ADC_TM_LOW_THR_ENABLE;
+		penv->vbat_monitor_params.low_thr = WCNSS_VBATT_THRESHOLD -
+		WCNSS_VBATT_GUARD;
+		penv->vbat_monitor_params.high_thr = 0;
+		pr_debug("wcnss: high voltage notification triggered\n");
+	} else {
+		pr_debug("wcnss: unknown voltage notification state: %d\n",
+				state);
+		mutex_unlock(&penv->vbat_monitor_mutex);
+		return;
+	}
+	pr_debug("wcnss: set low thr to %d and high to %d\n",
+			penv->vbat_monitor_params.low_thr,
+			penv->vbat_monitor_params.high_thr);
+
+	qpnp_adc_tm_channel_measure(penv->adc_tm_dev,
+			&penv->vbat_monitor_params);
+	schedule_delayed_work(&penv->vbatt_work, msecs_to_jiffies(2000));
+	mutex_unlock(&penv->vbat_monitor_mutex);
+}
+
+static int wcnss_setup_vbat_monitoring(void)
+{
+	int rc = -1;
+
+	if (!penv->adc_tm_dev) {
+		pr_err("wcnss: not setting up vbatt\n");
+		return rc;
+	}
+	penv->vbat_monitor_params.low_thr = WCNSS_VBATT_THRESHOLD;
+	penv->vbat_monitor_params.high_thr = WCNSS_VBATT_THRESHOLD;
+	penv->vbat_monitor_params.state_request = ADC_TM_HIGH_LOW_THR_ENABLE;
+	penv->vbat_monitor_params.channel = VBAT_SNS;
+	penv->vbat_monitor_params.btm_ctx = (void *)penv;
+	penv->vbat_monitor_params.timer_interval = ADC_MEAS1_INTERVAL_1S;
+	penv->vbat_monitor_params.threshold_notification = &wcnss_notify_vbat;
+	pr_debug("wcnss: set low thr to %d and high to %d\n",
+			penv->vbat_monitor_params.low_thr,
+			penv->vbat_monitor_params.high_thr);
+
+	rc = qpnp_adc_tm_channel_measure(penv->adc_tm_dev,
+					&penv->vbat_monitor_params);
+	if (rc)
+		pr_err("wcnss: tm setup failed: %d\n", rc);
+
+	return rc;
+}
+
+static void wcnss_update_vbatt(struct work_struct *work)
+{
+	struct vbatt_message vbatt_msg;
+	int ret = 0;
+
+	vbatt_msg.hdr.msg_type = WCNSS_VBATT_LEVEL_IND;
+	vbatt_msg.hdr.msg_len = sizeof(struct vbatt_message);
+	vbatt_msg.vbatt.threshold = WCNSS_VBATT_THRESHOLD;
+
+	mutex_lock(&penv->vbat_monitor_mutex);
+	if (penv->vbat_monitor_params.low_thr &&
+		(penv->fw_vbatt_state == WCNSS_VBATT_LOW ||
+			penv->fw_vbatt_state == WCNSS_CONFIG_UNSPECIFIED)) {
+		vbatt_msg.vbatt.curr_volt = WCNSS_VBATT_HIGH;
+		penv->fw_vbatt_state = WCNSS_VBATT_HIGH;
+		pr_debug("wcnss: send HIGH BATT to FW\n");
+	} else if (!penv->vbat_monitor_params.low_thr &&
+		(penv->fw_vbatt_state == WCNSS_VBATT_HIGH ||
+			penv->fw_vbatt_state == WCNSS_CONFIG_UNSPECIFIED)){
+		vbatt_msg.vbatt.curr_volt = WCNSS_VBATT_LOW;
+		penv->fw_vbatt_state = WCNSS_VBATT_LOW;
+		pr_debug("wcnss: send LOW BATT to FW\n");
+	} else {
+		mutex_unlock(&penv->vbat_monitor_mutex);
+		return;
+	}
+	mutex_unlock(&penv->vbat_monitor_mutex);
+	ret = wcnss_smd_tx(&vbatt_msg, vbatt_msg.hdr.msg_len);
+	if (ret < 0)
+		pr_err("wcnss: smd tx failed\n");
+	return;
+}
+
+
 static unsigned char wcnss_fw_status(void)
 {
 	int len = 0;
@@ -1277,6 +1428,7 @@
 		fw_status = wcnss_fw_status();
 		pr_debug("wcnss: received WCNSS_NVBIN_DNLD_RSP from ccpu %u\n",
 			fw_status);
+		wcnss_setup_vbat_monitoring();
 		break;
 
 	case WCNSS_CALDATA_DNLD_RSP:
@@ -1311,6 +1463,7 @@
 	return;
 }
 
+static DECLARE_RWSEM(wcnss_pm_sem);
 
 static void wcnss_nvbin_dnld(void)
 {
@@ -1326,12 +1479,14 @@
 	const struct firmware *nv = NULL;
 	struct device *dev = &penv->pdev->dev;
 
+	down_read(&wcnss_pm_sem);
+
 	ret = request_firmware(&nv, NVBIN_FILE, dev);
 
 	if (ret || !nv || !nv->data || !nv->size) {
 		pr_err("wcnss: %s: request_firmware failed for %s\n",
 			__func__, NVBIN_FILE);
-		return;
+		goto out;
 	}
 
 	/*
@@ -1424,6 +1579,9 @@
 	/* release firmware */
 	release_firmware(nv);
 
+out:
+	up_read(&wcnss_pm_sem);
+
 	return;
 }
 
@@ -1557,7 +1715,25 @@
 	return;
 }
 
+static int wcnss_pm_notify(struct notifier_block *b,
+			unsigned long event, void *p)
+{
+	switch (event) {
+	case PM_SUSPEND_PREPARE:
+		down_write(&wcnss_pm_sem);
+		break;
 
+	case PM_POST_SUSPEND:
+		up_write(&wcnss_pm_sem);
+		break;
+	}
+
+	return NOTIFY_DONE;
+}
+
+static struct notifier_block wcnss_pm_notifier = {
+	.notifier_call = wcnss_pm_notify,
+};
 
 static int
 wcnss_trigger_config(struct platform_device *pdev)
@@ -1716,6 +1892,29 @@
 			goto fail_ioremap6;
 		}
 
+		penv->wlan_tx_phy_aborts =  ioremap(MSM_PRONTO_TXP_PHY_ABORT,
+					SZ_8);
+		if (!penv->wlan_tx_phy_aborts) {
+			ret = -ENOMEM;
+			pr_err("%s: ioremap wlan TX PHY failed\n", __func__);
+			goto fail_ioremap7;
+		}
+		penv->wlan_brdg_err_source =  ioremap(MSM_PRONTO_BRDG_ERR_SRC,
+							SZ_8);
+		if (!penv->wlan_brdg_err_source) {
+			ret = -ENOMEM;
+			pr_err("%s: ioremap wlan BRDG ERR failed\n", __func__);
+			goto fail_ioremap8;
+		}
+
+	}
+	penv->adc_tm_dev = qpnp_get_adc_tm(&penv->pdev->dev, "wcnss");
+	if (IS_ERR(penv->adc_tm_dev)) {
+		pr_err("%s:  adc get failed\n", __func__);
+		penv->adc_tm_dev = NULL;
+	} else {
+		INIT_DELAYED_WORK(&penv->vbatt_work, wcnss_update_vbatt);
+		penv->fw_vbatt_state = WCNSS_CONFIG_UNSPECIFIED;
 	}
 
 	/* trigger initialization of the WCNSS */
@@ -1723,6 +1922,7 @@
 	if (IS_ERR(penv->pil)) {
 		dev_err(&pdev->dev, "Peripheral Loader failed on WCNSS.\n");
 		ret = PTR_ERR(penv->pil);
+		wcnss_pronto_log_debug_regs();
 		penv->pil = NULL;
 		goto fail_pil;
 	}
@@ -1732,6 +1932,12 @@
 fail_pil:
 	if (penv->riva_ccu_base)
 		iounmap(penv->riva_ccu_base);
+	if (penv->wlan_brdg_err_source)
+		iounmap(penv->wlan_brdg_err_source);
+fail_ioremap8:
+	if (penv->wlan_tx_phy_aborts)
+		iounmap(penv->wlan_tx_phy_aborts);
+fail_ioremap7:
 	if (penv->pronto_pll_base)
 		iounmap(penv->pronto_pll_base);
 fail_ioremap6:
@@ -1924,6 +2130,7 @@
 	}
 
 	mutex_init(&penv->dev_lock);
+	mutex_init(&penv->vbat_monitor_mutex);
 	init_waitqueue_head(&penv->read_wait);
 
 	/* Since we were built into the kernel we'll be called as part
@@ -1980,7 +2187,7 @@
 	platform_driver_register(&wcnss_wlan_driver);
 	platform_driver_register(&wcnss_wlan_ctrl_driver);
 	platform_driver_register(&wcnss_ctrl_driver);
-
+	register_pm_notifier(&wcnss_pm_notifier);
 #ifdef CONFIG_WCNSS_MEM_PRE_ALLOC
 	ret = wcnss_prealloc_init();
 	if (ret < 0)
@@ -1995,17 +2202,16 @@
 	if (penv) {
 		if (penv->pil)
 			subsystem_put(penv->pil);
-
-
 		penv = NULL;
 	}
 
-	platform_driver_unregister(&wcnss_ctrl_driver);
-	platform_driver_unregister(&wcnss_wlan_ctrl_driver);
-	platform_driver_unregister(&wcnss_wlan_driver);
 #ifdef CONFIG_WCNSS_MEM_PRE_ALLOC
 	wcnss_prealloc_deinit();
 #endif
+	unregister_pm_notifier(&wcnss_pm_notifier);
+	platform_driver_unregister(&wcnss_ctrl_driver);
+	platform_driver_unregister(&wcnss_wlan_ctrl_driver);
+	platform_driver_unregister(&wcnss_wlan_driver);
 }
 
 module_init(wcnss_wlan_init);
diff --git a/drivers/nfc/nfc-nci.c b/drivers/nfc/nfc-nci.c
index e832716..87c7c30 100644
--- a/drivers/nfc/nfc-nci.c
+++ b/drivers/nfc/nfc-nci.c
@@ -49,6 +49,7 @@
 #define MAX_QCA_REG		(116)
 
 static int nfc_i2c_write(struct i2c_client *client, u8 *buf, int len);
+static int nfcc_initialise(struct i2c_client *client, unsigned short curr_addr);
 
 struct qca199x_dev {
 	wait_queue_head_t read_wq;
@@ -167,6 +168,8 @@
 		count = MAX_BUFFER_SIZE;
 
 	mutex_lock(&qca199x_dev->read_mutex);
+	memset(tmp, 0, sizeof(tmp));
+	memset(len, 0, sizeof(len));
 	dmode = device_mode.handle_flavour;
 	/* FTM-RAW-I2C RD/WR MODE - Special Case */
 	if ((dmode == UNSOLICITED_FTM_RAW_MODE) ||
@@ -199,20 +202,25 @@
 	/* NORMAL NCI Behaviour */
 	/* Read the header */
 	ret = i2c_master_recv(qca199x_dev->client, len, PAYLOAD_HEADER_LENGTH);
-	if (ret != PAYLOAD_HEADER_LENGTH)
+	if (ret != PAYLOAD_HEADER_LENGTH) {
+		total = 0;
 		goto err;
+	}
 	length = len[PAYLOAD_HEADER_LENGTH - 1];
-
+	if (length == 0)
+		total = 0;
 	/** make sure full packet fits in the buffer **/
 	if ((length > 0) && ((length + PAYLOAD_HEADER_LENGTH) <= count)) {
 		/* Read the packet */
 		ret = i2c_master_recv(qca199x_dev->client, tmp, (length +
 			PAYLOAD_HEADER_LENGTH));
-		if (ret < 0)
+		if (ret < 0) {
+			total = 0;
 			goto err;
+		}
 		total = (length + PAYLOAD_HEADER_LENGTH);
 	}
-	mutex_unlock(&qca199x_dev->read_mutex);
+
 	if (total > 0) {
 		if ((total > count) || copy_to_user(buf, tmp, total)) {
 			dev_err(&qca199x_dev->client->dev,
@@ -221,6 +229,7 @@
 			total = -EFAULT;
 		}
 	}
+	mutex_unlock(&qca199x_dev->read_mutex);
 err:
 	if (ret < 0)
 		mutex_unlock(&qca199x_dev->read_mutex);
@@ -375,6 +384,7 @@
 			goto err_req;
 		}
 		gpio_set_value(qca199x_dev->dis_gpio, 0);
+		msleep(20);
 	} else if (arg == 1) {
 		gpio_set_value(qca199x_dev->dis_gpio, 0);
 		r = gpio_direction_output(qca199x_dev->dis_gpio, 1);
@@ -385,12 +395,20 @@
 			goto err_req;
 		}
 		gpio_set_value(qca199x_dev->dis_gpio, 1);
+		usleep(1000);
 	} else if (arg == 2) {
-		msleep(20);
+		r = nfcc_initialise(qca199x_dev->client, 0xE);
+		if (r) {
+			dev_err(&qca199x_dev->client->dev,
+					"nfc-nci probe: request nfcc initialise failed\n");
+			goto err_req;
+		}
 	} else if (arg == 3) {
 		msleep(20);
 	} else if (arg == 4) {
+		mutex_lock(&qca199x_dev->read_mutex);
 		nfcc_wake(NFCC_WAKE, filp);
+		mutex_unlock(&qca199x_dev->read_mutex);
 	} else if (arg == 5) {
 		nfcc_wake(NFCC_SLEEP, filp);
 	} else {
@@ -568,7 +586,7 @@
 	return r;
 }
 
-int nfcc_initialise(struct i2c_client *client, unsigned short curr_addr)
+static int nfcc_initialise(struct i2c_client *client, unsigned short curr_addr)
 {
 	int r = 0;
 	unsigned char raw_1p8_CONTROL_011[]	= {0x11, XTAL_CLOCK};
@@ -764,9 +782,9 @@
 		dev_err(&client->dev, "dis gpio not provided\n");
 		goto err_irq;
 	}
-	gpio_set_value(qca199x_dev->dis_gpio, 1);
+	gpio_set_value(platform_data->dis_gpio, 1);/* HPD */
 	msleep(20);
-	gpio_set_value(qca199x_dev->dis_gpio, 0);
+	gpio_set_value(platform_data->dis_gpio, 0);/* ULPM */
 
 	nfc_clk  = clk_get(&client->dev, "ref_clk");
 
diff --git a/drivers/of/of_batterydata.c b/drivers/of/of_batterydata.c
index 977a1e0..2061408 100644
--- a/drivers/of/of_batterydata.c
+++ b/drivers/of/of_batterydata.c
@@ -155,6 +155,35 @@
 	return 0;
 }
 
+static int of_batterydata_read_batt_id_kohm(const struct device_node *np,
+				const char *propname, struct batt_ids *batt_ids)
+{
+	struct property *prop;
+	const __be32 *data;
+	int num, i, *id_kohm = batt_ids->kohm;
+
+	prop = of_find_property(np, "qcom,batt-id-kohm", NULL);
+	if (!prop) {
+		pr_err("%s: No battery id resistor found\n", np->name);
+		return -EINVAL;
+	} else if (!prop->value) {
+		pr_err("%s: No battery id resistor value found, np->name\n",
+						np->name);
+		return -ENODATA;
+	} else if (prop->length > MAX_BATT_ID_NUM * sizeof(__be32)) {
+		pr_err("%s: Too many battery id resistors\n", np->name);
+		return -EINVAL;
+	}
+
+	num = prop->length/sizeof(__be32);
+	batt_ids->num = num;
+	data = prop->value;
+	for (i = 0; i < num; i++)
+		*id_kohm++ = be32_to_cpup(data++);
+
+	return 0;
+}
+
 #define OF_PROP_READ(property, qpnp_dt_property, node, rc, optional)	\
 do {									\
 	if (rc)								\
@@ -172,6 +201,7 @@
 } while (0)
 
 static int of_batterydata_load_battery_data(struct device_node *node,
+				int best_id_kohm,
 				struct bms_battery_data *batt_data)
 {
 	int rc;
@@ -197,7 +227,6 @@
 			"default-rbatt-mohm", node, rc, false);
 	OF_PROP_READ(batt_data->rbatt_capacitive_mohm,
 			"rbatt-capacitive-mohm", node, rc, false);
-	OF_PROP_READ(batt_data->batt_id_kohm, "batt-id-kohm", node, rc, false);
 	OF_PROP_READ(batt_data->flat_ocv_threshold_uv,
 			"flat-ocv-threshold", node, rc, true);
 	OF_PROP_READ(batt_data->max_voltage_uv,
@@ -205,6 +234,8 @@
 	OF_PROP_READ(batt_data->cutoff_uv, "v-cutoff-uv", node, rc, true);
 	OF_PROP_READ(batt_data->iterm_ua, "chg-term-ua", node, rc, true);
 
+	batt_data->batt_id_kohm = best_id_kohm;
+
 	return rc;
 }
 
@@ -229,8 +260,9 @@
 				int batt_id_uv)
 {
 	struct device_node *node, *best_node;
-	uint32_t id_kohm;
-	int delta, best_delta, batt_id_kohm, rpull_up_kohm, vadc_vdd_uv, rc = 0;
+	struct batt_ids batt_ids;
+	int delta, best_delta, batt_id_kohm, rpull_up_kohm,
+		vadc_vdd_uv, best_id_kohm, i, rc = 0;
 
 	node = batterydata_container_node;
 	OF_PROP_READ(rpull_up_kohm, "rpull-up-kohm", node, rc, false);
@@ -242,18 +274,24 @@
 					rpull_up_kohm, vadc_vdd_uv);
 	best_node = NULL;
 	best_delta = 0;
+	best_id_kohm = 0;
 
 	/*
 	 * Find the battery data with a battery id resistor closest to this one
 	 */
 	for_each_child_of_node(batterydata_container_node, node) {
-		rc = of_property_read_u32(node, "qcom,batt-id-kohm", &id_kohm);
+		rc = of_batterydata_read_batt_id_kohm(node,
+						"qcom,batt-id-kohm",
+						&batt_ids);
 		if (rc)
 			continue;
-		delta = abs((int)id_kohm - batt_id_kohm);
-		if (delta < best_delta || !best_node) {
-			best_node = node;
-			best_delta = delta;
+		for (i = 0; i < batt_ids.num; i++) {
+			delta = abs(batt_ids.kohm[i] - batt_id_kohm);
+			if (delta < best_delta || !best_node) {
+				best_node = node;
+				best_delta = delta;
+				best_id_kohm = batt_ids.kohm[i];
+			}
 		}
 	}
 
@@ -262,7 +300,8 @@
 		return -ENODATA;
 	}
 
-	return of_batterydata_load_battery_data(best_node, batt_data);
+	return of_batterydata_load_battery_data(best_node,
+					best_id_kohm, batt_data);
 }
 
 MODULE_LICENSE("GPL v2");
diff --git a/drivers/platform/msm/Makefile b/drivers/platform/msm/Makefile
index efb78e5..e6493b1 100644
--- a/drivers/platform/msm/Makefile
+++ b/drivers/platform/msm/Makefile
@@ -1,6 +1,10 @@
 #
 # Makefile for the MSM specific device drivers.
 #
+
+ccflags-y += -Idrivers/misc/
+
+
 obj-$(CONFIG_MSM_SSBI) += ssbi.o
 obj-$(CONFIG_USB_BAM) += usb_bam.o
 obj-$(CONFIG_IPA) += ipa/
diff --git a/drivers/platform/msm/qpnp-pwm.c b/drivers/platform/msm/qpnp-pwm.c
index 2fdc427..7d26bef 100644
--- a/drivers/platform/msm/qpnp-pwm.c
+++ b/drivers/platform/msm/qpnp-pwm.c
@@ -31,6 +31,8 @@
 #define QPNP_LPG_CHANNEL_BASE	"qpnp-lpg-channel-base"
 #define QPNP_LPG_LUT_BASE	"qpnp-lpg-lut-base"
 
+#define QPNP_PWM_MODE_ONLY_SUB_TYPE	0x0B
+
 /* LPG Control for LPG_PATTERN_CONFIG */
 #define QPNP_RAMP_DIRECTION_SHIFT	4
 #define QPNP_RAMP_DIRECTION_MASK	0x10
@@ -51,10 +53,13 @@
 #define QPNP_SET_PWM_CLK_SUB_TYPE(val, clk, pwm_size) \
 do { \
 	val = (clk + 1) & QPNP_PWM_FREQ_CLK_SELECT_MASK_SUB_TYPE; \
-	val |= ((pwm_size > 6 ? QPNP_PWM_SIZE_9_BIT_SUB_TYPE : 0) << \
-		QPNP_PWM_SIZE_SHIFT_SUB_TYPE) & QPNP_PWM_SIZE_MASK_SUB_TYPE; \
+	val |= (((pwm_size > 6 ? QPNP_PWM_SIZE_9_BIT_SUB_TYPE : 0) << \
+		QPNP_PWM_SIZE_SHIFT_SUB_TYPE) & QPNP_PWM_SIZE_MASK_SUB_TYPE); \
 } while (0)
 
+#define QPNP_GET_PWM_SIZE_SUB_TYPE(reg) ((reg & QPNP_PWM_SIZE_MASK_SUB_TYPE) \
+				>> QPNP_PWM_SIZE_SHIFT_SUB_TYPE)
+
 #define QPNP_PWM_SIZE_SHIFT			4
 #define QPNP_PWM_SIZE_MASK			0x30
 #define QPNP_PWM_FREQ_CLK_SELECT_MASK		0x03
@@ -194,8 +199,15 @@
 #define qpnp_check_gpled_lpg_channel(id) \
 	(id >= QPNP_GPLED_LPG_CHANNEL_RANGE_START && \
 	id <= QPNP_GPLED_LPG_CHANNEL_RANGE_END)
+
 #define QPNP_PWM_LUT_NOT_SUPPORTED	0x1
 
+/* Supported PWM sizes */
+#define QPNP_PWM_SIZE_6_BIT		6
+#define QPNP_PWM_SIZE_7_BIT		7
+#define QPNP_PWM_SIZE_8_BIT		8
+#define QPNP_PWM_SIZE_9_BIT		9
+
 /* LPG revisions */
 enum qpnp_lpg_revision {
 	QPNP_LPG_REVISION_0 = 0x0,
@@ -296,6 +308,7 @@
 	int				pwm_period;
 	int				pwm_duty;
 	struct pwm_period_config	period;
+	int				force_pwm_size;
 };
 
 /* Public facing structure */
@@ -361,6 +374,9 @@
 #define QPNP_DISABLE_LPG_MODE		qpnp_set_control(0, 0, 0, 0, 1)
 #define QPNP_IS_PWM_CONFIG_SELECTED(val) (val & QPNP_PWM_SRC_SELECT_MASK)
 
+#define QPNP_ENABLE_PWM_MODE_ONLY_SUB_TYPE			0x80
+#define QPNP_DISABLE_PWM_MODE_ONLY_SUB_TYPE			0x0
+#define QPNP_PWM_MODE_ONLY_ENABLE_DISABLE_MASK_SUB_TYPE	0x80
 
 static inline void qpnp_convert_to_lut_flags(int *flags,
 				struct qpnp_lut_config *l_config)
@@ -410,14 +426,16 @@
  * (PWM Period / N) = (Pre-divide * Clock Period) * 2^m
  */
 static void qpnp_lpg_calc_period(unsigned int period_us,
-				   struct qpnp_pwm_config *pwm_conf)
+				   struct pwm_device *pwm)
 {
 	int		n, m, clk, div;
 	int		best_m, best_div, best_clk;
 	unsigned int	last_err, cur_err, min_err;
 	unsigned int	tmp_p, period_n;
-	int		id = pwm_conf->channel_id;
-	struct pwm_period_config *period = &pwm_conf->period;
+	int		id = pwm->pwm_config.channel_id;
+	int		force_pwm_size = pwm->pwm_config.force_pwm_size;
+	struct qpnp_lpg_chip *chip = pwm->chip;
+	struct pwm_period_config *period = &pwm->pwm_config.period;
 
 	/* PWM Period / N */
 	if (qpnp_check_gpled_lpg_channel(id))
@@ -435,6 +453,15 @@
 		period_n = (period_us >> n) * NSEC_PER_USEC;
 	}
 
+	if (force_pwm_size != 0) {
+		if (n < force_pwm_size)
+			period_n = period_n >> (force_pwm_size - n);
+		else
+			period_n = period_n << (n - force_pwm_size);
+		n = force_pwm_size;
+		pr_info("LPG channel '%d' pwm size is forced to=%d\n", id, n);
+	}
+
 	min_err = last_err = (unsigned)(-1);
 	best_m = 0;
 	best_clk = 0;
@@ -468,19 +495,20 @@
 	}
 
 	/* Adapt to optimal pwm size, the higher the resolution the better */
-	if (qpnp_check_gpled_lpg_channel(id)) {
-		if (n == 7 && best_m >= 1) {
-			n += 1;
-			best_m -= 1;
-		}
-	} else {
-		if (n == 6 && best_m >= 3) {
-			n += 3;
-			best_m -= 3;
-		} else {
-			if (n == 6) {
-				n += best_m;
-				best_m -= best_m;
+	if (!force_pwm_size) {
+		if (qpnp_check_gpled_lpg_channel(id)) {
+			if (n == 7 && best_m >= 1) {
+				n += 1;
+				best_m -= 1;
+			}
+		} else if (n == 6) {
+			if (best_m >= 3) {
+				n += 3;
+				best_m -= 3;
+			} else if (best_m >= 1 &&
+				chip->sub_type != QPNP_PWM_MODE_ONLY_SUB_TYPE) {
+				n += 1;
+				best_m -= 1;
 			}
 		}
 	}
@@ -581,14 +609,16 @@
 	struct qpnp_lpg_chip	*chip = pwm->chip;
 	struct qpnp_pwm_config	*pwm_config = &pwm->pwm_config;
 
-	if (chip->sub_type == 0x0B)
+	if (chip->sub_type == QPNP_PWM_MODE_ONLY_SUB_TYPE) {
 		QPNP_SET_PWM_CLK_SUB_TYPE(val, pwm_config->period.clk,
 				pwm_config->period.pwm_size);
-	else
+		mask = QPNP_PWM_SIZE_MASK_SUB_TYPE |
+				QPNP_PWM_FREQ_CLK_SELECT_MASK_SUB_TYPE;
+	} else {
 		QPNP_SET_PWM_CLK(val, pwm_config->period.clk,
 				pwm_config->period.pwm_size);
-
-	mask = QPNP_PWM_SIZE_MASK | QPNP_PWM_FREQ_CLK_SELECT_MASK;
+		mask = QPNP_PWM_SIZE_MASK | QPNP_PWM_FREQ_CLK_SELECT_MASK;
+	}
 
 	qpnp_lpg_save(&chip->qpnp_lpg_registers[QPNP_LPG_PWM_SIZE_CLK],
 							mask, val);
@@ -612,9 +642,14 @@
 	struct qpnp_lpg_config	*lpg_config = &chip->lpg_config;
 	int rc;
 
-	pwm_size = QPNP_GET_PWM_SIZE(
+	if (chip->sub_type == QPNP_PWM_MODE_ONLY_SUB_TYPE)
+		pwm_size = QPNP_GET_PWM_SIZE_SUB_TYPE(
+			chip->qpnp_lpg_registers[QPNP_LPG_PWM_SIZE_CLK]) ?
+				QPNP_MAX_PWM_BIT_SIZE : QPNP_MIN_PWM_BIT_SIZE;
+	else
+		pwm_size = QPNP_GET_PWM_SIZE(
 			chip->qpnp_lpg_registers[QPNP_LPG_PWM_SIZE_CLK]) +
-			QPNP_MIN_PWM_BIT_SIZE;
+				QPNP_MIN_PWM_BIT_SIZE;
 
 	max_pwm_value = (1 << pwm_size) - 1;
 
@@ -643,13 +678,14 @@
 	if (rc)
 		return rc;
 
-	if (chip->sub_type == 0x0B) {
+	if (chip->sub_type == QPNP_PWM_MODE_ONLY_SUB_TYPE) {
 		value = QPNP_PWM_SYNC_VALUE & QPNP_PWM_SYNC_MASK;
 		rc = spmi_ext_register_writel(chip->spmi_dev->ctrl,
 			chip->spmi_dev->sid,
 			SPMI_LPG_REG_ADDR(lpg_config->base_addr,
 			SPMI_LPG_PWM_SYNC), &value, 1);
 	}
+
 	return rc;
 }
 
@@ -710,6 +746,9 @@
 	struct qpnp_lpg_chip	*chip = pwm->chip;
 	u8			value, mask;
 
+	if (chip->sub_type == QPNP_PWM_MODE_ONLY_SUB_TYPE)
+		return 0;
+
 	value = QPNP_ENABLE_PWM_CONTROL;
 
 	mask = QPNP_EN_PWM_HIGH_MASK | QPNP_EN_PWM_LO_MASK |
@@ -1007,14 +1046,24 @@
 	u8			value, mask;
 	int			rc;
 
-	if (state == QPNP_PWM_ENABLE)
-		value = qpnp_enable_pwm_mode(&pwm->pwm_config);
-	else
-		value = QPNP_DISABLE_PWM_MODE;
+	if (chip->sub_type == QPNP_PWM_MODE_ONLY_SUB_TYPE) {
+		if (state == QPNP_PWM_ENABLE)
+			value = QPNP_ENABLE_PWM_MODE_ONLY_SUB_TYPE;
+		else
+			value = QPNP_DISABLE_PWM_MODE_ONLY_SUB_TYPE;
 
-	mask = QPNP_EN_PWM_HIGH_MASK | QPNP_EN_PWM_LO_MASK |
-		QPNP_EN_PWM_OUTPUT_MASK | QPNP_PWM_SRC_SELECT_MASK |
-					QPNP_PWM_EN_RAMP_GEN_MASK;
+		mask = QPNP_PWM_MODE_ONLY_ENABLE_DISABLE_MASK_SUB_TYPE;
+	} else {
+		if (state == QPNP_PWM_ENABLE)
+			value = qpnp_enable_pwm_mode(&pwm->pwm_config);
+		else
+			value = QPNP_DISABLE_PWM_MODE;
+
+		mask = QPNP_EN_PWM_HIGH_MASK | QPNP_EN_PWM_LO_MASK |
+			QPNP_EN_PWM_OUTPUT_MASK | QPNP_PWM_SRC_SELECT_MASK |
+				QPNP_PWM_EN_RAMP_GEN_MASK;
+	}
+
 
 	rc = qpnp_lpg_save_and_write(value, mask,
 		&pwm->chip->qpnp_lpg_registers[QPNP_ENABLE_CONTROL],
@@ -1046,7 +1095,7 @@
 	period = &pwm_config->period;
 
 	if (pwm_config->pwm_period != period_us) {
-		qpnp_lpg_calc_period(period_us, pwm_config);
+		qpnp_lpg_calc_period(period_us, pwm);
 		qpnp_lpg_save_period(pwm);
 		pwm_config->pwm_period = period_us;
 	}
@@ -1102,7 +1151,7 @@
 	period = &pwm_config->period;
 
 	if (pwm_config->pwm_period != period_us) {
-		qpnp_lpg_calc_period(period_us, pwm_config);
+		qpnp_lpg_calc_period(period_us, pwm);
 		qpnp_lpg_save_period(pwm);
 		pwm_config->pwm_period = period_us;
 	}
@@ -1164,7 +1213,8 @@
 	spin_lock_irqsave(&pwm->chip->lpg_lock, flags);
 
 	if (QPNP_IS_PWM_CONFIG_SELECTED(
-		chip->qpnp_lpg_registers[QPNP_ENABLE_CONTROL])) {
+		chip->qpnp_lpg_registers[QPNP_ENABLE_CONTROL]) ||
+			chip->flags & QPNP_PWM_LUT_NOT_SUPPORTED) {
 		rc = qpnp_lpg_configure_pwm_state(pwm, QPNP_PWM_ENABLE);
 	} else if (!(chip->flags & QPNP_PWM_LUT_NOT_SUPPORTED)) {
 			rc = qpnp_lpg_configure_lut_state(pwm, QPNP_LUT_ENABLE);
@@ -1329,7 +1379,8 @@
 
 	if (pwm_config->in_use) {
 		if (QPNP_IS_PWM_CONFIG_SELECTED(
-			chip->qpnp_lpg_registers[QPNP_ENABLE_CONTROL])) {
+			chip->qpnp_lpg_registers[QPNP_ENABLE_CONTROL]) ||
+				chip->flags & QPNP_PWM_LUT_NOT_SUPPORTED) {
 			rc = qpnp_lpg_configure_pwm_state(pwm,
 						QPNP_PWM_DISABLE);
 		} else if (!(chip->flags & QPNP_PWM_LUT_NOT_SUPPORTED)) {
@@ -1684,6 +1735,7 @@
 	struct pwm_device	*pwm_dev = &chip->pwm_dev;
 	struct qpnp_lpg_config	*lpg_config = &chip->lpg_config;
 	struct qpnp_lut_config	*lut_config = &lpg_config->lut_config;
+	int			force_pwm_size = 0;
 
 	rc = of_property_read_u32(of_node, "qcom,channel-id",
 				&pwm_dev->pwm_config.channel_id);
@@ -1693,6 +1745,27 @@
 		goto out;
 	}
 
+	/*
+	 * For cetrain LPG channels PWM size can be forced. So that
+	 * for every requested pwm period closest pwm frequency is
+	 * selected in qpnp_lpg_calc_period() for the forced pwm size.
+	 */
+	rc = of_property_read_u32(of_node, "qcom,force-pwm-size",
+				&force_pwm_size);
+	if (qpnp_check_gpled_lpg_channel(pwm_dev->pwm_config.channel_id)) {
+		if (!(force_pwm_size == QPNP_PWM_SIZE_7_BIT ||
+				force_pwm_size == QPNP_PWM_SIZE_8_BIT))
+			force_pwm_size = 0;
+	} else if (chip->sub_type == QPNP_PWM_MODE_ONLY_SUB_TYPE) {
+		if (!(force_pwm_size == QPNP_PWM_SIZE_6_BIT ||
+				force_pwm_size == QPNP_PWM_SIZE_9_BIT))
+			force_pwm_size = 0;
+	} else if (!(force_pwm_size == QPNP_PWM_SIZE_6_BIT ||
+				force_pwm_size == QPNP_PWM_SIZE_7_BIT ||
+				force_pwm_size == QPNP_PWM_SIZE_9_BIT))
+			force_pwm_size = 0;
+
+	pwm_dev->pwm_config.force_pwm_size = force_pwm_size;
 	res = spmi_get_resource_byname(spmi, NULL, IORESOURCE_MEM,
 					QPNP_LPG_CHANNEL_BASE);
 	if (!res) {
diff --git a/drivers/platform/msm/qpnp-revid.c b/drivers/platform/msm/qpnp-revid.c
index 897dc2a..a2876e0 100644
--- a/drivers/platform/msm/qpnp-revid.c
+++ b/drivers/platform/msm/qpnp-revid.c
@@ -13,6 +13,8 @@
 #include <linux/module.h>
 #include <linux/slab.h>
 #include <linux/spmi.h>
+#include <linux/err.h>
+#include <linux/qpnp-revid.h>
 
 #define REVID_REVISION1	0x0
 #define REVID_REVISION2	0x1
@@ -30,9 +32,21 @@
 	"PM8841",
 	"PM8019",
 	"PM8226",
-	"PM8110"
+	"PM8110",
+	"PMA8084",
+	"PMI8962",
+	"PMD9635",
 };
 
+struct revid_chip {
+	struct list_head	link;
+	struct device_node	*dev_node;
+	struct pmic_revid_data	data;
+};
+
+static LIST_HEAD(revid_chips);
+static DEFINE_MUTEX(revid_chips_lock);
+
 static struct of_device_id qpnp_revid_match_table[] = {
 	{ .compatible = QPNP_REVID_DEV_NAME },
 	{}
@@ -51,6 +65,35 @@
 	return val;
 }
 
+/**
+ * get_revid_data - Return the revision information of PMIC
+ * @dev_node: Pointer to the revid peripheral of the PMIC for which
+ *		revision information is seeked
+ *
+ * CONTEXT: Should be called in non atomic context
+ *
+ * RETURNS: pointer to struct pmic_revid_data filled with the information
+ *		about the PMIC revision
+ */
+struct pmic_revid_data *get_revid_data(struct device_node *dev_node)
+{
+	struct revid_chip *revid_chip;
+
+	if (!dev_node)
+		return ERR_PTR(-EINVAL);
+
+	mutex_lock(&revid_chips_lock);
+	list_for_each_entry(revid_chip, &revid_chips, link) {
+		if (dev_node == revid_chip->dev_node) {
+			mutex_unlock(&revid_chips_lock);
+			return &revid_chip->data;
+		}
+	}
+	mutex_unlock(&revid_chips_lock);
+	return ERR_PTR(-EINVAL);
+}
+EXPORT_SYMBOL(get_revid_data);
+
 #define PM8941_PERIPHERAL_SUBTYPE	0x01
 #define PM8226_PERIPHERAL_SUBTYPE	0x04
 static size_t build_pmic_string(char *buf, size_t n, int sid,
@@ -91,6 +134,7 @@
 	u8 option1, option2, option3, option4;
 	struct resource *resource;
 	char pmic_string[PMIC_STRING_MAXLENGTH] = {'\0'};
+	struct revid_chip *revid_chip;
 
 	resource = spmi_get_resource(spmi, NULL, IORESOURCE_MEM, 0);
 	if (!resource) {
@@ -111,6 +155,23 @@
 	pmic_subtype = qpnp_read_byte(spmi, resource->start + REVID_SUBTYPE);
 	pmic_status = qpnp_read_byte(spmi, resource->start + REVID_STATUS1);
 
+	revid_chip = devm_kzalloc(&spmi->dev, sizeof(struct revid_chip),
+						GFP_KERNEL);
+	if (!revid_chip)
+		return -ENOMEM;
+
+	revid_chip->dev_node = spmi->dev.of_node;
+	revid_chip->data.rev1 = rev1;
+	revid_chip->data.rev2 = rev2;
+	revid_chip->data.rev3 = rev3;
+	revid_chip->data.rev4 = rev4;
+	revid_chip->data.pmic_subtype = pmic_subtype;
+	revid_chip->data.pmic_type = pmic_type;
+
+	mutex_lock(&revid_chips_lock);
+	list_add(&revid_chip->link, &revid_chips);
+	mutex_unlock(&revid_chips_lock);
+
 	option1 = pmic_status & 0x3;
 	option2 = (pmic_status >> 2) & 0x3;
 	option3 = (pmic_status >> 4) & 0x3;
diff --git a/drivers/platform/msm/sps/sps.c b/drivers/platform/msm/sps/sps.c
index 6ccfd29..4f10cf8 100644
--- a/drivers/platform/msm/sps/sps.c
+++ b/drivers/platform/msm/sps/sps.c
@@ -81,6 +81,7 @@
 
 u32 d_type;
 bool enhd_pipe;
+bool imem;
 
 static void sps_device_de_init(void);
 
@@ -2430,13 +2431,16 @@
 
 	resource = platform_get_resource(pdev, IORESOURCE_MEM, 2);
 	if (resource) {
+		imem = true;
 		sps->pipemem_phys_base = resource->start;
 		sps->pipemem_size = resource_size(resource);
 		SPS_DBG("sps:pipemem.base=0x%x,size=0x%x.",
 			sps->pipemem_phys_base,
 			sps->pipemem_size);
-	} else
+	} else {
+		imem = false;
 		SPS_DBG("sps:No pipe memory on this target.\n");
+	}
 
 	resource  = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
 	if (resource) {
diff --git a/drivers/platform/msm/sps/sps_mem.c b/drivers/platform/msm/sps/sps_mem.c
index faa1618..34a2001 100644
--- a/drivers/platform/msm/sps/sps_mem.c
+++ b/drivers/platform/msm/sps/sps_mem.c
@@ -109,7 +109,7 @@
 	/* 2^8=128. The desc-fifo and data-fifo minimal allocation. */
 	int min_alloc_order = 8;
 
-	if ((d_type == 0) || (d_type == 2)) {
+	if ((d_type == 0) || (d_type == 2) || imem) {
 		iomem_phys = pipemem_phys_base;
 		iomem_size = pipemem_size;
 
@@ -136,7 +136,7 @@
 		return -ENOMEM;
 	}
 
-	if ((d_type == 0) || (d_type == 2)) {
+	if ((d_type == 0) || (d_type == 2) || imem) {
 		res = gen_pool_add(pool, (u32) iomem_virt, iomem_size, nid);
 		if (res)
 			return res;
diff --git a/drivers/platform/msm/sps/spsi.h b/drivers/platform/msm/sps/spsi.h
index f65fef7..353ece6 100644
--- a/drivers/platform/msm/sps/spsi.h
+++ b/drivers/platform/msm/sps/spsi.h
@@ -50,6 +50,7 @@
 
 extern u32 d_type;
 extern bool enhd_pipe;
+extern bool imem;
 
 #ifdef CONFIG_DEBUG_FS
 extern u8 debugfs_record_enabled;
diff --git a/drivers/platform/msm/ssm.c b/drivers/platform/msm/ssm.c
index 3afb954..1544b14 100644
--- a/drivers/platform/msm/ssm.c
+++ b/drivers/platform/msm/ssm.c
@@ -23,7 +23,6 @@
 #include <linux/mutex.h>
 #include <linux/ion.h>
 #include <linux/types.h>
-#include <linux/firmware.h>
 #include <linux/elf.h>
 #include <linux/platform_device.h>
 #include <linux/msm_ion.h>
@@ -31,45 +30,33 @@
 #include <mach/scm.h>
 #include <mach/msm_smd.h>
 
+#include "qseecom_kernel.h"
 #include "ssm.h"
 
 /* Macros */
 #define SSM_DEV_NAME			"ssm"
 #define MPSS_SUBSYS			0
 #define SSM_INFO_CMD_ID			1
-#define QSEOS_CHECK_VERSION_CMD		0x00001803
-
 #define MAX_APP_NAME_SIZE		32
-#define SSM_MSG_LEN			(104  + 4) /* bytes + pad */
+#define SSM_MSG_LEN			200
 #define SSM_MSG_FIELD_LEN		11
-#define SSM_HEADER_LEN			(SSM_MSG_FIELD_LEN * 4)
-#define ATOM_MSG_LEN			(SSM_HEADER_LEN + SSM_MSG_LEN)
-#define FIRMWARE_NAME			"ssmapp"
-#define TZAPP_NAME			"SsmApp"
-#define CHANNEL_NAME			"SSM_RTR"
+#define ATOM_MSG_LEN			(SSM_MSG_FIELD_LEN + SSM_MSG_LEN + 40)
 
-#define ALIGN_BUFFER(size)		((size + 4095) & ~4095)
+#define TZAPP_NAME			"SsmApp"
+#define CHANNEL_NAME			"SSM_RTR_MODEM_APPS"
 
 /* SSM driver structure.*/
 struct ssm_driver {
-	int32_t app_id;
 	int32_t app_status;
 	int32_t update_status;
-	int32_t atom_replay;
-	int32_t mtoa_replay;
-	uint32_t buff_len;
 	unsigned char *channel_name;
 	unsigned char *smd_buffer;
-	struct ion_client *ssm_ion_client;
-	struct ion_handle *ssm_ion_handle;
-	struct tzapp_get_mode_info_rsp *resp;
 	struct device *dev;
 	smd_channel_t *ch;
-	ion_phys_addr_t buff_phys;
-	void *buff_virt;
-	dev_t ssm_device_no;
 	struct work_struct ipc_work;
 	struct mutex mutex;
+	struct qseecom_handle *qseecom_handle;
+	struct tzapp_get_mode_info_rsp *resp;
 	bool key_status;
 	bool ready;
 };
@@ -87,32 +74,45 @@
 }
 
 /*
+ * Setup CMD/RSP pointers.
+ */
+static void setup_cmd_rsp_buffers(struct qseecom_handle *handle, void **cmd,
+		int *cmd_len, void **resp, int *resp_len)
+{
+	*cmd = handle->sbuf;
+	if (*cmd_len & QSEECOM_ALIGN_MASK)
+		*cmd_len = QSEECOM_ALIGN(*cmd_len);
+
+	*resp = handle->sbuf + *cmd_len;
+	if (*resp_len & QSEECOM_ALIGN_MASK)
+		*resp_len = QSEECOM_ALIGN(*resp_len);
+}
+
+/*
  * Send packet to modem over SMD channel.
  */
 static int update_modem(enum ssm_ipc_req ipc_req, struct ssm_driver *ssm,
 		int length, char *data)
 {
-	unsigned int packet_len = SSM_HEADER_LEN + length + 1;
-	int rc = 0;
+	unsigned int packet_len = length + SSM_MSG_FIELD_LEN;
+	int rc = 0, count;
 
-	ssm->atom_replay += 1;
-	snprintf(ssm->smd_buffer, SSM_HEADER_LEN + 1, "%10u|%10u|%10u|%10u|"
-			, packet_len, ssm->atom_replay, ipc_req, length);
-	memcpy(ssm->smd_buffer + SSM_HEADER_LEN, data, length);
-
-	ssm->smd_buffer[packet_len - 1] = '|';
+	snprintf(ssm->smd_buffer, SSM_MSG_FIELD_LEN + 1, "%10u|", ipc_req);
+	memcpy(ssm->smd_buffer + SSM_MSG_FIELD_LEN, data, length);
 
 	if (smd_write_avail(ssm->ch) < packet_len) {
 		dev_err(ssm->dev, "Not enough space dropping request\n");
 		rc = -ENOSPC;
+		goto out;
 	}
 
-	rc = smd_write(ssm->ch, ssm->smd_buffer, packet_len);
-	if (rc < packet_len) {
+	count = smd_write(ssm->ch, ssm->smd_buffer, packet_len);
+	if (count < packet_len) {
 		dev_err(ssm->dev, "smd_write failed for %d\n", ipc_req);
 		rc = -EIO;
 	}
 
+out:
 	return rc;
 }
 
@@ -120,144 +120,44 @@
  * Header Format
  * Each member of header is of 10 byte (ASCII).
  * Each entry is separated by '|' delimiter.
- * |<-10 bytes->|<-10 bytes->|<-10 bytes->|<-10 bytes->|<-10 bytes->|
- * |-----------------------------------------------------------------
- * | length     | replay no. | request    | msg_len    | message    |
- * |-----------------------------------------------------------------
+ * |<-10 bytes->|<-10 bytes->|
+ * |-------------------------|
+ * | IPC code   | error code |
+ * |-------------------------|
  *
  */
-static int  decode_header(char *buffer, int length,
-		struct ssm_common_msg *pkt)
+static int decode_packet(char *buffer, struct ssm_common_msg *pkt)
 {
 	int rc;
 
-	rc =  getint(buffer, &pkt->pktlen);
-	if (rc < 0)
-		return -EINVAL;
-
-	buffer += SSM_MSG_FIELD_LEN;
-	rc =  getint(buffer, &pkt->replaynum);
-	if (rc < 0)
-		return -EINVAL;
-
-	buffer += SSM_MSG_FIELD_LEN;
 	rc =  getint(buffer, (unsigned long *)&pkt->ipc_req);
 	if (rc < 0)
 		return -EINVAL;
 
 	buffer += SSM_MSG_FIELD_LEN;
-	rc =  getint(buffer, &pkt->msg_len);
-	if ((rc < 0) || (pkt->msg_len > SSM_MSG_LEN))
+	rc =  getint(buffer, (unsigned long *)&pkt->err_code);
+	if (rc < 0)
 		return -EINVAL;
 
-	pkt->msg = buffer + SSM_MSG_FIELD_LEN;
-
-	dev_dbg(ssm_drv->dev, "len %lu rep %lu req %d msg_len %lu\n",
-			pkt->pktlen, pkt->replaynum, pkt->ipc_req,
-			pkt->msg_len);
+	dev_dbg(ssm_drv->dev, "req %d error code %d\n",
+			pkt->ipc_req, pkt->err_code);
 	return 0;
 }
 
-/*
- * Decode address for storing the decryption key.
- * Only for Key Exchange
- * Message Format
- * |Length@Address|
- */
-static int decode_message(char *msg, unsigned int len, unsigned long *length,
-		unsigned long *address)
+static void process_message(struct ssm_common_msg pkt, struct ssm_driver *ssm)
 {
-	int i = 0, rc = 0;
-	char *buff;
 
-	buff = kzalloc(len, GFP_KERNEL);
-	if (!buff)
-		return -ENOMEM;
-	while (i < len) {
-		if (msg[i] == '@')
-			break;
-		i++;
-	}
-	if ((i < len) && (msg[i] == '@')) {
-		memcpy(buff, msg, i);
-		buff[i] = '\0';
-		rc = kstrtoul(skip_spaces(buff), 10, length);
-		if (rc || (length <= 0)) {
-			rc = -EINVAL;
-			goto exit;
-		}
-		memcpy(buff, &msg[i + 1], len - (i + 1));
-		buff[len - i] = '\0';
-		rc = kstrtoul(skip_spaces(buff), 10, address);
-	} else
-		rc = -EINVAL;
-
-exit:
-	kfree(buff);
-	return rc;
-}
-
-static void process_message(int cmd, char *msg, int len,
-		struct ssm_driver *ssm)
-{
-	int rc;
-	unsigned long key_len = 0, key_add = 0, val;
-	struct ssm_keyexchg_req req;
-
-	switch (cmd) {
-	case SSM_MTOA_KEY_EXCHANGE:
-		if (len < 3) {
-			dev_err(ssm->dev, "Invalid message\n");
-			break;
-		}
-
-		if (ssm->key_status) {
-			dev_err(ssm->dev, "Key exchange already done\n");
-			break;
-		}
-
-		rc = decode_message(msg, len, &key_len, &key_add);
-		if (rc) {
-			rc = update_modem(SSM_ATOM_KEY_STATUS, ssm,
-					1, "1");
-			break;
-		}
-
-		/*
-		 * We are doing key-exchange part here as it is very
-		 * specific for this case. For all other tz
-		 * communication we have generic function.
-		 */
-		req.ssid = MPSS_SUBSYS;
-		req.address = (void *)key_add;
-		req.length = key_len;
-		req.status = (uint32_t *)ssm->buff_phys;
-
-		*(unsigned int *)ssm->buff_virt = -1;
-		rc = scm_call(KEY_EXCHANGE, 0x1, &req,
-				sizeof(struct ssm_keyexchg_req), NULL, 0);
-		if (rc) {
-			dev_err(ssm->dev, "Call for key exchg failed %d", rc);
-			rc = update_modem(SSM_ATOM_KEY_STATUS, ssm,
-								1, "1");
-		} else {
-			/* Success encode packet and update modem */
-			rc = update_modem(SSM_ATOM_KEY_STATUS, ssm,
-					1, "0");
-			ssm->key_status = true;
-		}
-		break;
+	switch (pkt.ipc_req) {
 
 	case SSM_MTOA_MODE_UPDATE_STATUS:
-		msg[len] = '\0';
-		rc = kstrtoul(skip_spaces(msg), 10, &val);
-		if (val) {
+		if (pkt.err_code) {
 			dev_err(ssm->dev, "Modem mode update failed\n");
 			ssm->update_status = FAILED;
 		} else
 			ssm->update_status = SUCCESS;
 
-		dev_dbg(ssm->dev, "Modem mode update status %lu\n", val);
+		dev_dbg(ssm->dev, "Modem mode update status %d\n",
+								pkt.err_code);
 		break;
 
 	default:
@@ -279,7 +179,7 @@
 
 	mutex_lock(&ssm->mutex);
 	sz = smd_cur_packet_size(ssm->ch);
-	if ((sz <= 0) || (sz > ATOM_MSG_LEN)) {
+	if ((sz < SSM_MSG_FIELD_LEN) || (sz > ATOM_MSG_LEN)) {
 		dev_dbg(ssm_drv->dev, "Garbled message size\n");
 		goto unlock;
 	}
@@ -289,35 +189,18 @@
 		goto unlock;
 	}
 
-	if (sz < SSM_HEADER_LEN) {
-		dev_err(ssm_drv->dev, "Invalid packet\n");
-		goto unlock;
-	}
-
 	if (smd_read(ssm->ch, ssm->smd_buffer, sz) != sz) {
 		dev_err(ssm_drv->dev, "Incomplete data\n");
 		goto unlock;
 	}
 
-	rc = decode_header(ssm->smd_buffer, sz, &pkt);
+	rc = decode_packet(ssm->smd_buffer, &pkt);
 	if (rc < 0) {
 		dev_err(ssm_drv->dev, "Corrupted header\n");
 		goto unlock;
 	}
 
-	/* Check validity of message */
-	if (ssm->mtoa_replay >= (int)pkt.replaynum) {
-		dev_err(ssm_drv->dev, "Replay attack...\n");
-		goto unlock;
-	}
-
-	if (pkt.msg[pkt.msg_len] != '|') {
-		dev_err(ssm_drv->dev, "Garbled message\n");
-		goto unlock;
-	}
-
-	ssm->mtoa_replay = pkt.replaynum;
-	process_message(pkt.ipc_req, pkt.msg, pkt.msg_len, ssm);
+	process_message(pkt, ssm);
 
 unlock:
 	mutex_unlock(&ssm->mutex);
@@ -335,8 +218,7 @@
 	switch (event) {
 	case SMD_EVENT_OPEN:
 	case SMD_EVENT_CLOSE:
-		dev_info(ssm->dev, "Port %s\n",
-			(event == SMD_EVENT_OPEN) ? "opened" : "closed");
+		dev_dbg(ssm->dev, "SMD port status changed\n");
 		break;
 	case SMD_EVENT_DATA:
 		if (smd_read_avail(ssm->ch) > 0)
@@ -346,280 +228,22 @@
 }
 
 /*
- * Communication interface between ssm driver and TZ.
- */
-static int tz_scm_call(struct ssm_driver *ssm, void *tz_req, int tz_req_len,
-			void **tz_resp, int tz_resp_len)
-{
-	int rc;
-	struct common_req req;
-	struct common_resp resp;
-
-	memcpy((void *)ssm->buff_virt, tz_req, tz_req_len);
-
-	req.cmd_id = CLIENT_SEND_DATA_COMMAND;
-	req.app_id = ssm->app_id;
-	req.req_ptr = (void *)ssm->buff_phys;
-	req.req_len = tz_req_len;
-	req.resp_ptr = (void *)(ssm->buff_phys + tz_req_len);
-	req.resp_len = tz_resp_len;
-
-	rc = scm_call(SCM_SVC_TZSCHEDULER, 1, (const void *) &req,
-			sizeof(req), (void *)&resp, sizeof(resp));
-	if (rc) {
-		dev_err(ssm->dev, "SCM call failed for data command\n");
-		return rc;
-	}
-
-	if (resp.result != RESULT_SUCCESS) {
-		dev_err(ssm->dev, "Data command response failure %d\n",
-				resp.result);
-		return -EINVAL;
-	}
-
-	*tz_resp = (void *)(ssm->buff_virt + tz_req_len);
-
-	return rc;
-}
-
-/*
  * Load SSM application in TZ and start application:
- * 1. Check if SSM application is already loaded.
- * 2. Load SSM application firmware.
- * 3. Start SSM application in TZ.
  */
 static int ssm_load_app(struct ssm_driver *ssm)
 {
-	unsigned char name[MAX_APP_NAME_SIZE], *pos;
-	int rc, i, fw_count;
-	uint32_t buff_len, size = 0, ion_len;
-	struct check_app_req app_req;
-	struct scm_resp app_resp;
-	struct load_app app_img_info;
-	const struct firmware **fw, *fw_mdt;
-	const struct elf32_hdr *ehdr;
-	const struct elf32_phdr *phdr;
-	struct ion_handle *ion_handle;
-	ion_phys_addr_t buff_phys;
-	void *buff_virt;
+	int rc;
 
-	/* Check if TZ app already loaded */
-	app_req.cmd_id = APP_LOOKUP_COMMAND;
-	memcpy(app_req.app_name, TZAPP_NAME, MAX_APP_NAME_SIZE);
-
-	rc = scm_call(SCM_SVC_TZSCHEDULER, 1, &app_req,
-				sizeof(struct check_app_req),
-				&app_resp, sizeof(app_resp));
-	if (rc) {
-		dev_err(ssm->dev, "SCM call failed for LOOKUP COMMAND\n");
-		return -EINVAL;
-	}
-
-	if (app_resp.result == RESULT_FAILURE)
-		ssm->app_id = 0;
-	else
-		ssm->app_id = app_resp.data;
-
-	if (ssm->app_id) {
-		rc = 0;
-		dev_info(ssm->dev, "TZAPP already loaded...\n");
-		goto out;
-	}
-
-	/* APP not loaded get the firmware */
-	/* Get .mdt first */
-	rc =  request_firmware(&fw_mdt, FIRMWARE_NAME".mdt", ssm->dev);
-	if (rc) {
-		dev_err(ssm->dev, "Unable to get mdt file %s\n",
-						FIRMWARE_NAME".mdt");
-		rc = -EIO;
-		goto out;
-	}
-
-	if (fw_mdt->size < sizeof(*ehdr)) {
-		dev_err(ssm->dev, "Not big enough to be an elf header\n");
-		rc = -EIO;
-		goto release_mdt;
-	}
-
-	ehdr = (struct elf32_hdr *)fw_mdt->data;
-	if (memcmp(ehdr->e_ident, ELFMAG, SELFMAG)) {
-		dev_err(ssm->dev, "Not an elf header\n");
-		rc = -EIO;
-		goto release_mdt;
-	}
-
-	if (ehdr->e_phnum == 0) {
-		dev_err(ssm->dev, "No loadable segments\n");
-		rc = -EIO;
-		goto release_mdt;
-	}
-
-	phdr = (const struct elf32_phdr *)(fw_mdt->data +
-					sizeof(struct elf32_hdr));
-
-	fw = kzalloc((sizeof(struct firmware *) * ehdr->e_phnum), GFP_KERNEL);
-	if (!fw) {
-		rc = -ENOMEM;
-		goto release_mdt;
-	}
-
-	/* Valid .mdt now we need to load other parts .b0* */
-	for (fw_count = 0; fw_count < ehdr->e_phnum ; fw_count++) {
-		snprintf(name, MAX_APP_NAME_SIZE, FIRMWARE_NAME".b%02d",
-								fw_count);
-		rc = request_firmware(&fw[fw_count], name, ssm->dev);
-		if (rc < 0) {
-			rc = -EIO;
-			dev_err(ssm->dev, "Unable to get blob file\n");
-			goto release_blob;
-		}
-
-		if (fw[fw_count]->size != phdr->p_filesz) {
-			dev_err(ssm->dev, "Blob size %u doesn't match %u\n",
-					fw[fw_count]->size, phdr->p_filesz);
-			rc = -EIO;
-			goto release_blob;
-		}
-
-		phdr++;
-		size += fw[fw_count]->size;
-	}
-
-	/* Ion allocation for loading tzapp */
-	/* ION buffer size 4k aligned */
-	ion_len = ALIGN_BUFFER(size);
-	ion_handle = ion_alloc(ssm_drv->ssm_ion_client,
-			ion_len, SZ_4K, ION_HEAP(ION_QSECOM_HEAP_ID), 0);
-	if (IS_ERR_OR_NULL(ion_handle)) {
-		rc = PTR_ERR(ion_handle);
-		dev_err(ssm->dev, "Unable to get ion handle\n");
-		goto release_blob;
-	}
-
-	rc = ion_phys(ssm_drv->ssm_ion_client, ion_handle,
-			&buff_phys, &buff_len);
+	/* Load the APP */
+	rc = qseecom_start_app(&ssm->qseecom_handle, TZAPP_NAME, SZ_4K);
 	if (rc < 0) {
-		dev_err(ssm->dev, "Unable to get ion physical address\n");
-		goto ion_free;
+		dev_err(ssm->dev, "Unable to load SSM app\n");
+		ssm->app_status = FAILED;
+		return -EIO;
 	}
 
-	if (buff_len < size) {
-		rc = -ENOMEM;
-		goto ion_free;
-	}
-
-	buff_virt = ion_map_kernel(ssm_drv->ssm_ion_client,
-				ion_handle);
-	if (IS_ERR_OR_NULL((void *)buff_virt)) {
-		rc = PTR_ERR((void *)buff_virt);
-		dev_err(ssm->dev, "Unable to get ion virtual address\n");
-		goto ion_free;
-	}
-
-	/* Copy firmware to ION memory */
-	memcpy((unsigned char *)buff_virt, fw_mdt->data, fw_mdt->size);
-	pos = (unsigned char *)buff_virt + fw_mdt->size;
-	for (i = 0; i < ehdr->e_phnum; i++) {
-		memcpy(pos, fw[i]->data, fw[i]->size);
-		pos += fw[i]->size;
-	}
-
-	/* Loading app */
-	app_img_info.cmd_id = APP_START_COMMAND;
-	app_img_info.mdt_len = fw_mdt->size;
-	app_img_info.img_len = size;
-	app_img_info.phy_addr = buff_phys;
-
-	/* SCM call to load the TZ APP */
-	rc = scm_call(SCM_SVC_TZSCHEDULER, 1, &app_img_info,
-		sizeof(struct load_app), &app_resp, sizeof(app_resp));
-	if (rc) {
-		rc = -EIO;
-		dev_err(ssm->dev, "SCM call to load APP failed\n");
-		goto ion_unmap;
-	}
-
-	if (app_resp.result == RESULT_FAILURE) {
-		rc = -EIO;
-		dev_err(ssm->dev, "SCM command to load TzAPP failed\n");
-		goto ion_unmap;
-	}
-
-	ssm->app_id = app_resp.data;
 	ssm->app_status = SUCCESS;
-
-ion_unmap:
-	ion_unmap_kernel(ssm_drv->ssm_ion_client, ion_handle);
-ion_free:
-	ion_free(ssm_drv->ssm_ion_client, ion_handle);
-release_blob:
-	while (--fw_count >= 0)
-		release_firmware(fw[fw_count]);
-	kfree(fw);
-release_mdt:
-	release_firmware(fw_mdt);
-out:
-	return rc;
-}
-
-/*
- * Allocate buffer for transactions.
- */
-static int ssm_setup_ion(struct ssm_driver *ssm)
-{
-	int rc = 0;
-	unsigned int size;
-
-	size = ALIGN_BUFFER(ATOM_MSG_LEN);
-
-	/* ION client for communicating with TZ */
-	ssm->ssm_ion_client = msm_ion_client_create(UINT_MAX,
-							"ssm-kernel");
-	if (IS_ERR_OR_NULL(ssm->ssm_ion_client)) {
-		rc = PTR_ERR(ssm->ssm_ion_client);
-		dev_err(ssm->dev, "Ion client not created\n");
-		return rc;
-	}
-
-	/* Setup a small ION buffer for tz communication */
-	ssm->ssm_ion_handle = ion_alloc(ssm->ssm_ion_client,
-				size, SZ_4K, ION_HEAP(ION_QSECOM_HEAP_ID), 0);
-	if (IS_ERR_OR_NULL(ssm->ssm_ion_handle)) {
-		rc = PTR_ERR(ssm->ssm_ion_handle);
-		dev_err(ssm->dev, "Unable to get ion handle\n");
-		goto out;
-	}
-
-	rc = ion_phys(ssm->ssm_ion_client, ssm->ssm_ion_handle,
-			&ssm->buff_phys, &ssm->buff_len);
-	if (rc < 0) {
-		dev_err(ssm->dev,
-			"Unable to get ion buffer physical address\n");
-		goto ion_free;
-	}
-
-	if (ssm->buff_len < size) {
-		rc = -ENOMEM;
-		goto ion_free;
-	}
-
-	ssm->buff_virt = ion_map_kernel(ssm->ssm_ion_client,
-				ssm->ssm_ion_handle);
-	if (IS_ERR_OR_NULL((void *)ssm->buff_virt)) {
-		rc = PTR_ERR((void *)ssm->buff_virt);
-		dev_err(ssm->dev,
-			"Unable to get ion buffer virtual address\n");
-		goto ion_free;
-	}
-
-	return rc;
-
-ion_free:
-	ion_free(ssm->ssm_ion_client, ssm->ssm_ion_handle);
-out:
-	ion_client_destroy(ssm_drv->ssm_ion_client);
-	return rc;
+	return 0;
 }
 
 static struct ssm_platform_data *populate_ssm_pdata(struct device *dev)
@@ -649,8 +273,6 @@
 static int __devinit ssm_probe(struct platform_device *pdev)
 {
 	int rc;
-	uint32_t system_call_id;
-	char legacy = '\0';
 	struct ssm_platform_data *pdata;
 	struct ssm_driver *drv;
 
@@ -671,10 +293,16 @@
 		return -ENOMEM;
 	}
 
+	/* Allocate response buffer */
+	drv->resp = devm_kzalloc(&pdev->dev,
+			sizeof(struct tzapp_get_mode_info_rsp),
+			GFP_KERNEL);
+	if (!drv->resp) {
+		rc = -ENOMEM;
+		goto exit;
+	}
+
 	/* Initialize the driver structure */
-	drv->atom_replay = -1;
-	drv->mtoa_replay = -1;
-	drv->app_id = -1;
 	drv->app_status = RETRY;
 	drv->ready = false;
 	drv->update_status = FAILED;
@@ -691,40 +319,6 @@
 		goto exit;
 	}
 
-	/* Allocate response buffer */
-	drv->resp = devm_kzalloc(&pdev->dev,
-				sizeof(struct tzapp_get_mode_info_rsp),
-				GFP_KERNEL);
-	if (!drv->resp) {
-		rc = -ENOMEM;
-		goto exit;
-	}
-
-
-	/* Check for TZ version */
-	system_call_id = QSEOS_CHECK_VERSION_CMD;
-	rc = scm_call(SCM_SVC_INFO, SSM_INFO_CMD_ID, &system_call_id,
-			sizeof(system_call_id), &legacy, sizeof(legacy));
-	if (rc) {
-		dev_err(&pdev->dev, "Get version failed %d\n", rc);
-		rc = -EINVAL;
-		goto exit;
-	}
-
-	/* This driver only support 1.4 TZ and QSEOS */
-	if (!legacy) {
-		dev_err(&pdev->dev,
-				"Driver doesn't support legacy version\n");
-		rc = -EINVAL;
-		goto exit;
-
-	}
-
-	/* Setup the ion buffer for transaction */
-	rc = ssm_setup_ion(drv);
-	if (rc < 0)
-		goto exit;
-
 	drv->dev = &pdev->dev;
 	ssm_drv = drv;
 	platform_set_drvdata(pdev, ssm_drv);
@@ -741,10 +335,6 @@
 
 static int __devexit ssm_remove(struct platform_device *pdev)
 {
-	int rc;
-
-	struct scm_shutdown_req req;
-	struct scm_resp resp;
 
 	if (!ssm_drv)
 		return 0;
@@ -758,20 +348,11 @@
 	smd_close(ssm_drv->ch);
 	flush_work_sync(&ssm_drv->ipc_work);
 
-	/* ION clean up*/
-	ion_unmap_kernel(ssm_drv->ssm_ion_client, ssm_drv->ssm_ion_handle);
-	ion_free(ssm_drv->ssm_ion_client, ssm_drv->ssm_ion_handle);
-	ion_client_destroy(ssm_drv->ssm_ion_client);
-
 	/* Shutdown tzapp */
-	req.app_id = ssm_drv->app_id;
-	req.cmd_id = APP_SHUTDOWN_COMMAND;
-	rc = scm_call(SCM_SVC_TZSCHEDULER, 1, &req, sizeof(req),
-			&resp, sizeof(resp));
-	if (rc)
-		dev_err(&pdev->dev, "TZ_app Unload failed\n");
+	dev_dbg(&pdev->dev, "Shutting down TZapp\n");
+	qseecom_shutdown_app(&ssm_drv->qseecom_handle);
 
-	return rc;
+	return 0;
 }
 
 static struct of_device_id ssm_match_table[] = {
@@ -795,17 +376,15 @@
 /*
  * Interface for external OEM driver.
  * This interface supports following functionalities:
- * 1. Get TZAPP ID.
- * 2. Set default mode.
- * 3. Set mode (encrypted mode and it's length is passed as parameter).
- * 4. Set mode from TZ.
- * 5. Get status of mode update.
+ * 1. Set mode (encrypted mode and it's length is passed as parameter).
+ * 2. Set mode from TZ (read encrypted mode from TZ)
+ * 3. Get status of mode update.
  *
  */
 int ssm_oem_driver_intf(int cmd, char *mode, int len)
 {
 	int rc, req_len, resp_len;
-	struct tzapp_get_mode_info_req get_mode_req;
+	struct tzapp_get_mode_info_req *get_mode_req;
 	struct tzapp_get_mode_info_rsp *get_mode_resp;
 
 	/* If ssm_drv is NULL, probe failed */
@@ -819,7 +398,6 @@
 		rc = ssm_load_app(ssm_drv);
 		if (rc) {
 			rc = -ENODEV;
-			ssm_drv->app_status = FAILED;
 			goto unlock;
 		}
 	} else if (ssm_drv->app_status == FAILED) {
@@ -851,23 +429,43 @@
 	case SSM_READY:
 		break;
 
-	case SSM_GET_APP_ID:
-		rc = ssm_drv->app_id;
-		break;
-
 	case SSM_MODE_INFO_READY:
 		ssm_drv->update_status = RETRY;
 		/* Fill command structure */
 		req_len = sizeof(struct tzapp_get_mode_info_req);
 		resp_len = sizeof(struct tzapp_get_mode_info_rsp);
-		get_mode_req.tzapp_ssm_cmd = GET_ENC_MODE;
-		rc = tz_scm_call(ssm_drv, (void *)&get_mode_req,
-				req_len, (void **)&get_mode_resp, resp_len);
+		setup_cmd_rsp_buffers(ssm_drv->qseecom_handle,
+				(void **)&get_mode_req, &req_len,
+				(void **)&get_mode_resp, &resp_len);
+		get_mode_req->tzapp_ssm_cmd = GET_ENC_MODE;
+
+		rc = qseecom_set_bandwidth(ssm_drv->qseecom_handle, 1);
 		if (rc) {
 			ssm_drv->update_status = FAILED;
+			dev_err(ssm_drv->dev, "set bandwidth failed\n");
+			rc = -EIO;
+			break;
+		}
+		rc = qseecom_send_command(ssm_drv->qseecom_handle,
+				(void *)get_mode_req, req_len,
+				(void *)get_mode_resp, resp_len);
+		if (rc || get_mode_resp->status) {
+			ssm_drv->update_status = FAILED;
 			break;
 		}
+		rc = qseecom_set_bandwidth(ssm_drv->qseecom_handle, 0);
+		if (rc) {
+			ssm_drv->update_status = FAILED;
+			dev_err(ssm_drv->dev, "clear bandwidth failed\n");
+			rc = -EIO;
+			break;
+		}
 
+		if (get_mode_resp->enc_mode_len > ENC_MODE_MAX_SIZE) {
+			ssm_drv->update_status = FAILED;
+			rc = -EINVAL;
+			break;
+		}
 		/* Send mode_info to modem */
 		rc = update_modem(SSM_ATOM_MODE_UPDATE, ssm_drv,
 				get_mode_resp->enc_mode_len,
@@ -899,19 +497,6 @@
 		rc = ssm_drv->update_status;
 		break;
 
-	case SSM_SET_DEFAULT_MODE:
-		/* Modem does not send response for this */
-		ssm_drv->update_status = RETRY;
-		rc = update_modem(SSM_ATOM_SET_DEFAULT_MODE, ssm_drv,
-				1, "0");
-		if (rc)
-			ssm_drv->update_status = FAILED;
-		else
-			/* For default mode we don't get any resp
-			 * from modem.
-			 */
-			ssm_drv->update_status = SUCCESS;
-		break;
 	default:
 		rc = -EINVAL;
 		dev_err(ssm_drv->dev, "Invalid command\n");
diff --git a/drivers/platform/msm/ssm.h b/drivers/platform/msm/ssm.h
index 97add11..dcda1387 100644
--- a/drivers/platform/msm/ssm.h
+++ b/drivers/platform/msm/ssm.h
@@ -14,8 +14,7 @@
 #define __SSM_H_
 
 #define MAX_APP_NAME_SIZE	32
-#define MODE_INFO_MAX_SIZE	4
-#define ENC_MODE_MAX_SIZE	(100 + MODE_INFO_MAX_SIZE)
+#define ENC_MODE_MAX_SIZE	200
 
 /* tzapp response.*/
 enum tz_response {
@@ -30,35 +29,20 @@
 	KEY_EXCHANGE = 11,
 };
 
-/* Command list for QSEOS.*/
-enum qceos_cmd_id {
-	APP_START_COMMAND = 0x01,
-	APP_SHUTDOWN_COMMAND,
-	APP_LOOKUP_COMMAND,
-	CLIENT_SEND_DATA_COMMAND = 0x6,
-	QSEOS_CMD_MAX = 0xEFFFFFFF,
-};
-
 /* MODEM/SSM command list.*/
 enum ssm_ipc_req {
-	SSM_MTOA_KEY_EXCHANGE = 0x0000AAAA,
-	SSM_ATOM_KEY_STATUS,
+	SSM_IPC_MIN = 0x0000AAAB,
 	SSM_ATOM_MODE_UPDATE,
-	SSM_MTOA_MODE_UPDATE_STATUS,
-	SSM_MTOA_PREV_INVALID,
-	SSM_ATOM_PREV_INVALID,
-	SSM_ATOM_SET_DEFAULT_MODE,
+	SSM_MTOA_MODE_UPDATE_STATUS = SSM_IPC_MIN + 4,
 	SSM_INVALID_REQ,
 };
 
 /* OEM reuest commands list.*/
 enum oem_req {
 	SSM_READY,
-	SSM_GET_APP_ID,
 	SSM_MODE_INFO_READY,
 	SSM_SET_MODE,
 	SSM_GET_MODE_STATUS,
-	SSM_SET_DEFAULT_MODE,
 	SSM_INVALID,
 };
 
@@ -69,33 +53,6 @@
 	FAILED = -1,
 };
 
-__packed struct load_app {
-	uint32_t cmd_id;
-	uint32_t mdt_len;
-	uint32_t img_len;
-	uint32_t phy_addr;
-	char     app_name[MAX_APP_NAME_SIZE];
-};
-
-/* Stop tzapp reuest.*/
-__packed struct scm_shutdown_req {
-	uint32_t cmd_id;
-	uint32_t app_id;
-};
-
-/* Common tzos response.*/
-__packed struct scm_resp {
-	uint32_t result;
-	enum tz_response resp_type;
-	unsigned int data;
-};
-
-/* tzos request.*/
-__packed struct check_app_req {
-	uint32_t cmd_id;
-	char     app_name[MAX_APP_NAME_SIZE];
-};
-
 /* tzapp encode mode reuest.*/
 __packed struct tzapp_mode_enc_req {
 	uint32_t tzapp_ssm_cmd;
@@ -123,38 +80,11 @@
 	long status;
 };
 
-/* tzos key exchange request.*/
-__packed struct ssm_keyexchg_req {
-	uint32_t ssid;
-	void *address;
-	uint32_t length;
-	uint32_t *status;
-};
-
-/* tzos common request.*/
-__packed struct common_req {
-	uint32_t cmd_id;
-	uint32_t app_id;
-	void *req_ptr;
-	uint32_t req_len;
-	void *resp_ptr;
-	uint32_t resp_len;
-};
-
-/* tzos common response.*/
-__packed struct common_resp {
-	uint32_t result;
-	uint32_t type;
-	uint32_t data;
-};
-
 /* Modem/SSM packet format.*/
 struct ssm_common_msg {
-	unsigned long pktlen;
-	unsigned long replaynum;
 	enum ssm_ipc_req ipc_req;
-	unsigned long msg_len;
-	char *msg;
+	int err_code;
+
 };
 
 #endif
diff --git a/drivers/platform/msm/usb_bam.c b/drivers/platform/msm/usb_bam.c
index 408681c..4be727f 100644
--- a/drivers/platform/msm/usb_bam.c
+++ b/drivers/platform/msm/usb_bam.c
@@ -162,6 +162,11 @@
 	struct work_struct finish_suspend_work;
 };
 
+struct usb_bam_hsic_host_info {
+	struct device *dev;
+	bool in_lpm;
+};
+
 static spinlock_t usb_bam_ipa_handshake_info_lock;
 static struct usb_bam_ipa_handshake_info info;
 static spinlock_t usb_bam_peer_handshake_info_lock;
@@ -169,8 +174,7 @@
 static spinlock_t usb_bam_lock; /* Protect ctx and usb_bam_connections */
 static struct usb_bam_pipe_connect *usb_bam_connections;
 static struct usb_bam_ctx_type ctx;
-
-static struct device *hsic_host_dev;
+static struct usb_bam_hsic_host_info hsic_host_info;
 
 static int __usb_bam_register_wake_cb(u8 idx, int (*callback)(void *user),
 	void *param, bool trigger_cb_per_pipe);
@@ -184,15 +188,16 @@
 		pr_debug("%s: Getting hsic device %x\n", __func__,
 			(int)dev);
 		pm_runtime_get(dev);
-	} else if (hsic_host_dev) {
+	} else if (hsic_host_info.dev) {
 		pr_debug("%s: Putting hsic device %x\n", __func__,
-			(int)hsic_host_dev);
+			(int)hsic_host_info.dev);
 		/* Just free previous device*/
 		info.in_lpm[HSIC_BAM] = true;
-		pm_runtime_put(hsic_host_dev);
+		pm_runtime_put(hsic_host_info.dev);
 	}
 
-	hsic_host_dev = dev;
+	hsic_host_info.dev = dev;
+	hsic_host_info.in_lpm = false;
 }
 
 static int get_bam_type_from_core_name(const char *name)
@@ -351,7 +356,7 @@
 		/*
 		 * Enable USB PRIVATE RAM to be used for BAM FIFOs
 		 * HSUSB: Only RAM13 is used for BAM FIFOs
-		 * SSUSB: RAM11, 12, 13 are used for BAM FIFOs
+		 * SSUSB: RAM12, 13 are used for BAM FIFOs
 		 */
 		bam = pipe_connect->bam_type;
 		if (bam < 0)
@@ -360,7 +365,7 @@
 		if (bam == HSUSB_BAM)
 			ram1_value = 0x4;
 		else
-			ram1_value = 0x7;
+			ram1_value = 0x6;
 
 		pr_debug("Writing 0x%x to QSCRATCH_RAM1\n", ram1_value);
 		writel_relaxed(ram1_value, ctx.qscratch_ram1_reg);
@@ -847,18 +852,24 @@
 	return;
 }
 
+/**
+ * usb_bam_resume_hsic_host: vote for hsic host core resume.
+ * In addition also resume all hsic pipes that are connected to
+ * the ipa peer bam.
+ *
+ * NOTE: This function should be called in a context that hold
+ *	 usb_bam_lock.
+ */
 static void usb_bam_resume_hsic_host(void)
 {
 	int i;
 	struct usb_bam_pipe_connect *pipe_iter;
 
-	spin_lock(&usb_bam_lock);
-
 	/* Exit from "full suspend" in case of hsic host */
-	if (hsic_host_dev && info.in_lpm[HSIC_BAM]) {
+	if (hsic_host_info.dev && info.in_lpm[HSIC_BAM]) {
 		pr_debug("%s: Getting hsic device %x\n", __func__,
-			(int)hsic_host_dev);
-		pm_runtime_get(hsic_host_dev);
+			(int)hsic_host_info.dev);
+		pm_runtime_get(hsic_host_info.dev);
 		info.in_lpm[HSIC_BAM] = false;
 
 		for (i = 0; i < ctx.max_connections; i++) {
@@ -873,8 +884,6 @@
 			}
 		}
 	}
-
-	spin_unlock(&usb_bam_lock);
 }
 
 static int cons_request_resource(enum usb_bam cur_bam)
@@ -905,16 +914,26 @@
 
 		break;
 	case HSIC_BAM:
+		/*
+		 * Vote for hsic resume, however the core
+		 * resume may not be completed yet or on the other hand
+		 * hsic core might already be resumed, due to a vote
+		 * by other driver, in this case we will just renew our
+		 * vote here.
+		 */
+		usb_bam_resume_hsic_host();
 
-			usb_bam_resume_hsic_host();
+		/*
+		 * Return sucess if there are pipes connected
+		 * and hsic core is actually not in lpm.
+		 * If in lpm, grant will occur on resume
+		 * finish (see msm_bam_hsic_notify_on_resume)
+		 */
+		if (ctx.pipes_enabled_per_bam[cur_bam] &&
+		    !hsic_host_info.in_lpm) {
+			ret = 0;
+		}
 
-			/*
-			 * Return sucess if there are pipes connected
-			 * and not in lpm
-			 */
-			if (ctx.pipes_enabled_per_bam[cur_bam] &&
-			    !info.in_lpm[cur_bam])
-				ret = 0;
 		break;
 	case SSUSB_BAM:
 	default:
@@ -926,6 +945,7 @@
 
 	if (ret == -EINPROGRESS)
 		pr_debug("%s: EINPROGRESS on cons_request", __func__);
+
 	return ret;
 }
 
@@ -968,10 +988,10 @@
 		 * Allow to go to lpm for now. Actual state will be checked
 		 * in msm_bam_hsic_lpm_ok() just before going to lpm.
 		 */
-		if (hsic_host_dev && !info.in_lpm[HSIC_BAM]) {
+		if (hsic_host_info.dev && !info.in_lpm[HSIC_BAM]) {
 			pr_debug("%s: Putting hsic device %x\n", __func__,
-			(int)hsic_host_dev);
-			pm_runtime_put(hsic_host_dev);
+			(int)hsic_host_info.dev);
+			pm_runtime_put(hsic_host_info.dev);
 			info.in_lpm[HSIC_BAM] = true;
 		}
 	}
@@ -1315,6 +1335,8 @@
 
 void msm_bam_wait_for_hsic_prod_granted(void)
 {
+	spin_lock(&usb_bam_lock);
+
 	ctx.is_bam_inactivity[HSIC_BAM] = false;
 
 	/* Get back to resume state including wakeup ipa */
@@ -1322,10 +1344,19 @@
 
 	/* Ensure getting the producer resource */
 	wait_for_prod_granted(HSIC_BAM);
+
+	spin_unlock(&usb_bam_lock);
 }
 
 void msm_bam_hsic_notify_on_resume(void)
 {
+	spin_lock(&usb_bam_lock);
+
+	hsic_host_info.in_lpm = false;
+
+	/* HSIC resume completed. Notify CONS grant if CONS was requested */
+	notify_usb_connected(HSIC_BAM);
+
 	/*
 	 * This function is called to notify the usb bam driver
 	 * that the hsic core and hsic bam hw are fully resumed
@@ -1334,6 +1365,8 @@
 	 */
 	if (ctx.inactivity_timer_ms[HSIC_BAM])
 		usb_bam_set_inactivity_timer(HSIC_BAM);
+
+	spin_unlock(&usb_bam_lock);
 }
 
 bool msm_bam_hsic_lpm_ok(void)
@@ -1341,7 +1374,7 @@
 	int i;
 	struct usb_bam_pipe_connect *pipe_iter;
 
-	if (hsic_host_dev) {
+	if (hsic_host_info.dev) {
 
 		pr_debug("%s: Starting hsic full suspend sequence\n",
 			__func__);
@@ -1363,7 +1396,7 @@
 
 			/* HSIC host will go now to lpm */
 			pr_debug("%s: vote for suspend hsic %x\n",
-				__func__, (int)hsic_host_dev);
+				__func__, (int)hsic_host_info.dev);
 
 			for (i = 0; i < ctx.max_connections; i++) {
 				pipe_iter =
@@ -1379,6 +1412,8 @@
 				}
 			}
 
+			hsic_host_info.in_lpm = true;
+
 			spin_unlock(&usb_bam_lock);
 			return true;
 		}
@@ -1392,7 +1427,7 @@
 				info.cur_cons_state[HSIC_BAM],
 				info.cur_prod_state[HSIC_BAM],
 				info.in_lpm[HSIC_BAM]);
-			pm_runtime_get(hsic_host_dev);
+			pm_runtime_get(hsic_host_info.dev);
 			info.in_lpm[HSIC_BAM] = false;
 			spin_unlock(&usb_bam_lock);
 		} else
@@ -1469,11 +1504,11 @@
 		sps_device_reset(ctx.h_bam[cur_bam]);
 
 		/* On re-connect assume out from lpm for HSIC BAM */
-		if (cur_bam == HSIC_BAM && hsic_host_dev &&
+		if (cur_bam == HSIC_BAM && hsic_host_info.dev &&
 		    info.in_lpm[HSIC_BAM]) {
 			pr_debug("%s: Getting hsic device %x\n",
-					__func__, (int)hsic_host_dev);
-			pm_runtime_get(hsic_host_dev);
+					__func__, (int)hsic_host_info.dev);
+			pm_runtime_get(hsic_host_info.dev);
 		}
 
 		/* On re-connect assume out from lpm for all BAMs */
@@ -1583,8 +1618,10 @@
 		 * until we complete releasing the hsic consumer and producer
 		 * resources against the ipa resource manager.
 		 */
+		spin_lock(&usb_bam_lock);
 		if (pipe_connect->bam_type == HSIC_BAM)
 			usb_bam_resume_hsic_host();
+		spin_unlock(&usb_bam_lock);
 
 		/* Notify about wakeup / activity of the bam */
 		if (event_info->callback)
@@ -1660,12 +1697,12 @@
 		 * If consumer is up, we will wait to the release consumer
 		 * notification.
 		 */
-		if (hsic_host_dev &&
+		if (hsic_host_info.dev &&
 		    info.cur_cons_state[HSIC_BAM] ==
 		    IPA_RM_RESOURCE_RELEASED && !info.in_lpm[HSIC_BAM]) {
 			pr_debug("%s: Putting hsic device %x\n", __func__,
-			(int)hsic_host_dev);
-			pm_runtime_put(hsic_host_dev);
+			(int)hsic_host_info.dev);
+			pm_runtime_put(hsic_host_info.dev);
 			info.in_lpm[HSIC_BAM] = true;
 		}
 
diff --git a/drivers/power/power_supply_sysfs.c b/drivers/power/power_supply_sysfs.c
index 982c30b..02fd276 100644
--- a/drivers/power/power_supply_sysfs.c
+++ b/drivers/power/power_supply_sysfs.c
@@ -54,8 +54,8 @@
 		"Unknown", "N/A", "Trickle", "Fast"
 	};
 	static char *health_text[] = {
-		"Unknown", "Good", "Overheat", "Dead", "Over voltage",
-		"Unspecified failure", "Cold",
+		"Unknown", "Good", "Overheat", "Warm", "Dead", "Over voltage",
+		"Unspecified failure", "Cold", "Cool"
 	};
 	static char *technology_text[] = {
 		"Unknown", "NiMH", "Li-ion", "Li-poly", "LiFe", "NiCd",
@@ -171,6 +171,8 @@
 	POWER_SUPPLY_ATTR(capacity),
 	POWER_SUPPLY_ATTR(capacity_level),
 	POWER_SUPPLY_ATTR(temp),
+	POWER_SUPPLY_ATTR(temp_cool),
+	POWER_SUPPLY_ATTR(temp_warm),
 	POWER_SUPPLY_ATTR(temp_ambient),
 	POWER_SUPPLY_ATTR(time_to_empty_now),
 	POWER_SUPPLY_ATTR(time_to_empty_avg),
diff --git a/drivers/power/qpnp-bms.c b/drivers/power/qpnp-bms.c
index c43a777..49e57b9 100644
--- a/drivers/power/qpnp-bms.c
+++ b/drivers/power/qpnp-bms.c
@@ -23,6 +23,7 @@
 #include <linux/spmi.h>
 #include <linux/rtc.h>
 #include <linux/delay.h>
+#include <linux/sched.h>
 #include <linux/qpnp/qpnp-adc.h>
 #include <linux/qpnp/power-on.h>
 #include <linux/of_batterydata.h>
@@ -82,7 +83,7 @@
 #define IAVG_STEP_SIZE_MA		50
 #define IAVG_START			600
 #define IAVG_INVALID			0xFF
-#define SOC_INVALID			0xFF
+#define SOC_INVALID			0x7E
 
 #define IAVG_SAMPLES 16
 
@@ -143,8 +144,11 @@
 	bool				bms_psy_registered;
 	struct power_supply		*batt_psy;
 	struct spmi_device		*spmi;
+	wait_queue_head_t		bms_wait_queue;
 	u16				base;
 	u16				iadc_base;
+	u16				batt_pres_addr;
+	u16				soc_storage_addr;
 
 	u8				revision1;
 	u8				revision2;
@@ -186,6 +190,7 @@
 	struct mutex			vbat_monitor_mutex;
 	struct mutex			soc_invalidation_mutex;
 	struct mutex			last_soc_mutex;
+	struct mutex			status_lock;
 
 	bool				use_external_rsense;
 	bool				use_ocv_thresholds;
@@ -276,6 +281,8 @@
 	struct bms_irq			sw_cc_thr_irq;
 	struct bms_irq			ocv_thr_irq;
 	struct qpnp_vadc_chip		*vadc_dev;
+	struct qpnp_iadc_chip		*iadc_dev;
+	struct qpnp_adc_tm_chip		*adc_tm_dev;
 };
 
 static struct of_device_id qpnp_bms_match_table[] = {
@@ -289,6 +296,7 @@
 
 static enum power_supply_property msm_bms_power_props[] = {
 	POWER_SUPPLY_PROP_CAPACITY,
+	POWER_SUPPLY_PROP_STATUS,
 	POWER_SUPPLY_PROP_CURRENT_NOW,
 	POWER_SUPPLY_PROP_RESISTANCE,
 	POWER_SUPPLY_PROP_CHARGE_COUNTER,
@@ -515,13 +523,13 @@
 	return result_uv;
 }
 
-static s64 cc_reverse_adjust_for_gain(s64 uv)
+static s64 cc_reverse_adjust_for_gain(struct qpnp_bms_chip *chip, s64 uv)
 {
 	struct qpnp_iadc_calib calibration;
 	int gain;
 	s64 result_uv;
 
-	qpnp_iadc_get_gain_and_offset(&calibration);
+	qpnp_iadc_get_gain_and_offset(chip->iadc_dev, &calibration);
 	gain = (int)calibration.gain_raw - (int)calibration.offset_raw;
 
 	pr_debug("reverse adjusting_uv = %lld\n", uv);
@@ -544,7 +552,7 @@
 {
 	struct qpnp_iadc_calib calibration;
 
-	qpnp_iadc_get_gain_and_offset(&calibration);
+	qpnp_iadc_get_gain_and_offset(chip->iadc_dev, &calibration);
 	return cc_adjust_for_gain(cc_reading_to_uv(reading),
 			calibration.gain_raw - calibration.offset_raw);
 }
@@ -587,7 +595,7 @@
 	temp_current = div_s64((vsense_uv * 1000000LL),
 				(int)chip->r_sense_uohm);
 
-	rc = qpnp_iadc_comp_result(&temp_current);
+	rc = qpnp_iadc_comp_result(chip->iadc_dev, &temp_current);
 	if (rc)
 		pr_debug("error compensation failed: %d\n", rc);
 
@@ -814,7 +822,8 @@
 		}
 		*vbat_uv = (int)v_result.physical;
 	} else {
-		rc = qpnp_iadc_vadc_sync_read(iadc_channel, &i_result,
+		rc = qpnp_iadc_vadc_sync_read(chip->iadc_dev,
+					iadc_channel, &i_result,
 					VBAT_SNS, &v_result);
 		if (rc) {
 			pr_err("adc sync read failed with rc: %d\n", rc);
@@ -1055,7 +1064,7 @@
 		return *software_counter;
 	}
 
-	qpnp_iadc_get_gain_and_offset(&calibration);
+	qpnp_iadc_get_gain_and_offset(chip->iadc_dev, &calibration);
 	pr_debug("%scc = %lld, die_temp = %lld\n",
 			cc_type == SHDW_CC ? "shdw_" : "",
 			cc, result.physical);
@@ -1065,7 +1074,7 @@
 					- calibration.offset_raw);
 	cc_pvh = cc_uv_to_pvh(cc_voltage_uv);
 	cc_uah = div_s64(cc_pvh, chip->r_sense_uohm);
-	rc = qpnp_iadc_comp_result(&cc_uah);
+	rc = qpnp_iadc_comp_result(chip->iadc_dev, &cc_uah);
 	if (rc)
 		pr_debug("error compensation failed: %d\n", rc);
 	if (clear_cc == RESET) {
@@ -1505,24 +1514,6 @@
 	pr_debug("UUC = %uuAh\n", params->uuc_uah);
 }
 
-static bool is_shutdown_soc_within_limits(struct qpnp_bms_chip *chip, int soc)
-{
-	if (chip->shutdown_soc_invalid) {
-		pr_debug("NOT forcing shutdown soc = %d\n", chip->shutdown_soc);
-		return 0;
-	}
-
-	if (abs(chip->shutdown_soc - soc) > chip->shutdown_soc_valid_limit) {
-		pr_debug("rejecting shutdown soc = %d, soc = %d limit = %d\n",
-			chip->shutdown_soc, soc,
-			chip->shutdown_soc_valid_limit);
-		chip->shutdown_soc_invalid = true;
-		return 0;
-	}
-
-	return 1;
-}
-
 static int bound_soc(int soc)
 {
 	soc = max(0, soc);
@@ -1609,6 +1600,7 @@
 
 module_param_cb(bms_reset, &bms_reset_ops, &bms_reset, 0644);
 
+#define SOC_STORAGE_MASK	0xFE
 static void backup_soc_and_iavg(struct qpnp_bms_chip *chip, int batt_temp,
 				int soc)
 {
@@ -1621,15 +1613,12 @@
 	else
 		temp = 0;
 
-	rc = qpnp_write_wrapper(chip, &temp,
-			chip->base + IAVG_STORAGE_REG, 1);
-
-	temp = soc;
+	rc = qpnp_write_wrapper(chip, &temp, chip->base + IAVG_STORAGE_REG, 1);
 
 	/* don't store soc if temperature is below 5degC */
 	if (batt_temp > IGNORE_SOC_TEMP_DECIDEG)
-		rc = qpnp_write_wrapper(chip, &temp,
-				chip->base + SOC_STORAGE_REG, 1);
+		qpnp_masked_write_base(chip, chip->soc_storage_addr,
+				SOC_STORAGE_MASK, (soc + 1) << 1);
 }
 
 static int scale_soc_while_chg(struct qpnp_bms_chip *chip, int chg_time_sec,
@@ -1679,6 +1668,7 @@
 #define SOC_CATCHUP_SEC_PER_PERCENT	60
 #define MAX_CATCHUP_SOC	(SOC_CATCHUP_SEC_MAX / SOC_CATCHUP_SEC_PER_PERCENT)
 #define SOC_CHANGE_PER_SEC		5
+#define REPORT_SOC_WAIT_MS		10000
 static int report_cc_based_soc(struct qpnp_bms_chip *chip)
 {
 	int soc, soc_change;
@@ -1690,6 +1680,18 @@
 	int rc;
 	bool charging, charging_since_last_report;
 
+	rc = wait_event_interruptible_timeout(chip->bms_wait_queue,
+			chip->calculated_soc != -EINVAL,
+			round_jiffies_relative(msecs_to_jiffies
+			(REPORT_SOC_WAIT_MS)));
+
+	if (rc == 0 && chip->calculated_soc == -EINVAL) {
+		pr_debug("calculate soc timed out\n");
+	} else if (rc == -ERESTARTSYS) {
+		pr_err("Wait for SoC interrupted.\n");
+		return rc;
+	}
+
 	rc = qpnp_vadc_read(chip->vadc_dev, LR_MUX1_BATT_THERM, &result);
 
 	if (rc) {
@@ -1804,6 +1806,7 @@
 				int vbat_uv, int ibat_ua, int batt_temp)
 {
 	int chg_soc, soc_ibat, batt_terminal_uv, weight_ibat, weight_cc;
+	int new_ocv_uv;
 
 	batt_terminal_uv = vbat_uv + (ibat_ua * chip->r_conn_mohm) / 1000;
 
@@ -1855,8 +1858,6 @@
 
 	/* always report a higher soc */
 	if (chg_soc > chip->prev_chg_soc) {
-		int new_ocv_uv;
-
 		chip->prev_chg_soc = chg_soc;
 
 		find_ocv_for_soc(chip, params, batt_temp, chg_soc, &new_ocv_uv);
@@ -2012,6 +2013,9 @@
 		pr_debug("new delta ocv = %d\n", delta_ocv_uv);
 	}
 
+	if (wake_lock_active(&chip->low_voltage_wake_lock))
+		goto skip_limits;
+
 	if (chip->last_ocv_uv > chip->flat_ocv_threshold_uv)
 		correction_limit_uv = chip->high_ocv_correction_limit_uv;
 	else
@@ -2027,6 +2031,8 @@
 		pr_debug("new delta ocv = %d\n", delta_ocv_uv);
 	}
 
+skip_limits:
+
 	chip->last_ocv_uv -= delta_ocv_uv;
 
 	if (chip->last_ocv_uv >= chip->max_voltage_uv)
@@ -2132,9 +2138,9 @@
 		target_cc_uah = CC_STEP_INCREMENT_UAH;
 	}
 	iadc_comp_factor = 100000;
-	qpnp_iadc_comp_result(&iadc_comp_factor);
+	qpnp_iadc_comp_result(chip->iadc_dev, &iadc_comp_factor);
 	target_cc_uah = div64_s64(target_cc_uah * 100000, iadc_comp_factor);
-	target_cc_uah = cc_reverse_adjust_for_gain(target_cc_uah);
+	target_cc_uah = cc_reverse_adjust_for_gain(chip, target_cc_uah);
 	cc_raw_64 = convert_cc_uah_to_raw(chip, target_cc_uah);
 	cc_raw = convert_s64_to_s36(cc_raw_64);
 
@@ -2163,37 +2169,22 @@
 			(uint16_t)ocv_raw);
 }
 
-#define SLEEP_RECALC_INTERVAL	3
-static int calculate_state_of_charge(struct qpnp_bms_chip *chip,
+static int calculate_raw_soc(struct qpnp_bms_chip *chip,
 					struct raw_soc_params *raw,
+					struct soc_params *params,
 					int batt_temp)
 {
-	int soc, new_ocv_uv, previous_soc;
-	int shutdown_soc, new_calculated_soc, remaining_usable_charge_uah;
-	struct soc_params params;
+	int soc, new_ocv_uv;
+	int remaining_usable_charge_uah;
 
-	if (!is_battery_present(chip)) {
-		pr_debug("battery gone, reporting 100\n");
-		new_calculated_soc = 100;
-		goto done_calculating;
-	}
-	calculate_soc_params(chip, raw, &params, batt_temp);
 	/* calculate remaining usable charge */
-	remaining_usable_charge_uah = params.ocv_charge_uah
-					- params.cc_uah
-					- params.uuc_uah;
-
+	remaining_usable_charge_uah = params->ocv_charge_uah
+					- params->cc_uah
+					- params->uuc_uah;
 	pr_debug("RUC = %duAh\n", remaining_usable_charge_uah);
-	if (params.fcc_uah - params.uuc_uah <= 0) {
-		pr_debug("FCC = %duAh, UUC = %duAh forcing soc = 0\n",
-						params.fcc_uah,
-						params.uuc_uah);
-		new_calculated_soc = 0;
-		goto done_calculating;
-	}
 
 	soc = DIV_ROUND_CLOSEST((remaining_usable_charge_uah * 100),
-				(params.fcc_uah - params.uuc_uah));
+				(params->fcc_uah - params->uuc_uah));
 
 	if (chip->first_time_calc_soc && soc < 0) {
 		/*
@@ -2201,16 +2192,16 @@
 		 * in a bad soc. Adjust ocv to get 0 soc
 		 */
 		pr_debug("soc is %d, adjusting pon ocv to make it 0\n", soc);
-		find_ocv_for_soc(chip, &params, batt_temp, 0, &new_ocv_uv);
+		find_ocv_for_soc(chip, params, batt_temp, 0, &new_ocv_uv);
 		chip->last_ocv_uv = new_ocv_uv;
 
-		remaining_usable_charge_uah = params.ocv_charge_uah
-					- params.cc_uah
-					- params.uuc_uah;
+		remaining_usable_charge_uah = params->ocv_charge_uah
+					- params->cc_uah
+					- params->uuc_uah;
 
 		soc = DIV_ROUND_CLOSEST((remaining_usable_charge_uah * 100),
-					(params.fcc_uah
-						- params.uuc_uah));
+					(params->fcc_uah
+						- params->uuc_uah));
 		pr_debug("DONE for O soc is %d, pon ocv adjusted to %duV\n",
 				soc, chip->last_ocv_uv);
 	}
@@ -2221,20 +2212,49 @@
 	if (soc < 0) {
 		pr_debug("bad rem_usb_chg = %d rem_chg %d, cc_uah %d, unusb_chg %d\n",
 				remaining_usable_charge_uah,
-				params.ocv_charge_uah,
-				params.cc_uah, params.uuc_uah);
+				params->ocv_charge_uah,
+				params->cc_uah, params->uuc_uah);
 
 		pr_debug("for bad rem_usb_chg last_ocv_uv = %d batt_temp = %d fcc = %d soc =%d\n",
 				chip->last_ocv_uv, batt_temp,
-				params.fcc_uah, soc);
+				params->fcc_uah, soc);
 		soc = 0;
 	}
 
+	return soc;
+}
+
+#define SLEEP_RECALC_INTERVAL	3
+static int calculate_state_of_charge(struct qpnp_bms_chip *chip,
+					struct raw_soc_params *raw,
+					int batt_temp)
+{
+	struct soc_params params;
+	int soc, previous_soc, shutdown_soc, new_calculated_soc;
+	int remaining_usable_charge_uah, new_ocv_uv;
+
+	calculate_soc_params(chip, raw, &params, batt_temp);
+	if (!is_battery_present(chip)) {
+		pr_debug("battery gone, reporting 100\n");
+		new_calculated_soc = 100;
+		goto done_calculating;
+	}
+
+	if (params.fcc_uah - params.uuc_uah <= 0) {
+		pr_debug("FCC = %duAh, UUC = %duAh forcing soc = 0\n",
+						params.fcc_uah,
+						params.uuc_uah);
+		new_calculated_soc = 0;
+		goto done_calculating;
+	}
+
+	soc = calculate_raw_soc(chip, raw, &params, batt_temp);
+
 	mutex_lock(&chip->soc_invalidation_mutex);
 	shutdown_soc = chip->shutdown_soc;
 
 	if (chip->first_time_calc_soc && soc != shutdown_soc
-			&& is_shutdown_soc_within_limits(chip, soc)) {
+			&& !chip->shutdown_soc_invalid) {
 		/*
 		 * soc for the first time - use shutdown soc
 		 * to adjust pon ocv since it is a small percent away from
@@ -2297,6 +2317,7 @@
 				params.delta_time_s);
 	}
 	mutex_unlock(&chip->last_soc_mutex);
+	wake_up_interruptible(&chip->bms_wait_queue);
 
 	if (new_calculated_soc != previous_soc && chip->bms_psy_registered) {
 		power_supply_changed(&chip->bms_psy);
@@ -2343,6 +2364,53 @@
 	return voltage_based_soc;
 }
 
+static int recalculate_raw_soc(struct qpnp_bms_chip *chip)
+{
+	int batt_temp, rc, soc;
+	struct qpnp_vadc_result result;
+	struct raw_soc_params raw;
+	struct soc_params params;
+
+	bms_stay_awake(&chip->soc_wake_source);
+	if (chip->use_voltage_soc) {
+		soc = calculate_soc_from_voltage(chip);
+	} else {
+		if (!chip->batfet_closed)
+			qpnp_iadc_calibrate_for_trim(chip->iadc_dev, true);
+		rc = qpnp_vadc_read(chip->vadc_dev, LR_MUX1_BATT_THERM,
+								&result);
+		if (rc) {
+			pr_err("error reading vadc LR_MUX1_BATT_THERM = %d, rc = %d\n",
+						LR_MUX1_BATT_THERM, rc);
+			soc = chip->calculated_soc;
+		} else {
+			pr_debug("batt_temp phy = %lld meas = 0x%llx\n",
+							result.physical,
+							result.measurement);
+			batt_temp = (int)result.physical;
+
+			mutex_lock(&chip->last_ocv_uv_mutex);
+			read_soc_params_raw(chip, &raw, batt_temp);
+			calculate_soc_params(chip, &raw, &params, batt_temp);
+			if (!is_battery_present(chip)) {
+				pr_debug("battery gone\n");
+				soc = 0;
+			} else if (params.fcc_uah - params.uuc_uah <= 0) {
+				pr_debug("FCC = %duAh, UUC = %duAh forcing soc = 0\n",
+							params.fcc_uah,
+							params.uuc_uah);
+				soc = 0;
+			} else {
+				soc = calculate_raw_soc(chip, &raw,
+							&params, batt_temp);
+			}
+			mutex_unlock(&chip->last_ocv_uv_mutex);
+		}
+	}
+	bms_relax(&chip->soc_wake_source);
+	return soc;
+}
+
 static int recalculate_soc(struct qpnp_bms_chip *chip)
 {
 	int batt_temp, rc, soc;
@@ -2353,13 +2421,14 @@
 	mutex_lock(&chip->vbat_monitor_mutex);
 	if (chip->vbat_monitor_params.state_request !=
 			ADC_TM_HIGH_LOW_THR_DISABLE)
-		qpnp_adc_tm_channel_measure(&chip->vbat_monitor_params);
+		qpnp_adc_tm_channel_measure(chip->adc_tm_dev,
+					&chip->vbat_monitor_params);
 	mutex_unlock(&chip->vbat_monitor_mutex);
 	if (chip->use_voltage_soc) {
 		soc = calculate_soc_from_voltage(chip);
 	} else {
 		if (!chip->batfet_closed)
-			qpnp_iadc_calibrate_for_trim(true);
+			qpnp_iadc_calibrate_for_trim(chip->iadc_dev, true);
 		rc = qpnp_vadc_read(chip->vadc_dev, LR_MUX1_BATT_THERM,
 								&result);
 		if (rc) {
@@ -2455,7 +2524,8 @@
 				chip->vbat_monitor_params.low_thr,
 				chip->vbat_monitor_params.high_thr);
 	}
-	qpnp_adc_tm_channel_measure(&chip->vbat_monitor_params);
+	qpnp_adc_tm_channel_measure(chip->adc_tm_dev,
+					&chip->vbat_monitor_params);
 	mutex_unlock(&chip->vbat_monitor_mutex);
 }
 
@@ -2503,7 +2573,8 @@
 				chip->vbat_monitor_params.low_thr,
 				chip->vbat_monitor_params.high_thr);
 	}
-	qpnp_adc_tm_channel_measure(&chip->vbat_monitor_params);
+	qpnp_adc_tm_channel_measure(chip->adc_tm_dev,
+					&chip->vbat_monitor_params);
 	mutex_unlock(&chip->vbat_monitor_mutex);
 }
 
@@ -2527,7 +2598,7 @@
 			configure_vbat_monitor_low(chip);
 		} else {
 			pr_debug("faulty btm trigger, discarding\n");
-			qpnp_adc_tm_channel_measure(
+			qpnp_adc_tm_channel_measure(chip->adc_tm_dev,
 					&chip->vbat_monitor_params);
 		}
 	} else if (state == ADC_TM_HIGH_STATE) {
@@ -2537,7 +2608,7 @@
 			configure_vbat_monitor_high(chip);
 		} else {
 			pr_debug("faulty btm trigger, discarding\n");
-			qpnp_adc_tm_channel_measure(
+			qpnp_adc_tm_channel_measure(chip->adc_tm_dev,
 					&chip->vbat_monitor_params);
 		}
 	} else {
@@ -2553,7 +2624,8 @@
 
 	chip->vbat_monitor_params.state_request = ADC_TM_HIGH_LOW_THR_DISABLE;
 
-	rc = qpnp_adc_tm_disable_chan_meas(&chip->vbat_monitor_params);
+	rc = qpnp_adc_tm_channel_measure(chip->adc_tm_dev,
+						&chip->vbat_monitor_params);
 	if (rc) {
 		pr_err("tm disable failed: %d\n", rc);
 		return rc;
@@ -2573,12 +2645,6 @@
 {
 	int rc;
 
-	rc = qpnp_adc_tm_is_ready();
-	if (rc) {
-		pr_info("adc tm is not ready yet: %d, defer probe\n", rc);
-		return -EPROBE_DEFER;
-	}
-
 	chip->vbat_monitor_params.low_thr = chip->low_voltage_threshold;
 	chip->vbat_monitor_params.high_thr = chip->max_voltage_uv
 							- VBATT_ERROR_MARGIN;
@@ -2596,12 +2662,14 @@
 		chip->vbat_monitor_params.state_request =
 			ADC_TM_HIGH_LOW_THR_DISABLE;
 	} else {
-		rc = qpnp_adc_tm_channel_measure(&chip->vbat_monitor_params);
+		rc = qpnp_adc_tm_channel_measure(chip->adc_tm_dev,
+						&chip->vbat_monitor_params);
 		if (rc) {
 			pr_err("tm setup failed: %d\n", rc);
-			return rc;
+		return rc;
 		}
 	}
+
 	pr_debug("setup complete\n");
 	return 0;
 }
@@ -2961,7 +3029,7 @@
 	 */
 
 	for (i = 0; (!chip->batfet_closed) && i < MAX_CAL_TRIES; i++) {
-		rc = qpnp_iadc_calibrate_for_trim(false);
+		rc = qpnp_iadc_calibrate_for_trim(chip->iadc_dev, false);
 		/*
 		 * Wait 20mS after calibration and before reading battery
 		 * current. The BMS h/w uses calibration values in the
@@ -3044,7 +3112,10 @@
 {
 	int status = get_battery_status(chip);
 
+	mutex_lock(&chip->status_lock);
 	if (chip->battery_status != status) {
+		pr_debug("status = %d, shadow status = %d\n",
+				status, chip->battery_status);
 		if (status == POWER_SUPPLY_STATUS_CHARGING) {
 			pr_debug("charging started\n");
 			charging_began(chip);
@@ -3058,6 +3129,7 @@
 			pr_debug("battery full\n");
 			enable_bms_irq(&chip->ocv_thr_irq);
 			enable_bms_irq(&chip->sw_cc_thr_irq);
+			recalculate_soc(chip);
 		} else if (chip->battery_status
 				== POWER_SUPPLY_STATUS_FULL) {
 			pr_debug("battery not full any more\n");
@@ -3070,6 +3142,7 @@
 		 * recalculation to update the SoC */
 		schedule_work(&chip->recalc_work);
 	}
+	mutex_unlock(&chip->status_lock);
 }
 
 #define CALIB_WRKARND_DIG_MAJOR_MAX		0x03
@@ -3086,11 +3159,11 @@
 		if (batfet_closed == false) {
 			/* batfet opened */
 			schedule_work(&chip->batfet_open_work);
-			qpnp_iadc_skip_calibration();
+			qpnp_iadc_skip_calibration(chip->iadc_dev);
 		} else {
 			/* batfet closed */
-			qpnp_iadc_calibrate_for_trim(true);
-			qpnp_iadc_resume_calibration();
+			qpnp_iadc_calibrate_for_trim(chip->iadc_dev, true);
+			qpnp_iadc_resume_calibration(chip->iadc_dev);
 		}
 	}
 }
@@ -3144,6 +3217,9 @@
 	case POWER_SUPPLY_PROP_CAPACITY:
 		val->intval = get_prop_bms_capacity(chip);
 		break;
+	case POWER_SUPPLY_PROP_STATUS:
+		val->intval = chip->battery_status;
+		break;
 	case POWER_SUPPLY_PROP_CURRENT_NOW:
 		val->intval = get_prop_bms_current_now(chip);
 		break;
@@ -3208,61 +3284,120 @@
 	return 0;
 }
 
-static void read_shutdown_soc_and_iavg(struct qpnp_bms_chip *chip)
+static int read_shutdown_iavg_ma(struct qpnp_bms_chip *chip)
 {
+	u8 iavg;
 	int rc;
-	u8 temp;
 
-	if (chip->ignore_shutdown_soc) {
-		chip->shutdown_soc_invalid = true;
-		chip->shutdown_soc = 0;
-		chip->shutdown_iavg_ma = 0;
+	rc = qpnp_read_wrapper(chip, &iavg, chip->base + IAVG_STORAGE_REG, 1);
+	if (rc) {
+		pr_err("failed to read addr = %d %d assuming %d\n",
+				chip->base + IAVG_STORAGE_REG, rc,
+				IAVG_START);
+		return IAVG_START;
+	} else if (iavg == IAVG_INVALID) {
+		pr_err("invalid iavg read from BMS1_DATA_REG_1, using %d\n",
+				IAVG_START);
+		return IAVG_START;
 	} else {
-		rc = qpnp_read_wrapper(chip, &temp,
-				chip->base + IAVG_STORAGE_REG, 1);
-		if (rc) {
-			pr_err("failed to read addr = %d %d assuming %d\n",
-					chip->base + IAVG_STORAGE_REG, rc,
-					IAVG_START);
-			chip->shutdown_iavg_ma = IAVG_START;
-		} else if (temp == IAVG_INVALID) {
-			pr_err("invalid iavg read from BMS1_DATA_REG_1, using %d\n",
-					IAVG_START);
-			chip->shutdown_iavg_ma = IAVG_START;
-		} else {
-			if (temp == 0) {
-				chip->shutdown_iavg_ma = IAVG_START;
-			} else {
-				chip->shutdown_iavg_ma = IAVG_START
-					+ IAVG_STEP_SIZE_MA * (temp + 1);
-			}
-		}
+		if (iavg == 0)
+			return IAVG_START;
+		else
+			return IAVG_START + IAVG_STEP_SIZE_MA * (iavg + 1);
+	}
+}
 
-		rc = qpnp_read_wrapper(chip, &temp,
-				chip->base + SOC_STORAGE_REG, 1);
-		if (rc) {
-			pr_err("failed to read addr = %d %d\n",
-					chip->base + SOC_STORAGE_REG, rc);
-		} else {
-			chip->shutdown_soc = temp;
+static int read_shutdown_soc(struct qpnp_bms_chip *chip)
+{
+	u8 stored_soc;
+	int rc, shutdown_soc;
 
-			if (chip->shutdown_soc == SOC_INVALID) {
-				pr_debug("No shutdown soc available\n");
-				chip->shutdown_soc_invalid = true;
-				chip->shutdown_iavg_ma = 0;
-			}
-		}
+	/*
+	 * The previous SOC is stored in the first 7 bits of the register as
+	 * (Shutdown SOC + 1). This allows for register reset values of both
+	 * 0x00 and 0x7F.
+	 */
+	rc = qpnp_read_wrapper(chip, &stored_soc, chip->soc_storage_addr, 1);
+	if (rc) {
+		pr_err("failed to read addr = %d %d\n",
+				chip->soc_storage_addr, rc);
+		return SOC_INVALID;
 	}
 
-	/* read the SOC storage to determine if there was a battery removal */
-	rc = qpnp_read_wrapper(chip, &temp, chip->base + SOC_STORAGE_REG, 1);
-	if (!rc) {
-		if (temp == SOC_INVALID)
-			chip->battery_removed = true;
+	if ((stored_soc >> 1) > 0)
+		shutdown_soc = (stored_soc >> 1) - 1;
+	else
+		shutdown_soc = SOC_INVALID;
+
+	pr_debug("stored soc = 0x%02x, shutdown_soc = %d\n",
+			stored_soc, shutdown_soc);
+	return shutdown_soc;
+}
+
+#define BAT_REMOVED_OFFMODE_BIT		BIT(6)
+static bool is_battery_replaced_in_offmode(struct qpnp_bms_chip *chip)
+{
+	u8 batt_pres;
+	int rc;
+
+	if (chip->batt_pres_addr) {
+		rc = qpnp_read_wrapper(chip, &batt_pres,
+				chip->batt_pres_addr, 1);
+		pr_debug("offmode removed: %02x\n", batt_pres);
+		if (!rc && (batt_pres & BAT_REMOVED_OFFMODE_BIT))
+			return true;
+	}
+	return false;
+}
+
+static void load_shutdown_data(struct qpnp_bms_chip *chip)
+{
+	int calculated_soc, shutdown_soc;
+	bool invalid_stored_soc;
+	bool offmode_battery_replaced;
+	bool shutdown_soc_out_of_limit;
+
+	/*
+	 * Read the saved shutdown SoC from the configured register and
+	 * check if the value has been reset
+	 */
+	shutdown_soc = read_shutdown_soc(chip);
+	invalid_stored_soc = (shutdown_soc == SOC_INVALID);
+
+	/*
+	 * Do a quick run of SoC calculation to find whether the shutdown soc
+	 * is close enough.
+	 */
+	calculated_soc = recalculate_raw_soc(chip);
+	shutdown_soc_out_of_limit = (abs(shutdown_soc - calculated_soc)
+			> chip->shutdown_soc_valid_limit);
+	pr_debug("calculated_soc = %d, valid_limit = %d\n",
+			calculated_soc, chip->shutdown_soc_valid_limit);
+
+	/*
+	 * Check if the battery has been replaced while the system was powered
+	 * down.
+	 */
+	offmode_battery_replaced = is_battery_replaced_in_offmode(chip);
+
+	/* Invalidate the shutdown SoC if any of these conditions hold true */
+	if (chip->ignore_shutdown_soc
+			|| invalid_stored_soc
+			|| offmode_battery_replaced
+			|| shutdown_soc_out_of_limit) {
+		chip->battery_removed = true;
+		chip->shutdown_soc_invalid = true;
+		chip->shutdown_iavg_ma = 0;
+		pr_debug("Ignoring shutdown SoC: invalid = %d, offmode = %d, out_of_limit = %d\n",
+				invalid_stored_soc, offmode_battery_replaced,
+				shutdown_soc_out_of_limit);
+	} else {
+		chip->shutdown_iavg_ma = read_shutdown_iavg_ma(chip);
+		chip->shutdown_soc = shutdown_soc;
 	}
 
-
-	pr_debug("shutdown_soc = %d shutdown_iavg = %d shutdown_soc_invalid = %d, battery_removed = %d\n",
+	pr_debug("raw_soc = %d shutdown_soc = %d shutdown_iavg = %d shutdown_soc_invalid = %d, battery_removed = %d\n",
+			calculated_soc,
 			chip->shutdown_soc,
 			chip->shutdown_iavg_ma,
 			chip->shutdown_soc_invalid,
@@ -3307,7 +3442,7 @@
 static int set_battery_data(struct qpnp_bms_chip *chip)
 {
 	int64_t battery_id;
-	int rc;
+	int rc, dt_data = false;
 	struct bms_battery_data *batt_data;
 	struct device_node *node;
 
@@ -3343,6 +3478,10 @@
 			batt_data->rbatt_sf_lut = kzalloc(
 					sizeof(struct sf_lut), GFP_KERNEL);
 
+			batt_data->max_voltage_uv = -1;
+			batt_data->cutoff_uv = -1;
+			batt_data->iterm_ua = -1;
+
 			rc = of_batterydata_read_data(node,
 					batt_data, battery_id);
 			if (rc) {
@@ -3352,6 +3491,8 @@
 				kfree(batt_data->rbatt_sf_lut);
 				kfree(batt_data);
 				batt_data = &palladium_1500_data;
+			} else {
+				dt_data = true;
 			}
 		} else {
 			pr_warn("invalid battid, palladium 1500 assumed batt_id %llx\n",
@@ -3371,13 +3512,16 @@
 	chip->flat_ocv_threshold_uv = batt_data->flat_ocv_threshold_uv;
 
 	/* Override battery properties if specified in the battery profile */
-	if (batt_data->max_voltage_uv >= 0)
+	if (batt_data->max_voltage_uv >= 0 && dt_data)
 		chip->max_voltage_uv = batt_data->max_voltage_uv;
-	if (batt_data->cutoff_uv >= 0)
+	if (batt_data->cutoff_uv >= 0 && dt_data)
 		chip->v_cutoff_uv = batt_data->cutoff_uv;
-	if (batt_data->iterm_ua >= 0)
+	if (batt_data->iterm_ua >= 0 && dt_data)
 		chip->chg_term_ua = batt_data->iterm_ua;
 
+	if (dt_data)
+		kfree(batt_data);
+
 	if (chip->pc_temp_ocv_lut == NULL) {
 		pr_err("temp ocv lut table is NULL\n");
 		return -EINVAL;
@@ -3385,6 +3529,38 @@
 	return 0;
 }
 
+static int bms_get_adc(struct qpnp_bms_chip *chip,
+					struct spmi_device *spmi)
+{
+	int rc = 0;
+
+	chip->vadc_dev = qpnp_get_vadc(&spmi->dev, "bms");
+	if (IS_ERR(chip->vadc_dev)) {
+		rc = PTR_ERR(chip->vadc_dev);
+		if (rc != -EPROBE_DEFER)
+			pr_err("vadc property missing, rc=%d\n", rc);
+		return rc;
+	}
+
+	chip->iadc_dev = qpnp_get_iadc(&spmi->dev, "bms");
+	if (IS_ERR(chip->iadc_dev)) {
+		rc = PTR_ERR(chip->iadc_dev);
+		if (rc != -EPROBE_DEFER)
+			pr_err("iadc property missing, rc=%d\n", rc);
+		return rc;
+	}
+
+	chip->adc_tm_dev = qpnp_get_adc_tm(&spmi->dev, "bms");
+	if (IS_ERR(chip->adc_tm_dev)) {
+		rc = PTR_ERR(chip->adc_tm_dev);
+		if (rc != -EPROBE_DEFER)
+			pr_err("adc-tm not ready, defer probe\n");
+		return rc;
+	}
+
+	return 0;
+}
+
 #define SPMI_PROP_READ(chip_prop, qpnp_spmi_property, retval)		\
 do {									\
 	if (retval)							\
@@ -3579,6 +3755,18 @@
 			return -ENXIO;
 		}
 
+		pr_debug("Node name = %s\n", spmi_resource->of_node->name);
+
+		if (strcmp("qcom,batt-pres-status",
+					spmi_resource->of_node->name) == 0) {
+			chip->batt_pres_addr = resource->start;
+			continue;
+		} else if (strcmp("qcom,soc-storage-reg",
+					spmi_resource->of_node->name) == 0) {
+			chip->soc_storage_addr = resource->start;
+			continue;
+		}
+
 		rc = qpnp_read_wrapper(chip, &type,
 				resource->start + REG_OFFSET_PERP_TYPE, 1);
 		if (rc) {
@@ -3617,7 +3805,14 @@
 		dev_err(&spmi->dev, "BMS_IADC peripheral was not registered\n");
 		return -EINVAL;
 	}
+	if (chip->soc_storage_addr == 0) {
+		/* default to dvdd backed BMS data reg0 */
+		chip->soc_storage_addr = chip->base + SOC_STORAGE_REG;
+	}
 
+	pr_debug("bms-base = 0x%04x, iadc-base = 0x%04x, bat-pres-reg = 0x%04x, soc-storage-reg = 0x%04x\n",
+			chip->base, chip->iadc_base,
+			chip->batt_pres_addr, chip->soc_storage_addr);
 	return 0;
 }
 
@@ -3683,7 +3878,7 @@
 			chip->software_shdw_cc_uah = 0;
 		}
 
-		rc = qpnp_iadc_get_rsense(&rds_rsense_nohm);
+		rc = qpnp_iadc_get_rsense(chip->iadc_dev, &rds_rsense_nohm);
 		if (rc) {
 			pr_err("Unable to read RDS resistance value from IADC; rc = %d\n",
 								rc);
@@ -3740,7 +3935,8 @@
 						- chip->temperature_margin;
 	chip->die_temp_monitor_params.state_request =
 						ADC_TM_HIGH_LOW_THR_ENABLE;
-	return qpnp_adc_tm_channel_measure(&chip->die_temp_monitor_params);
+	return qpnp_adc_tm_channel_measure(chip->adc_tm_dev,
+					&chip->die_temp_monitor_params);
 }
 
 static void btm_notify_die_temp(enum qpnp_tm_state state, void *ctx)
@@ -3763,17 +3959,14 @@
 
 static int setup_die_temp_monitoring(struct qpnp_bms_chip *chip)
 {
-	int rc = qpnp_adc_tm_is_ready();
-	if (rc) {
-		pr_info("adc tm is not ready yet: %d, defer probe\n", rc);
-		return -EPROBE_DEFER;
-	}
+	int rc;
+
 	chip->die_temp_monitor_params.channel = DIE_TEMP;
 	chip->die_temp_monitor_params.btm_ctx = (void *)chip;
 	chip->die_temp_monitor_params.timer_interval = ADC_MEAS1_INTERVAL_1S;
 	chip->die_temp_monitor_params.threshold_notification =
 						&btm_notify_die_temp;
-	refresh_die_temp_monitor(chip);
+	rc = refresh_die_temp_monitor(chip);
 	if (rc) {
 		pr_err("tm setup failed: %d\n", rc);
 		return rc;
@@ -3795,26 +3988,17 @@
 		return -ENOMEM;
 	}
 
-	chip->vadc_dev = qpnp_get_vadc(&(spmi->dev), "bms");
-	if (IS_ERR(chip->vadc_dev)) {
-		rc = PTR_ERR(chip->vadc_dev);
-		if (rc != -EPROBE_DEFER)
-			pr_err("vadc property missing, rc=%d\n", rc);
+	rc = bms_get_adc(chip, spmi);
+	if (rc < 0)
 		goto error_read;
-	}
-
-	rc = qpnp_iadc_is_ready();
-	if (rc) {
-		pr_info("iadc not ready: %d, deferring probe\n", rc);
-		rc = -EPROBE_DEFER;
-		goto error_read;
-	}
 
 	mutex_init(&chip->bms_output_lock);
 	mutex_init(&chip->last_ocv_uv_mutex);
 	mutex_init(&chip->vbat_monitor_mutex);
 	mutex_init(&chip->soc_invalidation_mutex);
 	mutex_init(&chip->last_soc_mutex);
+	mutex_init(&chip->status_lock);
+	init_waitqueue_head(&chip->bms_wait_queue);
 
 	warm_reset = qpnp_pon_is_warm_reset();
 	rc = warm_reset;
@@ -3899,7 +4083,10 @@
 	INIT_WORK(&chip->recalc_work, recalculate_work);
 	INIT_WORK(&chip->batfet_open_work, batfet_open_work);
 
-	read_shutdown_soc_and_iavg(chip);
+	dev_set_drvdata(&spmi->dev, chip);
+	device_init_wakeup(&spmi->dev, 1);
+
+	load_shutdown_data(chip);
 
 	if (chip->enable_fcc_learning) {
 		if (chip->battery_removed) {
@@ -3919,9 +4106,6 @@
 		}
 	}
 
-	dev_set_drvdata(&spmi->dev, chip);
-	device_init_wakeup(&spmi->dev, 1);
-
 	rc = setup_vbat_monitoring(chip);
 	if (rc < 0) {
 		pr_err("failed to set up voltage notifications: %d\n", rc);
diff --git a/drivers/power/qpnp-charger.c b/drivers/power/qpnp-charger.c
index a1edce6b..6e9dc57 100644
--- a/drivers/power/qpnp-charger.c
+++ b/drivers/power/qpnp-charger.c
@@ -29,6 +29,8 @@
 #include <linux/regulator/of_regulator.h>
 #include <linux/regulator/machine.h>
 #include <linux/of_batterydata.h>
+#include <linux/qpnp-revid.h>
+#include <linux/android_alarm.h>
 
 /* Interrupt offsets */
 #define INT_RT_STS(base)			(base + 0x10)
@@ -84,7 +86,9 @@
 #define CHGR_STATUS				0x09
 #define CHGR_BAT_IF_VCP				0x42
 #define CHGR_BAT_IF_BATFET_CTRL1		0x90
+#define CHGR_BAT_IF_SPARE			0xDF
 #define CHGR_MISC_BOOT_DONE			0x42
+#define CHGR_BUCK_PSTG_CTRL			0x73
 #define CHGR_BUCK_COMPARATOR_OVRIDE_1		0xEB
 #define CHGR_BUCK_COMPARATOR_OVRIDE_3		0xED
 #define CHGR_BUCK_BCK_VBAT_REG_MODE		0x74
@@ -93,6 +97,7 @@
 #define USB_CHG_GONE_REV_BST			0xED
 #define BUCK_VCHG_OV				0x77
 #define BUCK_TEST_SMBC_MODES			0xE6
+#define BUCK_CTRL_TRIM1				0xF1
 #define SEC_ACCESS				0xD0
 #define BAT_IF_VREF_BAT_THM_CTRL		0x4A
 #define BAT_IF_BPD_CTRL				0x48
@@ -102,6 +107,7 @@
 #define BAT_IF_BTC_CTRL				0x49
 #define USB_OCP_THR				0x52
 #define USB_OCP_CLR				0x53
+#define BAT_IF_TEMP_STATUS			0x09
 
 #define REG_OFFSET_PERP_SUBTYPE			0x05
 
@@ -201,9 +207,10 @@
 /* Workaround flags */
 #define CHG_FLAGS_VCP_WA		BIT(0)
 #define BOOST_FLASH_WA			BIT(1)
+#define POWER_STAGE_WA			BIT(2)
 
 struct qpnp_chg_irq {
-	unsigned int		irq;
+	int		irq;
 	unsigned long		disabled;
 };
 
@@ -282,11 +289,11 @@
 	struct qpnp_chg_irq		chg_failed;
 	struct qpnp_chg_irq		chg_vbatdet_lo;
 	struct qpnp_chg_irq		batt_pres;
-	struct qpnp_chg_irq		vchg_loop;
 	struct qpnp_chg_irq		batt_temp_ok;
 	bool				bat_is_cool;
 	bool				bat_is_warm;
 	bool				chg_done;
+	bool				charger_monitor_checked;
 	bool				usb_present;
 	bool				dc_present;
 	bool				batt_present;
@@ -304,6 +311,7 @@
 	int				prev_usb_max_ma;
 	int				set_vddmax_mv;
 	int				delta_vddmax_mv;
+	u8				trim_center;
 	unsigned int			warm_bat_mv;
 	unsigned int			cool_bat_mv;
 	unsigned int			resume_delta_mv;
@@ -330,12 +338,20 @@
 	uint32_t			flags;
 	struct qpnp_adc_tm_btm_param	adc_param;
 	struct work_struct		adc_measure_work;
+	struct work_struct		adc_disable_work;
 	struct delayed_work		arb_stop_work;
 	struct delayed_work		eoc_work;
-	struct wake_lock		eoc_wake_lock;
+	struct work_struct		soc_check_work;
+	struct delayed_work		aicl_check_work;
 	struct qpnp_chg_regulator	otg_vreg;
 	struct qpnp_chg_regulator	boost_vreg;
+	struct qpnp_chg_regulator	batfet_vreg;
 	struct qpnp_vadc_chip		*vadc_dev;
+	struct qpnp_adc_tm_chip		*adc_tm_dev;
+	struct mutex			jeita_configure_lock;
+	struct alarm			reduce_power_stage_alarm;
+	struct work_struct		reduce_power_stage_work;
+	bool				power_stage_workaround_running;
 };
 
 
@@ -603,6 +619,24 @@
 	return (dcin_valid_rt_sts & DCIN_VALID_IRQ) ? 1 : 0;
 }
 
+static int
+qpnp_chg_is_ichg_loop_active(struct qpnp_chg_chip *chip)
+{
+	u8 buck_sts;
+	int rc;
+
+	rc = qpnp_chg_read(chip, &buck_sts, INT_RT_STS(chip->buck_base), 1);
+
+	if (rc) {
+		pr_err("spmi read failed: addr=%03X, rc=%d\n",
+				INT_RT_STS(chip->buck_base), rc);
+		return rc;
+	}
+	pr_debug("buck usb sts 0x%x\n", buck_sts);
+
+	return (buck_sts & ICHG_LOOP_IRQ) ? 1 : 0;
+}
+
 #define QPNP_CHG_I_MAX_MIN_100		100
 #define QPNP_CHG_I_MAX_MIN_150		150
 #define QPNP_CHG_I_MAX_MIN_MA		200
@@ -926,19 +960,17 @@
 	struct qpnp_chg_chip *chip = container_of(work,
 				struct qpnp_chg_chip, adc_measure_work);
 
-	if (qpnp_adc_tm_channel_measure(&chip->adc_param))
+	if (qpnp_adc_tm_channel_measure(chip->adc_tm_dev, &chip->adc_param))
 		pr_err("request ADC error\n");
 }
 
-static irqreturn_t
-qpnp_chg_buck_vchg_loop_irq_handler(int irq, void *_chip)
+static void
+qpnp_bat_if_adc_disable_work(struct work_struct *work)
 {
-	struct qpnp_chg_chip *chip = _chip;
+	struct qpnp_chg_chip *chip = container_of(work,
+				struct qpnp_chg_chip, adc_disable_work);
 
-	if (chip->bat_if_base)
-		power_supply_changed(&chip->batt_psy);
-
-	return IRQ_HANDLED;
+	qpnp_adc_tm_disable_chan_meas(chip->adc_tm_dev, &chip->adc_param);
 }
 
 #define EOC_CHECK_PERIOD_MS	10000
@@ -959,17 +991,20 @@
 	if (!chip->charging_disabled && (chg_sts & FAST_CHG_ON_IRQ)) {
 		schedule_delayed_work(&chip->eoc_work,
 			msecs_to_jiffies(EOC_CHECK_PERIOD_MS));
-		wake_lock(&chip->eoc_wake_lock);
-		qpnp_chg_disable_irq(&chip->chg_vbatdet_lo);
-	} else {
-		qpnp_chg_charge_en(chip, !chip->charging_disabled);
+		pm_stay_awake(chip->dev);
 	}
+	qpnp_chg_disable_irq(&chip->chg_vbatdet_lo);
 
+	pr_debug("psy changed usb_psy\n");
 	power_supply_changed(chip->usb_psy);
-	if (chip->dc_chgpth_base)
+	if (chip->dc_chgpth_base) {
+		pr_debug("psy changed dc_psy\n");
 		power_supply_changed(&chip->dc_psy);
-	if (chip->bat_if_base)
+	}
+	if (chip->bat_if_base) {
+		pr_debug("psy changed batt_psy\n");
 		power_supply_changed(&chip->batt_psy);
+	}
 	return IRQ_HANDLED;
 }
 
@@ -1016,6 +1051,72 @@
 	return IRQ_HANDLED;
 }
 
+#define QPNP_CHG_VDDMAX_MIN		3400
+#define QPNP_CHG_V_MIN_MV		3240
+#define QPNP_CHG_V_MAX_MV		4500
+#define QPNP_CHG_V_STEP_MV		10
+#define QPNP_CHG_BUCK_TRIM1_STEP	10
+#define QPNP_CHG_BUCK_VDD_TRIM_MASK	0xF0
+static int
+qpnp_chg_vddmax_and_trim_set(struct qpnp_chg_chip *chip,
+		int voltage, int trim_mv)
+{
+	int rc, trim_set;
+	u8 vddmax = 0, trim = 0;
+
+	if (voltage < QPNP_CHG_VDDMAX_MIN
+			|| voltage > QPNP_CHG_V_MAX_MV) {
+		pr_err("bad mV=%d asked to set\n", voltage);
+		return -EINVAL;
+	}
+
+	vddmax = (voltage - QPNP_CHG_V_MIN_MV) / QPNP_CHG_V_STEP_MV;
+	rc = qpnp_chg_write(chip, &vddmax, chip->chgr_base + CHGR_VDD_MAX, 1);
+	if (rc) {
+		pr_err("Failed to write vddmax: %d\n", rc);
+		return rc;
+	}
+
+	rc = qpnp_chg_masked_write(chip,
+		chip->buck_base + SEC_ACCESS,
+		0xFF,
+		0xA5, 1);
+	if (rc) {
+		pr_err("failed to write SEC_ACCESS rc=%d\n", rc);
+		return rc;
+	}
+	trim_set = clamp((int)chip->trim_center
+			+ (trim_mv / QPNP_CHG_BUCK_TRIM1_STEP),
+			0, 0xF);
+	trim = (u8)trim_set << 4;
+	rc = qpnp_chg_masked_write(chip,
+		chip->buck_base + BUCK_CTRL_TRIM1,
+		QPNP_CHG_BUCK_VDD_TRIM_MASK,
+		trim, 1);
+	if (rc) {
+		pr_err("Failed to write buck trim1: %d\n", rc);
+		return rc;
+	}
+	pr_debug("voltage=%d+%d setting vddmax: %02x, trim: %02x\n",
+			voltage, trim_mv, vddmax, trim);
+	return 0;
+}
+
+/* JEITA compliance logic */
+static void
+qpnp_chg_set_appropriate_vddmax(struct qpnp_chg_chip *chip)
+{
+	if (chip->bat_is_cool)
+		qpnp_chg_vddmax_and_trim_set(chip, chip->cool_bat_mv,
+				chip->delta_vddmax_mv);
+	else if (chip->bat_is_warm)
+		qpnp_chg_vddmax_and_trim_set(chip, chip->warm_bat_mv,
+				chip->delta_vddmax_mv);
+	else
+		qpnp_chg_vddmax_and_trim_set(chip, chip->max_voltage_mv,
+				chip->delta_vddmax_mv);
+}
+
 #define ENUM_T_STOP_BIT		BIT(0)
 static irqreturn_t
 qpnp_chg_usb_usbin_valid_irq_handler(int irq, void *_chip)
@@ -1035,12 +1136,22 @@
 	if (chip->usb_present ^ usb_present) {
 		chip->usb_present = usb_present;
 		if (!usb_present) {
+			if (!qpnp_chg_is_dc_chg_plugged_in(chip)) {
+				chip->delta_vddmax_mv = 0;
+				qpnp_chg_set_appropriate_vddmax(chip);
+			}
 			qpnp_chg_usb_suspend_enable(chip, 1);
-			chip->chg_done = false;
+			if (!qpnp_chg_is_dc_chg_plugged_in(chip))
+				chip->chg_done = false;
 			chip->prev_usb_max_ma = -EINVAL;
 		} else {
+			if (!qpnp_chg_is_dc_chg_plugged_in(chip)) {
+				chip->delta_vddmax_mv = 0;
+				qpnp_chg_set_appropriate_vddmax(chip);
+			}
 			schedule_delayed_work(&chip->eoc_work,
 				msecs_to_jiffies(EOC_CHECK_PERIOD_MS));
+			schedule_work(&chip->soc_check_work);
 		}
 
 		power_supply_set_present(chip->usb_psy, chip->usb_present);
@@ -1058,6 +1169,7 @@
 	batt_temp_good = qpnp_chg_is_batt_temp_ok(chip);
 	pr_debug("batt-temp triggered: %d\n", batt_temp_good);
 
+	pr_debug("psy changed batt_psy\n");
 	power_supply_changed(&chip->batt_psy);
 	return IRQ_HANDLED;
 }
@@ -1073,12 +1185,19 @@
 
 	if (chip->batt_present ^ batt_present) {
 		chip->batt_present = batt_present;
+		pr_debug("psy changed batt_psy\n");
 		power_supply_changed(&chip->batt_psy);
+		pr_debug("psy changed usb_psy\n");
 		power_supply_changed(chip->usb_psy);
 
-		if (chip->cool_bat_decidegc && chip->warm_bat_decidegc
+		if ((chip->cool_bat_decidegc || chip->warm_bat_decidegc)
 						&& batt_present) {
+			pr_debug("enabling vadc notifications\n");
 			schedule_work(&chip->adc_measure_work);
+		} else if ((chip->cool_bat_decidegc || chip->warm_bat_decidegc)
+				&& !batt_present) {
+			schedule_work(&chip->adc_disable_work);
+			pr_debug("disabling vadc notifications\n");
 		}
 	}
 
@@ -1096,12 +1215,22 @@
 
 	if (chip->dc_present ^ dc_present) {
 		chip->dc_present = dc_present;
-		if (!dc_present)
+		if (!dc_present && !qpnp_chg_is_usb_chg_plugged_in(chip)) {
+			chip->delta_vddmax_mv = 0;
+			qpnp_chg_set_appropriate_vddmax(chip);
 			chip->chg_done = false;
-		else
+		} else {
+			if (!qpnp_chg_is_usb_chg_plugged_in(chip)) {
+				chip->delta_vddmax_mv = 0;
+				qpnp_chg_set_appropriate_vddmax(chip);
+			}
 			schedule_delayed_work(&chip->eoc_work,
 				msecs_to_jiffies(EOC_CHECK_PERIOD_MS));
+			schedule_work(&chip->soc_check_work);
+		}
+		pr_debug("psy changed dc_psy\n");
 		power_supply_changed(&chip->dc_psy);
+		pr_debug("psy changed batt_psy\n");
 		power_supply_changed(&chip->batt_psy);
 	}
 
@@ -1124,11 +1253,16 @@
 	if (rc)
 		pr_err("Failed to write chg_fail clear bit!\n");
 
-	if (chip->bat_if_base)
+	if (chip->bat_if_base) {
+		pr_debug("psy changed batt_psy\n");
 		power_supply_changed(&chip->batt_psy);
+	}
+	pr_debug("psy changed usb_psy\n");
 	power_supply_changed(chip->usb_psy);
-	if (chip->dc_chgpth_base)
+	if (chip->dc_chgpth_base) {
+		pr_debug("psy changed dc_psy\n");
 		power_supply_changed(&chip->dc_psy);
+	}
 	return IRQ_HANDLED;
 }
 
@@ -1140,8 +1274,10 @@
 	pr_debug("TRKL IRQ triggered\n");
 
 	chip->chg_done = false;
-	if (chip->bat_if_base)
+	if (chip->bat_if_base) {
+		pr_debug("psy changed batt_psy\n");
 		power_supply_changed(&chip->batt_psy);
+	}
 
 	return IRQ_HANDLED;
 }
@@ -1159,21 +1295,31 @@
 
 	pr_debug("FAST_CHG IRQ triggered\n");
 	chip->chg_done = false;
-	if (chip->bat_if_base)
+	if (chip->bat_if_base) {
+		pr_debug("psy changed batt_psy\n");
 		power_supply_changed(&chip->batt_psy);
+	}
+
+	pr_debug("psy changed usb_psy\n");
 	power_supply_changed(chip->usb_psy);
-	if (chip->dc_chgpth_base)
+
+	if (chip->dc_chgpth_base) {
+		pr_debug("psy changed dc_psy\n");
 		power_supply_changed(&chip->dc_psy);
+	}
+
 	if (chip->resuming_charging) {
 		chip->resuming_charging = false;
 		qpnp_chg_set_appropriate_vbatdet(chip);
 	}
 
+	if (!chip->charging_disabled) {
+		schedule_delayed_work(&chip->eoc_work,
+			msecs_to_jiffies(EOC_CHECK_PERIOD_MS));
+		pm_stay_awake(chip->dev);
+	}
+
 	qpnp_chg_enable_irq(&chip->chg_vbatdet_lo);
-	if (chgr_sts & FAST_CHG_ON_IRQ)
-		qpnp_chg_enable_irq(&chip->vchg_loop);
-	else
-		qpnp_chg_disable_irq(&chip->vchg_loop);
 
 	return IRQ_HANDLED;
 }
@@ -1201,6 +1347,8 @@
 	case POWER_SUPPLY_PROP_SYSTEM_TEMP_LEVEL:
 	case POWER_SUPPLY_PROP_INPUT_CURRENT_MAX:
 	case POWER_SUPPLY_PROP_VOLTAGE_MIN:
+	case POWER_SUPPLY_PROP_COOL_TEMP:
+	case POWER_SUPPLY_PROP_WARM_TEMP:
 		return 1;
 	default:
 		break;
@@ -1313,6 +1461,8 @@
 	POWER_SUPPLY_PROP_CHARGE_FULL_DESIGN,
 	POWER_SUPPLY_PROP_CHARGE_FULL,
 	POWER_SUPPLY_PROP_TEMP,
+	POWER_SUPPLY_PROP_COOL_TEMP,
+	POWER_SUPPLY_PROP_WARM_TEMP,
 	POWER_SUPPLY_PROP_SYSTEM_TEMP_LEVEL,
 	POWER_SUPPLY_PROP_CYCLE_COUNT,
 };
@@ -1355,6 +1505,28 @@
 	return 0;
 }
 
+static void
+qpnp_aicl_check_work(struct work_struct *work)
+{
+	struct delayed_work *dwork = to_delayed_work(work);
+	struct qpnp_chg_chip *chip = container_of(dwork,
+				struct qpnp_chg_chip, aicl_check_work);
+	union power_supply_propval ret = {0,};
+
+	if (!charger_monitor && qpnp_chg_is_usb_chg_plugged_in(chip)) {
+		chip->usb_psy->get_property(chip->usb_psy,
+			  POWER_SUPPLY_PROP_CURRENT_MAX, &ret);
+		if ((ret.intval / 1000) > USB_WALL_THRESHOLD_MA) {
+			pr_debug("no charger_monitor present set iusbmax %d\n",
+					ret.intval / 1000);
+			qpnp_chg_iusbmax_set(chip, ret.intval / 1000);
+		}
+	} else {
+		pr_debug("charger_monitor is present\n");
+	}
+	chip->charger_monitor_checked = true;
+}
+
 static int
 get_prop_battery_voltage_now(struct qpnp_chg_chip *chip)
 {
@@ -1441,7 +1613,7 @@
 get_prop_batt_status(struct qpnp_chg_chip *chip)
 {
 	int rc;
-	u8 chgr_sts;
+	u8 chgr_sts, bat_if_sts;
 
 	if ((qpnp_chg_is_usb_chg_plugged_in(chip) ||
 		qpnp_chg_is_dc_chg_plugged_in(chip)) && chip->chg_done) {
@@ -1454,9 +1626,15 @@
 		return POWER_SUPPLY_CHARGE_TYPE_NONE;
 	}
 
-	if (chgr_sts & TRKL_CHG_ON_IRQ)
+	rc = qpnp_chg_read(chip, &bat_if_sts, INT_RT_STS(chip->bat_if_base), 1);
+	if (rc) {
+		pr_err("failed to read bat_if sts %d\n", rc);
+		return POWER_SUPPLY_CHARGE_TYPE_NONE;
+	}
+
+	if (chgr_sts & TRKL_CHG_ON_IRQ && bat_if_sts & BAT_FET_ON_IRQ)
 		return POWER_SUPPLY_STATUS_CHARGING;
-	if (chgr_sts & FAST_CHG_ON_IRQ)
+	if (chgr_sts & FAST_CHG_ON_IRQ && bat_if_sts & BAT_FET_ON_IRQ)
 		return POWER_SUPPLY_STATUS_CHARGING;
 
 	return POWER_SUPPLY_STATUS_DISCHARGING;
@@ -1515,29 +1693,40 @@
 get_prop_capacity(struct qpnp_chg_chip *chip)
 {
 	union power_supply_propval ret = {0,};
+	int battery_status, bms_status, soc, charger_in;
 
 	if (chip->use_default_batt_values || !get_prop_batt_present(chip))
 		return DEFAULT_CAPACITY;
 
 	if (chip->bms_psy) {
 		chip->bms_psy->get_property(chip->bms_psy,
-			  POWER_SUPPLY_PROP_CAPACITY, &ret);
-		if (get_prop_batt_status(chip) == POWER_SUPPLY_STATUS_FULL
+				POWER_SUPPLY_PROP_CAPACITY, &ret);
+		soc = ret.intval;
+		battery_status = get_prop_batt_status(chip);
+		chip->bms_psy->get_property(chip->bms_psy,
+				POWER_SUPPLY_PROP_STATUS, &ret);
+		bms_status = ret.intval;
+		charger_in = qpnp_chg_is_usb_chg_plugged_in(chip) ||
+			qpnp_chg_is_dc_chg_plugged_in(chip);
+
+		if (battery_status != POWER_SUPPLY_STATUS_CHARGING
+				&& bms_status != POWER_SUPPLY_STATUS_CHARGING
+				&& charger_in
 				&& !chip->resuming_charging
 				&& !chip->charging_disabled
 				&& chip->soc_resume_limit
-				&& ret.intval <= chip->soc_resume_limit) {
-			pr_debug("resuming charging at %d%% soc\n", ret.intval);
+				&& soc <= chip->soc_resume_limit) {
+			pr_debug("resuming charging at %d%% soc\n", soc);
 			chip->resuming_charging = true;
 			qpnp_chg_set_appropriate_vbatdet(chip);
 			qpnp_chg_charge_en(chip, !chip->charging_disabled);
 		}
-		if (ret.intval == 0) {
+		if (soc == 0) {
 			if (!qpnp_chg_is_usb_chg_plugged_in(chip)
 				&& !qpnp_chg_is_usb_chg_plugged_in(chip))
 				pr_warn_ratelimited("Battery 0, CHG absent\n");
 		}
-		return ret.intval;
+		return soc;
 	} else {
 		pr_debug("No BMS supply registered return 50\n");
 	}
@@ -1629,18 +1818,29 @@
 		} else {
 			qpnp_chg_usb_suspend_enable(chip, 0);
 			if (((ret.intval / 1000) > USB_WALL_THRESHOLD_MA)
-					&& (charger_monitor)) {
+					&& (charger_monitor ||
+					!chip->charger_monitor_checked)) {
 				qpnp_chg_iusbmax_set(chip,
 						USB_WALL_THRESHOLD_MA);
 			} else {
 				qpnp_chg_iusbmax_set(chip, ret.intval / 1000);
 			}
+
+			if ((chip->flags & POWER_STAGE_WA)
+			&& ((ret.intval / 1000) > USB_WALL_THRESHOLD_MA)
+			&& !chip->power_stage_workaround_running) {
+				chip->power_stage_workaround_running = true;
+				pr_debug("usb wall chg inserted starting power stage workaround charger_monitor = %d\n",
+						charger_monitor);
+				schedule_work(&chip->reduce_power_stage_work);
+			}
 		}
 		chip->prev_usb_max_ma = ret.intval;
 	}
 
 skip_set_iusb_max:
 	pr_debug("end of power supply changed\n");
+	pr_debug("psy changed batt_psy\n");
 	power_supply_changed(&chip->batt_psy);
 }
 
@@ -1680,6 +1880,12 @@
 	case POWER_SUPPLY_PROP_TEMP:
 		val->intval = get_prop_batt_temp(chip);
 		break;
+	case POWER_SUPPLY_PROP_COOL_TEMP:
+		val->intval = chip->cool_bat_decidegc;
+		break;
+	case POWER_SUPPLY_PROP_WARM_TEMP:
+		val->intval = chip->warm_bat_decidegc;
+		break;
 	case POWER_SUPPLY_PROP_CAPACITY:
 		val->intval = get_prop_capacity(chip);
 		break;
@@ -1831,9 +2037,6 @@
 			QPNP_CHG_TCHG_MASK, temp, 1);
 }
 
-#define QPNP_CHG_V_MIN_MV	3240
-#define QPNP_CHG_V_MAX_MV	4500
-#define QPNP_CHG_V_STEP_MV	10
 static int
 qpnp_chg_vddsafe_set(struct qpnp_chg_chip *chip, int voltage)
 {
@@ -1850,25 +2053,6 @@
 		chip->chgr_base + CHGR_VDD_SAFE, 1);
 }
 
-#define QPNP_CHG_VDDMAX_MIN	3400
-static int
-qpnp_chg_vddmax_set(struct qpnp_chg_chip *chip, int voltage)
-{
-	u8 temp = 0;
-
-	if (voltage < QPNP_CHG_VDDMAX_MIN
-			|| voltage > QPNP_CHG_V_MAX_MV) {
-		pr_err("bad mV=%d asked to set\n", voltage);
-		return -EINVAL;
-	}
-	chip->set_vddmax_mv = voltage + chip->delta_vddmax_mv;
-
-	temp = (chip->set_vddmax_mv - QPNP_CHG_V_MIN_MV) / QPNP_CHG_V_STEP_MV;
-
-	pr_debug("voltage=%d setting %02x\n", chip->set_vddmax_mv, temp);
-	return qpnp_chg_write(chip, &temp, chip->chgr_base + CHGR_VDD_MAX, 1);
-}
-
 #define BOOST_MIN_UV	4200000
 #define BOOST_MAX_UV	5500000
 #define BOOST_STEP_UV	50000
@@ -1911,18 +2095,6 @@
 	return BOOST_MIN_UV + ((boost_reg - BOOST_MIN) * BOOST_STEP_UV);
 }
 
-/* JEITA compliance logic */
-static void
-qpnp_chg_set_appropriate_vddmax(struct qpnp_chg_chip *chip)
-{
-	if (chip->bat_is_cool)
-		qpnp_chg_vddmax_set(chip, chip->cool_bat_mv);
-	else if (chip->bat_is_warm)
-		qpnp_chg_vddmax_set(chip, chip->warm_bat_mv);
-	else
-		qpnp_chg_vddmax_set(chip, chip->max_voltage_mv);
-}
-
 static void
 qpnp_chg_set_appropriate_battery_current(struct qpnp_chg_chip *chip)
 {
@@ -2181,22 +2353,80 @@
 	.list_voltage		= qpnp_chg_regulator_boost_list_voltage,
 };
 
-#define MIN_DELTA_MV_TO_INCREASE_VDD_MAX	13
-#define MAX_DELTA_VDD_MAX_MV			30
+#define BATFET_LPM_MASK		0xC0
+#define BATFET_LPM		0x40
+#define BATFET_NO_LPM		0x00
+static int
+qpnp_chg_regulator_batfet_enable(struct regulator_dev *rdev)
+{
+	struct qpnp_chg_chip *chip = rdev_get_drvdata(rdev);
+	int rc;
+
+	rc = qpnp_chg_masked_write(chip,
+			chip->bat_if_base + CHGR_BAT_IF_SPARE,
+			BATFET_LPM_MASK, BATFET_NO_LPM, 1);
+	if (rc)
+		pr_err("failed to write to batt_if rc=%d\n", rc);
+	return rc;
+}
+
+static int
+qpnp_chg_regulator_batfet_disable(struct regulator_dev *rdev)
+{
+	struct qpnp_chg_chip *chip = rdev_get_drvdata(rdev);
+	int rc;
+
+	rc = qpnp_chg_masked_write(chip,
+			chip->bat_if_base + CHGR_BAT_IF_SPARE,
+			BATFET_LPM_MASK, BATFET_LPM, 1);
+	if (rc)
+		pr_err("failed to write to batt_if rc=%d\n", rc);
+	return rc;
+}
+
+static int
+qpnp_chg_regulator_batfet_is_enabled(struct regulator_dev *rdev)
+{
+	struct qpnp_chg_chip *chip = rdev_get_drvdata(rdev);
+	int rc;
+	u8 reg;
+
+	rc = qpnp_chg_read(chip, &reg,
+				chip->bat_if_base + CHGR_BAT_IF_SPARE, 1);
+	if (rc) {
+		pr_err("failed to read batt_if rc=%d\n", rc);
+		return rc;
+	}
+
+	if (reg && BATFET_LPM_MASK == BATFET_NO_LPM)
+		return 1;
+
+	return 0;
+}
+
+static struct regulator_ops qpnp_chg_batfet_vreg_ops = {
+	.enable			= qpnp_chg_regulator_batfet_enable,
+	.disable		= qpnp_chg_regulator_batfet_disable,
+	.is_enabled		= qpnp_chg_regulator_batfet_is_enabled,
+};
+
+#define MIN_DELTA_MV_TO_INCREASE_VDD_MAX	8
+#define MAX_DELTA_VDD_MAX_MV			80
+#define VDD_MAX_CENTER_OFFSET			4
 static void
 qpnp_chg_adjust_vddmax(struct qpnp_chg_chip *chip, int vbat_mv)
 {
 	int delta_mv, closest_delta_mv, sign;
 
-	delta_mv = chip->max_voltage_mv - vbat_mv;
+	delta_mv = chip->max_voltage_mv - VDD_MAX_CENTER_OFFSET - vbat_mv;
 	if (delta_mv > 0 && delta_mv < MIN_DELTA_MV_TO_INCREASE_VDD_MAX) {
 		pr_debug("vbat is not low enough to increase vdd\n");
 		return;
 	}
 
 	sign = delta_mv > 0 ? 1 : -1;
-	closest_delta_mv = ((delta_mv + sign * QPNP_CHG_V_STEP_MV / 2)
-			/ QPNP_CHG_V_STEP_MV) * QPNP_CHG_V_STEP_MV;
+	closest_delta_mv = ((delta_mv + sign * QPNP_CHG_BUCK_TRIM1_STEP / 2)
+			/ QPNP_CHG_BUCK_TRIM1_STEP) * QPNP_CHG_BUCK_TRIM1_STEP;
 	pr_debug("max_voltage = %d, vbat_mv = %d, delta_mv = %d, closest = %d\n",
 			chip->max_voltage_mv, vbat_mv,
 			delta_mv, closest_delta_mv);
@@ -2207,6 +2437,7 @@
 }
 
 #define CONSECUTIVE_COUNT	3
+#define VBATDET_MAX_ERR_MV	50
 static void
 qpnp_eoc_work(struct work_struct *work)
 {
@@ -2214,10 +2445,12 @@
 	struct qpnp_chg_chip *chip = container_of(dwork,
 				struct qpnp_chg_chip, eoc_work);
 	static int count;
+	static int vbat_low_count;
 	int ibat_ma, vbat_mv, rc = 0;
 	u8 batt_sts = 0, buck_sts = 0, chg_sts = 0;
+	bool vbat_lower_than_vbatdet;
 
-	wake_lock(&chip->eoc_wake_lock);
+	pm_stay_awake(chip->dev);
 	qpnp_chg_charge_en(chip, !chip->charging_disabled);
 
 	rc = qpnp_chg_read(chip, &batt_sts, INT_RT_STS(chip->bat_if_base), 1);
@@ -2255,11 +2488,24 @@
 		pr_debug("ibat_ma = %d vbat_mv = %d term_current_ma = %d\n",
 				ibat_ma, vbat_mv, chip->term_current);
 
-		if ((!(chg_sts & VBAT_DET_LOW_IRQ)) && (vbat_mv <
-			(chip->max_voltage_mv - chip->resume_delta_mv))) {
-			pr_debug("woke up too early\n");
-			qpnp_chg_enable_irq(&chip->chg_vbatdet_lo);
-			goto stop_eoc;
+		vbat_lower_than_vbatdet = !(chg_sts & VBAT_DET_LOW_IRQ);
+		if (vbat_lower_than_vbatdet && vbat_mv <
+				(chip->max_voltage_mv - chip->resume_delta_mv
+				 - VBATDET_MAX_ERR_MV)) {
+			vbat_low_count++;
+			pr_debug("woke up too early vbat_mv = %d, max_mv = %d, resume_mv = %d tolerance_mv = %d low_count = %d\n",
+					vbat_mv, chip->max_voltage_mv,
+					chip->resume_delta_mv,
+					VBATDET_MAX_ERR_MV, vbat_low_count);
+			if (vbat_low_count >= CONSECUTIVE_COUNT) {
+				pr_debug("woke up too early stopping\n");
+				qpnp_chg_enable_irq(&chip->chg_vbatdet_lo);
+				goto stop_eoc;
+			} else {
+				goto check_again_later;
+			}
+		} else {
+			vbat_low_count = 0;
 		}
 
 		if (buck_sts & VDD_LOOP_IRQ)
@@ -2277,8 +2523,15 @@
 		} else {
 			if (count == CONSECUTIVE_COUNT) {
 				pr_info("End of Charging\n");
-				qpnp_chg_charge_en(chip, 0);
+				chip->delta_vddmax_mv = 0;
+				qpnp_chg_set_appropriate_vddmax(chip);
 				chip->chg_done = true;
+				qpnp_chg_charge_en(chip, 0);
+				/* sleep for a second before enabling */
+				msleep(2000);
+				qpnp_chg_charge_en(chip,
+						!chip->charging_disabled);
+				pr_debug("psy changed batt_psy\n");
 				power_supply_changed(&chip->batt_psy);
 				qpnp_chg_enable_irq(&chip->chg_vbatdet_lo);
 				goto stop_eoc;
@@ -2289,16 +2542,27 @@
 		}
 	} else {
 		pr_debug("not charging\n");
-			goto stop_eoc;
+		goto stop_eoc;
 	}
 
+check_again_later:
 	schedule_delayed_work(&chip->eoc_work,
 		msecs_to_jiffies(EOC_CHECK_PERIOD_MS));
 	return;
 
 stop_eoc:
+	vbat_low_count = 0;
 	count = 0;
-	wake_unlock(&chip->eoc_wake_lock);
+	pm_relax(chip->dev);
+}
+
+static void
+qpnp_chg_soc_check_work(struct work_struct *work)
+{
+	struct qpnp_chg_chip *chip = container_of(work,
+				struct qpnp_chg_chip, soc_check_work);
+
+	get_prop_capacity(chip);
 }
 
 #define HYSTERISIS_DECIDEGC 20
@@ -2380,10 +2644,267 @@
 		qpnp_chg_set_appropriate_vbatdet(chip);
 	}
 
-	if (qpnp_adc_tm_channel_measure(&chip->adc_param))
-		pr_err("request ADC error\n");
+	pr_debug("warm %d, cool %d, low = %d deciDegC, high = %d deciDegC\n",
+			chip->bat_is_warm, chip->bat_is_cool,
+			chip->adc_param.low_temp, chip->adc_param.high_temp);
 
-	power_supply_changed(&chip->batt_psy);
+	if (qpnp_adc_tm_channel_measure(chip->adc_tm_dev, &chip->adc_param))
+		pr_err("request ADC error\n");
+}
+
+#define MIN_COOL_TEMP	-300
+#define MAX_WARM_TEMP	1000
+
+static int
+qpnp_chg_configure_jeita(struct qpnp_chg_chip *chip,
+		enum power_supply_property psp, int temp_degc)
+{
+	int rc = 0;
+
+	if ((temp_degc < MIN_COOL_TEMP) || (temp_degc > MAX_WARM_TEMP)) {
+		pr_err("Bad temperature request %d\n", temp_degc);
+		return -EINVAL;
+	}
+
+	mutex_lock(&chip->jeita_configure_lock);
+	switch (psp) {
+	case POWER_SUPPLY_PROP_COOL_TEMP:
+		if (temp_degc >=
+			(chip->warm_bat_decidegc - HYSTERISIS_DECIDEGC)) {
+			pr_err("Can't set cool %d higher than warm %d - hysterisis %d\n",
+					temp_degc, chip->warm_bat_decidegc,
+					HYSTERISIS_DECIDEGC);
+			rc = -EINVAL;
+			goto mutex_unlock;
+		}
+		if (chip->bat_is_cool)
+			chip->adc_param.high_temp =
+				temp_degc + HYSTERISIS_DECIDEGC;
+		else if (!chip->bat_is_warm)
+			chip->adc_param.low_temp = temp_degc;
+
+		chip->cool_bat_decidegc = temp_degc;
+		break;
+	case POWER_SUPPLY_PROP_WARM_TEMP:
+		if (temp_degc <=
+			(chip->cool_bat_decidegc + HYSTERISIS_DECIDEGC)) {
+			pr_err("Can't set warm %d higher than cool %d + hysterisis %d\n",
+					temp_degc, chip->warm_bat_decidegc,
+					HYSTERISIS_DECIDEGC);
+			rc = -EINVAL;
+			goto mutex_unlock;
+		}
+		if (chip->bat_is_warm)
+			chip->adc_param.low_temp =
+				temp_degc - HYSTERISIS_DECIDEGC;
+		else if (!chip->bat_is_cool)
+			chip->adc_param.high_temp = temp_degc;
+
+		chip->warm_bat_decidegc = temp_degc;
+		break;
+	default:
+		rc = -EINVAL;
+		goto mutex_unlock;
+	}
+
+	schedule_work(&chip->adc_measure_work);
+
+mutex_unlock:
+	mutex_unlock(&chip->jeita_configure_lock);
+	return rc;
+}
+
+#define POWER_STAGE_REDUCE_CHECK_PERIOD_SECONDS		20
+#define POWER_STAGE_REDUCE_MAX_VBAT_UV			3900000
+#define POWER_STAGE_REDUCE_MIN_VCHG_UV			4800000
+#define POWER_STAGE_SEL_MASK				0x0F
+#define POWER_STAGE_REDUCED				0x01
+#define POWER_STAGE_DEFAULT				0x0F
+static bool
+qpnp_chg_is_power_stage_reduced(struct qpnp_chg_chip *chip)
+{
+	int rc;
+	u8 reg;
+
+	rc = qpnp_chg_read(chip, &reg,
+				 chip->buck_base + CHGR_BUCK_PSTG_CTRL,
+				 1);
+	if (rc) {
+		pr_err("Error %d reading power stage register\n", rc);
+		return false;
+	}
+
+	if ((reg & POWER_STAGE_SEL_MASK) == POWER_STAGE_DEFAULT)
+		return false;
+
+	return true;
+}
+
+static int
+qpnp_chg_power_stage_set(struct qpnp_chg_chip *chip, bool reduce)
+{
+	int rc;
+	u8 reg = 0xA5;
+
+	rc = qpnp_chg_write(chip, &reg,
+				 chip->buck_base + SEC_ACCESS,
+				 1);
+	if (rc) {
+		pr_err("Error %d writing 0xA5 to buck's 0x%x reg\n",
+				rc, SEC_ACCESS);
+		return rc;
+	}
+
+	reg = POWER_STAGE_DEFAULT;
+	if (reduce)
+		reg = POWER_STAGE_REDUCED;
+	rc = qpnp_chg_write(chip, &reg,
+				 chip->buck_base + CHGR_BUCK_PSTG_CTRL,
+				 1);
+
+	if (rc)
+		pr_err("Error %d writing 0x%x power stage register\n", rc, reg);
+	return rc;
+}
+
+static int
+qpnp_chg_get_vusbin_uv(struct qpnp_chg_chip *chip)
+{
+	int rc = 0;
+	struct qpnp_vadc_result results;
+
+	rc = qpnp_vadc_read(chip->vadc_dev, USBIN, &results);
+	if (rc) {
+		pr_err("Unable to read vbat rc=%d\n", rc);
+		return 0;
+	}
+	return results.physical;
+}
+
+static
+int get_vusb_averaged(struct qpnp_chg_chip *chip, int sample_count)
+{
+	int vusb_uv = 0;
+	int i;
+
+	/* avoid  overflows */
+	if (sample_count > 256)
+		sample_count = 256;
+
+	for (i = 0; i < sample_count; i++)
+		vusb_uv += qpnp_chg_get_vusbin_uv(chip);
+
+	vusb_uv = vusb_uv / sample_count;
+	return vusb_uv;
+}
+
+static
+int get_vbat_averaged(struct qpnp_chg_chip *chip, int sample_count)
+{
+	int vbat_uv = 0;
+	int i;
+
+	/* avoid  overflows */
+	if (sample_count > 256)
+		sample_count = 256;
+
+	for (i = 0; i < sample_count; i++)
+		vbat_uv += get_prop_battery_voltage_now(chip);
+
+	vbat_uv = vbat_uv / sample_count;
+	return vbat_uv;
+}
+
+static void
+qpnp_chg_reduce_power_stage(struct qpnp_chg_chip *chip)
+{
+	struct timespec ts;
+	bool power_stage_reduced_in_hw = qpnp_chg_is_power_stage_reduced(chip);
+	bool reduce_power_stage = false;
+	int vbat_uv = get_vbat_averaged(chip, 16);
+	int vusb_uv = get_vusb_averaged(chip, 16);
+	bool fast_chg =
+		(get_prop_charge_type(chip) == POWER_SUPPLY_CHARGE_TYPE_FAST);
+	static int count_restore_power_stage;
+	static int count_reduce_power_stage;
+	bool vchg_loop = get_prop_vchg_loop(chip);
+	bool ichg_loop = qpnp_chg_is_ichg_loop_active(chip);
+	bool usb_present = qpnp_chg_is_usb_chg_plugged_in(chip);
+	bool usb_ma_above_wall =
+		(qpnp_chg_usb_iusbmax_get(chip) > USB_WALL_THRESHOLD_MA);
+
+	if (fast_chg
+		&& usb_present
+		&& usb_ma_above_wall
+		&& vbat_uv < POWER_STAGE_REDUCE_MAX_VBAT_UV
+		&& vusb_uv > POWER_STAGE_REDUCE_MIN_VCHG_UV)
+		reduce_power_stage = true;
+
+	if ((usb_present && usb_ma_above_wall)
+		&& (vchg_loop || ichg_loop))
+		reduce_power_stage = true;
+
+	if (power_stage_reduced_in_hw && !reduce_power_stage) {
+		count_restore_power_stage++;
+		count_reduce_power_stage = 0;
+	} else if (!power_stage_reduced_in_hw && reduce_power_stage) {
+		count_reduce_power_stage++;
+		count_restore_power_stage = 0;
+	} else if (power_stage_reduced_in_hw == reduce_power_stage) {
+		count_restore_power_stage = 0;
+		count_reduce_power_stage = 0;
+	}
+
+	pr_debug("power_stage_hw = %d reduce_power_stage = %d usb_present = %d usb_ma_above_wall = %d vbat_uv(16) = %d vusb_uv(16) = %d fast_chg = %d , ichg = %d, vchg = %d, restore,reduce = %d, %d\n",
+			power_stage_reduced_in_hw, reduce_power_stage,
+			usb_present, usb_ma_above_wall,
+			vbat_uv, vusb_uv, fast_chg,
+			ichg_loop, vchg_loop,
+			count_restore_power_stage, count_reduce_power_stage);
+
+	if (!power_stage_reduced_in_hw && reduce_power_stage) {
+		if (count_reduce_power_stage >= 2) {
+			qpnp_chg_power_stage_set(chip, true);
+			power_stage_reduced_in_hw = true;
+		}
+	}
+
+	if (power_stage_reduced_in_hw && !reduce_power_stage) {
+		if (count_restore_power_stage >= 6
+				|| (!usb_present || !usb_ma_above_wall)) {
+			qpnp_chg_power_stage_set(chip, false);
+			power_stage_reduced_in_hw = false;
+		}
+	}
+
+	if (usb_present && usb_ma_above_wall) {
+		getnstimeofday(&ts);
+		ts.tv_sec += POWER_STAGE_REDUCE_CHECK_PERIOD_SECONDS;
+		alarm_start_range(&chip->reduce_power_stage_alarm,
+					timespec_to_ktime(ts),
+					timespec_to_ktime(ts));
+	} else {
+		pr_debug("stopping power stage workaround\n");
+		chip->power_stage_workaround_running = false;
+	}
+}
+
+static void
+qpnp_chg_reduce_power_stage_work(struct work_struct *work)
+{
+	struct qpnp_chg_chip *chip = container_of(work,
+				struct qpnp_chg_chip, reduce_power_stage_work);
+
+	qpnp_chg_reduce_power_stage(chip);
+}
+
+static void
+qpnp_chg_reduce_power_stage_callback(struct alarm *alarm)
+{
+	struct qpnp_chg_chip *chip = container_of(alarm, struct qpnp_chg_chip,
+						reduce_power_stage_alarm);
+
+	schedule_work(&chip->reduce_power_stage_work);
 }
 
 static int
@@ -2412,6 +2933,7 @@
 		return -EINVAL;
 	}
 
+	pr_debug("psy changed dc_psy\n");
 	power_supply_changed(&chip->dc_psy);
 	return rc;
 }
@@ -2423,12 +2945,28 @@
 {
 	struct qpnp_chg_chip *chip = container_of(psy, struct qpnp_chg_chip,
 								batt_psy);
+	int rc = 0;
 
 	switch (psp) {
+	case POWER_SUPPLY_PROP_COOL_TEMP:
+		rc = qpnp_chg_configure_jeita(chip, psp, val->intval);
+		break;
+	case POWER_SUPPLY_PROP_WARM_TEMP:
+		rc = qpnp_chg_configure_jeita(chip, psp, val->intval);
+		break;
 	case POWER_SUPPLY_PROP_CHARGING_ENABLED:
 		chip->charging_disabled = !(val->intval);
-		qpnp_chg_charge_en(chip, !chip->charging_disabled);
-		qpnp_chg_force_run_on_batt(chip, chip->charging_disabled);
+		if (chip->charging_disabled) {
+			/* disable charging */
+			qpnp_chg_charge_en(chip, !chip->charging_disabled);
+			qpnp_chg_force_run_on_batt(chip,
+						chip->charging_disabled);
+		} else {
+			/* enable charging */
+			qpnp_chg_force_run_on_batt(chip,
+					chip->charging_disabled);
+			qpnp_chg_charge_en(chip, !chip->charging_disabled);
+		}
 		break;
 	case POWER_SUPPLY_PROP_SYSTEM_TEMP_LEVEL:
 		qpnp_batt_system_temp_level_set(chip, val->intval);
@@ -2443,19 +2981,44 @@
 		return -EINVAL;
 	}
 
+	pr_debug("psy changed batt_psy\n");
 	power_supply_changed(&chip->batt_psy);
-	return 0;
+	return rc;
 }
 
-static void
+static int
 qpnp_chg_setup_flags(struct qpnp_chg_chip *chip)
 {
 	if (chip->revision > 0 && chip->type == SMBB)
 		chip->flags |= CHG_FLAGS_VCP_WA;
 	if (chip->type == SMBB)
 		chip->flags |= BOOST_FLASH_WA;
-	if (chip->type == SMBBP)
-		chip->flags |= BOOST_FLASH_WA;
+	if (chip->type == SMBBP) {
+		struct device_node *revid_dev_node;
+		struct pmic_revid_data *revid_data;
+
+		chip->flags |=  BOOST_FLASH_WA;
+
+		revid_dev_node = of_parse_phandle(chip->spmi->dev.of_node,
+						"qcom,pmic-revid", 0);
+		if (!revid_dev_node) {
+			pr_err("Missing qcom,pmic-revid property\n");
+			return -EINVAL;
+		}
+		revid_data = get_revid_data(revid_dev_node);
+		if (IS_ERR(revid_data)) {
+			pr_err("Couldnt get revid data rc = %ld\n",
+						PTR_ERR(revid_data));
+			return PTR_ERR(revid_data);
+		}
+
+		if (revid_data->rev4 < PM8226_V2P1_REV4
+			|| ((revid_data->rev4 == PM8226_V2P1_REV4)
+				&& (revid_data->rev3 <= PM8226_V2P1_REV3))) {
+			chip->flags |= POWER_STAGE_WA;
+		}
+	}
+	return 0;
 }
 
 static int
@@ -2552,7 +3115,7 @@
 			rc |= devm_request_irq(chip->dev,
 				chip->chg_vbatdet_lo.irq,
 				qpnp_chg_vbatdet_lo_irq_handler,
-				IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING,
+				IRQF_TRIGGER_RISING,
 				"vbat-det-lo", chip);
 			if (rc < 0) {
 				pr_err("Can't request %d vbat-det-lo: %d\n",
@@ -2610,24 +3173,6 @@
 		case SMBB_BUCK_SUBTYPE:
 		case SMBBP_BUCK_SUBTYPE:
 		case SMBCL_BUCK_SUBTYPE:
-			chip->vchg_loop.irq = spmi_get_irq_byname(spmi,
-						spmi_resource, "vchg-loop");
-			if (chip->vchg_loop.irq < 0) {
-				pr_err("Unable to get vchg-loop irq\n");
-				return rc;
-			}
-			rc = devm_request_irq(chip->dev, chip->vchg_loop.irq,
-				qpnp_chg_buck_vchg_loop_irq_handler,
-				IRQF_TRIGGER_RISING,
-				"vchg-loop", chip);
-			if (rc < 0) {
-				pr_err("Can't request %d vchg-loop irq: %d\n",
-						chip->vchg_loop.irq, rc);
-				return rc;
-			}
-
-			enable_irq_wake(chip->vchg_loop.irq);
-			qpnp_chg_disable_irq(&chip->vchg_loop);
 			break;
 
 		case SMBB_USB_CHGPTH_SUBTYPE:
@@ -2733,6 +3278,8 @@
 			return rc;
 		}
 
+		batt_data.max_voltage_uv = -1;
+		batt_data.iterm_ua = -1;
 		rc = of_batterydata_read_data(node,
 				&batt_data, result.physical);
 		if (rc) {
@@ -2771,11 +3318,6 @@
 			pr_debug("failed setting  min_voltage rc=%d\n", rc);
 			return rc;
 		}
-		rc = qpnp_chg_vddmax_set(chip, chip->max_voltage_mv);
-		if (rc) {
-			pr_debug("failed setting max_voltage rc=%d\n", rc);
-			return rc;
-		}
 		rc = qpnp_chg_vddsafe_set(chip, chip->safe_voltage_mv);
 		if (rc) {
 			pr_debug("failed setting safe_voltage rc=%d\n", rc);
@@ -2835,6 +3377,15 @@
 			pr_debug("failed to enable IR drop comp rc=%d\n", rc);
 			return rc;
 		}
+
+		rc = qpnp_chg_read(chip, &chip->trim_center,
+				chip->buck_base + BUCK_CTRL_TRIM1, 1);
+		if (rc) {
+			pr_debug("failed to read trim center rc=%d\n", rc);
+			return rc;
+		}
+		chip->trim_center >>= 4;
+		pr_debug("trim center = %02x\n", chip->trim_center);
 		break;
 	case SMBB_BAT_IF_SUBTYPE:
 	case SMBBP_BAT_IF_SUBTYPE:
@@ -2872,6 +3423,32 @@
 			pr_debug("failed to force on VREF_BAT_THM rc=%d\n", rc);
 			return rc;
 		}
+
+		init_data = of_get_regulator_init_data(chip->dev,
+					       spmi_resource->of_node);
+
+		if (init_data->constraints.name) {
+			rdesc			= &(chip->batfet_vreg.rdesc);
+			rdesc->owner		= THIS_MODULE;
+			rdesc->type		= REGULATOR_VOLTAGE;
+			rdesc->ops		= &qpnp_chg_batfet_vreg_ops;
+			rdesc->name		= init_data->constraints.name;
+
+			init_data->constraints.valid_ops_mask
+				|= REGULATOR_CHANGE_STATUS;
+
+			chip->batfet_vreg.rdev = regulator_register(rdesc,
+					chip->dev, init_data, chip,
+					spmi_resource->of_node);
+			if (IS_ERR(chip->batfet_vreg.rdev)) {
+				rc = PTR_ERR(chip->batfet_vreg.rdev);
+				chip->batfet_vreg.rdev = NULL;
+				if (rc != -EPROBE_DEFER)
+					pr_err("batfet reg failed, rc=%d\n",
+							rc);
+				return rc;
+			}
+		}
 		break;
 	case SMBB_USB_CHGPTH_SUBTYPE:
 	case SMBBP_USB_CHGPTH_SUBTYPE:
@@ -3067,6 +3644,7 @@
 	if (rc) {
 		/* Select BAT_THM as default BPD scheme */
 		chip->bpd_detection = BPD_TYPE_BAT_THM;
+		rc = 0;
 	} else {
 		chip->bpd_detection = get_bpd(bpd);
 		if (chip->bpd_detection < 0) {
@@ -3076,10 +3654,12 @@
 	}
 
 	/* Look up JEITA compliance parameters if cool and warm temp provided */
-	if (chip->cool_bat_decidegc && chip->warm_bat_decidegc) {
-		rc = qpnp_adc_tm_is_ready();
-		if (rc) {
-			pr_err("tm not ready %d\n", rc);
+	if (chip->cool_bat_decidegc || chip->warm_bat_decidegc) {
+		chip->adc_tm_dev = qpnp_get_adc_tm(chip->dev, "chg");
+		if (IS_ERR(chip->adc_tm_dev)) {
+			rc = PTR_ERR(chip->adc_tm_dev);
+			if (rc != -EPROBE_DEFER)
+				pr_err("adc-tm not ready, defer probe\n");
 			return rc;
 		}
 
@@ -3165,6 +3745,12 @@
 		goto fail_chg_enable;
 	}
 
+	mutex_init(&chip->jeita_configure_lock);
+	alarm_init(&chip->reduce_power_stage_alarm, ANDROID_ALARM_RTC_WAKEUP,
+			qpnp_chg_reduce_power_stage_callback);
+	INIT_WORK(&chip->reduce_power_stage_work,
+			qpnp_chg_reduce_power_stage_work);
+
 	/* Get all device tree properties */
 	rc = qpnp_charger_read_dt_props(chip);
 	if (rc)
@@ -3206,11 +3792,11 @@
 				if (rc != -EPROBE_DEFER)
 					pr_err("vadc property missing\n");
 				goto fail_chg_enable;
+			}
 
 			rc = qpnp_chg_load_battery_data(chip);
 			if (rc)
 				goto fail_chg_enable;
-			}
 		}
 	}
 
@@ -3270,16 +3856,6 @@
 				0xff,
 				0x00, 1);
 
-			rc = qpnp_chg_masked_write(chip,
-				chip->buck_base + SEC_ACCESS,
-				0xFF,
-				0xA5, 1);
-
-			rc = qpnp_chg_masked_write(chip,
-				chip->buck_base + BUCK_TEST_SMBC_MODES,
-				0xFF,
-				0x80, 1);
-
 			if (chip->duty_cycle_100p) {
 				rc = qpnp_buck_set_100_duty_cycle_enable(chip,
 						1);
@@ -3377,12 +3953,14 @@
 		}
 		INIT_WORK(&chip->adc_measure_work,
 			qpnp_bat_if_adc_measure_work);
+		INIT_WORK(&chip->adc_disable_work,
+			qpnp_bat_if_adc_disable_work);
 	}
 
-	wake_lock_init(&chip->eoc_wake_lock,
-		WAKE_LOCK_SUSPEND, "qpnp-chg-eoc-lock");
 	INIT_DELAYED_WORK(&chip->eoc_work, qpnp_eoc_work);
 	INIT_DELAYED_WORK(&chip->arb_stop_work, qpnp_arb_stop_work);
+	INIT_WORK(&chip->soc_check_work, qpnp_chg_soc_check_work);
+	INIT_DELAYED_WORK(&chip->aicl_check_work, qpnp_aicl_check_work);
 
 	if (chip->dc_chgpth_base) {
 		chip->dc_psy.name = "qpnp-dc";
@@ -3404,17 +3982,21 @@
 	}
 
 	/* Turn on appropriate workaround flags */
-	qpnp_chg_setup_flags(chip);
+	rc = qpnp_chg_setup_flags(chip);
+	if (rc < 0) {
+		pr_err("failed to setup flags rc=%d\n", rc);
+		goto unregister_dc_psy;
+	}
 
 	if (chip->maxinput_dc_ma && chip->dc_chgpth_base) {
 		rc = qpnp_chg_idcmax_set(chip, chip->maxinput_dc_ma);
 		if (rc) {
 			pr_err("Error setting idcmax property %d\n", rc);
-			goto unregister_batt;
+			goto unregister_dc_psy;
 		}
 	}
 
-	if (chip->cool_bat_decidegc && chip->warm_bat_decidegc
+	if ((chip->cool_bat_decidegc || chip->warm_bat_decidegc)
 							&& chip->bat_if_base) {
 		chip->adc_param.low_temp = chip->cool_bat_decidegc;
 		chip->adc_param.high_temp = chip->warm_bat_decidegc;
@@ -3426,17 +4008,18 @@
 		chip->adc_param.channel = LR_MUX1_BATT_THERM;
 
 		if (get_prop_batt_present(chip)) {
-			rc = qpnp_adc_tm_channel_measure(&chip->adc_param);
+			rc = qpnp_adc_tm_channel_measure(chip->adc_tm_dev,
+							&chip->adc_param);
 			if (rc) {
 				pr_err("request ADC error %d\n", rc);
-				goto fail_chg_enable;
+				goto unregister_dc_psy;
 			}
 		}
 	}
 	rc = qpnp_chg_bat_if_configure_btc(chip);
 	if (rc) {
 		pr_err("failed to configure btc %d\n", rc);
-		goto unregister_batt;
+		goto unregister_dc_psy;
 	}
 
 	qpnp_chg_charge_en(chip, !chip->charging_disabled);
@@ -3446,11 +4029,11 @@
 	rc = qpnp_chg_request_irqs(chip);
 	if (rc) {
 		pr_err("failed to request interrupts %d\n", rc);
-		goto unregister_batt;
+		goto unregister_dc_psy;
 	}
 
-	qpnp_chg_usb_usbin_valid_irq_handler(USBIN_VALID_IRQ, chip);
-	qpnp_chg_dc_dcin_valid_irq_handler(DCIN_VALID_IRQ, chip);
+	qpnp_chg_usb_usbin_valid_irq_handler(chip->usbin_valid.irq, chip);
+	qpnp_chg_dc_dcin_valid_irq_handler(chip->dcin_valid.irq, chip);
 	power_supply_set_present(chip->usb_psy,
 			qpnp_chg_is_usb_chg_plugged_in(chip));
 
@@ -3459,6 +4042,8 @@
 	if (qpnp_chg_is_usb_chg_plugged_in(chip))
 		power_supply_set_online(chip->usb_psy, 1);
 
+	schedule_delayed_work(&chip->aicl_check_work,
+		msecs_to_jiffies(EOC_CHECK_PERIOD_MS));
 	pr_info("success chg_dis = %d, bpd = %d, usb = %d, dc = %d b_health = %d batt_present = %d\n",
 			chip->charging_disabled,
 			chip->bpd_detection,
@@ -3468,6 +4053,9 @@
 			get_prop_batt_health(chip));
 	return 0;
 
+unregister_dc_psy:
+	if (chip->dc_chgpth_base)
+		power_supply_unregister(&chip->dc_psy);
 unregister_batt:
 	if (chip->bat_if_base)
 		power_supply_unregister(&chip->batt_psy);
@@ -3484,9 +4072,10 @@
 qpnp_charger_remove(struct spmi_device *spmi)
 {
 	struct qpnp_chg_chip *chip = dev_get_drvdata(&spmi->dev);
-	if (chip->cool_bat_decidegc && chip->warm_bat_decidegc
+	if ((chip->cool_bat_decidegc || chip->warm_bat_decidegc)
 						&& chip->batt_present) {
-		qpnp_adc_tm_disable_chan_meas(&chip->adc_param);
+		qpnp_adc_tm_disable_chan_meas(chip->adc_tm_dev,
+							&chip->adc_param);
 	}
 	cancel_work_sync(&chip->adc_measure_work);
 	cancel_delayed_work_sync(&chip->eoc_work);
diff --git a/drivers/regulator/core.c b/drivers/regulator/core.c
index 0ebb944..450c4fb 100644
--- a/drivers/regulator/core.c
+++ b/drivers/regulator/core.c
@@ -3357,14 +3357,6 @@
 		ret = set_supply(rdev, r);
 		if (ret < 0)
 			goto scrub;
-
-		/* Enable supply if rail is enabled */
-		if (rdev->desc->ops->is_enabled &&
-				rdev->desc->ops->is_enabled(rdev)) {
-			ret = regulator_enable(rdev->supply);
-			if (ret < 0)
-				goto scrub;
-		}
 	}
 
 	/* add consumers devices */
diff --git a/drivers/rtc/alarm.c b/drivers/rtc/alarm.c
index e318ecf..1648cba 100644
--- a/drivers/rtc/alarm.c
+++ b/drivers/rtc/alarm.c
@@ -25,6 +25,7 @@
 
 #include <asm/mach/time.h>
 
+#define ALARM_DELTA 120
 #define ANDROID_ALARM_PRINT_ERROR (1U << 0)
 #define ANDROID_ALARM_PRINT_INIT_STATUS (1U << 1)
 #define ANDROID_ALARM_PRINT_TSET (1U << 2)
@@ -454,7 +455,7 @@
 			rtc_delta.tv_sec, rtc_delta.tv_nsec);
 		if (rtc_current_time + 1 >= rtc_alarm_time) {
 			pr_alarm(SUSPEND, "alarm about to go off\n");
-			memset(&rtc_alarm, 0, sizeof(rtc_alarm));
+			rtc_time_to_tm(0, &rtc_alarm.time);
 			rtc_alarm.enabled = 0;
 			rtc_set_alarm(alarm_rtc_dev, &rtc_alarm);
 
@@ -479,7 +480,7 @@
 
 	pr_alarm(SUSPEND, "alarm_resume(%p)\n", pdev);
 
-	memset(&alarm, 0, sizeof(alarm));
+	rtc_time_to_tm(0, &alarm.time);
 	alarm.enabled = 0;
 	rtc_set_alarm(alarm_rtc_dev, &alarm);
 
@@ -512,6 +513,15 @@
 	rtc_tm_to_time(&rtc_time, &rtc_secs);
 	alarm_delta = wall_time.tv_sec - rtc_secs;
 	alarm_time = power_on_alarm - alarm_delta;
+
+	/*
+	 * Substract ALARM_DELTA from actual alarm time
+	 * to powerup the device before actual alarm
+	 * expiration.
+	 */
+	if ((alarm_time - ALARM_DELTA) > rtc_secs)
+		alarm_time -= ALARM_DELTA;
+
 	if (alarm_time <= rtc_secs)
 		goto disable_alarm;
 
diff --git a/drivers/scsi/ufs/ufshcd-pci.c b/drivers/scsi/ufs/ufshcd-pci.c
index 5cb1d75..48be39a 100644
--- a/drivers/scsi/ufs/ufshcd-pci.c
+++ b/drivers/scsi/ufs/ufshcd-pci.c
@@ -92,7 +92,6 @@
 	struct ufs_hba *hba = pci_get_drvdata(pdev);
 
 	disable_irq(pdev->irq);
-	free_irq(pdev->irq, hba);
 	ufshcd_remove(hba);
 	pci_release_regions(pdev);
 	pci_set_drvdata(pdev, NULL);
diff --git a/drivers/scsi/ufs/ufshcd-pltfrm.c b/drivers/scsi/ufs/ufshcd-pltfrm.c
index 5634caf..c42db40 100644
--- a/drivers/scsi/ufs/ufshcd-pltfrm.c
+++ b/drivers/scsi/ufs/ufshcd-pltfrm.c
@@ -33,9 +33,10 @@
  * this program.
  */
 
-#include "ufshcd.h"
 #include <linux/platform_device.h>
 
+#include "ufshcd.h"
+
 #ifdef CONFIG_PM
 /**
  * ufshcd_pltfrm_suspend - suspend power management function
@@ -97,56 +98,39 @@
 	struct ufs_hba *hba;
 	void __iomem *mmio_base;
 	struct resource *mem_res;
-	struct resource *irq_res;
-	resource_size_t mem_size;
-	int err;
+	int irq, err;
 	struct device *dev = &pdev->dev;
 
 	mem_res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
 	if (!mem_res) {
-		dev_err(&pdev->dev,
-			"Memory resource not available\n");
+		dev_err(dev, "Memory resource not available\n");
 		err = -ENODEV;
-		goto out_error;
+		goto out;
 	}
 
-	mem_size = resource_size(mem_res);
-	if (!request_mem_region(mem_res->start, mem_size, "ufshcd")) {
-		dev_err(&pdev->dev,
-			"Cannot reserve the memory resource\n");
-		err = -EBUSY;
-		goto out_error;
+	mmio_base = devm_ioremap_resource(dev, mem_res);
+	if (IS_ERR(mmio_base)) {
+		dev_err(dev, "memory map failed\n");
+		err = PTR_ERR(mmio_base);
+		goto out;
 	}
 
-	mmio_base = ioremap_nocache(mem_res->start, mem_size);
-	if (!mmio_base) {
-		dev_err(&pdev->dev, "memory map failed\n");
-		err = -ENOMEM;
-		goto out_release_regions;
-	}
-
-	irq_res = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
-	if (!irq_res) {
-		dev_err(&pdev->dev, "IRQ resource not available\n");
+	irq = platform_get_irq(pdev, 0);
+	if (irq < 0) {
+		dev_err(dev, "IRQ resource not available\n");
 		err = -ENODEV;
-		goto out_iounmap;
+		goto out;
 	}
 
-	err = ufshcd_init(&pdev->dev, &hba, mmio_base, irq_res->start);
+	err = ufshcd_init(dev, &hba, mmio_base, irq);
 	if (err) {
-		dev_err(&pdev->dev, "Intialization failed\n");
-		goto out_iounmap;
+		dev_err(dev, "Intialization failed\n");
+		goto out;
 	}
 
 	platform_set_drvdata(pdev, hba);
 
-	return 0;
-
-out_iounmap:
-	iounmap(mmio_base);
-out_release_regions:
-	release_mem_region(mem_res->start, mem_size);
-out_error:
+out:
 	return err;
 }
 
@@ -158,26 +142,10 @@
  */
 static int ufshcd_pltfrm_remove(struct platform_device *pdev)
 {
-	struct resource *mem_res;
-	resource_size_t mem_size;
 	struct ufs_hba *hba =  platform_get_drvdata(pdev);
 
 	disable_irq(hba->irq);
-
-	/* Some buggy controllers raise interrupt after
-	 * the resources are removed. So first we unregister the
-	 * irq handler and then the resources used by driver
-	 */
-
-	free_irq(hba->irq, hba);
 	ufshcd_remove(hba);
-	mem_res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-	if (!mem_res)
-		dev_err(&pdev->dev, "ufshcd: Memory resource not available\n");
-	else {
-		mem_size = resource_size(mem_res);
-		release_mem_region(mem_res->start, mem_size);
-	}
 	return 0;
 }
 
diff --git a/drivers/scsi/ufs/ufshcd.c b/drivers/scsi/ufs/ufshcd.c
index df02ff1..b743bd6 100644
--- a/drivers/scsi/ufs/ufshcd.c
+++ b/drivers/scsi/ufs/ufshcd.c
@@ -191,38 +191,6 @@
 }
 
 /**
- * ufshcd_free_hba_memory - Free allocated memory for LRB, request
- *			    and task lists
- * @hba: Pointer to adapter instance
- */
-static inline void ufshcd_free_hba_memory(struct ufs_hba *hba)
-{
-	size_t utmrdl_size, utrdl_size, ucdl_size;
-
-	kfree(hba->lrb);
-
-	if (hba->utmrdl_base_addr) {
-		utmrdl_size = sizeof(struct utp_task_req_desc) * hba->nutmrs;
-		dma_free_coherent(hba->dev, utmrdl_size,
-				  hba->utmrdl_base_addr, hba->utmrdl_dma_addr);
-	}
-
-	if (hba->utrdl_base_addr) {
-		utrdl_size =
-		(sizeof(struct utp_transfer_req_desc) * hba->nutrs);
-		dma_free_coherent(hba->dev, utrdl_size,
-				  hba->utrdl_base_addr, hba->utrdl_dma_addr);
-	}
-
-	if (hba->ucdl_base_addr) {
-		ucdl_size =
-		(sizeof(struct utp_transfer_cmd_desc) * hba->nutrs);
-		dma_free_coherent(hba->dev, ucdl_size,
-				  hba->ucdl_base_addr, hba->ucdl_dma_addr);
-	}
-}
-
-/**
  * ufshcd_is_valid_req_rsp - checks if controller TR response is valid
  * @ucd_rsp_ptr: pointer to response UPIU
  *
@@ -690,10 +658,10 @@
 
 	/* Allocate memory for UTP command descriptors */
 	ucdl_size = (sizeof(struct utp_transfer_cmd_desc) * hba->nutrs);
-	hba->ucdl_base_addr = dma_alloc_coherent(hba->dev,
-						 ucdl_size,
-						 &hba->ucdl_dma_addr,
-						 GFP_KERNEL);
+	hba->ucdl_base_addr = dmam_alloc_coherent(hba->dev,
+						  ucdl_size,
+						  &hba->ucdl_dma_addr,
+						  GFP_KERNEL);
 
 	/*
 	 * UFSHCI requires UTP command descriptor to be 128 byte aligned.
@@ -713,10 +681,10 @@
 	 * UFSHCI requires 1024 byte alignment of UTRD
 	 */
 	utrdl_size = (sizeof(struct utp_transfer_req_desc) * hba->nutrs);
-	hba->utrdl_base_addr = dma_alloc_coherent(hba->dev,
-						  utrdl_size,
-						  &hba->utrdl_dma_addr,
-						  GFP_KERNEL);
+	hba->utrdl_base_addr = dmam_alloc_coherent(hba->dev,
+						   utrdl_size,
+						   &hba->utrdl_dma_addr,
+						   GFP_KERNEL);
 	if (!hba->utrdl_base_addr ||
 	    WARN_ON(hba->utrdl_dma_addr & (PAGE_SIZE - 1))) {
 		dev_err(hba->dev,
@@ -729,10 +697,10 @@
 	 * UFSHCI requires 1024 byte alignment of UTMRD
 	 */
 	utmrdl_size = sizeof(struct utp_task_req_desc) * hba->nutmrs;
-	hba->utmrdl_base_addr = dma_alloc_coherent(hba->dev,
-						   utmrdl_size,
-						   &hba->utmrdl_dma_addr,
-						   GFP_KERNEL);
+	hba->utmrdl_base_addr = dmam_alloc_coherent(hba->dev,
+						    utmrdl_size,
+						    &hba->utmrdl_dma_addr,
+						    GFP_KERNEL);
 	if (!hba->utmrdl_base_addr ||
 	    WARN_ON(hba->utmrdl_dma_addr & (PAGE_SIZE - 1))) {
 		dev_err(hba->dev,
@@ -741,14 +709,15 @@
 	}
 
 	/* Allocate memory for local reference block */
-	hba->lrb = kcalloc(hba->nutrs, sizeof(struct ufshcd_lrb), GFP_KERNEL);
+	hba->lrb = devm_kzalloc(hba->dev,
+				hba->nutrs * sizeof(struct ufshcd_lrb),
+				GFP_KERNEL);
 	if (!hba->lrb) {
 		dev_err(hba->dev, "LRB Memory allocation failed\n");
 		goto out;
 	}
 	return 0;
 out:
-	ufshcd_free_hba_memory(hba);
 	return -ENOMEM;
 }
 
@@ -1682,17 +1651,6 @@
 EXPORT_SYMBOL_GPL(ufshcd_resume);
 
 /**
- * ufshcd_hba_free - free allocated memory for
- *			host memory space data structures
- * @hba: per adapter instance
- */
-static void ufshcd_hba_free(struct ufs_hba *hba)
-{
-	iounmap(hba->mmio_base);
-	ufshcd_free_hba_memory(hba);
-}
-
-/**
  * ufshcd_remove - de-allocate SCSI host and host memory space
  *		data structure memory
  * @hba - per adapter instance
@@ -1701,9 +1659,7 @@
 {
 	/* disable interrupts */
 	ufshcd_disable_intr(hba, hba->intr_mask);
-
 	ufshcd_hba_stop(hba);
-	ufshcd_hba_free(hba);
 
 	scsi_remove_host(hba->host);
 	scsi_host_put(hba->host);
@@ -1789,23 +1745,23 @@
 	mutex_init(&hba->uic_cmd_mutex);
 
 	/* IRQ registration */
-	err = request_irq(irq, ufshcd_intr, IRQF_SHARED, UFSHCD, hba);
+	err = devm_request_irq(dev, irq, ufshcd_intr, IRQF_SHARED, UFSHCD, hba);
 	if (err) {
 		dev_err(hba->dev, "request irq failed\n");
-		goto out_lrb_free;
+		goto out_disable;
 	}
 
 	/* Enable SCSI tag mapping */
 	err = scsi_init_shared_tag_map(host, host->can_queue);
 	if (err) {
 		dev_err(hba->dev, "init shared queue failed\n");
-		goto out_free_irq;
+		goto out_disable;
 	}
 
 	err = scsi_add_host(host, hba->dev);
 	if (err) {
 		dev_err(hba->dev, "scsi_add_host failed\n");
-		goto out_free_irq;
+		goto out_disable;
 	}
 
 	/* Host controller enable */
@@ -1823,10 +1779,6 @@
 
 out_remove_scsi_host:
 	scsi_remove_host(hba->host);
-out_free_irq:
-	free_irq(irq, hba);
-out_lrb_free:
-	ufshcd_free_hba_memory(hba);
 out_disable:
 	scsi_host_put(host);
 out_error:
diff --git a/drivers/slimbus/slim-msm-ngd.c b/drivers/slimbus/slim-msm-ngd.c
index 2f19863..0c9959c 100644
--- a/drivers/slimbus/slim-msm-ngd.c
+++ b/drivers/slimbus/slim-msm-ngd.c
@@ -226,6 +226,8 @@
 	u8 *puc;
 	int ret = 0;
 	u8 la = txn->la;
+	u8 txn_mt;
+	u16 txn_mc = txn->mc;
 	u8 wbuf[SLIM_MSGQ_BUF_LEN];
 
 	if (!pm_runtime_enabled(dev->dev) && dev->state == MSM_CTRL_ASLEEP &&
@@ -402,6 +404,14 @@
 		puc[1] += dev->port_b;
 	}
 	dev->err = 0;
+	/*
+	 * If it's a read txn, it may be freed if a response is received by
+	 * received thread before reaching end of this function.
+	 * mc, mt may have changed to convert standard slimbus code/type to
+	 * satellite user-defined message. Reinitialize again
+	 */
+	txn_mc = txn->mc;
+	txn_mt = txn->mt;
 	dev->wr_comp = &tx_sent;
 	ret = msm_send_msg_buf(dev, pbuf, txn->rl,
 			NGD_BASE(dev->ctrl.nr, dev->ver) + NGD_TX_MSG);
@@ -427,7 +437,7 @@
 		void __iomem *ngd = dev->base + NGD_BASE(dev->ctrl.nr,
 							dev->ver);
 		dev_err(dev->dev, "TX failed :MC:0x%x,mt:0x%x, ret:%d, ver:%d",
-				txn->mc, txn->mt, ret, dev->ver);
+				txn_mc, txn_mt, ret, dev->ver);
 		conf = readl_relaxed(ngd);
 		stat = readl_relaxed(ngd + NGD_STATUS);
 		rx_msgq = readl_relaxed(ngd + NGD_RX_MSGQ_CFG);
@@ -438,10 +448,10 @@
 		pr_err("conf:0x%x,stat:0x%x,rxmsgq:0x%x", conf, stat, rx_msgq);
 		pr_err("int_stat:0x%x,int_en:0x%x,int_cll:0x%x", int_stat,
 						int_en, int_clr);
-	} else if (txn->mt == SLIM_MSG_MT_DEST_REFERRED_USER &&
-		(txn->mc == SLIM_USR_MC_CONNECT_SRC ||
-		 txn->mc == SLIM_USR_MC_CONNECT_SINK ||
-		 txn->mc == SLIM_USR_MC_DISCONNECT_PORT)) {
+	} else if (txn_mt == SLIM_MSG_MT_DEST_REFERRED_USER &&
+		(txn_mc == SLIM_USR_MC_CONNECT_SRC ||
+		 txn_mc == SLIM_USR_MC_CONNECT_SINK ||
+		 txn_mc == SLIM_USR_MC_DISCONNECT_PORT)) {
 		int timeout;
 		mutex_unlock(&dev->tx_lock);
 		msm_slim_put_ctrl(dev);
@@ -461,7 +471,7 @@
 	}
 ngd_xfer_err:
 	mutex_unlock(&dev->tx_lock);
-	if (txn->mc != SLIM_USR_MC_REPORT_SATELLITE)
+	if (txn_mc != SLIM_USR_MC_REPORT_SATELLITE)
 		msm_slim_put_ctrl(dev);
 	return ret ? ret : dev->err;
 }
@@ -988,7 +998,6 @@
 		container_of(qmi, struct msm_slim_ctrl, qmi);
 	struct slim_controller *ctrl = &dev->ctrl;
 	struct slim_device *sbdev;
-	int i;
 
 	ngd_slim_enable(dev, false);
 	/* disconnect BAM pipes */
@@ -997,14 +1006,9 @@
 	if (dev->use_tx_msgqs == MSM_MSGQ_ENABLED)
 		dev->use_tx_msgqs = MSM_MSGQ_DOWN;
 	msm_slim_sps_exit(dev, false);
-	mutex_lock(&ctrl->m_ctrl);
 	/* device up should be called again after SSR */
 	list_for_each_entry(sbdev, &ctrl->devs, dev_list)
-		sbdev->notified = false;
-	/* invalidate logical addresses */
-	for (i = 0; i < ctrl->num_dev; i++)
-		ctrl->addrt[i].valid = false;
-	mutex_unlock(&ctrl->m_ctrl);
+		slim_report_absent(sbdev);
 	pr_info("SLIM ADSP SSR (DOWN) done");
 }
 
diff --git a/drivers/slimbus/slimbus.c b/drivers/slimbus/slimbus.c
index 201470f..b074289 100644
--- a/drivers/slimbus/slimbus.c
+++ b/drivers/slimbus/slimbus.c
@@ -286,20 +286,41 @@
 	.release	= slim_dev_release,
 };
 
-static void slim_report_present(struct work_struct *work)
+static void slim_report(struct work_struct *work)
 {
 	u8 laddr;
-	int ret;
+	int ret, i;
 	struct slim_driver *sbdrv;
 	struct slim_device *sbdev =
 			container_of(work, struct slim_device, wd);
-	if (sbdev->notified || !sbdev->dev.driver)
+	struct slim_controller *ctrl = sbdev->ctrl;
+	if (!sbdev->dev.driver)
+		return;
+	/* check if device-up or down needs to be called */
+	mutex_lock(&ctrl->m_ctrl);
+	/* address no longer valid, means device reported absent */
+	for (i = 0; i < ctrl->num_dev; i++) {
+		if (sbdev->laddr == ctrl->addrt[i].laddr &&
+			ctrl->addrt[i].valid == false &&
+			sbdev->notified)
+			break;
+	}
+	mutex_unlock(&ctrl->m_ctrl);
+	sbdrv = to_slim_driver(sbdev->dev.driver);
+	if (i < ctrl->num_dev) {
+		sbdev->notified = false;
+		if (sbdrv->device_down)
+			sbdrv->device_down(sbdev);
+		return;
+	}
+	if (sbdev->notified)
 		return;
 	ret = slim_get_logical_addr(sbdev, sbdev->e_addr, 6, &laddr);
-	sbdrv = to_slim_driver(sbdev->dev.driver);
-	if (!ret && sbdrv->device_up) {
-		sbdev->notified = true;
-		sbdrv->device_up(sbdev);
+	if (!ret) {
+		if (sbdrv)
+			sbdev->notified = true;
+		if (sbdrv->device_up)
+			sbdrv->device_up(sbdev);
 	}
 }
 
@@ -322,7 +343,7 @@
 	INIT_LIST_HEAD(&sbdev->mark_define);
 	INIT_LIST_HEAD(&sbdev->mark_suspend);
 	INIT_LIST_HEAD(&sbdev->mark_removal);
-	INIT_WORK(&sbdev->wd, slim_report_present);
+	INIT_WORK(&sbdev->wd, slim_report);
 	mutex_lock(&ctrl->m_ctrl);
 	list_add_tail(&sbdev->dev_list, &ctrl->devs);
 	mutex_unlock(&ctrl->m_ctrl);
@@ -604,6 +625,31 @@
 EXPORT_SYMBOL_GPL(slim_add_numbered_controller);
 
 /*
+ * slim_report_absent: Controller calls this function when a device
+ *	reports absent, OR when the device cannot be communicated with
+ * @sbdev: Device that cannot be reached, or sent report absent
+ */
+void slim_report_absent(struct slim_device *sbdev)
+{
+	struct slim_controller *ctrl;
+	int i;
+	if (!sbdev)
+		return;
+	ctrl = sbdev->ctrl;
+	if (!ctrl)
+		return;
+	/* invalidate logical addresses */
+	mutex_lock(&ctrl->m_ctrl);
+	for (i = 0; i < ctrl->num_dev; i++) {
+		if (sbdev->laddr == ctrl->addrt[i].laddr)
+			ctrl->addrt[i].valid = false;
+	}
+	mutex_unlock(&ctrl->m_ctrl);
+	queue_work(ctrl->wq, &sbdev->wd);
+}
+EXPORT_SYMBOL(slim_report_absent);
+
+/*
  * slim_msg_response: Deliver Message response received from a device to the
  *	framework.
  * @ctrl: Controller handle
diff --git a/drivers/spi/spi_qsd.c b/drivers/spi/spi_qsd.c
index 25b4b5e..4512d02 100644
--- a/drivers/spi/spi_qsd.c
+++ b/drivers/spi/spi_qsd.c
@@ -2664,7 +2664,6 @@
 struct msm_spi_platform_data * __init msm_spi_dt_to_pdata(
 			struct platform_device *pdev, struct msm_spi *dd)
 {
-	int i;
 	struct msm_spi_platform_data *pdata;
 
 	pdata = devm_kzalloc(&pdev->dev, sizeof(*pdata), GFP_KERNEL);
@@ -2725,10 +2724,6 @@
 			pdata->use_bam = false;
 		}
 	}
-
-	for (i = 0; i < ARRAY_SIZE(spi_cs_rsrcs); ++i)
-		dd->cs_gpios[i].valid = (dd->cs_gpios[i].gpio_num >= 0);
-
 	return pdata;
 }
 
@@ -2834,10 +2829,12 @@
 						i + ARRAY_SIZE(spi_rsrcs));
 			dd->cs_gpios[i].gpio_num = resource ?
 							resource->start : -1;
-			dd->cs_gpios[i].valid = 0;
 		}
 	}
 
+	for (i = 0; i < ARRAY_SIZE(spi_cs_rsrcs); ++i)
+		dd->cs_gpios[i].valid = 0;
+
 	dd->pdata = pdata;
 	resource = platform_get_resource(pdev, IORESOURCE_MEM, 0);
 	if (!resource) {
diff --git a/drivers/spmi/qpnp-int.c b/drivers/spmi/qpnp-int.c
index 03e9021..3e14333 100644
--- a/drivers/spmi/qpnp-int.c
+++ b/drivers/spmi/qpnp-int.c
@@ -591,8 +591,9 @@
 }
 EXPORT_SYMBOL(qpnpint_unregister_controller);
 
-int qpnpint_handle_irq(struct spmi_controller *spmi_ctrl,
-		       struct qpnp_irq_spec *spec)
+static int __qpnpint_handle_irq(struct spmi_controller *spmi_ctrl,
+		       struct qpnp_irq_spec *spec,
+		       bool show)
 {
 	struct irq_domain *domain;
 	unsigned long hwirq, busno;
@@ -617,12 +618,40 @@
 	domain = chip_lookup[busno]->domain;
 	irq = irq_radix_revmap_lookup(domain, hwirq);
 
-	generic_handle_irq(irq);
+	if (show) {
+		struct irq_desc *desc;
+		const char *name = "null";
+
+		desc = irq_to_desc(irq);
+		if (desc == NULL)
+			name = "stray irq";
+		else if (desc->action && desc->action->name)
+			name = desc->action->name;
+
+		pr_warn("%d triggered [0x%01x, 0x%02x,0x%01x] %s\n",
+				irq, spec->slave, spec->per, spec->irq, name);
+	} else {
+		generic_handle_irq(irq);
+	}
 
 	return 0;
 }
+
+int qpnpint_handle_irq(struct spmi_controller *spmi_ctrl,
+		       struct qpnp_irq_spec *spec)
+{
+	return  __qpnpint_handle_irq(spmi_ctrl, spec, false);
+}
+
 EXPORT_SYMBOL(qpnpint_handle_irq);
 
+int qpnpint_show_irq(struct spmi_controller *spmi_ctrl,
+		       struct qpnp_irq_spec *spec)
+{
+	return  __qpnpint_handle_irq(spmi_ctrl, spec, true);
+}
+EXPORT_SYMBOL(qpnpint_show_irq);
+
 int __init qpnpint_of_init(struct device_node *node, struct device_node *parent)
 {
 	struct q_chip_data *chip_d;
diff --git a/drivers/spmi/spmi-pmic-arb.c b/drivers/spmi/spmi-pmic-arb.c
index f85a576..bc328e0 100644
--- a/drivers/spmi/spmi-pmic-arb.c
+++ b/drivers/spmi/spmi-pmic-arb.c
@@ -24,6 +24,7 @@
 #include <linux/of_spmi.h>
 #include <linux/module.h>
 #include <linux/seq_file.h>
+#include <linux/syscore_ops.h>
 #include <mach/qpnp-int.h>
 #include "spmi-dbgfs.h"
 
@@ -126,9 +127,12 @@
 	u32			mapping_table[SPMI_MAPPING_TABLE_LEN];
 };
 
+static struct spmi_pmic_arb_dev *the_pmic_arb;
+
 static u32 pmic_arb_read(struct spmi_pmic_arb_dev *dev, u32 offset)
 {
 	u32 val = readl_relaxed(dev->base + offset);
+
 	pr_debug("address 0x%p, val 0x%x\n", dev->base + offset, val);
 	return val;
 }
@@ -485,7 +489,7 @@
 }
 
 static irqreturn_t
-periph_interrupt(struct spmi_pmic_arb_dev *pmic_arb, u8 apid)
+periph_interrupt(struct spmi_pmic_arb_dev *pmic_arb, u8 apid, bool show)
 {
 	u16 ppid = get_peripheral_id(pmic_arb, apid);
 	void __iomem *intr = pmic_arb->intr;
@@ -511,10 +515,12 @@
 	/* Read the peripheral specific interrupt bits */
 	status = readl_relaxed(intr + SPMI_PIC_IRQ_STATUS(apid));
 
-	/* Clear the peripheral interrupts */
-	writel_relaxed(status, intr + SPMI_PIC_IRQ_CLEAR(apid));
-	/* Interrupt needs to be cleared/acknowledged before exiting ISR */
-	mb();
+	if (!show) {
+		/* Clear the peripheral interrupts */
+		writel_relaxed(status, intr + SPMI_PIC_IRQ_CLEAR(apid));
+		/* Irq needs to be cleared/acknowledged before exiting ISR */
+		mb();
+	}
 
 	dev_dbg(pmic_arb->dev,
 		"interrupt, apid:0x%x, sid:0x%x, pid:0x%x, intr:0x%x\n",
@@ -528,14 +534,20 @@
 				.per = pid,
 				.irq = i,
 			};
-			qpnpint_handle_irq(&pmic_arb->controller, &irq_spec);
+			if (show)
+				qpnpint_show_irq(&pmic_arb->controller,
+								&irq_spec);
+			else
+				qpnpint_handle_irq(&pmic_arb->controller,
+								&irq_spec);
 		}
 	}
 	return IRQ_HANDLED;
 }
 
 /* Peripheral interrupt handler */
-static irqreturn_t pmic_arb_periph_irq(int irq, void *dev_id)
+static irqreturn_t
+__pmic_arb_periph_irq(int irq, void *dev_id, bool show)
 {
 	struct spmi_pmic_arb_dev *pmic_arb = dev_id;
 	void __iomem *intr = pmic_arb->intr;
@@ -556,7 +568,8 @@
 		for (j = 0; status && j < 32; ++j, status >>= 1) {
 			if (status & 0x1) {
 				u8 id = (i * 32) + j;
-				ret |= periph_interrupt(pmic_arb, id);
+
+				ret |= periph_interrupt(pmic_arb, id, show);
 			}
 		}
 	}
@@ -564,6 +577,22 @@
 	return ret;
 }
 
+static irqreturn_t pmic_arb_periph_irq(int irq, void *dev_id)
+{
+	return __pmic_arb_periph_irq(irq, dev_id, false);
+}
+
+static void spmi_pmic_arb_resume(void)
+{
+	if (qpnpint_show_resume_irq())
+		__pmic_arb_periph_irq(the_pmic_arb->pic_irq,
+						the_pmic_arb, true);
+}
+
+static struct syscore_ops spmi_pmic_arb_syscore_ops = {
+	.resume = spmi_pmic_arb_resume,
+};
+
 /* Callback to register an APID for specific slave/peripheral */
 static int pmic_arb_intr_priv_data(struct spmi_controller *ctrl,
 				struct qpnp_irq_spec *spec, uint32_t *data)
@@ -766,6 +795,9 @@
 	pr_debug("PMIC Arb Version 0x%x\n",
 			pmic_arb_read(pmic_arb, PMIC_ARB_VERSION));
 
+	the_pmic_arb = pmic_arb;
+	register_syscore_ops(&spmi_pmic_arb_syscore_ops);
+
 	return 0;
 
 err_reg_controller:
diff --git a/drivers/staging/android/Kconfig b/drivers/staging/android/Kconfig
index 43d17c2..b46bbaf 100644
--- a/drivers/staging/android/Kconfig
+++ b/drivers/staging/android/Kconfig
@@ -25,6 +25,14 @@
 	tristate "Android log driver"
 	default n
 
+config LOGCAT_SIZE
+	int "Adjust android log buffer sizes"
+	default 256
+	depends on ANDROID_LOGGER
+	help
+	  Set logger buffer size. Enter a number greater than zero.
+	  Any value less than 256 is recommended. Reduce value to save kernel static memory size.
+
 config ANDROID_PERSISTENT_RAM
 	bool
 	depends on HAVE_MEMBLOCK
diff --git a/drivers/staging/android/binder.c b/drivers/staging/android/binder.c
index 3abc3b9..b7bf74e 100644
--- a/drivers/staging/android/binder.c
+++ b/drivers/staging/android/binder.c
@@ -33,6 +33,7 @@
 #include <linux/uaccess.h>
 #include <linux/vmalloc.h>
 #include <linux/slab.h>
+#include <linux/security.h>
 
 #include "binder.h"
 
@@ -1488,6 +1489,10 @@
 			return_error = BR_DEAD_REPLY;
 			goto err_dead_binder;
 		}
+		if (security_binder_transaction(proc->tsk, target_proc->tsk) < 0) {
+			return_error = BR_FAILED_REPLY;
+			goto err_invalid_target_handle;
+		}
 		if (!(tr->flags & TF_ONE_WAY) && thread->transaction_stack) {
 			struct binder_transaction *tmp;
 			tmp = thread->transaction_stack;
@@ -1633,6 +1638,10 @@
 					fp->cookie, node->cookie);
 				goto err_binder_get_ref_for_node_failed;
 			}
+			if (security_binder_transfer_binder(proc->tsk, target_proc->tsk)) {
+				return_error = BR_FAILED_REPLY;
+				goto err_binder_get_ref_for_node_failed;
+			}
 			ref = binder_get_ref_for_node(target_proc, node);
 			if (ref == NULL) {
 				return_error = BR_FAILED_REPLY;
@@ -1662,6 +1671,10 @@
 				return_error = BR_FAILED_REPLY;
 				goto err_binder_get_ref_failed;
 			}
+			if (security_binder_transfer_binder(proc->tsk, target_proc->tsk)) {
+				return_error = BR_FAILED_REPLY;
+				goto err_binder_get_ref_failed;
+			}
 			if (ref->node->proc == target_proc) {
 				if (fp->type == BINDER_TYPE_HANDLE)
 					fp->type = BINDER_TYPE_BINDER;
@@ -1715,6 +1728,11 @@
 				return_error = BR_FAILED_REPLY;
 				goto err_fget_failed;
 			}
+			if (security_binder_transfer_file(proc->tsk, target_proc->tsk, file) < 0) {
+				fput(file);
+				return_error = BR_FAILED_REPLY;
+				goto err_get_unused_fd_failed;
+			}
 			target_fd = task_get_unused_fd_flags(target_proc, O_CLOEXEC);
 			if (target_fd < 0) {
 				fput(file);
@@ -2748,6 +2766,9 @@
 			ret = -EBUSY;
 			goto err;
 		}
+		ret = security_binder_set_context_mgr(proc->tsk);
+		if (ret < 0)
+			goto err;
 		if (binder_context_mgr_uid != -1) {
 			if (binder_context_mgr_uid != current->cred->euid) {
 				binder_debug(BINDER_DEBUG_TOP_ERRORS,
diff --git a/drivers/staging/android/logger.c b/drivers/staging/android/logger.c
index e1e886c..267a8ec 100644
--- a/drivers/staging/android/logger.c
+++ b/drivers/staging/android/logger.c
@@ -29,6 +29,10 @@
 
 #include <asm/ioctls.h>
 
+#ifndef CONFIG_LOGCAT_SIZE
+#define CONFIG_LOGCAT_SIZE 256
+#endif
+
 /*
  * struct logger_log - represents a specific log, such as 'main' or 'radio'
  *
@@ -728,10 +732,10 @@
 	.size = SIZE, \
 };
 
-DEFINE_LOGGER_DEVICE(log_main, LOGGER_LOG_MAIN, 64*1024)
-DEFINE_LOGGER_DEVICE(log_events, LOGGER_LOG_EVENTS, 64*1024)
-DEFINE_LOGGER_DEVICE(log_radio, LOGGER_LOG_RADIO, 64*1024)
-DEFINE_LOGGER_DEVICE(log_system, LOGGER_LOG_SYSTEM, 64*1024)
+DEFINE_LOGGER_DEVICE(log_main, LOGGER_LOG_MAIN, CONFIG_LOGCAT_SIZE*1024)
+DEFINE_LOGGER_DEVICE(log_events, LOGGER_LOG_EVENTS, CONFIG_LOGCAT_SIZE*1024)
+DEFINE_LOGGER_DEVICE(log_radio, LOGGER_LOG_RADIO, CONFIG_LOGCAT_SIZE*1024)
+DEFINE_LOGGER_DEVICE(log_system, LOGGER_LOG_SYSTEM, CONFIG_LOGCAT_SIZE*1024)
 
 static struct logger_log *get_log_from_minor(int minor)
 {
diff --git a/drivers/thermal/msm8974-tsens.c b/drivers/thermal/msm8974-tsens.c
index 6933163..613af4e 100644
--- a/drivers/thermal/msm8974-tsens.c
+++ b/drivers/thermal/msm8974-tsens.c
@@ -164,7 +164,7 @@
 #define TSENS10_POINT2_BACKUP_MASK	0x3f000000
 
 #define TSENS_8X26_BASE0_MASK		0x1fe000
-#define TSENS0_8X26_POINT1_MASK		0x7f00000
+#define TSENS0_8X26_POINT1_MASK		0x7e00000
 #define TSENS1_8X26_POINT1_MASK		0x3f
 #define TSENS2_8X26_POINT1_MASK		0xfc0
 #define TSENS3_8X26_POINT1_MASK		0x3f000
@@ -174,11 +174,11 @@
 #define TSENS_8X26_TSENS_CAL_SEL	0xe0000000
 #define TSENS_8X26_BASE1_MASK		0xff
 #define TSENS0_8X26_POINT2_MASK		0x3f00
-#define TSENS1_8X26_POINT2_MASK		0xfc00
+#define TSENS1_8X26_POINT2_MASK		0xfc000
 #define TSENS2_8X26_POINT2_MASK		0x3f00000
 #define TSENS3_8X26_POINT2_MASK		0xfc000000
-#define TSENS4_8X26_POINT2_MASK		0xfc000000
-#define TSENS5_8X26_POINT2_MASK		0x3f00000
+#define TSENS4_8X26_POINT2_MASK		0x3f00000
+#define TSENS5_8X26_POINT2_MASK		0xfc000000
 #define TSENS6_8X26_POINT2_MASK		0x7e0000
 
 #define TSENS_8X26_CAL_SEL_SHIFT	29
@@ -564,7 +564,7 @@
 	unsigned int reg_cntl;
 	int code, hi_code, lo_code, code_err_chk, sensor_sw_id = 0, rc = 0;
 
-	if (!tm_sensor || trip < 0 || !temp)
+	if (!tm_sensor || trip < 0)
 		return -EINVAL;
 
 	rc = tsens_get_sw_id_mapping(tm_sensor->sensor_hw_num, &sensor_sw_id);
@@ -664,6 +664,15 @@
 			lower_thr = true;
 		}
 		if (upper_thr || lower_thr) {
+			unsigned long temp;
+			enum thermal_trip_type trip =
+					THERMAL_TRIP_CONFIGURABLE_LOW;
+
+			if (upper_thr)
+				trip = THERMAL_TRIP_CONFIGURABLE_HI;
+			tsens_tz_get_temp(tm->sensor[i].tz_dev, &temp);
+			thermal_sensor_trip(tm->sensor[i].tz_dev, trip, temp);
+
 			/* Notify user space */
 			queue_work(tm->tsens_wq, &tm->sensor[i].work);
 			rc = tsens_get_sw_id_mapping(
diff --git a/drivers/thermal/msm_thermal.c b/drivers/thermal/msm_thermal.c
index 974cadc..00df613 100644
--- a/drivers/thermal/msm_thermal.c
+++ b/drivers/thermal/msm_thermal.c
@@ -14,9 +14,11 @@
 #include <linux/kernel.h>
 #include <linux/init.h>
 #include <linux/module.h>
+#include <linux/kthread.h>
 #include <linux/mutex.h>
 #include <linux/msm_tsens.h>
 #include <linux/workqueue.h>
+#include <linux/completion.h>
 #include <linux/cpu.h>
 #include <linux/cpufreq.h>
 #include <linux/msm_tsens.h>
@@ -29,6 +31,7 @@
 #include <linux/sysfs.h>
 #include <linux/types.h>
 #include <linux/android_alarm.h>
+#include <linux/thermal.h>
 #include <mach/cpufreq.h>
 #include <mach/rpm-regulator.h>
 #include <mach/rpm-regulator-smd.h>
@@ -45,7 +48,10 @@
 static uint32_t wakeup_ms;
 static struct alarm thermal_rtc;
 static struct kobject *tt_kobj;
+static struct kobject *cc_kobj;
 static struct work_struct timer_work;
+static struct task_struct *hotplug_task;
+static struct completion hotplug_notify_complete;
 
 static int enabled;
 static int rails_cnt;
@@ -67,6 +73,14 @@
 static DEFINE_MUTEX(vdd_rstr_mutex);
 static DEFINE_MUTEX(psm_mutex);
 
+struct cpu_info {
+	uint32_t cpu;
+	bool offline;
+	bool user_offline;
+	const char *sensor_type;
+	struct sensor_threshold thresh[2];
+};
+
 struct rail {
 	const char *name;
 	uint32_t freq_req;
@@ -91,6 +105,7 @@
 
 static struct psm_rail *psm_rails;
 static struct rail *rails;
+static struct cpu_info cpus[NR_CPUS];
 
 struct vdd_rstr_enable {
 	struct kobj_attribute ko_attr;
@@ -658,11 +673,67 @@
 	}
 	mutex_unlock(&core_control_mutex);
 }
+/* Call with core_control_mutex locked */
+static int __ref update_offline_cores(int val)
+{
+	int cpu = 0;
+	int ret = 0;
+
+	if (!core_control_enabled)
+		return 0;
+
+	cpus_offlined = msm_thermal_info.core_control_mask & val;
+
+	for_each_possible_cpu(cpu) {
+		if (!(cpus_offlined & BIT(cpu)))
+			continue;
+		if (!cpu_online(cpu))
+			continue;
+		ret = cpu_down(cpu);
+		if (ret)
+			pr_err("%s: Unable to offline cpu%d\n",
+				KBUILD_MODNAME, cpu);
+	}
+	return ret;
+}
+
+static __ref int do_hotplug(void *data)
+{
+	int ret = 0;
+	int cpu = 0;
+	uint32_t mask = 0;
+
+	if (!core_control_enabled)
+		return -EINVAL;
+
+	while (!kthread_should_stop()) {
+		wait_for_completion(&hotplug_notify_complete);
+		INIT_COMPLETION(hotplug_notify_complete);
+		mask = 0;
+
+		mutex_lock(&core_control_mutex);
+		for_each_possible_cpu(cpu) {
+			if (cpus[cpu].offline || cpus[cpu].user_offline)
+				mask |= BIT(cpu);
+		}
+		if (mask != cpus_offlined)
+			update_offline_cores(mask);
+		mutex_unlock(&core_control_mutex);
+		sysfs_notify(cc_kobj, NULL, "cpus_offlined");
+	}
+
+	return ret;
+}
 #else
 static void do_core_control(long temp)
 {
 	return;
 }
+
+static __ref int do_hotplug(void *data)
+{
+	return 0;
+}
 #endif
 
 static int do_vdd_restriction(void)
@@ -848,7 +919,7 @@
 		if (core_control_enabled &&
 			(msm_thermal_info.core_control_mask & BIT(cpu)) &&
 			(cpus_offlined & BIT(cpu))) {
-			pr_info(
+			pr_debug(
 			"%s: Preventing cpu%d from coming online.\n",
 				KBUILD_MODNAME, cpu);
 			return NOTIFY_BAD;
@@ -896,6 +967,112 @@
 			ts.tv_sec, ts.tv_usec);
 }
 
+static int hotplug_notify(enum thermal_trip_type type, int temp, void *data)
+{
+	struct cpu_info *cpu_node = (struct cpu_info *)data;
+
+	pr_info("%s: %s reach temp threshold: %d\n", KBUILD_MODNAME,
+			cpu_node->sensor_type, temp);
+
+	if (!(msm_thermal_info.core_control_mask & BIT(cpu_node->cpu)))
+		return 0;
+	switch (type) {
+	case THERMAL_TRIP_CONFIGURABLE_HI:
+		if (!(cpu_node->offline))
+			cpu_node->offline = 1;
+		break;
+	case THERMAL_TRIP_CONFIGURABLE_LOW:
+		if (cpu_node->offline)
+			cpu_node->offline = 0;
+		break;
+	default:
+		break;
+	}
+	if (hotplug_task)
+		complete(&hotplug_notify_complete);
+	else
+		pr_err("%s: Hotplug task is not initialized\n", KBUILD_MODNAME);
+	return 0;
+}
+/* Adjust cpus offlined bit based on temperature reading. */
+static int hotplug_init_cpu_offlined(void)
+{
+	struct tsens_device tsens_dev;
+	long temp = 0;
+	int cpu = 0;
+
+	mutex_lock(&core_control_mutex);
+	for_each_possible_cpu(cpu) {
+		if (!(msm_thermal_info.core_control_mask & BIT(cpus[cpu].cpu)))
+			continue;
+		tsens_dev.sensor_num = sensor_get_id(\
+				(char *)cpus[cpu].sensor_type);
+		if (tsens_get_temp(&tsens_dev, &temp)) {
+			pr_err("%s: Unable to read TSENS sensor %d\n",
+				KBUILD_MODNAME, tsens_dev.sensor_num);
+			return -EINVAL;
+		}
+
+		if (temp >= msm_thermal_info.hotplug_temp_degC)
+			cpus[cpu].offline = 1;
+		else if (temp <= (msm_thermal_info.hotplug_temp_degC -
+			msm_thermal_info.hotplug_temp_hysteresis_degC))
+			cpus[cpu].offline = 0;
+	}
+	mutex_unlock(&core_control_mutex);
+
+	if (hotplug_task)
+		complete(&hotplug_notify_complete);
+	else {
+		pr_err("%s: Hotplug task is not initialized\n",
+					KBUILD_MODNAME);
+		return -EINVAL;
+	}
+	return 0;
+}
+
+static void hotplug_init(void)
+{
+	int cpu = 0;
+
+	if (hotplug_task)
+		return;
+
+	for_each_possible_cpu(cpu) {
+		if (!(msm_thermal_info.core_control_mask & BIT(cpus[cpu].cpu)))
+			continue;
+		cpus[cpu].cpu = (uint32_t)cpu;
+		cpus[cpu].thresh[0].temp = msm_thermal_info.hotplug_temp_degC;
+		cpus[cpu].thresh[0].trip = THERMAL_TRIP_CONFIGURABLE_HI;
+		cpus[cpu].thresh[0].notify = hotplug_notify;
+		cpus[cpu].thresh[0].data = (void *)&cpus[cpu];
+		sensor_set_trip(sensor_get_id((char *)cpus[cpu].sensor_type),
+				&cpus[cpu].thresh[0]);
+
+		cpus[cpu].thresh[1].temp = msm_thermal_info.hotplug_temp_degC -
+				msm_thermal_info.hotplug_temp_hysteresis_degC;
+		cpus[cpu].thresh[1].trip = THERMAL_TRIP_CONFIGURABLE_LOW;
+		cpus[cpu].thresh[1].notify = hotplug_notify;
+		cpus[cpu].thresh[1].data = (void *)&cpus[cpu];
+		sensor_set_trip(sensor_get_id((char *)cpus[cpu].sensor_type),
+				&cpus[cpu].thresh[1]);
+
+	}
+	init_completion(&hotplug_notify_complete);
+	hotplug_task = kthread_run(do_hotplug, NULL, "msm_thermal:hotplug");
+	if (IS_ERR(hotplug_task)) {
+		pr_err("%s: Failed to create do_hotplug thread\n",
+				KBUILD_MODNAME);
+		return;
+	}
+	/*
+	 * Adjust cpus offlined bit when hotplug intitializes so that the new
+	 * cpus offlined state is based on hotplug threshold range
+	 */
+	if (hotplug_init_cpu_offlined())
+		kthread_stop(hotplug_task);
+}
+
 /*
  * We will reset the cpu frequencies limits here. The core online/offline
  * status will be carried over to the process stopping the msm_thermal, as
@@ -922,9 +1099,10 @@
 	int ret = 0;
 
 	ret = param_set_bool(val, kp);
-	if (!enabled)
+	if (!enabled) {
 		disable_msm_thermal();
-	else
+		hotplug_init();
+	} else
 		pr_info("%s: no action for enabled = %d\n",
 				KBUILD_MODNAME, enabled);
 
@@ -941,37 +1119,6 @@
 module_param_cb(enabled, &module_ops, &enabled, 0644);
 MODULE_PARM_DESC(enabled, "enforce thermal limit on cpu");
 
-
-#ifdef CONFIG_SMP
-/* Call with core_control_mutex locked */
-static int __ref update_offline_cores(int val)
-{
-	int cpu = 0;
-	int ret = 0;
-
-	cpus_offlined = msm_thermal_info.core_control_mask & val;
-	if (!core_control_enabled)
-		return 0;
-
-	for_each_possible_cpu(cpu) {
-		if (!(cpus_offlined & BIT(cpu)))
-			continue;
-		if (!cpu_online(cpu))
-			continue;
-		ret = cpu_down(cpu);
-		if (ret)
-			pr_err("%s: Unable to offline cpu%d\n",
-				KBUILD_MODNAME, cpu);
-	}
-	return ret;
-}
-#else
-static int update_offline_cores(int val)
-{
-	return 0;
-}
-#endif
-
 static ssize_t show_cc_enabled(struct kobject *kobj,
 		struct kobj_attribute *attr, char *buf)
 {
@@ -984,7 +1131,6 @@
 	int ret = 0;
 	int val = 0;
 
-	mutex_lock(&core_control_mutex);
 	ret = kstrtoint(buf, 10, &val);
 	if (ret) {
 		pr_err("%s: Invalid input %s\n", KBUILD_MODNAME, buf);
@@ -998,14 +1144,17 @@
 	if (core_control_enabled) {
 		pr_info("%s: Core control enabled\n", KBUILD_MODNAME);
 		register_cpu_notifier(&msm_thermal_cpu_notifier);
-		update_offline_cores(cpus_offlined);
+		if (hotplug_task)
+			complete(&hotplug_notify_complete);
+		else
+			pr_err("%s: Hotplug task is not initialized\n",
+					KBUILD_MODNAME);
 	} else {
 		pr_info("%s: Core control disabled\n", KBUILD_MODNAME);
 		unregister_cpu_notifier(&msm_thermal_cpu_notifier);
 	}
 
 done_store_cc:
-	mutex_unlock(&core_control_mutex);
 	return count;
 }
 
@@ -1020,6 +1169,7 @@
 {
 	int ret = 0;
 	uint32_t val = 0;
+	int cpu;
 
 	mutex_lock(&core_control_mutex);
 	ret = kstrtouint(buf, 10, &val);
@@ -1034,10 +1184,16 @@
 		goto done_cc;
 	}
 
-	if (cpus_offlined == val)
-		goto done_cc;
+	for_each_possible_cpu(cpu) {
+		if (!(msm_thermal_info.core_control_mask & BIT(cpu)))
+			continue;
+		cpus[cpu].user_offline = !!(val & BIT(cpu));
+	}
 
-	update_offline_cores(val);
+	if (hotplug_task)
+		complete(&hotplug_notify_complete);
+	else
+		pr_err("%s: Hotplug task is not initialized\n", KBUILD_MODNAME);
 done_cc:
 	mutex_unlock(&core_control_mutex);
 	return count;
@@ -1108,7 +1264,6 @@
 static __init int msm_thermal_add_cc_nodes(void)
 {
 	struct kobject *module_kobj = NULL;
-	struct kobject *cc_kobj = NULL;
 	int ret = 0;
 
 	module_kobj = kset_find_obj(module_kset, KBUILD_MODNAME);
@@ -1190,8 +1345,7 @@
 		return -EINVAL;
 
 	enabled = 1;
-	if (num_possible_cpus() > 1)
-		core_control_enabled = 1;
+
 	INIT_DELAYED_WORK(&check_temp_work, check_temp);
 	schedule_delayed_work(&check_temp_work, 0);
 
@@ -1602,12 +1756,76 @@
 	return ret;
 }
 
+static int probe_cc(struct device_node *node, struct msm_thermal_data *data,
+		struct platform_device *pdev)
+{
+	char *key = NULL;
+	int cpu_cnt = 0;
+	int ret = 0;
+	int cpu = 0;
+
+	key = "qcom,core-limit-temp";
+	ret = of_property_read_u32(node, key, &data->core_limit_temp_degC);
+	if (ret)
+		goto read_node_fail;
+
+	key = "qcom,core-temp-hysteresis";
+	ret = of_property_read_u32(node, key, &data->core_temp_hysteresis_degC);
+	if (ret)
+		goto read_node_fail;
+
+	key = "qcom,core-control-mask";
+	ret = of_property_read_u32(node, key, &data->core_control_mask);
+	if (ret)
+		goto read_node_fail;
+
+	key = "qcom,hotplug-temp";
+	ret = of_property_read_u32(node, key, &data->hotplug_temp_degC);
+	if (ret)
+		goto read_node_fail;
+
+	key = "qcom,hotplug-temp-hysteresis";
+	ret = of_property_read_u32(node, key,
+			&data->hotplug_temp_hysteresis_degC);
+	if (ret)
+		goto read_node_fail;
+
+	key = "qcom,cpu-sensors";
+	cpu_cnt = of_property_count_strings(node, key);
+	if (cpu_cnt != num_possible_cpus()) {
+		pr_err("%s: Wrong number of cpu\n", KBUILD_MODNAME);
+		goto read_node_fail;
+	}
+
+	for_each_possible_cpu(cpu) {
+		cpus[cpu].cpu = cpu;
+		cpus[cpu].offline = 0;
+		cpus[cpu].user_offline = 0;
+		ret = of_property_read_string_index(node, key, cpu,
+				&cpus[cpu].sensor_type);
+		if (ret)
+			goto read_node_fail;
+	}
+
+	if (num_possible_cpus() > 1)
+		core_control_enabled = 1;
+
+read_node_fail:
+	if (ret) {
+		dev_info(&pdev->dev,
+			"%s:Failed reading node=%s, key=%s. KTM continues\n",
+			KBUILD_MODNAME, node->full_name, key);
+		core_control_enabled = 0;
+	}
+
+	return ret;
+}
+
 static int __devinit msm_thermal_dev_probe(struct platform_device *pdev)
 {
 	int ret = 0;
 	char *key = NULL;
 	struct device_node *node = pdev->dev.of_node;
-
 	struct msm_thermal_data data;
 
 	memset(&data, 0, sizeof(struct msm_thermal_data));
@@ -1640,15 +1858,7 @@
 	key = "qcom,freq-control-mask";
 	ret = of_property_read_u32(node, key, &data.freq_control_mask);
 
-	key = "qcom,core-limit-temp";
-	ret = of_property_read_u32(node, key, &data.core_limit_temp_degC);
-
-	key = "qcom,core-temp-hysteresis";
-	ret = of_property_read_u32(node, key, &data.core_temp_hysteresis_degC);
-
-	key = "qcom,core-control-mask";
-	ret = of_property_read_u32(node, key, &data.core_control_mask);
-
+	ret = probe_cc(node, &data, pdev);
 	/*
 	 * Probe optional properties below. Call probe_psm before
 	 * probe_vdd_rstr because rpm_regulator_get has to be called
diff --git a/drivers/thermal/qpnp-adc-tm.c b/drivers/thermal/qpnp-adc-tm.c
index eae5cc8..cf1801b 100644
--- a/drivers/thermal/qpnp-adc-tm.c
+++ b/drivers/thermal/qpnp-adc-tm.c
@@ -169,8 +169,22 @@
 #define QPNP_MIN_TIME			2000
 #define QPNP_MAX_TIME			2100
 
+struct qpnp_adc_thr_client_info {
+	struct list_head		list;
+	struct qpnp_adc_tm_btm_param	*btm_param;
+	int32_t				low_thr_requested;
+	int32_t				high_thr_requested;
+	enum qpnp_state_request		state_requested;
+	enum qpnp_state_request		state_req_copy;
+	bool				low_thr_set;
+	bool				high_thr_set;
+	bool				notify_low_thr;
+	bool				notify_high_thr;
+};
+
 struct qpnp_adc_tm_sensor {
 	struct thermal_zone_device	*tz_dev;
+	struct qpnp_adc_tm_chip		*chip;
 	enum thermal_device_mode	mode;
 	uint32_t			sensor_num;
 	enum qpnp_adc_meas_timer_select	timer_select;
@@ -180,71 +194,82 @@
 	uint32_t			btm_channel_num;
 	uint32_t			vadc_channel_num;
 	struct work_struct		work;
-	struct qpnp_adc_tm_btm_param	*btm_param;
 	bool				thermal_node;
-	bool				low_thr_notify;
-	bool				high_thr_notify;
 	uint32_t			scale_type;
+	struct list_head		thr_list;
 };
 
-struct qpnp_adc_tm_drv {
+struct qpnp_adc_tm_chip {
+	struct device			*dev;
 	struct qpnp_adc_drv		*adc;
+	struct list_head		list;
 	bool				adc_tm_initialized;
 	int				max_channels_available;
 	struct qpnp_vadc_chip		*vadc_dev;
+	struct work_struct		trigger_high_thr_work;
+	struct work_struct		trigger_low_thr_work;
 	struct qpnp_adc_tm_sensor	sensor[0];
 };
 
-struct qpnp_adc_tm_drv	*qpnp_adc_tm;
+LIST_HEAD(qpnp_adc_tm_device_list);
 
 struct qpnp_adc_tm_trip_reg_type {
-	uint16_t low_thr_lsb_addr;
-	uint16_t low_thr_msb_addr;
-	uint16_t high_thr_lsb_addr;
-	uint16_t high_thr_msb_addr;
-	u8 multi_meas_en;
-	u8 low_thr_int_chan_en;
-	u8 high_thr_int_chan_en;
-	u8 meas_interval_ctl;
+	enum qpnp_adc_tm_channel_select	btm_amux_chan;
+	uint16_t			low_thr_lsb_addr;
+	uint16_t			low_thr_msb_addr;
+	uint16_t			high_thr_lsb_addr;
+	uint16_t			high_thr_msb_addr;
+	u8				multi_meas_en;
+	u8				low_thr_int_chan_en;
+	u8				high_thr_int_chan_en;
+	u8				meas_interval_ctl;
 };
 
 static struct qpnp_adc_tm_trip_reg_type adc_tm_data[] = {
-	[QPNP_ADC_TM_M0_ADC_CH_SEL_CTL] = {QPNP_M0_LOW_THR_LSB,
+	[QPNP_ADC_TM_CHAN0] = {QPNP_ADC_TM_M0_ADC_CH_SEL_CTL,
+		QPNP_M0_LOW_THR_LSB,
 		QPNP_M0_LOW_THR_MSB, QPNP_M0_HIGH_THR_LSB,
 		QPNP_M0_HIGH_THR_MSB, QPNP_ADC_TM_MULTI_MEAS_EN_M0,
 		QPNP_ADC_TM_LOW_THR_INT_EN_M0, QPNP_ADC_TM_HIGH_THR_INT_EN_M0,
 		QPNP_ADC_TM_M0_MEAS_INTERVAL_CTL},
-	[QPNP_ADC_TM_M1_ADC_CH_SEL_CTL] = {QPNP_M1_LOW_THR_LSB,
+	[QPNP_ADC_TM_CHAN1] = {QPNP_ADC_TM_M1_ADC_CH_SEL_CTL,
+		QPNP_M1_LOW_THR_LSB,
 		QPNP_M1_LOW_THR_MSB, QPNP_M1_HIGH_THR_LSB,
 		QPNP_M1_HIGH_THR_MSB, QPNP_ADC_TM_MULTI_MEAS_EN_M1,
 		QPNP_ADC_TM_LOW_THR_INT_EN_M1, QPNP_ADC_TM_HIGH_THR_INT_EN_M1,
 		QPNP_ADC_TM_M1_MEAS_INTERVAL_CTL},
-	[QPNP_ADC_TM_M2_ADC_CH_SEL_CTL] = {QPNP_M2_LOW_THR_LSB,
+	[QPNP_ADC_TM_CHAN2] = {QPNP_ADC_TM_M2_ADC_CH_SEL_CTL,
+		QPNP_M2_LOW_THR_LSB,
 		QPNP_M2_LOW_THR_MSB, QPNP_M2_HIGH_THR_LSB,
 		QPNP_M2_HIGH_THR_MSB, QPNP_ADC_TM_MULTI_MEAS_EN_M2,
 		QPNP_ADC_TM_LOW_THR_INT_EN_M2, QPNP_ADC_TM_HIGH_THR_INT_EN_M2,
 		QPNP_ADC_TM_M2_MEAS_INTERVAL_CTL},
-	[QPNP_ADC_TM_M3_ADC_CH_SEL_CTL] = {QPNP_M3_LOW_THR_LSB,
+	[QPNP_ADC_TM_CHAN3] = {QPNP_ADC_TM_M3_ADC_CH_SEL_CTL,
+		QPNP_M3_LOW_THR_LSB,
 		QPNP_M3_LOW_THR_MSB, QPNP_M3_HIGH_THR_LSB,
 		QPNP_M3_HIGH_THR_MSB, QPNP_ADC_TM_MULTI_MEAS_EN_M3,
 		QPNP_ADC_TM_LOW_THR_INT_EN_M3, QPNP_ADC_TM_HIGH_THR_INT_EN_M3,
 		QPNP_ADC_TM_M3_MEAS_INTERVAL_CTL},
-	[QPNP_ADC_TM_M4_ADC_CH_SEL_CTL] = {QPNP_M4_LOW_THR_LSB,
+	[QPNP_ADC_TM_CHAN4] = {QPNP_ADC_TM_M4_ADC_CH_SEL_CTL,
+		QPNP_M4_LOW_THR_LSB,
 		QPNP_M4_LOW_THR_MSB, QPNP_M4_HIGH_THR_LSB,
 		QPNP_M4_HIGH_THR_MSB, QPNP_ADC_TM_MULTI_MEAS_EN_M4,
 		QPNP_ADC_TM_LOW_THR_INT_EN_M4, QPNP_ADC_TM_HIGH_THR_INT_EN_M4,
 		QPNP_ADC_TM_M4_MEAS_INTERVAL_CTL},
-	[QPNP_ADC_TM_M5_ADC_CH_SEL_CTL] = {QPNP_M5_LOW_THR_LSB,
+	[QPNP_ADC_TM_CHAN5] = {QPNP_ADC_TM_M5_ADC_CH_SEL_CTL,
+		QPNP_M5_LOW_THR_LSB,
 		QPNP_M5_LOW_THR_MSB, QPNP_M5_HIGH_THR_LSB,
 		QPNP_M5_HIGH_THR_MSB, QPNP_ADC_TM_MULTI_MEAS_EN_M5,
 		QPNP_ADC_TM_LOW_THR_INT_EN_M5, QPNP_ADC_TM_HIGH_THR_INT_EN_M5,
 		QPNP_ADC_TM_M5_MEAS_INTERVAL_CTL},
-	[QPNP_ADC_TM_M6_ADC_CH_SEL_CTL] = {QPNP_M6_LOW_THR_LSB,
+	[QPNP_ADC_TM_CHAN6] = {QPNP_ADC_TM_M6_ADC_CH_SEL_CTL,
+		QPNP_M6_LOW_THR_LSB,
 		QPNP_M6_LOW_THR_MSB, QPNP_M6_HIGH_THR_LSB,
 		QPNP_M6_HIGH_THR_MSB, QPNP_ADC_TM_MULTI_MEAS_EN_M6,
 		QPNP_ADC_TM_LOW_THR_INT_EN_M6, QPNP_ADC_TM_HIGH_THR_INT_EN_M6,
 		QPNP_ADC_TM_M6_MEAS_INTERVAL_CTL},
-	[QPNP_ADC_TM_M7_ADC_CH_SEL_CTL] = {QPNP_M7_LOW_THR_LSB,
+	[QPNP_ADC_TM_CHAN7] = {QPNP_ADC_TM_M7_ADC_CH_SEL_CTL,
+		QPNP_M7_LOW_THR_LSB,
 		QPNP_M7_LOW_THR_MSB, QPNP_M7_HIGH_THR_LSB,
 		QPNP_M7_HIGH_THR_MSB, QPNP_ADC_TM_MULTI_MEAS_EN_M7,
 		QPNP_ADC_TM_LOW_THR_INT_EN_M7, QPNP_ADC_TM_HIGH_THR_INT_EN_M7,
@@ -258,67 +283,79 @@
 	[SCALE_RPMIC_THERM] = {qpnp_adc_scale_millidegc_pmic_voltage_thr},
 };
 
-static int32_t qpnp_adc_tm_read_reg(int16_t reg, u8 *data)
+static int32_t qpnp_adc_tm_read_reg(struct qpnp_adc_tm_chip *chip,
+						int16_t reg, u8 *data)
 {
-	struct qpnp_adc_tm_drv *adc_tm = qpnp_adc_tm;
 	int rc = 0;
 
-	rc = spmi_ext_register_readl(adc_tm->adc->spmi->ctrl,
-		adc_tm->adc->slave, (adc_tm->adc->offset + reg), data, 1);
+	rc = spmi_ext_register_readl(chip->adc->spmi->ctrl,
+		chip->adc->slave, (chip->adc->offset + reg), data, 1);
 	if (rc < 0)
 		pr_err("adc-tm read reg %d failed with %d\n", reg, rc);
 
 	return rc;
 }
 
-static int32_t qpnp_adc_tm_write_reg(int16_t reg, u8 data)
+static int32_t qpnp_adc_tm_write_reg(struct qpnp_adc_tm_chip *chip,
+							int16_t reg, u8 data)
 {
-	struct qpnp_adc_tm_drv *adc_tm = qpnp_adc_tm;
 	int rc = 0;
 	u8 *buf;
 
 	buf = &data;
 
-	rc = spmi_ext_register_writel(adc_tm->adc->spmi->ctrl,
-		adc_tm->adc->slave, (adc_tm->adc->offset + reg), buf, 1);
+	rc = spmi_ext_register_writel(chip->adc->spmi->ctrl,
+		chip->adc->slave, (chip->adc->offset + reg), buf, 1);
 	if (rc < 0)
 		pr_err("adc-tm write reg %d failed with %d\n", reg, rc);
 
 	return rc;
 }
 
-static int32_t qpnp_adc_tm_enable(void)
+static int32_t qpnp_adc_tm_enable(struct qpnp_adc_tm_chip *chip)
 {
 	int rc = 0;
 	u8 data = 0;
 
 	data = QPNP_ADC_TM_EN;
-	rc = qpnp_adc_tm_write_reg(QPNP_EN_CTL1, data);
+	rc = qpnp_adc_tm_write_reg(chip, QPNP_EN_CTL1, data);
 	if (rc < 0)
 		pr_err("adc-tm enable failed\n");
 
 	return rc;
 }
 
-static int32_t qpnp_adc_tm_disable(void)
+static int32_t qpnp_adc_tm_disable(struct qpnp_adc_tm_chip *chip)
 {
 	u8 data = 0;
 	int rc = 0;
 
-	rc = qpnp_adc_tm_write_reg(QPNP_EN_CTL1, data);
+	rc = qpnp_adc_tm_write_reg(chip, QPNP_EN_CTL1, data);
 	if (rc < 0)
 		pr_err("adc-tm disable failed\n");
 
 	return rc;
 }
 
-static int32_t qpnp_adc_tm_enable_if_channel_meas(void)
+static int qpnp_adc_tm_is_valid(struct qpnp_adc_tm_chip *chip)
+{
+	struct qpnp_adc_tm_chip *adc_tm_chip = NULL;
+
+	list_for_each_entry(adc_tm_chip, &qpnp_adc_tm_device_list, list)
+		if (chip == adc_tm_chip)
+			return 0;
+
+	return -EINVAL;
+}
+
+static int32_t qpnp_adc_tm_enable_if_channel_meas(
+					struct qpnp_adc_tm_chip *chip)
 {
 	u8 adc_tm_meas_en = 0;
 	int rc = 0;
 
 	/* Check if a measurement request is still required */
-	rc = qpnp_adc_tm_read_reg(QPNP_ADC_TM_MULTI_MEAS_EN,
+	rc = qpnp_adc_tm_read_reg(chip, QPNP_ADC_TM_MULTI_MEAS_EN,
 							&adc_tm_meas_en);
 	if (rc) {
 		pr_err("adc-tm-tm read status high failed with %d\n", rc);
@@ -327,10 +364,11 @@
 
 	/* Enable only if there are pending measurement requests */
 	if (adc_tm_meas_en) {
-		qpnp_adc_tm_enable();
+		qpnp_adc_tm_enable(chip);
 
 		/* Request conversion */
-		rc = qpnp_adc_tm_write_reg(QPNP_CONV_REQ, QPNP_CONV_REQ_SET);
+		rc = qpnp_adc_tm_write_reg(chip, QPNP_CONV_REQ,
+							QPNP_CONV_REQ_SET);
 		if (rc < 0) {
 			pr_err("adc-tm request conversion failed\n");
 			return rc;
@@ -340,13 +378,13 @@
 	return rc;
 }
 
-static int32_t qpnp_adc_tm_req_sts_check(void)
+static int32_t qpnp_adc_tm_req_sts_check(struct qpnp_adc_tm_chip *chip)
 {
 	u8 status1;
 	int rc, count = 0;
 
 	/* The VADC_TM bank needs to be disabled for new conversion request */
-	rc = qpnp_adc_tm_read_reg(QPNP_ADC_TM_STATUS1, &status1);
+	rc = qpnp_adc_tm_read_reg(chip, QPNP_ADC_TM_STATUS1, &status1);
 	if (rc) {
 		pr_err("adc-tm read status1 failed\n");
 		return rc;
@@ -354,7 +392,7 @@
 
 	/* Disable the bank if a conversion is occuring */
 	while ((status1 & QPNP_STATUS1_REQ_STS) && (count < 5)) {
-		rc = qpnp_adc_tm_read_reg(QPNP_ADC_TM_STATUS1, &status1);
+		rc = qpnp_adc_tm_read_reg(chip, QPNP_ADC_TM_STATUS1, &status1);
 		if (rc < 0)
 			pr_err("adc-tm disable failed\n");
 		/* Wait time is based on the optimum sampling rate
@@ -367,18 +405,38 @@
 	return rc;
 }
 
-static int32_t qpnp_adc_tm_check_revision(uint32_t btm_chan_num)
+static int32_t qpnp_adc_tm_get_btm_idx(uint32_t btm_chan,
+						uint32_t *btm_chan_idx)
+{
+	int rc = 0, i;
+	bool chan_found = false;
+
+	for (i = 0; i < QPNP_ADC_TM_CHAN_NONE; i++) {
+		if (adc_tm_data[i].btm_amux_chan == btm_chan) {
+			*btm_chan_idx = i;
+			chan_found = true;
+		}
+	}
+
+	if (!chan_found)
+		return -EINVAL;
+
+	return rc;
+}
+
+static int32_t qpnp_adc_tm_check_revision(struct qpnp_adc_tm_chip *chip,
+							uint32_t btm_chan_num)
 {
 	u8 rev, perph_subtype;
 	int rc = 0;
 
-	rc = qpnp_adc_tm_read_reg(QPNP_REVISION3, &rev);
+	rc = qpnp_adc_tm_read_reg(chip, QPNP_REVISION3, &rev);
 	if (rc) {
 		pr_err("adc-tm revision read failed\n");
 		return rc;
 	}
 
-	rc = qpnp_adc_tm_read_reg(QPNP_PERPH_SUBTYPE, &perph_subtype);
+	rc = qpnp_adc_tm_read_reg(chip, QPNP_PERPH_SUBTYPE, &perph_subtype);
 	if (rc) {
 		pr_err("adc-tm perph_subtype read failed\n");
 		return rc;
@@ -394,30 +452,34 @@
 
 	return rc;
 }
-static int32_t qpnp_adc_tm_mode_select(u8 mode_ctl)
+static int32_t qpnp_adc_tm_mode_select(struct qpnp_adc_tm_chip *chip,
+								u8 mode_ctl)
 {
 	int rc;
 
 	mode_ctl |= (QPNP_ADC_TRIM_EN | QPNP_AMUX_TRIM_EN);
 
 	/* VADC_BTM current sets mode to recurring measurements */
-	rc = qpnp_adc_tm_write_reg(QPNP_MODE_CTL, mode_ctl);
+	rc = qpnp_adc_tm_write_reg(chip, QPNP_MODE_CTL, mode_ctl);
 	if (rc < 0)
 		pr_err("adc-tm write mode selection err\n");
 
 	return rc;
 }
 
-static int32_t qpnp_adc_tm_timer_interval_select(uint32_t btm_chan,
+static int32_t qpnp_adc_tm_timer_interval_select(
+		struct qpnp_adc_tm_chip *chip, uint32_t btm_chan,
 		struct qpnp_vadc_chan_properties *chan_prop)
 {
 	int rc;
 	u8 meas_interval_timer2 = 0;
+	uint32_t btm_chan_idx = 0;
 
 	/* Configure kernel clients to timer1 */
 	switch (chan_prop->timer_select) {
 	case ADC_MEAS_TIMER_SELECT1:
-		rc = qpnp_adc_tm_write_reg(QPNP_ADC_TM_MEAS_INTERVAL_CTL,
+		rc = qpnp_adc_tm_write_reg(chip,
+				QPNP_ADC_TM_MEAS_INTERVAL_CTL,
 				chan_prop->meas_interval1);
 		if (rc < 0) {
 			pr_err("timer1 configure failed\n");
@@ -426,7 +488,8 @@
 	break;
 	case ADC_MEAS_TIMER_SELECT2:
 		/* Thermal channels uses timer2, default to 1 second */
-		rc = qpnp_adc_tm_read_reg(QPNP_ADC_TM_MEAS_INTERVAL_CTL2,
+		rc = qpnp_adc_tm_read_reg(chip,
+				QPNP_ADC_TM_MEAS_INTERVAL_CTL2,
 				&meas_interval_timer2);
 		if (rc < 0) {
 			pr_err("timer2 configure read failed\n");
@@ -435,7 +498,8 @@
 		meas_interval_timer2 |=
 			(chan_prop->meas_interval2 <<
 			QPNP_ADC_TM_MEAS_INTERVAL_CTL2_SHIFT);
-		rc = qpnp_adc_tm_write_reg(QPNP_ADC_TM_MEAS_INTERVAL_CTL2,
+		rc = qpnp_adc_tm_write_reg(chip,
+			QPNP_ADC_TM_MEAS_INTERVAL_CTL2,
 			meas_interval_timer2);
 		if (rc < 0) {
 			pr_err("timer2 configure failed\n");
@@ -443,7 +507,8 @@
 		}
 	break;
 	case ADC_MEAS_TIMER_SELECT3:
-		rc = qpnp_adc_tm_read_reg(QPNP_ADC_TM_MEAS_INTERVAL_CTL2,
+		rc = qpnp_adc_tm_read_reg(chip,
+				QPNP_ADC_TM_MEAS_INTERVAL_CTL2,
 				&meas_interval_timer2);
 		if (rc < 0) {
 			pr_err("timer3 read failed\n");
@@ -451,7 +516,8 @@
 		}
 		chan_prop->meas_interval2 = ADC_MEAS3_INTERVAL_1S;
 		meas_interval_timer2 |= chan_prop->meas_interval2;
-		rc = qpnp_adc_tm_write_reg(QPNP_ADC_TM_MEAS_INTERVAL_CTL2,
+		rc = qpnp_adc_tm_write_reg(chip,
+			QPNP_ADC_TM_MEAS_INTERVAL_CTL2,
 			meas_interval_timer2);
 		if (rc < 0) {
 			pr_err("timer3 configure failed\n");
@@ -464,18 +530,67 @@
 	}
 
 	/* Select the timer to use for the corresponding channel */
-	adc_tm_data[btm_chan].meas_interval_ctl = chan_prop->timer_select;
+	rc = qpnp_adc_tm_get_btm_idx(btm_chan, &btm_chan_idx);
+	if (rc < 0) {
+		pr_err("Invalid btm channel idx\n");
+		return rc;
+	}
+	adc_tm_data[btm_chan_idx].meas_interval_ctl = chan_prop->timer_select;
 
 	return rc;
 }
 
-static int32_t qpnp_adc_tm_reg_update(uint16_t addr,
-		u8 mask, bool state)
+static int32_t qpnp_adc_tm_add_to_list(struct qpnp_adc_tm_chip *chip,
+				uint32_t dt_index,
+				struct qpnp_adc_tm_btm_param *param,
+				struct qpnp_vadc_chan_properties *chan_prop)
+{
+	struct qpnp_adc_thr_client_info *client_info = NULL;
+	bool client_info_exists = false;
+
+	list_for_each_entry(client_info,
+			&chip->sensor[dt_index].thr_list, list) {
+		if (client_info->btm_param == param) {
+			client_info->low_thr_requested = chan_prop->low_thr;
+			client_info->high_thr_requested = chan_prop->high_thr;
+			client_info->state_requested = param->state_request;
+			client_info->state_req_copy = param->state_request;
+			client_info->notify_low_thr = false;
+			client_info->notify_high_thr = false;
+			client_info_exists = true;
+			pr_debug("client found\n");
+		}
+	}
+
+	if (!client_info_exists) {
+		client_info = devm_kzalloc(chip->dev,
+			sizeof(struct qpnp_adc_thr_client_info), GFP_KERNEL);
+		if (!client_info) {
+			pr_err("%s: kzalloc() failed.\n", __func__);
+			return -ENOMEM;
+		}
+
+		pr_debug("new client\n");
+		client_info->btm_param = param;
+		client_info->low_thr_requested = chan_prop->low_thr;
+		client_info->high_thr_requested = chan_prop->high_thr;
+		client_info->state_requested = param->state_request;
+		client_info->state_req_copy = param->state_request;
+
+		list_add_tail(&client_info->list,
+					&chip->sensor[dt_index].thr_list);
+	}
+
+	return 0;
+}
+
+static int32_t qpnp_adc_tm_reg_update(struct qpnp_adc_tm_chip *chip,
+		uint16_t addr, u8 mask, bool state)
 {
 	u8 reg_value = 0;
 	int rc = 0;
 
-	rc = qpnp_adc_tm_read_reg(addr, &reg_value);
+	rc = qpnp_adc_tm_read_reg(chip, addr, &reg_value);
 	if (rc < 0) {
 		pr_err("read failed for addr:0x%x\n", addr);
 		return rc;
@@ -487,7 +602,7 @@
 
 	pr_debug("state:%d, reg:0x%x with bits:0x%x and mask:0x%x\n",
 					state, addr, reg_value, ~mask);
-	rc = qpnp_adc_tm_write_reg(addr, reg_value);
+	rc = qpnp_adc_tm_write_reg(chip, addr, reg_value);
 	if (rc < 0) {
 		pr_err("write failed for addr:%x\n", addr);
 		return rc;
@@ -496,58 +611,141 @@
 	return rc;
 }
 
-static int32_t qpnp_adc_tm_thr_update(uint32_t btm_chan,
-			struct qpnp_vadc_chan_properties *chan_prop)
+static int32_t qpnp_adc_tm_thr_update(struct qpnp_adc_tm_chip *chip,
+			uint32_t btm_chan, int32_t high_thr, int32_t low_thr)
 {
 	int rc = 0;
+	uint32_t btm_chan_idx = 0;
 
-	rc = qpnp_adc_tm_write_reg(
-			adc_tm_data[btm_chan].low_thr_lsb_addr,
-			QPNP_ADC_TM_THR_LSB_MASK(chan_prop->low_thr));
+	rc = qpnp_adc_tm_get_btm_idx(btm_chan, &btm_chan_idx);
+	if (rc < 0) {
+		pr_err("Invalid btm channel idx\n");
+		return rc;
+	}
+
+	rc = qpnp_adc_tm_write_reg(chip,
+			adc_tm_data[btm_chan_idx].low_thr_lsb_addr,
+			QPNP_ADC_TM_THR_LSB_MASK(low_thr));
 	if (rc < 0) {
 		pr_err("low threshold lsb setting failed\n");
 		return rc;
 	}
 
-	rc = qpnp_adc_tm_write_reg(
-		adc_tm_data[btm_chan].low_thr_msb_addr,
-		QPNP_ADC_TM_THR_MSB_MASK(chan_prop->low_thr));
+	rc = qpnp_adc_tm_write_reg(chip,
+		adc_tm_data[btm_chan_idx].low_thr_msb_addr,
+		QPNP_ADC_TM_THR_MSB_MASK(low_thr));
 	if (rc < 0) {
 		pr_err("low threshold msb setting failed\n");
 		return rc;
 	}
 
-	rc = qpnp_adc_tm_write_reg(
-		adc_tm_data[btm_chan].high_thr_lsb_addr,
-		QPNP_ADC_TM_THR_LSB_MASK(chan_prop->high_thr));
+	rc = qpnp_adc_tm_write_reg(chip,
+		adc_tm_data[btm_chan_idx].high_thr_lsb_addr,
+		QPNP_ADC_TM_THR_LSB_MASK(high_thr));
 	if (rc < 0) {
 		pr_err("high threshold lsb setting failed\n");
 		return rc;
 	}
 
-	rc = qpnp_adc_tm_write_reg(
-		adc_tm_data[btm_chan].high_thr_msb_addr,
-		QPNP_ADC_TM_THR_MSB_MASK(chan_prop->high_thr));
+	rc = qpnp_adc_tm_write_reg(chip,
+		adc_tm_data[btm_chan_idx].high_thr_msb_addr,
+		QPNP_ADC_TM_THR_MSB_MASK(high_thr));
 	if (rc < 0)
 		pr_err("high threshold msb setting failed\n");
 
-	pr_debug("client requested low:%d and high:%d\n",
-		chan_prop->low_thr, chan_prop->high_thr);
+	pr_debug("client requested high:%d and low:%d\n",
+		high_thr, low_thr);
 
 	return rc;
 }
 
-static int32_t qpnp_adc_tm_channel_configure(uint32_t btm_chan,
+static int32_t qpnp_adc_tm_manage_thresholds(struct qpnp_adc_tm_chip *chip,
+		uint32_t dt_index, uint32_t btm_chan)
+{
+	struct qpnp_adc_thr_client_info *client_info = NULL;
+	struct list_head *thr_list;
+	int high_thr = 0, low_thr = 0, rc = 0;
+
+
+	/* high_thr/low_thr starting point and reset the high_thr_set and
+		low_thr_set back to reset since the thresholds will be
+		recomputed */
+	list_for_each(thr_list,
+			&chip->sensor[dt_index].thr_list) {
+		client_info = list_entry(thr_list,
+					struct qpnp_adc_thr_client_info, list);
+		high_thr = client_info->high_thr_requested;
+		low_thr = client_info->low_thr_requested;
+		client_info->high_thr_set = false;
+		client_info->low_thr_set = false;
+	}
+
+	pr_debug("init threshold is high:%d and low:%d\n", high_thr, low_thr);
+
+	/* Find the min of high_thr and max of low_thr */
+	list_for_each(thr_list,
+			&chip->sensor[dt_index].thr_list) {
+		client_info = list_entry(thr_list,
+					struct qpnp_adc_thr_client_info, list);
+		if ((client_info->state_req_copy == ADC_TM_HIGH_THR_ENABLE) ||
+			(client_info->state_req_copy ==
+						ADC_TM_HIGH_LOW_THR_ENABLE))
+			if (client_info->high_thr_requested < high_thr)
+				high_thr = client_info->high_thr_requested;
+
+		if ((client_info->state_req_copy == ADC_TM_LOW_THR_ENABLE) ||
+			(client_info->state_req_copy ==
+						ADC_TM_HIGH_LOW_THR_ENABLE))
+			if (client_info->low_thr_requested > low_thr)
+				low_thr = client_info->low_thr_requested;
+
+		pr_debug("threshold compared is high:%d and low:%d\n",
+				client_info->high_thr_requested,
+				client_info->low_thr_requested);
+		pr_debug("current threshold is high:%d and low:%d\n",
+							high_thr, low_thr);
+	}
+
+	/* Check which of the high_thr and low_thr got set */
+	list_for_each(thr_list,
+			&chip->sensor[dt_index].thr_list) {
+		client_info = list_entry(thr_list,
+					struct qpnp_adc_thr_client_info, list);
+		if ((client_info->state_req_copy == ADC_TM_HIGH_THR_ENABLE) ||
+			(client_info->state_req_copy ==
+						ADC_TM_HIGH_LOW_THR_ENABLE))
+			if (high_thr == client_info->high_thr_requested)
+				client_info->high_thr_set = true;
+
+		if ((client_info->state_req_copy == ADC_TM_LOW_THR_ENABLE) ||
+			(client_info->state_req_copy ==
+						ADC_TM_HIGH_LOW_THR_ENABLE))
+			if (low_thr == client_info->low_thr_requested)
+				client_info->low_thr_set = true;
+	}
+
+	rc = qpnp_adc_tm_thr_update(chip, btm_chan, high_thr, low_thr);
+	if (rc < 0)
+		pr_err("setting chan:%d threshold failed\n", btm_chan);
+
+	pr_debug("threshold written is high:%d and low:%d\n",
+							high_thr, low_thr);
+
+	return 0;
+}
+
+static int32_t qpnp_adc_tm_channel_configure(struct qpnp_adc_tm_chip *chip,
+			uint32_t btm_chan,
 			struct qpnp_vadc_chan_properties *chan_prop,
 			uint32_t amux_channel)
 {
-	struct qpnp_adc_tm_drv *adc_tm = qpnp_adc_tm;
 	int rc = 0, i = 0, chan_idx = 0;
-	bool chan_found = false;
+	bool chan_found = false, high_thr_set = false, low_thr_set = false;
 	u8 sensor_mask = 0;
+	struct qpnp_adc_thr_client_info *client_info = NULL;
 
-	while (i < adc_tm->max_channels_available) {
-		if (adc_tm->sensor[i].btm_channel_num == btm_chan) {
+	while (i < chip->max_channels_available) {
+		if (chip->sensor[i].btm_channel_num == btm_chan) {
 			chan_idx = i;
 			chan_found = true;
 			i++;
@@ -561,23 +759,28 @@
 	}
 
 	sensor_mask = 1 << chan_idx;
-	if (!adc_tm->sensor[chan_idx].thermal_node) {
+	if (!chip->sensor[chan_idx].thermal_node) {
 		/* Update low and high notification thresholds */
-		rc = qpnp_adc_tm_thr_update(btm_chan,
-				chan_prop);
+		rc = qpnp_adc_tm_manage_thresholds(chip, chan_idx,
+				btm_chan);
 		if (rc < 0) {
 			pr_err("setting chan:%d threshold failed\n", btm_chan);
 			return rc;
 		}
 
-		if ((chan_prop->state_request ==
-					ADC_TM_LOW_THR_ENABLE) ||
-			(chan_prop->state_request ==
-					ADC_TM_HIGH_LOW_THR_ENABLE)) {
+		list_for_each_entry(client_info,
+				&chip->sensor[chan_idx].thr_list, list) {
+			if (client_info->high_thr_set == true)
+				high_thr_set = true;
+			if (client_info->low_thr_set == true)
+				low_thr_set = true;
+		}
+
+		if (low_thr_set) {
 			pr_debug("low sensor mask:%x with state:%d\n",
 					sensor_mask, chan_prop->state_request);
 			/* Enable low threshold's interrupt */
-			rc = qpnp_adc_tm_reg_update(
+			rc = qpnp_adc_tm_reg_update(chip,
 				QPNP_ADC_TM_LOW_THR_INT_EN, sensor_mask, true);
 			if (rc < 0) {
 				pr_err("low thr enable err:%d\n", btm_chan);
@@ -585,13 +788,10 @@
 			}
 		}
 
-		if ((chan_prop->state_request ==
-					ADC_TM_HIGH_THR_ENABLE) ||
-			(chan_prop->state_request ==
-					ADC_TM_HIGH_LOW_THR_ENABLE)) {
+		if (high_thr_set) {
 			/* Enable high threshold's interrupt */
 			pr_debug("high sensor mask:%x\n", sensor_mask);
-			rc = qpnp_adc_tm_reg_update(
+			rc = qpnp_adc_tm_reg_update(chip,
 				QPNP_ADC_TM_HIGH_THR_INT_EN, sensor_mask, true);
 			if (rc < 0) {
 				pr_err("high thr enable err:%d\n", btm_chan);
@@ -601,7 +801,7 @@
 	}
 
 	/* Enable corresponding BTM channel measurement */
-	rc = qpnp_adc_tm_reg_update(
+	rc = qpnp_adc_tm_reg_update(chip,
 		QPNP_ADC_TM_MULTI_MEAS_EN, sensor_mask, true);
 	if (rc < 0) {
 		pr_err("multi measurement en failed\n");
@@ -611,7 +811,7 @@
 	return rc;
 }
 
-static int32_t qpnp_adc_tm_configure(
+static int32_t qpnp_adc_tm_configure(struct qpnp_adc_tm_chip *chip,
 			struct qpnp_adc_amux_properties *chan_prop)
 {
 	u8 decimation = 0, op_cntrl = 0;
@@ -619,19 +819,19 @@
 	uint32_t btm_chan = 0;
 
 	/* Disable bank */
-	rc = qpnp_adc_tm_disable();
+	rc = qpnp_adc_tm_disable(chip);
 	if (rc)
 		return rc;
 
 	/* Check if a conversion is in progress */
-	rc = qpnp_adc_tm_req_sts_check();
+	rc = qpnp_adc_tm_req_sts_check(chip);
 	if (rc < 0) {
 		pr_err("adc-tm req_sts check failed\n");
 		return rc;
 	}
 
 	/* Set measurement in recurring mode */
-	rc = qpnp_adc_tm_mode_select(chan_prop->mode_sel);
+	rc = qpnp_adc_tm_mode_select(chip, chan_prop->mode_sel);
 	if (rc < 0) {
 		pr_err("adc-tm mode select failed\n");
 		return rc;
@@ -639,7 +839,7 @@
 
 	/* Configure AMUX channel select for the corresponding BTM channel*/
 	btm_chan = chan_prop->chan_prop->tm_channel_select;
-	rc = qpnp_adc_tm_write_reg(btm_chan, chan_prop->amux_channel);
+	rc = qpnp_adc_tm_write_reg(chip, btm_chan, chan_prop->amux_channel);
 	if (rc < 0) {
 		pr_err("adc-tm channel selection err\n");
 		return rc;
@@ -648,14 +848,14 @@
 	/* Digital paramater setup */
 	decimation |= chan_prop->decimation <<
 				QPNP_ADC_DIG_DEC_RATIO_SEL_SHIFT;
-	rc = qpnp_adc_tm_write_reg(QPNP_ADC_DIG_PARAM, decimation);
+	rc = qpnp_adc_tm_write_reg(chip, QPNP_ADC_DIG_PARAM, decimation);
 	if (rc < 0) {
 		pr_err("adc-tm digital parameter setup err\n");
 		return rc;
 	}
 
 	/* Hardware setting time */
-	rc = qpnp_adc_tm_write_reg(QPNP_HW_SETTLE_DELAY,
+	rc = qpnp_adc_tm_write_reg(chip, QPNP_HW_SETTLE_DELAY,
 					chan_prop->hw_settle_time);
 	if (rc < 0) {
 		pr_err("adc-tm hw settling time setup err\n");
@@ -663,7 +863,7 @@
 	}
 
 	/* Fast averaging setup */
-	rc = qpnp_adc_tm_write_reg(QPNP_FAST_AVG_CTL,
+	rc = qpnp_adc_tm_write_reg(chip, QPNP_FAST_AVG_CTL,
 					chan_prop->fast_avg_setup);
 	if (rc < 0) {
 		pr_err("adc-tm fast-avg setup err\n");
@@ -671,7 +871,7 @@
 	}
 
 	/* Measurement interval setup */
-	rc = qpnp_adc_tm_timer_interval_select(btm_chan,
+	rc = qpnp_adc_tm_timer_interval_select(chip, btm_chan,
 						chan_prop->chan_prop);
 	if (rc < 0) {
 		pr_err("adc-tm timer select failed\n");
@@ -679,17 +879,18 @@
 	}
 
 	/* Channel configuration setup */
-	rc = qpnp_adc_tm_channel_configure(btm_chan, chan_prop->chan_prop,
-					chan_prop->amux_channel);
+	rc = qpnp_adc_tm_channel_configure(chip, btm_chan,
+			chan_prop->chan_prop, chan_prop->amux_channel);
 	if (rc < 0) {
 		pr_err("adc-tm channel configure failed\n");
 		return rc;
 	}
 
 	/* Recurring interval measurement enable */
-	rc = qpnp_adc_tm_read_reg(QPNP_ADC_MEAS_INTERVAL_OP_CTL, &op_cntrl);
+	rc = qpnp_adc_tm_read_reg(chip, QPNP_ADC_MEAS_INTERVAL_OP_CTL,
+								&op_cntrl);
 	op_cntrl |= QPNP_ADC_MEAS_INTERVAL_OP;
-	rc = qpnp_adc_tm_reg_update(QPNP_ADC_MEAS_INTERVAL_OP_CTL,
+	rc = qpnp_adc_tm_reg_update(chip, QPNP_ADC_MEAS_INTERVAL_OP_CTL,
 			op_cntrl, true);
 	if (rc < 0) {
 		pr_err("adc-tm meas interval op configure failed\n");
@@ -697,12 +898,12 @@
 	}
 
 	/* Enable bank */
-	rc = qpnp_adc_tm_enable();
+	rc = qpnp_adc_tm_enable(chip);
 	if (rc)
 		return rc;
 
 	/* Request conversion */
-	rc = qpnp_adc_tm_write_reg(QPNP_CONV_REQ, QPNP_CONV_REQ_SET);
+	rc = qpnp_adc_tm_write_reg(chip, QPNP_CONV_REQ, QPNP_CONV_REQ_SET);
 	if (rc < 0) {
 		pr_err("adc-tm request conversion failed\n");
 		return rc;
@@ -714,13 +915,13 @@
 static int qpnp_adc_tm_get_mode(struct thermal_zone_device *thermal,
 			      enum thermal_device_mode *mode)
 {
-	struct qpnp_adc_tm_sensor *adc_tm_sensor = thermal->devdata;
+	struct qpnp_adc_tm_sensor *adc_tm = thermal->devdata;
 
-	if (!adc_tm_sensor || qpnp_adc_tm_check_revision(
-			adc_tm_sensor->btm_channel_num) || !mode)
+	if ((IS_ERR(adc_tm)) || qpnp_adc_tm_check_revision(
+			adc_tm->chip, adc_tm->btm_channel_num))
 		return -EINVAL;
 
-	*mode = adc_tm_sensor->mode;
+	*mode = adc_tm->mode;
 
 	return 0;
 }
@@ -729,35 +930,40 @@
 			      enum thermal_device_mode mode)
 {
 	struct qpnp_adc_tm_sensor *adc_tm = thermal->devdata;
-	struct qpnp_adc_tm_drv *adc_drv = qpnp_adc_tm;
+	struct qpnp_adc_tm_chip *chip = adc_tm->chip;
 	int rc = 0, channel;
 	u8 sensor_mask = 0;
 
-	if (!adc_tm || qpnp_adc_tm_check_revision(adc_tm->btm_channel_num))
+	if (qpnp_adc_tm_is_valid(chip)) {
+		pr_err("invalid device\n");
+		return -ENODEV;
+	}
+
+	if (qpnp_adc_tm_check_revision(chip, adc_tm->btm_channel_num))
 		return -EINVAL;
 
 	if (mode == THERMAL_DEVICE_ENABLED) {
-		adc_drv->adc->amux_prop->amux_channel =
+		chip->adc->amux_prop->amux_channel =
 					adc_tm->vadc_channel_num;
 		channel = adc_tm->sensor_num;
-		adc_drv->adc->amux_prop->decimation =
-			adc_drv->adc->adc_channels[channel].adc_decimation;
-		adc_drv->adc->amux_prop->hw_settle_time =
-			adc_drv->adc->adc_channels[channel].hw_settle_time;
-		adc_drv->adc->amux_prop->fast_avg_setup =
-			adc_drv->adc->adc_channels[channel].fast_avg_setup;
-		adc_drv->adc->amux_prop->mode_sel =
+		chip->adc->amux_prop->decimation =
+			chip->adc->adc_channels[channel].adc_decimation;
+		chip->adc->amux_prop->hw_settle_time =
+			chip->adc->adc_channels[channel].hw_settle_time;
+		chip->adc->amux_prop->fast_avg_setup =
+			chip->adc->adc_channels[channel].fast_avg_setup;
+		chip->adc->amux_prop->mode_sel =
 			ADC_OP_MEASUREMENT_INTERVAL << QPNP_OP_MODE_SHIFT;
-		adc_drv->adc->amux_prop->chan_prop->timer_select =
+		chip->adc->amux_prop->chan_prop->timer_select =
 					ADC_MEAS_TIMER_SELECT1;
-		adc_drv->adc->amux_prop->chan_prop->meas_interval1 =
+		chip->adc->amux_prop->chan_prop->meas_interval1 =
 						ADC_MEAS1_INTERVAL_1S;
-		adc_drv->adc->amux_prop->chan_prop->low_thr = adc_tm->low_thr;
-		adc_drv->adc->amux_prop->chan_prop->high_thr = adc_tm->high_thr;
-		adc_drv->adc->amux_prop->chan_prop->tm_channel_select =
+		chip->adc->amux_prop->chan_prop->low_thr = adc_tm->low_thr;
+		chip->adc->amux_prop->chan_prop->high_thr = adc_tm->high_thr;
+		chip->adc->amux_prop->chan_prop->tm_channel_select =
 			adc_tm->btm_channel_num;
 
-		rc = qpnp_adc_tm_configure(adc_drv->adc->amux_prop);
+		rc = qpnp_adc_tm_configure(chip, chip->adc->amux_prop);
 		if (rc) {
 			pr_err("adc-tm tm configure failed with %d\n", rc);
 			return -EINVAL;
@@ -765,27 +971,27 @@
 	} else if (mode == THERMAL_DEVICE_DISABLED) {
 		sensor_mask = 1 << adc_tm->sensor_num;
 		/* Disable bank */
-		rc = qpnp_adc_tm_disable();
+		rc = qpnp_adc_tm_disable(chip);
 		if (rc < 0) {
 			pr_err("adc-tm disable failed\n");
 			return rc;
 		}
 
 		/* Check if a conversion is in progress */
-		rc = qpnp_adc_tm_req_sts_check();
+		rc = qpnp_adc_tm_req_sts_check(chip);
 		if (rc < 0) {
 			pr_err("adc-tm req_sts check failed\n");
 			return rc;
 		}
 
-		rc = qpnp_adc_tm_reg_update(QPNP_ADC_TM_MULTI_MEAS_EN,
-			sensor_mask, false);
+		rc = qpnp_adc_tm_reg_update(chip,
+			QPNP_ADC_TM_MULTI_MEAS_EN, sensor_mask, false);
 		if (rc < 0) {
 			pr_err("multi measurement update failed\n");
 			return rc;
 		}
 
-		rc = qpnp_adc_tm_enable_if_channel_meas();
+		rc = qpnp_adc_tm_enable_if_channel_meas(chip);
 		if (rc < 0) {
 			pr_err("re-enabling measurement failed\n");
 			return rc;
@@ -801,9 +1007,12 @@
 				   int trip, enum thermal_trip_type *type)
 {
 	struct qpnp_adc_tm_sensor *adc_tm = thermal->devdata;
+	struct qpnp_adc_tm_chip *chip = adc_tm->chip;
 
-	if (!adc_tm || qpnp_adc_tm_check_revision(adc_tm->btm_channel_num)
-						|| !type || type < 0)
+	if (qpnp_adc_tm_is_valid(chip))
+		return -ENODEV;
+
+	if (qpnp_adc_tm_check_revision(chip, adc_tm->btm_channel_num))
 		return -EINVAL;
 
 	switch (trip) {
@@ -824,32 +1033,43 @@
 				   int trip, unsigned long *temp)
 {
 	struct qpnp_adc_tm_sensor *adc_tm_sensor = thermal->devdata;
-	struct qpnp_adc_tm_drv *adc_tm = qpnp_adc_tm;
+	struct qpnp_adc_tm_chip *chip = adc_tm_sensor->chip;
 	int64_t result = 0;
 	u8 trip_cool_thr0, trip_cool_thr1, trip_warm_thr0, trip_warm_thr1;
-	unsigned int reg, rc = 0, btm_channel_num;
+	unsigned int reg, rc = 0;
 	uint16_t reg_low_thr_lsb, reg_low_thr_msb;
 	uint16_t reg_high_thr_lsb, reg_high_thr_msb;
+	uint32_t btm_chan_idx = 0, btm_chan = 0;
 
-	if (!adc_tm || qpnp_adc_tm_check_revision(
-					adc_tm_sensor->btm_channel_num))
+	if (qpnp_adc_tm_is_valid(chip))
+		return -ENODEV;
+
+	if (qpnp_adc_tm_check_revision(chip, adc_tm_sensor->btm_channel_num))
 		return -EINVAL;
 
-	btm_channel_num = adc_tm_sensor->btm_channel_num;
-	reg_low_thr_lsb = adc_tm_data[btm_channel_num].low_thr_lsb_addr;
-	reg_low_thr_msb = adc_tm_data[btm_channel_num].low_thr_msb_addr;
-	reg_high_thr_lsb = adc_tm_data[btm_channel_num].high_thr_lsb_addr;
-	reg_high_thr_msb = adc_tm_data[btm_channel_num].high_thr_msb_addr;
+	btm_chan = adc_tm_sensor->btm_channel_num;
+	rc = qpnp_adc_tm_get_btm_idx(btm_chan, &btm_chan_idx);
+	if (rc < 0) {
+		pr_err("Invalid btm channel idx\n");
+		return rc;
+	}
+
+	reg_low_thr_lsb = adc_tm_data[btm_chan_idx].low_thr_lsb_addr;
+	reg_low_thr_msb = adc_tm_data[btm_chan_idx].low_thr_msb_addr;
+	reg_high_thr_lsb = adc_tm_data[btm_chan_idx].high_thr_lsb_addr;
+	reg_high_thr_msb = adc_tm_data[btm_chan_idx].high_thr_msb_addr;
 
 	switch (trip) {
 	case ADC_TM_TRIP_HIGH_WARM:
-		rc = qpnp_adc_tm_read_reg(reg_low_thr_lsb, &trip_warm_thr0);
+		rc = qpnp_adc_tm_read_reg(chip, reg_low_thr_lsb,
+							&trip_warm_thr0);
 		if (rc) {
 			pr_err("adc-tm low_thr_lsb err\n");
 			return rc;
 		}
 
-		rc = qpnp_adc_tm_read_reg(reg_low_thr_msb, &trip_warm_thr1);
+		rc = qpnp_adc_tm_read_reg(chip, reg_low_thr_msb,
+							&trip_warm_thr1);
 		if (rc) {
 			pr_err("adc-tm low_thr_msb err\n");
 			return rc;
@@ -857,13 +1077,15 @@
 	reg = (trip_warm_thr1 << 8) | trip_warm_thr0;
 	break;
 	case ADC_TM_TRIP_LOW_COOL:
-		rc = qpnp_adc_tm_read_reg(reg_high_thr_lsb, &trip_cool_thr0);
+		rc = qpnp_adc_tm_read_reg(chip, reg_high_thr_lsb,
+							&trip_cool_thr0);
 		if (rc) {
 			pr_err("adc-tm_tm high_thr_lsb err\n");
 			return rc;
 		}
 
-		rc = qpnp_adc_tm_read_reg(reg_high_thr_msb, &trip_cool_thr1);
+		rc = qpnp_adc_tm_read_reg(chip, reg_high_thr_msb,
+							&trip_cool_thr1);
 		if (rc) {
 			pr_err("adc-tm_tm high_thr_lsb err\n");
 			return rc;
@@ -874,7 +1096,7 @@
 		return -EINVAL;
 	}
 
-	rc = qpnp_adc_tm_scale_voltage_therm_pu2(adc_tm->vadc_dev, reg,
+	rc = qpnp_adc_tm_scale_voltage_therm_pu2(chip->vadc_dev, reg,
 								&result);
 	if (rc < 0) {
 		pr_err("Failed to lookup the therm thresholds\n");
@@ -889,19 +1111,22 @@
 static int qpnp_adc_tm_set_trip_temp(struct thermal_zone_device *thermal,
 				   int trip, long temp)
 {
-	struct qpnp_adc_tm_sensor *adc_tm_sensor = thermal->devdata;
-	struct qpnp_adc_tm_drv *adc_tm = qpnp_adc_tm;
+	struct qpnp_adc_tm_sensor *adc_tm = thermal->devdata;
+	struct qpnp_adc_tm_chip *chip = adc_tm->chip;
 	struct qpnp_adc_tm_config tm_config;
 	u8 trip_cool_thr0, trip_cool_thr1, trip_warm_thr0, trip_warm_thr1;
 	uint16_t reg_low_thr_lsb, reg_low_thr_msb;
 	uint16_t reg_high_thr_lsb, reg_high_thr_msb;
-	int rc = 0, btm_channel_num;
+	int rc = 0;
+	uint32_t btm_chan = 0, btm_chan_idx = 0;
 
-	if (!adc_tm || qpnp_adc_tm_check_revision(
-				adc_tm_sensor->btm_channel_num))
+	if (qpnp_adc_tm_is_valid(chip))
+		return -ENODEV;
+
+	if (qpnp_adc_tm_check_revision(chip, adc_tm->btm_channel_num))
 		return -EINVAL;
 
-	tm_config.channel = adc_tm_sensor->vadc_channel_num;
+	tm_config.channel = adc_tm->vadc_channel_num;
 	switch (trip) {
 	case ADC_TM_TRIP_HIGH_WARM:
 		tm_config.high_thr_temp = temp;
@@ -915,7 +1140,7 @@
 
 	pr_debug("requested a high - %d and low - %d with trip - %d\n",
 			tm_config.high_thr_temp, tm_config.low_thr_temp, trip);
-	rc = qpnp_adc_tm_scale_therm_voltage_pu2(adc_tm->vadc_dev, &tm_config);
+	rc = qpnp_adc_tm_scale_therm_voltage_pu2(chip->vadc_dev, &tm_config);
 	if (rc < 0) {
 		pr_err("Failed to lookup the adc-tm thresholds\n");
 		return rc;
@@ -926,40 +1151,50 @@
 	trip_cool_thr0 = ((tm_config.high_thr_voltage << 24) >> 24);
 	trip_cool_thr1 = ((tm_config.high_thr_voltage << 16) >> 24);
 
-	btm_channel_num = adc_tm_sensor->btm_channel_num;
-	reg_low_thr_lsb = adc_tm_data[btm_channel_num].low_thr_lsb_addr;
-	reg_low_thr_msb = adc_tm_data[btm_channel_num].low_thr_msb_addr;
-	reg_high_thr_lsb = adc_tm_data[btm_channel_num].high_thr_lsb_addr;
-	reg_high_thr_msb = adc_tm_data[btm_channel_num].high_thr_msb_addr;
+	btm_chan = adc_tm->btm_channel_num;
+	rc = qpnp_adc_tm_get_btm_idx(btm_chan, &btm_chan_idx);
+	if (rc < 0) {
+		pr_err("Invalid btm channel idx\n");
+		return rc;
+	}
+
+	reg_low_thr_lsb = adc_tm_data[btm_chan_idx].low_thr_lsb_addr;
+	reg_low_thr_msb = adc_tm_data[btm_chan_idx].low_thr_msb_addr;
+	reg_high_thr_lsb = adc_tm_data[btm_chan_idx].high_thr_lsb_addr;
+	reg_high_thr_msb = adc_tm_data[btm_chan_idx].high_thr_msb_addr;
 
 	switch (trip) {
 	case ADC_TM_TRIP_HIGH_WARM:
-		rc = qpnp_adc_tm_write_reg(reg_low_thr_lsb, trip_cool_thr0);
+		rc = qpnp_adc_tm_write_reg(chip, reg_low_thr_lsb,
+							trip_cool_thr0);
 		if (rc) {
 			pr_err("adc-tm_tm read threshold err\n");
 			return rc;
 		}
 
-		rc = qpnp_adc_tm_write_reg(reg_low_thr_msb, trip_cool_thr1);
+		rc = qpnp_adc_tm_write_reg(chip, reg_low_thr_msb,
+							trip_cool_thr1);
 		if (rc) {
 			pr_err("adc-tm_tm read threshold err\n");
 			return rc;
 		}
-	adc_tm_sensor->low_thr = tm_config.high_thr_voltage;
+	adc_tm->low_thr = tm_config.high_thr_voltage;
 	break;
 	case ADC_TM_TRIP_LOW_COOL:
-		rc = qpnp_adc_tm_write_reg(reg_high_thr_lsb, trip_warm_thr0);
+		rc = qpnp_adc_tm_write_reg(chip, reg_high_thr_lsb,
+							trip_warm_thr0);
 		if (rc) {
 			pr_err("adc-tm_tm read threshold err\n");
 			return rc;
 		}
 
-		rc = qpnp_adc_tm_write_reg(reg_high_thr_msb, trip_warm_thr1);
+		rc = qpnp_adc_tm_write_reg(chip, reg_high_thr_msb,
+							trip_warm_thr1);
 		if (rc) {
 			pr_err("adc-tm_tm read threshold err\n");
 			return rc;
 		}
-	adc_tm_sensor->high_thr = tm_config.low_thr_voltage;
+	adc_tm->high_thr = tm_config.low_thr_voltage;
 	break;
 	default:
 		return -EINVAL;
@@ -970,20 +1205,25 @@
 
 static void notify_battery_therm(struct qpnp_adc_tm_sensor *adc_tm)
 {
-	/* Battery therm's warm temperature translates to low voltage */
-	if (adc_tm->low_thr_notify) {
-		/* HIGH_STATE = WARM_TEMP for battery client */
-		adc_tm->btm_param->threshold_notification(
-		ADC_TM_WARM_STATE, adc_tm->btm_param->btm_ctx);
-		adc_tm->low_thr_notify = false;
-	}
+	struct qpnp_adc_thr_client_info *client_info = NULL;
 
-	/* Battery therm's cool temperature translates to high voltage */
-	if (adc_tm->high_thr_notify) {
-		/* LOW_STATE = COOL_TEMP for battery client */
-		adc_tm->btm_param->threshold_notification(
-		ADC_TM_COOL_STATE, adc_tm->btm_param->btm_ctx);
-		adc_tm->high_thr_notify = false;
+	list_for_each_entry(client_info,
+			&adc_tm->thr_list, list) {
+		/* Batt therm's warm temperature translates to low voltage */
+		if (client_info->notify_low_thr) {
+			/* HIGH_STATE = WARM_TEMP for battery client */
+			client_info->btm_param->threshold_notification(
+			ADC_TM_WARM_STATE, client_info->btm_param->btm_ctx);
+			client_info->notify_low_thr = false;
+		}
+
+		/* Batt therm's cool temperature translates to high voltage */
+		if (client_info->notify_high_thr) {
+			/* LOW_STATE = COOL_TEMP for battery client */
+			client_info->btm_param->threshold_notification(
+			ADC_TM_COOL_STATE, client_info->btm_param->btm_ctx);
+			client_info->notify_high_thr = false;
+		}
 	}
 
 	return;
@@ -991,19 +1231,32 @@
 
 static void notify_clients(struct qpnp_adc_tm_sensor *adc_tm)
 {
-	/* For non batt therm clients */
-	if (adc_tm->low_thr_notify) {
-		pr_debug("notify kernel with low state\n");
-		adc_tm->btm_param->threshold_notification(
-		ADC_TM_LOW_STATE, adc_tm->btm_param->btm_ctx);
-		adc_tm->low_thr_notify = false;
-	}
+	struct qpnp_adc_thr_client_info *client_info = NULL;
 
-	if (adc_tm->high_thr_notify) {
-		pr_debug("notify kernel with high state\n");
-		adc_tm->btm_param->threshold_notification(
-		ADC_TM_HIGH_STATE, adc_tm->btm_param->btm_ctx);
-		adc_tm->high_thr_notify = false;
+	list_for_each_entry(client_info,
+			&adc_tm->thr_list, list) {
+		/* For non batt therm clients */
+		if (client_info->notify_low_thr) {
+			if (client_info->btm_param->threshold_notification
+								!= NULL) {
+				pr_debug("notify kernel with low state\n");
+				client_info->btm_param->threshold_notification(
+					ADC_TM_LOW_STATE,
+					client_info->btm_param->btm_ctx);
+				client_info->notify_low_thr = false;
+			}
+		}
+
+		if (client_info->notify_high_thr) {
+			if (client_info->btm_param->threshold_notification
+								!= NULL) {
+				pr_debug("notify kernel with high state\n");
+				client_info->btm_param->threshold_notification(
+					ADC_TM_HIGH_STATE,
+					client_info->btm_param->btm_ctx);
+				client_info->notify_high_thr = false;
+			}
+		}
 	}
 
 	return;
@@ -1019,12 +1272,10 @@
 					NULL, "btm");
 		pr_debug("notifying uspace client\n");
 	} else {
-		if (adc_tm->btm_param->threshold_notification != NULL) {
-			if (adc_tm->scale_type == SCALE_RBATT_THERM)
-				notify_battery_therm(adc_tm);
-			else
-				notify_clients(adc_tm);
-		}
+		if (adc_tm->scale_type == SCALE_RBATT_THERM)
+			notify_battery_therm(adc_tm);
+		else
+			notify_clients(adc_tm);
 	}
 
 	return;
@@ -1034,11 +1285,16 @@
 			int trip, enum thermal_trip_activation_mode mode)
 {
 	struct qpnp_adc_tm_sensor *adc_tm = thermal->devdata;
+	struct qpnp_adc_tm_chip *chip = adc_tm->chip;
 	int rc = 0, sensor_mask = 0;
 	u8 thr_int_en = 0;
 	bool state = false;
+	uint32_t btm_chan_idx = 0, btm_chan = 0;
 
-	if (!adc_tm || qpnp_adc_tm_check_revision(adc_tm->btm_channel_num))
+	if (qpnp_adc_tm_is_valid(chip))
+		return -ENODEV;
+
+	if (qpnp_adc_tm_check_revision(chip, adc_tm->btm_channel_num))
 		return -EINVAL;
 
 	if (mode == THERMAL_TRIP_ACTIVATION_ENABLED)
@@ -1048,24 +1304,29 @@
 
 	pr_debug("Sensor number:%x with state:%d\n", adc_tm->sensor_num, state);
 
+	btm_chan = adc_tm->btm_channel_num;
+	rc = qpnp_adc_tm_get_btm_idx(btm_chan, &btm_chan_idx);
+	if (rc < 0) {
+		pr_err("Invalid btm channel idx\n");
+		return rc;
+	}
+
 	switch (trip) {
 	case ADC_TM_TRIP_HIGH_WARM:
 		/* low_thr (lower voltage) for higher temp */
-		thr_int_en = adc_tm_data[adc_tm->btm_channel_num].
-							low_thr_int_chan_en;
-		rc = qpnp_adc_tm_reg_update(QPNP_ADC_TM_LOW_THR_INT_EN,
+		thr_int_en = adc_tm_data[btm_chan_idx].low_thr_int_chan_en;
+		rc = qpnp_adc_tm_reg_update(chip, QPNP_ADC_TM_LOW_THR_INT_EN,
 				sensor_mask, state);
 		if (rc)
-			pr_err("channel:%x failed\n", adc_tm->btm_channel_num);
+			pr_err("channel:%x failed\n", btm_chan);
 	break;
 	case ADC_TM_TRIP_LOW_COOL:
 		/* high_thr (higher voltage) for cooler temp */
-		thr_int_en = adc_tm_data[adc_tm->btm_channel_num].
-							high_thr_int_chan_en;
-		rc = qpnp_adc_tm_reg_update(QPNP_ADC_TM_HIGH_THR_INT_EN,
+		thr_int_en = adc_tm_data[btm_chan_idx].high_thr_int_chan_en;
+		rc = qpnp_adc_tm_reg_update(chip, QPNP_ADC_TM_HIGH_THR_INT_EN,
 				sensor_mask, state);
 		if (rc)
-			pr_err("channel:%x failed\n", adc_tm->btm_channel_num);
+			pr_err("channel:%x failed\n", btm_chan);
 	break;
 	default:
 		return -EINVAL;
@@ -1074,32 +1335,34 @@
 	return rc;
 }
 
-static int qpnp_adc_tm_read_status(void)
+static int qpnp_adc_tm_read_status(struct qpnp_adc_tm_chip *chip)
 {
-	struct qpnp_adc_tm_drv *adc_tm = qpnp_adc_tm;
 	u8 status_low = 0, status_high = 0, qpnp_adc_tm_meas_en = 0;
 	u8 adc_tm_low_enable = 0, adc_tm_high_enable = 0;
 	u8 sensor_mask = 0;
-	int rc = 0, sensor_notify_num = 0, i = 0, sensor_num = 0, btm_chan_num;
+	int rc = 0, sensor_notify_num = 0, i = 0, sensor_num = 0;
+	uint32_t btm_chan_num = 0;
+	struct qpnp_adc_thr_client_info *client_info = NULL;
+	struct list_head *thr_list;
 
-	if (!adc_tm || !adc_tm->adc_tm_initialized)
+	if (qpnp_adc_tm_is_valid(chip))
 		return -ENODEV;
 
-	mutex_lock(&adc_tm->adc->adc_lock);
+	mutex_lock(&chip->adc->adc_lock);
 
-	rc = qpnp_adc_tm_req_sts_check();
+	rc = qpnp_adc_tm_req_sts_check(chip);
 	if (rc) {
 		pr_err("adc-tm-tm req sts check failed with %d\n", rc);
 		goto fail;
 	}
 
-	rc = qpnp_adc_tm_read_reg(QPNP_ADC_TM_STATUS_LOW, &status_low);
+	rc = qpnp_adc_tm_read_reg(chip, QPNP_ADC_TM_STATUS_LOW, &status_low);
 	if (rc) {
 		pr_err("adc-tm-tm read status low failed with %d\n", rc);
 		goto fail;
 	}
 
-	rc = qpnp_adc_tm_read_reg(QPNP_ADC_TM_STATUS_HIGH, &status_high);
+	rc = qpnp_adc_tm_read_reg(chip, QPNP_ADC_TM_STATUS_HIGH, &status_high);
 	if (rc) {
 		pr_err("adc-tm-tm read status high failed with %d\n", rc);
 		goto fail;
@@ -1107,7 +1370,7 @@
 
 	/* Check which interrupt threshold is lower and measure against the
 	 * enabled channel */
-	rc = qpnp_adc_tm_read_reg(QPNP_ADC_TM_MULTI_MEAS_EN,
+	rc = qpnp_adc_tm_read_reg(chip, QPNP_ADC_TM_MULTI_MEAS_EN,
 							&qpnp_adc_tm_meas_en);
 	if (rc) {
 		pr_err("adc-tm-tm read status high failed with %d\n", rc);
@@ -1119,37 +1382,36 @@
 
 	if (adc_tm_high_enable) {
 		sensor_notify_num = adc_tm_high_enable;
-		while (i < adc_tm->max_channels_available) {
+		while (i < chip->max_channels_available) {
 			if ((sensor_notify_num & 0x1) == 1)
 				sensor_num = i;
 			sensor_notify_num >>= 1;
 			i++;
 		}
 
-		btm_chan_num = adc_tm->sensor[sensor_num].btm_channel_num;
+		btm_chan_num = chip->sensor[sensor_num].btm_channel_num;
 		pr_debug("high:sen:%d, hs:0x%x, ls:0x%x, meas_en:0x%x\n",
 			sensor_num, adc_tm_high_enable, adc_tm_low_enable,
 			qpnp_adc_tm_meas_en);
-		if (!adc_tm->sensor[sensor_num].thermal_node) {
+		if (!chip->sensor[sensor_num].thermal_node) {
 			/* For non thermal registered clients
 				such as usb_id, vbatt, pmic_therm */
 			sensor_mask = 1 << sensor_num;
 			pr_debug("non thermal node - mask:%x\n", sensor_mask);
-			rc = qpnp_adc_tm_reg_update(
+			rc = qpnp_adc_tm_reg_update(chip,
 				QPNP_ADC_TM_HIGH_THR_INT_EN,
 				sensor_mask, false);
 			if (rc < 0) {
 				pr_err("high threshold int read failed\n");
 				goto fail;
 			}
-			adc_tm->sensor[sensor_num].high_thr_notify = true;
 		} else {
 			/* Uses the thermal sysfs registered device to disable
 				the corresponding high voltage threshold which
 				 is triggered by low temp */
 			pr_debug("thermal node with mask:%x\n", sensor_mask);
 			rc = qpnp_adc_tm_activate_trip_type(
-				adc_tm->sensor[sensor_num].tz_dev,
+				chip->sensor[sensor_num].tz_dev,
 				ADC_TM_TRIP_LOW_COOL,
 				THERMAL_TRIP_ACTIVATION_DISABLED);
 			if (rc < 0) {
@@ -1157,42 +1419,56 @@
 				goto fail;
 			}
 		}
+		list_for_each(thr_list, &chip->sensor[sensor_num].thr_list) {
+			client_info = list_entry(thr_list,
+					struct qpnp_adc_thr_client_info, list);
+			if (client_info->high_thr_set) {
+				client_info->high_thr_set = false;
+				client_info->notify_high_thr = true;
+				if (client_info->state_req_copy ==
+						ADC_TM_HIGH_LOW_THR_ENABLE)
+					client_info->state_req_copy =
+							ADC_TM_LOW_THR_ENABLE;
+				else
+					client_info->state_req_copy =
+							ADC_TM_HIGH_THR_DISABLE;
+			}
+		}
 	}
 
 	if (adc_tm_low_enable) {
 		sensor_notify_num = adc_tm_low_enable;
 		i = 0;
-		while (i < adc_tm->max_channels_available) {
+		while (i < chip->max_channels_available) {
 			if ((sensor_notify_num & 0x1) == 1)
 				sensor_num = i;
 			sensor_notify_num >>= 1;
 			i++;
 		}
 
-		btm_chan_num = adc_tm->sensor[sensor_num].btm_channel_num;
+		btm_chan_num = chip->sensor[sensor_num].btm_channel_num;
 		pr_debug("low:sen:%d, hs:0x%x, ls:0x%x, meas_en:0x%x\n",
 			sensor_num, adc_tm_high_enable, adc_tm_low_enable,
 			qpnp_adc_tm_meas_en);
-		if (!adc_tm->sensor[sensor_num].thermal_node) {
+		if (!chip->sensor[sensor_num].thermal_node) {
 			/* For non thermal registered clients
 				such as usb_id, vbatt, pmic_therm */
 			pr_debug("non thermal node - mask:%x\n", sensor_mask);
 			sensor_mask = 1 << sensor_num;
-			rc = qpnp_adc_tm_reg_update(
+			rc = qpnp_adc_tm_reg_update(chip,
 				QPNP_ADC_TM_LOW_THR_INT_EN,
 				sensor_mask, false);
 			if (rc < 0) {
 				pr_err("low threshold int read failed\n");
 				goto fail;
 			}
-			adc_tm->sensor[sensor_num].low_thr_notify = true;
 		} else {
 			/* Uses the thermal sysfs registered device to disable
 				the corresponding low voltage threshold which
 				 is triggered by high temp */
 			pr_debug("thermal node with mask:%x\n", sensor_mask);
 			rc = qpnp_adc_tm_activate_trip_type(
-				adc_tm->sensor[sensor_num].tz_dev,
+				chip->sensor[sensor_num].tz_dev,
 				ADC_TM_TRIP_HIGH_WARM,
 				THERMAL_TRIP_ACTIVATION_DISABLED);
 			if (rc < 0) {
@@ -1200,17 +1476,36 @@
 				goto fail;
 			}
 		}
+		list_for_each(thr_list, &chip->sensor[sensor_num].thr_list) {
+			client_info = list_entry(thr_list,
+					struct qpnp_adc_thr_client_info, list);
+			if (client_info->low_thr_set) {
+				/* mark the corresponding clients threshold
+					as not set */
+				client_info->low_thr_set = false;
+				client_info->notify_low_thr = true;
+				if (client_info->state_req_copy ==
+						ADC_TM_HIGH_LOW_THR_ENABLE)
+					client_info->state_req_copy =
+							ADC_TM_HIGH_THR_ENABLE;
+				else
+					client_info->state_req_copy =
+							ADC_TM_LOW_THR_DISABLE;
+			}
+		}
 	}
 
+	qpnp_adc_tm_manage_thresholds(chip, sensor_num, btm_chan_num);
+
 	if (adc_tm_high_enable || adc_tm_low_enable) {
-		rc = qpnp_adc_tm_reg_update(QPNP_ADC_TM_MULTI_MEAS_EN,
+		rc = qpnp_adc_tm_reg_update(chip, QPNP_ADC_TM_MULTI_MEAS_EN,
 			sensor_mask, false);
 		if (rc < 0) {
 			pr_err("multi meas disable for channel failed\n");
 			goto fail;
 		}
 
-		rc = qpnp_adc_tm_enable_if_channel_meas();
+		rc = qpnp_adc_tm_enable_if_channel_meas(chip);
 		if (rc < 0) {
 			pr_err("re-enabling measurement failed\n");
 			return rc;
@@ -1220,62 +1515,58 @@
 								sensor_mask);
 
 fail:
-	mutex_unlock(&adc_tm->adc->adc_lock);
+	mutex_unlock(&chip->adc->adc_lock);
 
 	if (adc_tm_high_enable || adc_tm_low_enable)
-		schedule_work(&adc_tm->sensor[sensor_num].work);
+		schedule_work(&chip->sensor[sensor_num].work);
 
 	return rc;
 }
 
 static void qpnp_adc_tm_high_thr_work(struct work_struct *work)
 {
+	struct qpnp_adc_tm_chip *chip = container_of(work,
+			struct qpnp_adc_tm_chip, trigger_high_thr_work);
 	int rc;
 
-	rc = qpnp_adc_tm_read_status();
+	rc = qpnp_adc_tm_read_status(chip);
 	if (rc < 0)
 		pr_err("adc-tm high thr work failed\n");
 
 	return;
 }
-DECLARE_WORK(trigger_completion_adc_tm_high_thr_work,
-					qpnp_adc_tm_high_thr_work);
 
 static irqreturn_t qpnp_adc_tm_high_thr_isr(int irq, void *data)
 {
-	qpnp_adc_tm_disable();
+	struct qpnp_adc_tm_chip *chip = data;
 
-	schedule_work(&trigger_completion_adc_tm_high_thr_work);
+	qpnp_adc_tm_disable(chip);
+
+	schedule_work(&chip->trigger_high_thr_work);
 
 	return IRQ_HANDLED;
 }
 
 static void qpnp_adc_tm_low_thr_work(struct work_struct *work)
 {
+	struct qpnp_adc_tm_chip *chip = container_of(work,
+			struct qpnp_adc_tm_chip, trigger_low_thr_work);
 	int rc;
 
-	rc = qpnp_adc_tm_read_status();
+	rc = qpnp_adc_tm_read_status(chip);
 	if (rc < 0)
 		pr_err("adc-tm low thr work failed\n");
 
 	return;
 }
-DECLARE_WORK(trigger_completion_adc_tm_low_thr_work, qpnp_adc_tm_low_thr_work);
 
 static irqreturn_t qpnp_adc_tm_low_thr_isr(int irq, void *data)
 {
-	qpnp_adc_tm_disable();
+	struct qpnp_adc_tm_chip *chip = data;
 
-	schedule_work(&trigger_completion_adc_tm_low_thr_work);
+	qpnp_adc_tm_disable(chip);
 
-	return IRQ_HANDLED;
-}
-
-static irqreturn_t qpnp_adc_tm_isr(int irq, void *dev_id)
-{
-	struct qpnp_adc_tm_drv *adc_tm = dev_id;
-
-	complete(&adc_tm->adc->adc_rslt_completion);
+	schedule_work(&chip->trigger_low_thr_work);
 
 	return IRQ_HANDLED;
 }
@@ -1284,11 +1575,11 @@
 			     unsigned long *temp)
 {
 	struct qpnp_adc_tm_sensor *adc_tm_sensor = thermal->devdata;
-	struct qpnp_adc_tm_drv *adc_tm = qpnp_adc_tm;
+	struct qpnp_adc_tm_chip *chip = adc_tm_sensor->chip;
 	struct qpnp_vadc_result result;
 	int rc = 0;
 
-	rc = qpnp_vadc_read(adc_tm->vadc_dev,
+	rc = qpnp_vadc_read(chip->vadc_dev,
 				adc_tm_sensor->vadc_channel_num, &result);
 	if (rc)
 		return rc;
@@ -1308,26 +1599,28 @@
 	.set_trip_temp = qpnp_adc_tm_set_trip_temp,
 };
 
-int32_t qpnp_adc_tm_channel_measure(struct qpnp_adc_tm_btm_param *param)
+int32_t qpnp_adc_tm_channel_measure(struct qpnp_adc_tm_chip *chip,
+					struct qpnp_adc_tm_btm_param *param)
 {
-	struct qpnp_adc_tm_drv *adc_tm = qpnp_adc_tm;
 	uint32_t channel, dt_index = 0, scale_type = 0;
 	int rc = 0, i = 0;
 	bool chan_found = false;
 
-	if (!adc_tm || !adc_tm->adc_tm_initialized)
+	if (qpnp_adc_tm_is_valid(chip)) {
+		pr_err("chip not valid\n");
 		return -ENODEV;
+	}
 
 	if (param->threshold_notification == NULL) {
 		pr_debug("No notification for high/low temp??\n");
 		return -EINVAL;
 	}
 
-	mutex_lock(&adc_tm->adc->adc_lock);
+	mutex_lock(&chip->adc->adc_lock);
 
 	channel = param->channel;
-	while (i < adc_tm->max_channels_available) {
-		if (adc_tm->adc->adc_channels[i].channel_num ==
+	while (i < chip->max_channels_available) {
+		if (chip->adc->adc_channels[i].channel_num ==
 							channel) {
 			dt_index = i;
 			chan_found = true;
@@ -1342,12 +1635,12 @@
 		goto fail_unlock;
 	}
 
-	rc = qpnp_adc_tm_check_revision(
-			adc_tm->sensor[dt_index].btm_channel_num);
+	rc = qpnp_adc_tm_check_revision(chip,
+			chip->sensor[dt_index].btm_channel_num);
 	if (rc < 0)
 		goto fail_unlock;
 
-	scale_type = adc_tm->adc->adc_channels[dt_index].adc_scale_fn;
+	scale_type = chip->adc->adc_channels[dt_index].adc_scale_fn;
 	if (scale_type >= SCALE_RSCALE_NONE) {
 		rc = -EBADF;
 		goto fail_unlock;
@@ -1355,155 +1648,159 @@
 
 	pr_debug("channel:%d, scale_type:%d, dt_idx:%d",
 					channel, scale_type, dt_index);
-	adc_tm->adc->amux_prop->amux_channel = channel;
-	adc_tm->adc->amux_prop->decimation =
-			adc_tm->adc->adc_channels[dt_index].adc_decimation;
-	adc_tm->adc->amux_prop->hw_settle_time =
-			adc_tm->adc->adc_channels[dt_index].hw_settle_time;
-	adc_tm->adc->amux_prop->fast_avg_setup =
-			adc_tm->adc->adc_channels[dt_index].fast_avg_setup;
-	adc_tm->adc->amux_prop->mode_sel =
+	chip->adc->amux_prop->amux_channel = channel;
+	chip->adc->amux_prop->decimation =
+			chip->adc->adc_channels[dt_index].adc_decimation;
+	chip->adc->amux_prop->hw_settle_time =
+			chip->adc->adc_channels[dt_index].hw_settle_time;
+	chip->adc->amux_prop->fast_avg_setup =
+			chip->adc->adc_channels[dt_index].fast_avg_setup;
+	chip->adc->amux_prop->mode_sel =
 		ADC_OP_MEASUREMENT_INTERVAL << QPNP_OP_MODE_SHIFT;
-	adc_tm->adc->amux_prop->chan_prop->meas_interval1 =
+	chip->adc->amux_prop->chan_prop->meas_interval1 =
 						ADC_MEAS1_INTERVAL_1S;
-	adc_tm_rscale_fn[scale_type].chan(adc_tm->vadc_dev, param,
-			&adc_tm->adc->amux_prop->chan_prop->low_thr,
-			&adc_tm->adc->amux_prop->chan_prop->high_thr);
-	adc_tm->adc->amux_prop->chan_prop->tm_channel_select =
-				adc_tm->sensor[dt_index].btm_channel_num;
-	adc_tm->adc->amux_prop->chan_prop->timer_select =
+	adc_tm_rscale_fn[scale_type].chan(chip->vadc_dev, param,
+			&chip->adc->amux_prop->chan_prop->low_thr,
+			&chip->adc->amux_prop->chan_prop->high_thr);
+	qpnp_adc_tm_add_to_list(chip, dt_index, param,
+				chip->adc->amux_prop->chan_prop);
+	chip->adc->amux_prop->chan_prop->tm_channel_select =
+				chip->sensor[dt_index].btm_channel_num;
+	chip->adc->amux_prop->chan_prop->timer_select =
 					ADC_MEAS_TIMER_SELECT1;
-	adc_tm->adc->amux_prop->chan_prop->state_request =
+	chip->adc->amux_prop->chan_prop->state_request =
 					param->state_request;
-	rc = qpnp_adc_tm_configure(adc_tm->adc->amux_prop);
+	rc = qpnp_adc_tm_configure(chip, chip->adc->amux_prop);
 	if (rc) {
 		pr_err("adc-tm configure failed with %d\n", rc);
 		goto fail_unlock;
 	}
 
-	adc_tm->sensor[dt_index].btm_param = param;
-	adc_tm->sensor[dt_index].scale_type = scale_type;
+	chip->sensor[dt_index].scale_type = scale_type;
 
 fail_unlock:
-	mutex_unlock(&adc_tm->adc->adc_lock);
+	mutex_unlock(&chip->adc->adc_lock);
 
 	return rc;
 }
 EXPORT_SYMBOL(qpnp_adc_tm_channel_measure);
 
-int32_t qpnp_adc_tm_disable_chan_meas(struct qpnp_adc_tm_btm_param *param)
+int32_t qpnp_adc_tm_disable_chan_meas(struct qpnp_adc_tm_chip *chip,
+					struct qpnp_adc_tm_btm_param *param)
 {
-	struct qpnp_adc_tm_drv *adc_tm = qpnp_adc_tm;
 	uint32_t channel, dt_index = 0, btm_chan_num;
 	u8 sensor_mask = 0;
 	int rc = 0;
 
-	if (!adc_tm || !adc_tm->adc_tm_initialized)
+	if (qpnp_adc_tm_is_valid(chip))
 		return -ENODEV;
 
-	mutex_lock(&adc_tm->adc->adc_lock);
+	mutex_lock(&chip->adc->adc_lock);
 
 	/* Disable bank */
-	rc = qpnp_adc_tm_disable();
+	rc = qpnp_adc_tm_disable(chip);
 	if (rc < 0) {
 		pr_err("adc-tm disable failed\n");
 		goto fail;
 	}
 
 	/* Check if a conversion is in progress */
-	rc = qpnp_adc_tm_req_sts_check();
+	rc = qpnp_adc_tm_req_sts_check(chip);
 	if (rc < 0) {
 		pr_err("adc-tm req_sts check failed\n");
 		goto fail;
 	}
 
 	channel = param->channel;
-	while ((adc_tm->adc->adc_channels[dt_index].channel_num
-		!= channel) && (dt_index < adc_tm->max_channels_available))
+	while ((chip->adc->adc_channels[dt_index].channel_num
+		!= channel) && (dt_index < chip->max_channels_available))
 		dt_index++;
 
-	if (dt_index >= adc_tm->max_channels_available) {
+	if (dt_index >= chip->max_channels_available) {
 		pr_err("not a valid ADC_TMN channel\n");
 		rc = -EINVAL;
 		goto fail;
 	}
 
-	btm_chan_num = adc_tm->sensor[dt_index].btm_channel_num;
-	sensor_mask = 1 << adc_tm->sensor[dt_index].sensor_num;
+	btm_chan_num = chip->sensor[dt_index].btm_channel_num;
+	sensor_mask = 1 << chip->sensor[dt_index].sensor_num;
 
-	rc = qpnp_adc_tm_reg_update(QPNP_ADC_TM_LOW_THR_INT_EN,
+	rc = qpnp_adc_tm_reg_update(chip, QPNP_ADC_TM_LOW_THR_INT_EN,
 		sensor_mask, false);
 	if (rc < 0) {
 		pr_err("low threshold int write failed\n");
 		goto fail;
 	}
 
-	rc = qpnp_adc_tm_reg_update(QPNP_ADC_TM_HIGH_THR_INT_EN,
+	rc = qpnp_adc_tm_reg_update(chip, QPNP_ADC_TM_HIGH_THR_INT_EN,
 		sensor_mask, false);
 	if (rc < 0) {
 		pr_err("high threshold int enable failed\n");
 		goto fail;
 	}
 
-	rc = qpnp_adc_tm_reg_update(QPNP_ADC_TM_MULTI_MEAS_EN,
+	rc = qpnp_adc_tm_reg_update(chip, QPNP_ADC_TM_MULTI_MEAS_EN,
 		sensor_mask, false);
 	if (rc < 0) {
 		pr_err("multi measurement en failed\n");
 		goto fail;
 	}
 
-	rc = qpnp_adc_tm_enable_if_channel_meas();
+	rc = qpnp_adc_tm_enable_if_channel_meas(chip);
 	if (rc < 0)
 		pr_err("re-enabling measurement failed\n");
 
 fail:
-	mutex_unlock(&adc_tm->adc->adc_lock);
+	mutex_unlock(&chip->adc->adc_lock);
 
 	return rc;
 }
 EXPORT_SYMBOL(qpnp_adc_tm_disable_chan_meas);
 
-int32_t qpnp_adc_tm_usbid_configure(struct qpnp_adc_tm_btm_param *param)
+int32_t qpnp_adc_tm_usbid_configure(struct qpnp_adc_tm_chip *chip,
+				struct qpnp_adc_tm_btm_param *param)
 {
 	param->channel = LR_MUX10_PU2_AMUX_USB_ID_LV;
-	return qpnp_adc_tm_channel_measure(param);
+	return qpnp_adc_tm_channel_measure(chip, param);
 }
 EXPORT_SYMBOL(qpnp_adc_tm_usbid_configure);
 
-int32_t qpnp_adc_tm_usbid_end(void)
+int32_t qpnp_adc_tm_usbid_end(struct qpnp_adc_tm_chip *chip)
 {
 	struct qpnp_adc_tm_btm_param param;
 
-	return qpnp_adc_tm_disable_chan_meas(&param);
+	return qpnp_adc_tm_disable_chan_meas(chip, &param);
 }
 EXPORT_SYMBOL(qpnp_adc_tm_usbid_end);
 
-int32_t qpnp_adc_tm_is_ready(void)
+struct qpnp_adc_tm_chip *qpnp_get_adc_tm(struct device *dev, const char *name)
 {
-	struct qpnp_adc_tm_drv *adc_tm = qpnp_adc_tm;
+	struct qpnp_adc_tm_chip *chip;
+	struct device_node *node = NULL;
+	char prop_name[QPNP_MAX_PROP_NAME_LEN];
 
-	if (!adc_tm || !adc_tm->adc_tm_initialized)
-		return -EPROBE_DEFER;
-	else
-		return 0;
+	snprintf(prop_name, QPNP_MAX_PROP_NAME_LEN, "qcom,%s-adc_tm", name);
+
+	node = of_parse_phandle(dev->of_node, prop_name, 0);
+	if (node == NULL)
+		return ERR_PTR(-ENODEV);
+
+	list_for_each_entry(chip, &qpnp_adc_tm_device_list, list)
+		if (chip->adc->spmi->dev.of_node == node)
+			return chip;
+
+	return ERR_PTR(-EPROBE_DEFER);
 }
-EXPORT_SYMBOL(qpnp_adc_tm_is_ready);
+EXPORT_SYMBOL(qpnp_get_adc_tm);
 
 static int __devinit qpnp_adc_tm_probe(struct spmi_device *spmi)
 {
 	struct device_node *node = spmi->dev.of_node, *child;
-	struct qpnp_adc_tm_drv *adc_tm;
+	struct qpnp_adc_tm_chip *chip;
 	struct qpnp_adc_drv *adc_qpnp;
-	int32_t count_adc_channel_list = 0, rc, sen_idx = 0;
+	int32_t count_adc_channel_list = 0, rc, sen_idx = 0, i = 0;
 	u8 thr_init = 0;
-
-	if (!node)
-		return -EINVAL;
-
-	if (qpnp_adc_tm) {
-		pr_err("adc-tm already in use\n");
-		return -EBUSY;
-	}
+	bool thermal_node = false;
 
 	for_each_child_of_node(node, child)
 		count_adc_channel_list++;
@@ -1513,16 +1810,15 @@
 		return -EINVAL;
 	}
 
-	adc_tm = devm_kzalloc(&spmi->dev, sizeof(struct qpnp_adc_tm_drv) +
+	chip = devm_kzalloc(&spmi->dev, sizeof(struct qpnp_adc_tm_chip) +
 			(count_adc_channel_list *
 			sizeof(struct qpnp_adc_tm_sensor)),
 				GFP_KERNEL);
-	if (!adc_tm) {
+	if (!chip) {
 		dev_err(&spmi->dev, "Unable to allocate memory\n");
 		return -ENOMEM;
 	}
 
-	qpnp_adc_tm = adc_tm;
 	adc_qpnp = devm_kzalloc(&spmi->dev, sizeof(struct qpnp_adc_drv),
 			GFP_KERNEL);
 	if (!adc_qpnp) {
@@ -1531,75 +1827,44 @@
 		goto fail;
 	}
 
-	adc_tm->adc = adc_qpnp;
+	chip->dev = &(spmi->dev);
+	chip->adc = adc_qpnp;
 
-	rc = qpnp_adc_get_devicetree_data(spmi, adc_tm->adc);
+	rc = qpnp_adc_get_devicetree_data(spmi, chip->adc);
 	if (rc) {
 		dev_err(&spmi->dev, "failed to read device tree\n");
 		goto fail;
 	}
-	mutex_init(&adc_tm->adc->adc_lock);
+	mutex_init(&chip->adc->adc_lock);
 
 	/* Register the ADC peripheral interrupt */
-	adc_tm->adc->adc_high_thr_irq = spmi_get_irq_byname(spmi,
+	chip->adc->adc_high_thr_irq = spmi_get_irq_byname(spmi,
 						NULL, "high-thr-en-set");
-	if (adc_tm->adc->adc_high_thr_irq < 0) {
+	if (chip->adc->adc_high_thr_irq < 0) {
 		pr_err("Invalid irq\n");
 		rc = -ENXIO;
 		goto fail;
 	}
 
-	adc_tm->adc->adc_low_thr_irq = spmi_get_irq_byname(spmi,
+	chip->adc->adc_low_thr_irq = spmi_get_irq_byname(spmi,
 						NULL, "low-thr-en-set");
-	if (adc_tm->adc->adc_low_thr_irq < 0) {
+	if (chip->adc->adc_low_thr_irq < 0) {
 		pr_err("Invalid irq\n");
 		rc = -ENXIO;
 		goto fail;
 	}
 
-	adc_tm->vadc_dev = qpnp_get_vadc(&spmi->dev, "adc_tm");
-	if (IS_ERR(adc_tm->vadc_dev)) {
-		rc = PTR_ERR(adc_tm->vadc_dev);
+	chip->vadc_dev = qpnp_get_vadc(&spmi->dev, "adc_tm");
+	if (IS_ERR(chip->vadc_dev)) {
+		rc = PTR_ERR(chip->vadc_dev);
 		if (rc != -EPROBE_DEFER)
 			pr_err("vadc property missing, rc=%d\n", rc);
 		goto fail;
 	}
 
-	rc = devm_request_irq(&spmi->dev, adc_tm->adc->adc_irq_eoc,
-				qpnp_adc_tm_isr, IRQF_TRIGGER_RISING,
-				"qpnp_adc_tm_interrupt", adc_tm);
-	if (rc) {
-		dev_err(&spmi->dev,
-			"failed to request adc irq with error %d\n", rc);
-		goto fail;
-	} else {
-		enable_irq_wake(adc_tm->adc->adc_irq_eoc);
-	}
-
-	rc = devm_request_irq(&spmi->dev, adc_tm->adc->adc_high_thr_irq,
-				qpnp_adc_tm_high_thr_isr,
-		IRQF_TRIGGER_RISING, "qpnp_adc_tm_high_interrupt", adc_tm);
-	if (rc) {
-		dev_err(&spmi->dev, "failed to request adc irq\n");
-		goto fail;
-	} else {
-		enable_irq_wake(adc_tm->adc->adc_high_thr_irq);
-	}
-
-	rc = devm_request_irq(&spmi->dev, adc_tm->adc->adc_low_thr_irq,
-				qpnp_adc_tm_low_thr_isr,
-		IRQF_TRIGGER_RISING, "qpnp_adc_tm_low_interrupt", adc_tm);
-	if (rc) {
-		dev_err(&spmi->dev, "failed to request adc irq\n");
-		goto fail;
-	} else {
-		enable_irq_wake(adc_tm->adc->adc_low_thr_irq);
-	}
-
 	for_each_child_of_node(node, child) {
 		char name[25];
 		int btm_channel_num;
-		bool thermal_node = false;
 
 		rc = of_property_read_u32(child,
 				"qcom,btm-channel-number", &btm_channel_num);
@@ -1607,80 +1872,117 @@
 			pr_err("Invalid btm channel number\n");
 			goto fail;
 		}
-		adc_tm->sensor[sen_idx].btm_channel_num = btm_channel_num;
-		adc_tm->sensor[sen_idx].vadc_channel_num =
-				adc_tm->adc->adc_channels[sen_idx].channel_num;
-		adc_tm->sensor[sen_idx].sensor_num = sen_idx;
+		chip->sensor[sen_idx].btm_channel_num = btm_channel_num;
+		chip->sensor[sen_idx].vadc_channel_num =
+				chip->adc->adc_channels[sen_idx].channel_num;
+		chip->sensor[sen_idx].sensor_num = sen_idx;
+		chip->sensor[sen_idx].chip = chip;
 		pr_debug("btm_chan:%x, vadc_chan:%x\n", btm_channel_num,
-			adc_tm->adc->adc_channels[sen_idx].channel_num);
+			chip->adc->adc_channels[sen_idx].channel_num);
 		thermal_node = of_property_read_bool(child,
 					"qcom,thermal-node");
 		if (thermal_node) {
 			/* Register with the thermal zone */
 			pr_debug("thermal node%x\n", btm_channel_num);
-			adc_tm->sensor[sen_idx].mode = THERMAL_DEVICE_DISABLED;
-			adc_tm->sensor[sen_idx].thermal_node = true;
+			chip->sensor[sen_idx].mode = THERMAL_DEVICE_DISABLED;
+			chip->sensor[sen_idx].thermal_node = true;
 			snprintf(name, sizeof(name),
-				adc_tm->adc->adc_channels[sen_idx].name);
-			adc_tm->sensor[sen_idx].meas_interval =
+				chip->adc->adc_channels[sen_idx].name);
+			chip->sensor[sen_idx].meas_interval =
 				QPNP_ADC_TM_MEAS_INTERVAL;
-			adc_tm->sensor[sen_idx].low_thr =
+			chip->sensor[sen_idx].low_thr =
 						QPNP_ADC_TM_M0_LOW_THR;
-			adc_tm->sensor[sen_idx].high_thr =
+			chip->sensor[sen_idx].high_thr =
 						QPNP_ADC_TM_M0_HIGH_THR;
-			adc_tm->sensor[sen_idx].tz_dev =
+			chip->sensor[sen_idx].tz_dev =
 				thermal_zone_device_register(name,
 				ADC_TM_TRIP_NUM,
-				&adc_tm->sensor[sen_idx],
+				&chip->sensor[sen_idx],
 				&qpnp_adc_tm_thermal_ops, 0, 0, 0, 0);
-			if (IS_ERR(adc_tm->sensor[sen_idx].tz_dev))
+			if (IS_ERR(chip->sensor[sen_idx].tz_dev))
 				pr_err("thermal device register failed.\n");
 		}
-		INIT_WORK(&adc_tm->sensor[sen_idx].work, notify_adc_tm_fn);
+		INIT_WORK(&chip->sensor[sen_idx].work, notify_adc_tm_fn);
+		INIT_LIST_HEAD(&chip->sensor[sen_idx].thr_list);
 		sen_idx++;
 	}
-	adc_tm->max_channels_available = count_adc_channel_list;
-	dev_set_drvdata(&spmi->dev, adc_tm);
-	rc = qpnp_adc_tm_write_reg(QPNP_ADC_TM_HIGH_THR_INT_EN, thr_init);
+	chip->max_channels_available = count_adc_channel_list;
+	INIT_WORK(&chip->trigger_high_thr_work, qpnp_adc_tm_high_thr_work);
+	INIT_WORK(&chip->trigger_low_thr_work, qpnp_adc_tm_low_thr_work);
+
+	rc = qpnp_adc_tm_write_reg(chip, QPNP_ADC_TM_HIGH_THR_INT_EN,
+								thr_init);
 	if (rc < 0) {
 		pr_err("high thr init failed\n");
 		goto fail;
 	}
 
-	rc = qpnp_adc_tm_write_reg(QPNP_ADC_TM_LOW_THR_INT_EN, thr_init);
+	rc = qpnp_adc_tm_write_reg(chip, QPNP_ADC_TM_LOW_THR_INT_EN,
+								thr_init);
 	if (rc < 0) {
 		pr_err("low thr init failed\n");
 		goto fail;
 	}
 
-	rc = qpnp_adc_tm_write_reg(QPNP_ADC_TM_MULTI_MEAS_EN, thr_init);
+	rc = qpnp_adc_tm_write_reg(chip, QPNP_ADC_TM_MULTI_MEAS_EN,
+								thr_init);
 	if (rc < 0) {
 		pr_err("multi meas en failed\n");
 		goto fail;
 	}
 
-	adc_tm->adc_tm_initialized = true;
+	rc = devm_request_irq(&spmi->dev, chip->adc->adc_high_thr_irq,
+				qpnp_adc_tm_high_thr_isr,
+		IRQF_TRIGGER_RISING, "qpnp_adc_tm_high_interrupt", chip);
+	if (rc) {
+		dev_err(&spmi->dev, "failed to request adc irq\n");
+		goto fail;
+	} else {
+		enable_irq_wake(chip->adc->adc_high_thr_irq);
+	}
+
+	rc = devm_request_irq(&spmi->dev, chip->adc->adc_low_thr_irq,
+				qpnp_adc_tm_low_thr_isr,
+		IRQF_TRIGGER_RISING, "qpnp_adc_tm_low_interrupt", chip);
+	if (rc) {
+		dev_err(&spmi->dev, "failed to request adc irq\n");
+		goto fail;
+	} else {
+		enable_irq_wake(chip->adc->adc_low_thr_irq);
+	}
+
+	dev_set_drvdata(&spmi->dev, chip);
+	list_add(&chip->list, &qpnp_adc_tm_device_list);
 
 	pr_debug("OK\n");
 	return 0;
 fail:
-	qpnp_adc_tm = NULL;
+	for_each_child_of_node(node, child) {
+		thermal_node = of_property_read_bool(child,
+					"qcom,thermal-node");
+		if (thermal_node)
+			thermal_zone_device_unregister(chip->sensor[i].tz_dev);
+		i++;
+	}
+	dev_set_drvdata(&spmi->dev, NULL);
 	return rc;
 }
 
 static int __devexit qpnp_adc_tm_remove(struct spmi_device *spmi)
 {
-	struct qpnp_adc_tm_drv *adc_tm = dev_get_drvdata(&spmi->dev);
-	struct device_node *node = spmi->dev.of_node;
-	struct device_node *child;
+	struct qpnp_adc_tm_chip *chip = dev_get_drvdata(&spmi->dev);
+	struct device_node *node = spmi->dev.of_node, *child;
+	bool thermal_node = false;
 	int i = 0;
 
 	for_each_child_of_node(node, child) {
-		thermal_zone_device_unregister(adc_tm->sensor[i].tz_dev);
+		thermal_node = of_property_read_bool(child,
+					"qcom,thermal-node");
+		if (thermal_node)
+			thermal_zone_device_unregister(chip->sensor[i].tz_dev);
 		i++;
 	}
 
-	adc_tm->adc_tm_initialized = false;
 	dev_set_drvdata(&spmi->dev, NULL);
 
 	return 0;
diff --git a/drivers/thermal/thermal_sys.c b/drivers/thermal/thermal_sys.c
index fd1a2fc..1cf901e 100644
--- a/drivers/thermal/thermal_sys.c
+++ b/drivers/thermal/thermal_sys.c
@@ -4,6 +4,7 @@
  *  Copyright (C) 2008 Intel Corp
  *  Copyright (C) 2008 Zhang Rui <rui.zhang@intel.com>
  *  Copyright (C) 2008 Sujith Thomas <sujith.thomas@intel.com>
+ *  Copyright (c) 2013, The Linux Foundation. All rights reserved.
  *
  *  ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  *
@@ -60,6 +61,273 @@
 static LIST_HEAD(thermal_cdev_list);
 static DEFINE_MUTEX(thermal_list_lock);
 
+static LIST_HEAD(sensor_info_list);
+static DEFINE_MUTEX(sensor_list_lock);
+
+static struct sensor_info *get_sensor(uint32_t sensor_id)
+{
+	struct sensor_info *pos, *var;
+
+	list_for_each_entry_safe(pos, var, &sensor_info_list, sensor_list) {
+		if (pos->sensor_id == sensor_id)
+			break;
+	}
+
+	return pos;
+}
+
+int sensor_get_id(char *name)
+{
+	struct sensor_info *pos, *var;
+
+	list_for_each_entry_safe(pos, var, &sensor_info_list, sensor_list) {
+		if (!strcmp(pos->tz->type, name))
+			return pos->sensor_id;
+	}
+
+	return -ENODEV;
+}
+EXPORT_SYMBOL(sensor_get_id);
+
+static void __update_sensor_thresholds(struct sensor_info *sensor)
+{
+	int min = INT_MIN;
+	int max = INT_MAX;
+	struct sensor_threshold *pos, *var;
+	enum thermal_trip_type type;
+	int i;
+	unsigned long curr_temp;
+
+	for (i = 0; ((sensor->max_idx == -1) || (sensor->min_idx == -1)) &&
+		(sensor->tz->ops->get_trip_type) && (i < sensor->tz->trips);
+		i++) {
+		sensor->tz->ops->get_trip_type(sensor->tz, i, &type);
+		if (type == THERMAL_TRIP_CONFIGURABLE_HI)
+			sensor->max_idx = i;
+		if (type == THERMAL_TRIP_CONFIGURABLE_LOW)
+			sensor->min_idx = i;
+	}
+
+	get_cpu();
+	sensor->tz->ops->get_temp(sensor->tz, &curr_temp);
+	list_for_each_entry_safe(pos, var, &sensor->threshold_list, list) {
+		if ((pos->trip == THERMAL_TRIP_CONFIGURABLE_LOW) &&
+				(pos->temp < (int)curr_temp))
+			if (pos->temp > min)
+				min = pos->temp;
+		if ((pos->trip == THERMAL_TRIP_CONFIGURABLE_HI) &&
+				(pos->temp > (int)curr_temp))
+			if (pos->temp < max)
+				max = pos->temp;
+	}
+	put_cpu();
+
+	if (sensor->tz->ops->set_trip_temp) {
+		if (max != INT_MAX) {
+			sensor->tz->ops->set_trip_temp(sensor->tz,
+				sensor->max_idx, max);
+			sensor->threshold_max = max;
+		}
+		if (min != INT_MIN) {
+			sensor->tz->ops->set_trip_temp(sensor->tz,
+				sensor->min_idx, min);
+			sensor->threshold_min = min;
+		}
+	}
+
+	pr_debug("sensor %d, min: %d, max %d\n", sensor->sensor_id, min, max);
+}
+
+static void sensor_update_work(struct work_struct *work)
+{
+	struct sensor_info *sensor = container_of(work, struct sensor_info,
+						work);
+	mutex_lock(&sensor->lock);
+	__update_sensor_thresholds(sensor);
+	mutex_unlock(&sensor->lock);
+}
+
+/* May be called in an interrupt context.
+ * Do NOT call sensor_set_trip from this function
+ */
+int thermal_sensor_trip(struct thermal_zone_device *tz,
+		enum thermal_trip_type trip, unsigned long temp)
+{
+	struct sensor_threshold *pos, *var;
+	int ret = -ENODEV;
+
+	if (trip != THERMAL_TRIP_CONFIGURABLE_HI &&
+			trip != THERMAL_TRIP_CONFIGURABLE_LOW)
+		return 0;
+
+	if (list_empty(&tz->sensor.threshold_list))
+		return 0;
+
+	list_for_each_entry_safe(pos, var, &tz->sensor.threshold_list, list) {
+		if (pos->trip != trip)
+			continue;
+		if (((trip == THERMAL_TRIP_CONFIGURABLE_LOW) &&
+			(pos->temp <= tz->sensor.threshold_min) &&
+			(pos->temp >= (int) temp)) ||
+			((trip == THERMAL_TRIP_CONFIGURABLE_HI) &&
+				(pos->temp >= tz->sensor.threshold_max) &&
+				(pos->temp <= (int)temp))) {
+			pos->notify(trip, temp, pos->data);
+		}
+	}
+
+	schedule_work(&tz->sensor.work);
+
+	return ret;
+}
+EXPORT_SYMBOL(thermal_sensor_trip);
+
+int sensor_set_trip(uint32_t sensor_id, struct sensor_threshold *threshold)
+{
+	struct sensor_threshold *pos, *var;
+	struct sensor_info *sensor = get_sensor(sensor_id);
+
+	if (!sensor)
+		return -ENODEV;
+
+	if (!threshold || !threshold->notify)
+		return -EFAULT;
+
+	mutex_lock(&sensor->lock);
+	list_for_each_entry_safe(pos, var, &sensor->threshold_list, list) {
+		if (pos == threshold)
+			break;
+	}
+
+	if (pos != threshold) {
+		INIT_LIST_HEAD(&threshold->list);
+		list_add(&threshold->list, &sensor->threshold_list);
+	}
+
+	__update_sensor_thresholds(sensor);
+	mutex_unlock(&sensor->lock);
+
+	return 0;
+
+}
+EXPORT_SYMBOL(sensor_set_trip);
+
+int sensor_cancel_trip(uint32_t sensor_id, struct sensor_threshold *threshold)
+{
+	struct sensor_threshold *pos, *var;
+	struct sensor_info *sensor = get_sensor(sensor_id);
+
+	if (!sensor)
+		return -ENODEV;
+
+	mutex_lock(&sensor->lock);
+	list_for_each_entry_safe(pos, var, &sensor->threshold_list, list) {
+		if (pos == threshold) {
+			list_del(&pos->list);
+			break;
+		}
+	}
+
+	__update_sensor_thresholds(sensor);
+	mutex_unlock(&sensor->lock);
+
+	return 0;
+}
+EXPORT_SYMBOL(sensor_cancel_trip);
+
+static int sensor_get_trip_temp(struct thermal_zone_device *tz,
+		int type, unsigned long *temp)
+{
+	struct sensor_info *sensor = get_sensor(tz->id);
+
+	if (!sensor)
+		return -EFAULT;
+
+	switch (type) {
+	case THERMAL_TRIP_CONFIGURABLE_HI:
+		*temp = tz->sensor.threshold_max;
+		break;
+	case THERMAL_TRIP_CONFIGURABLE_LOW:
+		*temp = tz->sensor.threshold_min;
+		break;
+	default:
+		tz->ops->get_trip_temp(tz, type, temp);
+		break;
+	}
+
+	return 0;
+}
+
+static int tz_notify_trip(enum thermal_trip_type type, int temp, void *data)
+{
+	struct thermal_zone_device *tz = (struct thermal_zone_device *)data;
+
+	pr_debug("sensor %d tripped: type %d temp %d\n",
+			tz->sensor.sensor_id, type, temp);
+
+	return 0;
+}
+
+int sensor_set_trip_temp(struct thermal_zone_device *tz,
+		int trip, long temp)
+{
+	int ret = 0;
+	enum thermal_trip_type type;
+
+	if (!tz->ops->get_trip_type)
+		return -EPERM;
+
+	tz->ops->get_trip_type(tz, trip, &type);
+	switch (type) {
+	case THERMAL_TRIP_CONFIGURABLE_HI:
+		tz->tz_threshold[0].temp = temp;
+		tz->tz_threshold[0].trip = THERMAL_TRIP_CONFIGURABLE_HI;
+		tz->tz_threshold[0].notify = tz_notify_trip;
+		tz->tz_threshold[0].data = tz;
+		ret = sensor_set_trip(tz->sensor.sensor_id,
+					&tz->tz_threshold[0]);
+		break;
+	case THERMAL_TRIP_CONFIGURABLE_LOW:
+		tz->tz_threshold[1].temp = temp;
+		tz->tz_threshold[1].trip = THERMAL_TRIP_CONFIGURABLE_LOW;
+		tz->tz_threshold[1].notify = tz_notify_trip;
+		tz->tz_threshold[1].data = tz;
+		ret = sensor_set_trip(tz->sensor.sensor_id,
+					&tz->tz_threshold[1]);
+		break;
+	default:
+		ret = tz->ops->set_trip_temp(tz, trip, temp);
+		break;
+	}
+
+	return ret;
+}
+
+int sensor_init(struct thermal_zone_device *tz)
+{
+	struct sensor_info *sensor = &tz->sensor;
+
+	sensor->sensor_id = tz->id;
+	sensor->tz = tz;
+	sensor->threshold_min = 0;
+	sensor->threshold_max = INT_MAX;
+	sensor->max_idx = -1;
+	sensor->min_idx = -1;
+	mutex_init(&sensor->lock);
+	INIT_LIST_HEAD(&sensor->sensor_list);
+	INIT_LIST_HEAD(&sensor->threshold_list);
+	INIT_LIST_HEAD(&tz->tz_threshold[0].list);
+	INIT_LIST_HEAD(&tz->tz_threshold[1].list);
+	tz->tz_threshold[0].notify = NULL;
+	tz->tz_threshold[0].data = NULL;
+	tz->tz_threshold[1].notify = NULL;
+	tz->tz_threshold[1].data = NULL;
+	list_add(&sensor->sensor_list, &sensor_info_list);
+	INIT_WORK(&sensor->work, sensor_update_work);
+
+	return 0;
+}
+
 static int get_idr(struct idr *idr, struct mutex *lock, int *id)
 {
 	int err;
@@ -243,7 +511,7 @@
 	if (!sscanf(attr->attr.name, "trip_point_%d_temp", &trip))
 		return -EINVAL;
 
-	ret = tz->ops->get_trip_temp(tz, trip, &temperature);
+	ret = sensor_get_trip_temp(tz, trip, &temperature);
 
 	if (ret)
 		return ret;
@@ -268,7 +536,8 @@
 	if (!sscanf(buf, "%ld", &temperature))
 		return -EINVAL;
 
-	ret = tz->ops->set_trip_temp(tz, trip, temperature);
+	ret = sensor_set_trip_temp(tz, trip, temperature);
+
 	if (ret)
 		return ret;
 
@@ -1313,6 +1582,7 @@
 		if (result)
 			break;
 		}
+	sensor_init(tz);
 	mutex_unlock(&thermal_list_lock);
 
 	INIT_DELAYED_WORK(&(tz->poll_queue), thermal_zone_device_check);
@@ -1372,6 +1642,10 @@
 				   &trip_point_attrs[count * 2 + 1]);
 	}
 	thermal_remove_hwmon_sysfs(tz);
+	flush_work(&tz->sensor.work);
+	mutex_lock(&thermal_list_lock);
+	list_del(&tz->sensor.sensor_list);
+	mutex_unlock(&thermal_list_lock);
 	release_idr(&thermal_tz_idr, &thermal_idr_lock, tz->id);
 	idr_destroy(&tz->idr);
 	mutex_destroy(&tz->lock);
diff --git a/drivers/tty/n_tty.c b/drivers/tty/n_tty.c
index 94b6eda..8eb5573 100644
--- a/drivers/tty/n_tty.c
+++ b/drivers/tty/n_tty.c
@@ -81,20 +81,31 @@
 }
 
 /**
- *	n_tty_set__room	-	receive space
+ *	n_tty_set_room	-	receive space
  *	@tty: terminal
  *
- *	Called by the driver to find out how much data it is
- *	permitted to feed to the line discipline without any being lost
- *	and thus to manage flow control. Not serialized. Answers for the
- *	"instant".
+ *	Sets tty->receive_room to reflect the currently available space
+ *	in the input buffer, and re-schedules the flip buffer work if space
+ *	just became available.
+ *
+ *	Locks: Concurrent update is protected with read_lock
  */
 
 static void n_tty_set_room(struct tty_struct *tty)
 {
-	/* tty->read_cnt is not read locked ? */
-	int	left = N_TTY_BUF_SIZE - tty->read_cnt - 1;
+	int left;
 	int old_left;
+	unsigned long flags;
+
+	spin_lock_irqsave(&tty->read_lock, flags);
+
+	if (I_PARMRK(tty)) {
+		/* Multiply read_cnt by 3, since each byte might take up to
+		 * three times as many spaces when PARMRK is set (depending on
+		 * its flags, e.g. parity error). */
+		left = N_TTY_BUF_SIZE - tty->read_cnt * 3 - 1;
+	} else
+		left = N_TTY_BUF_SIZE - tty->read_cnt - 1;
 
 	/*
 	 * If we are doing input canonicalization, and there are no
@@ -107,6 +118,8 @@
 	old_left = tty->receive_room;
 	tty->receive_room = left;
 
+	spin_unlock_irqrestore(&tty->read_lock, flags);
+
 	/* Did this open up the receive buffer? We may need to flip */
 	if (left && !old_left)
 		schedule_work(&tty->buf.work);
@@ -1811,7 +1824,6 @@
 				retval = -ERESTARTSYS;
 				break;
 			}
-			/* FIXME: does n_tty_set_room need locking ? */
 			n_tty_set_room(tty);
 			timeout = schedule_timeout(timeout);
 			BUG_ON(!tty->read_buf);
diff --git a/drivers/tty/serial/msm_serial_hs_lite.c b/drivers/tty/serial/msm_serial_hs_lite.c
index d520253..a4a4f28 100644
--- a/drivers/tty/serial/msm_serial_hs_lite.c
+++ b/drivers/tty/serial/msm_serial_hs_lite.c
@@ -47,6 +47,8 @@
 #include <linux/of_device.h>
 #include <linux/of_gpio.h>
 #include <linux/wakelock.h>
+#include <linux/types.h>
+#include <asm/byteorder.h>
 #include <mach/board.h>
 #include <mach/msm_serial_hs_lite.h>
 #include <mach/msm_bus.h>
@@ -166,12 +168,17 @@
 static inline void msm_hsl_write(struct uart_port *port,
 				 unsigned int val, unsigned int off)
 {
-	iowrite32(val, port->membase + off);
+	__iowmb();
+	__raw_writel_no_log((__force __u32)cpu_to_le32(val),
+		port->membase + off);
 }
 static inline unsigned int msm_hsl_read(struct uart_port *port,
 		     unsigned int off)
 {
-	return ioread32(port->membase + off);
+	unsigned int v = le32_to_cpu((__force __le32)__raw_readl_no_log(
+		port->membase + off));
+	__iormb();
+	return v;
 }
 
 static unsigned int msm_serial_hsl_has_gsbi(struct uart_port *port)
diff --git a/drivers/tty/tty_buffer.c b/drivers/tty/tty_buffer.c
index 3d29607..24b18cb 100644
--- a/drivers/tty/tty_buffer.c
+++ b/drivers/tty/tty_buffer.c
@@ -463,8 +463,6 @@
 			int count;
 			char *char_buf;
 			unsigned char *flag_buf;
-			unsigned int left = 0;
-			unsigned int max_space;
 
 			count = head->commit - head->read;
 			if (!count) {
@@ -474,38 +472,11 @@
 				tty_buffer_free(tty, head);
 				continue;
 			}
-			/* Ldisc or user is trying to flush the buffers
-			   we are feeding to the ldisc, stop feeding the
-			   line discipline as we want to empty the queue */
-			if (test_bit(TTY_FLUSHPENDING, &tty->flags))
-				break;
-
-			/* update receive room */
-			spin_lock(&tty->read_lock);
-			if (tty->update_room_in_ldisc) {
-				if ((tty->read_cnt == N_TTY_BUF_SIZE - 1) &&
-					(tty->receive_room ==
-						N_TTY_BUF_SIZE - 1))
-					tty->rr_bug++;
-				left = N_TTY_BUF_SIZE - tty->read_cnt - 1;
-			}
-			spin_unlock(&tty->read_lock);
 
 			if (!tty->receive_room)
 				break;
-
-			if (tty->update_room_in_ldisc && !left) {
-				schedule_work(&tty->buf.work);
-				break;
-			}
-
-			if (tty->update_room_in_ldisc)
-				max_space = min(left, tty->receive_room);
-			else
-				max_space = tty->receive_room;
-
-			if (count > max_space)
-				count = max_space;
+			if (count > tty->receive_room)
+				count = tty->receive_room;
 			char_buf = head->char_buf_ptr + head->read;
 			flag_buf = head->flag_buf_ptr + head->read;
 			head->read += count;
@@ -513,17 +484,19 @@
 			disc->ops->receive_buf(tty, char_buf,
 							flag_buf, count);
 			spin_lock_irqsave(&tty->buf.lock, flags);
+			/* Ldisc or user is trying to flush the buffers.
+			   We may have a deferred request to flush the
+			   input buffer, if so pull the chain under the lock
+			   and empty the queue */
+			if (test_bit(TTY_FLUSHPENDING, &tty->flags)) {
+				__tty_buffer_flush(tty);
+				clear_bit(TTY_FLUSHPENDING, &tty->flags);
+				wake_up(&tty->read_wait);
+				break;
+			}
 		}
 		clear_bit(TTY_FLUSHING, &tty->flags);
 	}
-
-	/* We may have a deferred request to flush the input buffer,
-	   if so pull the chain under the lock and empty the queue */
-	if (test_bit(TTY_FLUSHPENDING, &tty->flags)) {
-		__tty_buffer_flush(tty);
-		clear_bit(TTY_FLUSHPENDING, &tty->flags);
-		wake_up(&tty->read_wait);
-	}
 	spin_unlock_irqrestore(&tty->buf.lock, flags);
 
 	tty_ldisc_deref(disc);
diff --git a/drivers/usb/dwc3/core.c b/drivers/usb/dwc3/core.c
index db6fec9..98c6884 100644
--- a/drivers/usb/dwc3/core.c
+++ b/drivers/usb/dwc3/core.c
@@ -111,7 +111,33 @@
 	reg = dwc3_readl(dwc->regs, DWC3_GCTL);
 	reg &= ~(DWC3_GCTL_PRTCAPDIR(DWC3_GCTL_PRTCAP_OTG));
 	reg |= DWC3_GCTL_PRTCAPDIR(mode);
+	/*
+	 * Set this bit so that device attempts three more times at SS, even
+	 * if it failed previously to operate in SS mode.
+	 */
+	reg |= DWC3_GCTL_U2RSTECN;
+	if (mode == DWC3_GCTL_PRTCAP_HOST) {
+		/*
+		 * Allow ITP generated off of ref clk based counter instead
+		 * of UTMI/ULPI clk based counter, when superspeed only is
+		 * active so that UTMI/ULPI PHY can be suspened.
+		 */
+		reg |= DWC3_GCTL_SOFITPSYNC;
+		reg &= ~(DWC3_GCTL_PWRDNSCALEMASK);
+		reg |= DWC3_GCTL_PWRDNSCALE(2);
+	} else if (mode == DWC3_GCTL_PRTCAP_DEVICE) {
+		reg &= ~(DWC3_GCTL_PWRDNSCALEMASK);
+		reg |= DWC3_GCTL_PWRDNSCALE(2);
+		reg &= ~(DWC3_GCTL_SOFITPSYNC);
+	}
+	reg |= DWC3_GCTL_U2EXIT_LFPS;
 	dwc3_writel(dwc->regs, DWC3_GCTL, reg);
+	reg = dwc3_readl(dwc->regs, DWC3_GUSB3PIPECTL(0));
+	reg |= DWC3_GUSB3PIPECTL_SUSPHY;
+	dwc3_writel(dwc->regs, DWC3_GUSB3PIPECTL(0), reg);
+	reg = dwc3_readl(dwc->regs, DWC3_GUSB2PHYCFG(0));
+	reg |= DWC3_GUSB2PHYCFG_SUSPHY;
+	dwc3_writel(dwc->regs, DWC3_GUSB2PHYCFG(0), reg);
 }
 
 /**
@@ -127,6 +153,9 @@
 	reg |= DWC3_GCTL_CORESOFTRESET;
 	dwc3_writel(dwc->regs, DWC3_GCTL, reg);
 
+	if (dwc->revision >= DWC3_REVISION_230A)
+		dwc3_notify_event(dwc, DWC3_CONTROLLER_RESET_EVENT);
+
 	/* Assert USB3 PHY reset */
 	reg = dwc3_readl(dwc->regs, DWC3_GUSB3PIPECTL(0));
 	reg |= DWC3_GUSB3PIPECTL_PHYSOFTRST;
@@ -155,6 +184,9 @@
 	reg = dwc3_readl(dwc->regs, DWC3_GCTL);
 	reg &= ~DWC3_GCTL_CORESOFTRESET;
 	dwc3_writel(dwc->regs, DWC3_GCTL, reg);
+
+	if (dwc->revision >= DWC3_REVISION_230A)
+		dwc3_notify_event(dwc, DWC3_CONTROLLER_POST_RESET_EVENT);
 }
 
 /**
@@ -473,6 +505,20 @@
 	dwc3_gadget_restart(dwc);
 }
 
+static void (*notify_event) (struct dwc3 *, unsigned);
+void dwc3_set_notifier(void (*notify)(struct dwc3 *, unsigned))
+{
+	notify_event = notify;
+}
+EXPORT_SYMBOL(dwc3_set_notifier);
+
+void dwc3_notify_event(struct dwc3 *dwc, unsigned event)
+{
+	if (dwc->notify_event)
+		dwc->notify_event(dwc, event);
+}
+EXPORT_SYMBOL(dwc3_notify_event);
+
 #define DWC3_ALIGN_MASK		(16 - 1)
 
 static u64 dwc3_dma_mask = DMA_BIT_MASK(64);
@@ -504,6 +550,7 @@
 	if (!dev->coherent_dma_mask)
 		dev->coherent_dma_mask = DMA_BIT_MASK(64);
 
+	dwc->notify_event = notify_event;
 	res = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
 	if (!res) {
 		dev_err(dev, "missing IRQ\n");
diff --git a/drivers/usb/dwc3/core.h b/drivers/usb/dwc3/core.h
index 2064c13..674efb3 100644
--- a/drivers/usb/dwc3/core.h
+++ b/drivers/usb/dwc3/core.h
@@ -163,7 +163,10 @@
 
 /* Global Configuration Register */
 #define DWC3_GCTL_PWRDNSCALE(n)	((n) << 19)
+#define DWC3_GCTL_PWRDNSCALEMASK (0xFFF80000)
 #define DWC3_GCTL_U2RSTECN	(1 << 16)
+#define DWC3_GCTL_SOFITPSYNC	(1 << 10)
+#define DWC3_GCTL_U2EXIT_LFPS	(1 << 2)
 #define DWC3_GCTL_RAMCLKSEL(x)	(((x) & DWC3_GCTL_CLK_MASK) << 6)
 #define DWC3_GCTL_CLK_BUS	(0)
 #define DWC3_GCTL_CLK_PIPE	(1)
@@ -643,6 +646,9 @@
 	__le64	dma_adr[DWC3_MAX_HIBER_SCRATCHBUFS];
 };
 
+#define DWC3_CONTROLLER_ERROR_EVENT			0
+#define DWC3_CONTROLLER_RESET_EVENT			1
+#define DWC3_CONTROLLER_POST_RESET_EVENT		2
 /**
  * struct dwc3 - representation of our controller
  * @ctrl_req: usb control request which is used for ep0
@@ -687,6 +693,7 @@
  * @mem: points to start of memory which is used for this struct.
  * @hwparams: copy of hwparams registers
  * @root: debugfs root folder pointer
+ * @tx_fifo_size: Available RAM size for TX fifo allocation
  */
 struct dwc3 {
 	struct usb_ctrlrequest	*ctrl_req;
@@ -771,6 +778,8 @@
 
 	/* Indicate if software connect was issued by the usb_gadget_driver */
 	bool			softconnect;
+	void (*notify_event) (struct dwc3 *, unsigned);
+	int			tx_fifo_size;
 };
 
 /* -------------------------------------------------------------------------- */
@@ -922,6 +931,9 @@
 void dwc3_post_host_reset_core_init(struct dwc3 *dwc);
 int dwc3_event_buffers_setup(struct dwc3 *dwc);
 
+extern void dwc3_set_notifier(
+		void (*notify) (struct dwc3 *dwc3, unsigned event));
+extern void dwc3_notify_event(struct dwc3 *dwc3, unsigned event);
 extern int dwc3_get_device_id(void);
 extern void dwc3_put_device_id(int id);
 
diff --git a/drivers/usb/dwc3/debug.h b/drivers/usb/dwc3/debug.h
index b156c5f..4901f4b 100644
--- a/drivers/usb/dwc3/debug.h
+++ b/drivers/usb/dwc3/debug.h
@@ -46,6 +46,7 @@
 extern void dbg_setup(u8, const struct usb_ctrlrequest*);
 extern int dwc3_debugfs_init(struct dwc3 *);
 extern void dwc3_debugfs_exit(struct dwc3 *);
+extern void dbg_print_reg(const char *name, int reg);
 #else
 static inline void dbg_event(u8, const char*, int)
 {  }
@@ -57,6 +58,8 @@
 {  }
 static inline void dbg_setup(u8, const struct usb_ctrlrequest*)
 {  }
+static inline void dbg_print_reg(const char *name, int reg)
+{  }
 static inline int dwc3_debugfs_init(struct dwc3 *d)
 {  return 0;  }
 static inline void dwc3_debugfs_exit(struct dwc3 *d)
diff --git a/drivers/usb/dwc3/debugfs.c b/drivers/usb/dwc3/debugfs.c
index df95646..a2580fc 100644
--- a/drivers/usb/dwc3/debugfs.c
+++ b/drivers/usb/dwc3/debugfs.c
@@ -972,6 +972,28 @@
 }
 
 /**
+ * dbg_print_reg: prints a reg value
+ * @name:   reg name
+ * @reg: reg value to be printed
+ */
+void dbg_print_reg(const char *name, int reg)
+{
+	unsigned long flags;
+
+	write_lock_irqsave(&dbg_dwc3_data.lck, flags);
+
+	scnprintf(dbg_dwc3_data.buf[dbg_dwc3_data.idx], DBG_DATA_MSG,
+		  "%s = 0x%08x\n", name, reg);
+
+	dbg_inc(&dbg_dwc3_data.idx);
+
+	write_unlock_irqrestore(&dbg_dwc3_data.lck, flags);
+
+	if (dbg_dwc3_data.tty != 0)
+		pr_notice("%s = 0x%08x\n", name, reg);
+}
+
+/**
  * store_events: configure if events are going to be also printed to console
  *
  */
diff --git a/drivers/usb/dwc3/dwc3-msm.c b/drivers/usb/dwc3/dwc3-msm.c
index e1a7d58..60d7119 100644
--- a/drivers/usb/dwc3/dwc3-msm.c
+++ b/drivers/usb/dwc3/dwc3-msm.c
@@ -50,6 +50,7 @@
 #include "dwc3_otg.h"
 #include "core.h"
 #include "gadget.h"
+#include "debug.h"
 
 /* ADC threshold values */
 static int adc_low_threshold = 700;
@@ -140,6 +141,7 @@
 #define QSCRATCH_REG_OFFSET	(0x000F8800)
 #define QSCRATCH_CTRL_REG      (QSCRATCH_REG_OFFSET + 0x04)
 #define QSCRATCH_GENERAL_CFG	(QSCRATCH_REG_OFFSET + 0x08)
+#define QSCRATCH_RAM1_REG	(QSCRATCH_REG_OFFSET + 0x0C)
 #define HS_PHY_CTRL_REG		(QSCRATCH_REG_OFFSET + 0x10)
 #define PARAMETER_OVERRIDE_X_REG (QSCRATCH_REG_OFFSET + 0x14)
 #define CHARGING_DET_CTRL_REG	(QSCRATCH_REG_OFFSET + 0x18)
@@ -156,6 +158,8 @@
 #define SS_CR_PROTOCOL_CAP_DATA_REG (QSCRATCH_REG_OFFSET + 0x48)
 #define SS_CR_PROTOCOL_READ_REG     (QSCRATCH_REG_OFFSET + 0x4C)
 #define SS_CR_PROTOCOL_WRITE_REG    (QSCRATCH_REG_OFFSET + 0x50)
+#define PWR_EVNT_IRQ_STAT_REG    (QSCRATCH_REG_OFFSET + 0x58)
+#define PWR_EVNT_IRQ_MASK_REG    (QSCRATCH_REG_OFFSET + 0x5C)
 
 struct dwc3_msm_req_complete {
 	struct list_head list_item;
@@ -197,6 +201,7 @@
 	bool			lpm_irq_seen;
 	struct delayed_work	resume_work;
 	struct work_struct	restart_usb_work;
+	struct work_struct	usb_block_reset_work;
 	struct dwc3_charger	charger;
 	struct usb_phy		*otg_xceiv;
 	struct delayed_work	chg_work;
@@ -204,6 +209,7 @@
 	int			pmic_id_irq;
 	struct work_struct	id_work;
 	struct qpnp_adc_tm_btm_param	adc_param;
+	struct qpnp_adc_tm_chip *adc_tm_dev;
 	struct delayed_work	init_adc_work;
 	bool			id_adc_detect;
 	u8			dcd_retries;
@@ -218,11 +224,13 @@
 	unsigned int		vdd_no_vol_level;
 	unsigned int		vdd_low_vol_level;
 	unsigned int		vdd_high_vol_level;
+	unsigned int		tx_fifo_size;
+	unsigned int		qdss_tx_fifo_size;
 	bool			vbus_active;
 	bool			ext_inuse;
 	enum dwc3_id_state	id_state;
 	unsigned long		lpm_flags;
-#define MDWC3_CORECLK_OFF		BIT(0)
+#define MDWC3_PHY_REF_AND_CORECLK_OFF	BIT(0)
 #define MDWC3_TCXO_SHUTDOWN		BIT(1)
 
 	u32 qscratch_ctl_val;
@@ -409,6 +417,37 @@
 }
 
 /**
+ * Dump all QSCRATCH registers.
+ *
+ */
+static void dwc3_msm_dump_phy_info(struct dwc3_msm *mdwc)
+{
+
+	dbg_print_reg("SSPHY_CTRL_REG", dwc3_msm_read_reg(mdwc->base,
+						SS_PHY_CTRL_REG));
+	dbg_print_reg("HSPHY_CTRL_REG", dwc3_msm_read_reg(mdwc->base,
+						HS_PHY_CTRL_REG));
+	dbg_print_reg("QSCRATCH_CTRL_REG", dwc3_msm_read_reg(mdwc->base,
+						QSCRATCH_CTRL_REG));
+	dbg_print_reg("QSCRATCH_GENERAL_CFG", dwc3_msm_read_reg(mdwc->base,
+						QSCRATCH_GENERAL_CFG));
+	dbg_print_reg("PARAMETER_OVERRIDE_X_REG", dwc3_msm_read_reg(mdwc->base,
+						PARAMETER_OVERRIDE_X_REG));
+	dbg_print_reg("HS_PHY_IRQ_STAT_REG", dwc3_msm_read_reg(mdwc->base,
+						HS_PHY_IRQ_STAT_REG));
+	dbg_print_reg("SS_PHY_PARAM_CTRL_1", dwc3_msm_read_reg(mdwc->base,
+						SS_PHY_PARAM_CTRL_1));
+	dbg_print_reg("SS_PHY_PARAM_CTRL_2", dwc3_msm_read_reg(mdwc->base,
+						SS_PHY_PARAM_CTRL_2));
+	dbg_print_reg("QSCRATCH_RAM1_REG", dwc3_msm_read_reg(mdwc->base,
+						QSCRATCH_RAM1_REG));
+	dbg_print_reg("PWR_EVNT_IRQ_STAT_REG", dwc3_msm_read_reg(mdwc->base,
+						PWR_EVNT_IRQ_STAT_REG));
+	dbg_print_reg("PWR_EVNT_IRQ_MASK_REG", dwc3_msm_read_reg(mdwc->base,
+						PWR_EVNT_IRQ_MASK_REG));
+}
+
+/**
  * Return DBM EP number according to usb endpoint number.
  *
  */
@@ -992,6 +1031,19 @@
 }
 EXPORT_SYMBOL(msm_ep_unconfig);
 
+void dwc3_tx_fifo_resize_request(struct usb_ep *ep, bool qdss_enabled)
+{
+	struct dwc3_ep *dep = to_dwc3_ep(ep);
+	struct dwc3 *dwc = dep->dwc;
+	struct dwc3_msm *mdwc = dev_get_drvdata(dwc->dev->parent);
+
+	if (qdss_enabled)
+		dwc->tx_fifo_size = mdwc->qdss_tx_fifo_size;
+	else
+		dwc->tx_fifo_size = mdwc->tx_fifo_size;
+}
+EXPORT_SYMBOL(dwc3_tx_fifo_resize_request);
+
 static void dwc3_restart_usb_work(struct work_struct *w)
 {
 	struct dwc3_msm *mdwc = container_of(w, struct dwc3_msm,
@@ -1380,8 +1432,14 @@
 }
 
 /* Initialize QSCRATCH registers for HSPHY and SSPHY operation */
-static void dwc3_msm_qscratch_reg_init(struct dwc3_msm *mdwc)
+static void dwc3_msm_qscratch_reg_init(struct dwc3_msm *mdwc,
+						unsigned event_status)
 {
+	if (event_status == DWC3_CONTROLLER_POST_RESET_EVENT) {
+		dwc3_msm_ss_phy_reg_init(mdwc);
+		return;
+	}
+
 	/* SSPHY Initialization: Use ref_clk from pads and set its parameters */
 	dwc3_msm_write_reg(mdwc->base, SS_PHY_CTRL_REG, 0x10210002);
 	msleep(30);
@@ -1392,7 +1450,7 @@
 	dwc3_msm_write_reg(mdwc->base, SS_PHY_CTRL_REG, 0x10210002);
 	usleep_range(2000, 2200);
 	/* Ref clock must be stable now, enable ref clock for HS mode */
-	dwc3_msm_write_reg(mdwc->base, SS_PHY_CTRL_REG, 0x10210102);
+	dwc3_msm_write_reg(mdwc->base, SS_PHY_CTRL_REG, 0x11210102);
 	usleep_range(2000, 2200);
 	/*
 	 * HSPHY Initialization: Enable UTMI clock and clamp enable HVINTs,
@@ -1400,8 +1458,8 @@
 	 */
 	dwc3_msm_write_reg(mdwc->base, HS_PHY_CTRL_REG, 0x5220bb2);
 	usleep_range(2000, 2200);
-	/* Disable (bypass) VBUS and ID filters */
-	dwc3_msm_write_reg(mdwc->base, QSCRATCH_GENERAL_CFG, 0x78);
+	/* Set XHCI_REV bit (2) to 1 - XHCI version 1.0 */
+	dwc3_msm_write_reg(mdwc->base, QSCRATCH_GENERAL_CFG, 0x4);
 	/*
 	 * write HSPHY init value to QSCRATCH reg to set HSPHY parameters like
 	 * VBUS valid threshold, disconnect valid threshold, DC voltage level,
@@ -1414,14 +1472,14 @@
 					PARAMETER_OVERRIDE_X_REG, 0x03FFFFFF,
 					mdwc->hsphy_init_seq & 0x03FFFFFF);
 
-	/* Enable master clock for RAMs to allow BAM to access RAMs when
-	 * RAM clock gating is enabled via DWC3's GCTL. Otherwise, issues
+	/*
+	 * Enable master clock for RAMs to allow BAM to access RAMs when
+	 * RAM clock gating is enabled via DWC3's GCTL. Otherwise issues
 	 * are seen where RAM clocks get turned OFF in SS mode
 	 */
 	dwc3_msm_write_reg(mdwc->base, CGCTL_REG,
 		dwc3_msm_read_reg(mdwc->base, CGCTL_REG) | 0x18);
 
-	dwc3_msm_ss_phy_reg_init(mdwc);
 	/*
 	 * This is required to restore the POR value after userspace
 	 * is done with charger detection.
@@ -1430,6 +1488,37 @@
 		dwc3_msm_read_reg(mdwc->base, QSCRATCH_CTRL_REG);
 }
 
+static void dwc3_msm_notify_event(struct dwc3 *dwc, unsigned event)
+{
+	struct dwc3_msm *mdwc = dev_get_drvdata(dwc->dev->parent);
+
+	switch (event) {
+	case DWC3_CONTROLLER_ERROR_EVENT:
+		dev_info(mdwc->dev, "DWC3_CONTROLLER_ERROR_EVENT received\n");
+		dwc3_msm_dump_phy_info(mdwc);
+		/*
+		 * schedule work for doing block reset for recovery from erratic
+		 * error event.
+		 */
+		queue_work(system_nrt_wq, &mdwc->usb_block_reset_work);
+		break;
+	case DWC3_CONTROLLER_RESET_EVENT:
+		dev_dbg(mdwc->dev, "DWC3_CONTROLLER_RESET_EVENT received\n");
+		dwc3_msm_qscratch_reg_init(mdwc, DWC3_CONTROLLER_RESET_EVENT);
+		break;
+	case DWC3_CONTROLLER_POST_RESET_EVENT:
+		dev_dbg(mdwc->dev,
+				"DWC3_CONTROLLER_POST_RESET_EVENT received\n");
+		dwc3_msm_qscratch_reg_init(mdwc,
+					DWC3_CONTROLLER_POST_RESET_EVENT);
+		dwc->tx_fifo_size = mdwc->tx_fifo_size;
+		break;
+	default:
+		dev_dbg(mdwc->dev, "unknown dwc3 event\n");
+		break;
+	}
+}
+
 static void dwc3_msm_block_reset(struct dwc3_ext_xceiv *xceiv, bool core_reset)
 {
 	struct dwc3_msm *mdwc = container_of(xceiv, struct dwc3_msm, ext_xceiv);
@@ -1446,9 +1535,6 @@
 			return;
 
 		usleep_range(10000, 12000);
-
-		/* Reinitialize QSCRATCH registers after block reset */
-		dwc3_msm_qscratch_reg_init(mdwc);
 	}
 
 	/* Reset the DBM */
@@ -1457,6 +1543,16 @@
 	dwc3_msm_dbm_soft_reset(mdwc, 0);
 }
 
+static void dwc3_block_reset_usb_work(struct work_struct *w)
+{
+	struct dwc3_msm *mdwc = container_of(w, struct dwc3_msm,
+						usb_block_reset_work);
+
+	dev_dbg(mdwc->dev, "%s\n", __func__);
+
+	dwc3_msm_block_reset(&mdwc->ext_xceiv, true);
+}
+
 static void dwc3_chg_enable_secondary_det(struct dwc3_msm *mdwc)
 {
 	u32 chg_ctrl;
@@ -1686,6 +1782,7 @@
 	bool dcp;
 	bool host_bus_suspend;
 	bool host_ss_active;
+	bool host_ss_suspend;
 
 	dev_dbg(mdwc->dev, "%s: entering lpm\n", __func__);
 
@@ -1712,6 +1809,7 @@
 	      (mdwc->charger.chg_type == DWC3_PROPRIETARY_CHARGER) ||
 	      (mdwc->charger.chg_type == DWC3_FLOATED_CHARGER));
 	host_bus_suspend = mdwc->host_mode == 1;
+	host_ss_suspend = host_bus_suspend && host_ss_active;
 
 	if (!dcp && !host_bus_suspend)
 		dwc3_msm_write_reg(mdwc->base, QSCRATCH_CTRL_REG,
@@ -1723,13 +1821,17 @@
 	 * 3. Set TEST_POWERED_DOWN in SS_PHY_CTRL_REG to enable PHY retention
 	 * 4. Disable SSPHY ref clk
 	 */
-	dwc3_msm_write_readback(mdwc->base, SS_PHY_CTRL_REG, (1 << 8), 0x0);
-	dwc3_msm_write_readback(mdwc->base, SS_PHY_CTRL_REG, (1 << 28), 0x0);
-	dwc3_msm_write_readback(mdwc->base, SS_PHY_CTRL_REG, (1 << 26),
+	if (!host_ss_suspend) {
+		dwc3_msm_write_readback(mdwc->base, SS_PHY_CTRL_REG, (1 << 8),
+									0x0);
+		dwc3_msm_write_readback(mdwc->base, SS_PHY_CTRL_REG, (1 << 28),
+									0x0);
+		dwc3_msm_write_readback(mdwc->base, SS_PHY_CTRL_REG, (1 << 26),
 								(1 << 26));
-
+	}
 	usleep_range(1000, 1200);
-	clk_disable_unprepare(mdwc->ref_clk);
+	if (!host_ss_suspend)
+		clk_disable_unprepare(mdwc->ref_clk);
 
 	if (host_bus_suspend) {
 		/* Sequence for host bus suspend case:
@@ -1774,9 +1876,9 @@
 	if (!host_bus_suspend)
 		dwc3_msm_config_gdsc(mdwc, 0);
 
-	if (!host_bus_suspend || !host_ss_active) {
+	if (!host_ss_suspend) {
 		clk_disable_unprepare(mdwc->core_clk);
-		mdwc->lpm_flags |= MDWC3_CORECLK_OFF;
+		mdwc->lpm_flags |= MDWC3_PHY_REF_AND_CORECLK_OFF;
 	}
 	clk_disable_unprepare(mdwc->iface_clk);
 
@@ -1824,6 +1926,7 @@
 	int ret;
 	bool dcp;
 	bool host_bus_suspend;
+	bool resume_from_core_clk_off = false;
 
 	dev_dbg(mdwc->dev, "%s: exiting lpm\n", __func__);
 
@@ -1834,6 +1937,9 @@
 
 	pm_stay_awake(mdwc->dev);
 
+	if (mdwc->lpm_flags & MDWC3_PHY_REF_AND_CORECLK_OFF)
+		resume_from_core_clk_off = true;
+
 	if (mdwc->bus_perf_client) {
 		ret = msm_bus_scale_client_update_request(
 						mdwc->bus_perf_client, 1);
@@ -1872,13 +1978,14 @@
 	if (!host_bus_suspend && !dcp)
 		dwc3_hsusb_config_vddcx(mdwc, 1);
 
-	clk_prepare_enable(mdwc->ref_clk);
+	if (mdwc->lpm_flags & MDWC3_PHY_REF_AND_CORECLK_OFF)
+		clk_prepare_enable(mdwc->ref_clk);
 	usleep_range(1000, 1200);
 
 	clk_prepare_enable(mdwc->iface_clk);
-	if (mdwc->lpm_flags & MDWC3_CORECLK_OFF) {
+	if (mdwc->lpm_flags & MDWC3_PHY_REF_AND_CORECLK_OFF) {
 		clk_prepare_enable(mdwc->core_clk);
-		mdwc->lpm_flags &= ~MDWC3_CORECLK_OFF;
+		mdwc->lpm_flags &= ~MDWC3_PHY_REF_AND_CORECLK_OFF;
 	}
 
 	if (host_bus_suspend) {
@@ -1891,10 +1998,6 @@
 
 		/* Disable DP and DM HV interrupt */
 		dwc3_msm_write_reg(mdwc->base, ALT_INTERRUPT_EN_REG, 0x000);
-
-		/* Clear suspend bit in GUSB2PHYCONFIG register */
-		dwc3_msm_write_readback(mdwc->base, DWC3_GUSB2PHYCFG(0),
-								0x40, 0x0);
 	} else {
 		/* Disable HV interrupt */
 		if (mdwc->otg_xceiv && (!mdwc->ext_xceiv.otg_capability))
@@ -1918,23 +2021,27 @@
 
 	}
 
-	/* Assert SS PHY RESET */
-	dwc3_msm_write_readback(mdwc->base, SS_PHY_CTRL_REG, (1 << 7),
+	if (resume_from_core_clk_off) {
+		/* Assert SS PHY RESET */
+		dwc3_msm_write_readback(mdwc->base, SS_PHY_CTRL_REG, (1 << 7),
 								(1 << 7));
-	dwc3_msm_write_readback(mdwc->base, SS_PHY_CTRL_REG, (1 << 28),
+		dwc3_msm_write_readback(mdwc->base, SS_PHY_CTRL_REG, (1 << 28),
 								(1 << 28));
-	dwc3_msm_write_readback(mdwc->base, SS_PHY_CTRL_REG, (1 << 8),
+		dwc3_msm_write_readback(mdwc->base, SS_PHY_CTRL_REG, (1 << 8),
 								(1 << 8));
-	dwc3_msm_write_readback(mdwc->base, SS_PHY_CTRL_REG, (1 << 26), 0x0);
-	/* 10usec delay required before de-asserting SS PHY RESET */
-	udelay(10);
-	dwc3_msm_write_readback(mdwc->base, SS_PHY_CTRL_REG, (1 << 7), 0x0);
+		dwc3_msm_write_readback(mdwc->base, SS_PHY_CTRL_REG, (1 << 26),
+									0x0);
+		/* 10usec delay required before de-asserting SS PHY RESET */
+		udelay(10);
+		dwc3_msm_write_readback(mdwc->base, SS_PHY_CTRL_REG, (1 << 7),
+									0x0);
 
-	/*
-	 * Reinitilize SSPHY parameters as SS_PHY RESET will reset
-	 * the internal registers to default values.
-	 */
-	dwc3_msm_ss_phy_reg_init(mdwc);
+		/*
+		 * Reinitilize SSPHY parameters as SS_PHY RESET will reset
+		 * the internal registers to default values.
+		 */
+		dwc3_msm_ss_phy_reg_init(mdwc);
+	}
 	atomic_set(&mdwc->in_lpm, 0);
 
 	/* match disable_irq call from isr */
@@ -2071,7 +2178,7 @@
 
 static struct dentry *dwc3_debugfs_root;
 
-static void dwc3_debugfs_init(struct dwc3_msm *mdwc)
+static void dwc3_msm_debugfs_init(struct dwc3_msm *mdwc)
 {
 	dwc3_debugfs_root = debugfs_create_dir("msm_dwc3", NULL);
 
@@ -2356,7 +2463,7 @@
 	dwc3_id_work(&mdwc->id_work);
 
 	/* re-arm ADC interrupt */
-	qpnp_adc_tm_usbid_configure(&mdwc->adc_param);
+	qpnp_adc_tm_usbid_configure(mdwc->adc_tm_dev, &mdwc->adc_param);
 }
 
 static void dwc3_init_adc_work(struct work_struct *w)
@@ -2365,10 +2472,14 @@
 							init_adc_work.work);
 	int ret;
 
-	ret = qpnp_adc_tm_is_ready();
-	if (ret == -EPROBE_DEFER) {
-		queue_delayed_work(system_nrt_wq, to_delayed_work(w),
+	mdwc->adc_tm_dev = qpnp_get_adc_tm(mdwc->dev, "dwc_usb3-adc_tm");
+	if (IS_ERR(mdwc->adc_tm_dev)) {
+		if (PTR_ERR(mdwc->adc_tm_dev) == -EPROBE_DEFER)
+			queue_delayed_work(system_nrt_wq, to_delayed_work(w),
 					msecs_to_jiffies(100));
+		else
+			mdwc->adc_tm_dev = NULL;
+
 		return;
 	}
 
@@ -2379,7 +2490,7 @@
 	mdwc->adc_param.btm_ctx = mdwc;
 	mdwc->adc_param.threshold_notification = dwc3_adc_notification;
 
-	ret = qpnp_adc_tm_usbid_configure(&mdwc->adc_param);
+	ret = qpnp_adc_tm_usbid_configure(mdwc->adc_tm_dev, &mdwc->adc_param);
 	if (ret) {
 		dev_err(mdwc->dev, "%s: request ADC error %d\n", __func__, ret);
 		return;
@@ -2414,7 +2525,7 @@
 			dwc3_init_adc_work(&mdwc->init_adc_work.work);
 		return size;
 	} else if (!strnicmp(buf, "disable", 7)) {
-		qpnp_adc_tm_usbid_end();
+		qpnp_adc_tm_usbid_end(mdwc->adc_tm_dev);
 		mdwc->id_adc_detect = false;
 		return size;
 	}
@@ -2597,6 +2708,7 @@
 	INIT_DELAYED_WORK(&mdwc->chg_work, dwc3_chg_detect_work);
 	INIT_DELAYED_WORK(&mdwc->resume_work, dwc3_resume_work);
 	INIT_WORK(&mdwc->restart_usb_work, dwc3_restart_usb_work);
+	INIT_WORK(&mdwc->usb_block_reset_work, dwc3_block_reset_usb_work);
 	INIT_WORK(&mdwc->id_work, dwc3_id_work);
 	INIT_DELAYED_WORK(&mdwc->init_adc_work, dwc3_init_adc_work);
 	init_completion(&mdwc->ext_chg_wait);
@@ -2866,8 +2978,6 @@
 	else if (!mdwc->hsphy_init_seq)
 		dev_warn(&pdev->dev, "incorrect hsphyinitseq.Using PORvalue\n");
 
-	dwc3_msm_qscratch_reg_init(mdwc);
-
 	pm_runtime_set_active(mdwc->dev);
 	pm_runtime_enable(mdwc->dev);
 
@@ -2887,6 +2997,17 @@
 		goto disable_hs_ldo;
 	}
 
+	if (of_property_read_u32(node, "qcom,dwc-usb3-msm-tx-fifo-size",
+				 &mdwc->tx_fifo_size))
+		dev_err(&pdev->dev,
+			"unable to read platform data tx fifo size\n");
+
+	if (of_property_read_u32(node, "qcom,dwc-usb3-msm-qdss-tx-fifo-size",
+				 &mdwc->qdss_tx_fifo_size))
+		dev_err(&pdev->dev,
+			"unable to read platform data qdss tx fifo size\n");
+
+	dwc3_set_notifier(&dwc3_msm_notify_event);
 	/* usb_psy required only for vbus_notifications or charging support */
 	if (mdwc->ext_xceiv.otg_capability ||
 			!mdwc->charger.charging_disabled) {
@@ -2985,7 +3106,7 @@
 
 	device_init_wakeup(mdwc->dev, 1);
 	pm_stay_awake(mdwc->dev);
-	dwc3_debugfs_init(mdwc);
+	dwc3_msm_debugfs_init(mdwc);
 
 	return 0;
 
@@ -3044,7 +3165,7 @@
 	}
 
 	if (mdwc->id_adc_detect)
-		qpnp_adc_tm_usbid_end();
+		qpnp_adc_tm_usbid_end(mdwc->adc_tm_dev);
 	if (dwc3_debugfs_root)
 		debugfs_remove_recursive(dwc3_debugfs_root);
 	if (mdwc->otg_xceiv) {
diff --git a/drivers/usb/dwc3/dwc3_otg.c b/drivers/usb/dwc3/dwc3_otg.c
index d0d9d34..5348eb5 100644
--- a/drivers/usb/dwc3/dwc3_otg.c
+++ b/drivers/usb/dwc3/dwc3_otg.c
@@ -24,6 +24,7 @@
 #include "io.h"
 #include "xhci.h"
 
+#define VBUS_REG_CHECK_DELAY	(jiffies + msecs_to_jiffies(1000))
 #define MAX_INVALID_CHRGR_RETRY 3
 static int max_chgr_retry_count = MAX_INVALID_CHRGR_RETRY;
 module_param(max_chgr_retry_count, int, S_IRUGO | S_IWUSR);
@@ -56,6 +57,19 @@
 		reg = dwc3_readl(dwc->regs, DWC3_GCTL);
 		reg &= ~(DWC3_GCTL_PRTCAPDIR(DWC3_GCTL_PRTCAP_OTG));
 		reg |= DWC3_GCTL_PRTCAPDIR(DWC3_GCTL_PRTCAP_HOST);
+		/*
+		 * Allow ITP generated off of ref clk based counter instead
+		 * of UTMI/ULPI clk based counter, when superspeed only is
+		 * active so that UTMI/ULPI can be suspened.
+		 */
+		reg |= DWC3_GCTL_SOFITPSYNC;
+		/*
+		 * Set this bit so that device attempts three more times at SS,
+		 * even if it failed previously to operate in SS mode.
+		 */
+		reg |= DWC3_GCTL_U2RSTECN;
+		reg &= ~(DWC3_GCTL_PWRDNSCALEMASK);
+		reg |= DWC3_GCTL_PWRDNSCALE(2);
 		dwc3_writel(dwc->regs, DWC3_GCTL, reg);
 	}
 }
@@ -126,6 +140,14 @@
 		reg = dwc3_readl(dwc->regs, DWC3_GCTL);
 		reg &= ~(DWC3_GCTL_PRTCAPDIR(DWC3_GCTL_PRTCAP_OTG));
 		reg |= DWC3_GCTL_PRTCAPDIR(DWC3_GCTL_PRTCAP_DEVICE);
+		/*
+		 * Set this bit so that device attempts three more times at SS,
+		 * even if it failed previously to operate in SS mode.
+	 */
+		reg |= DWC3_GCTL_U2RSTECN;
+		reg &= ~(DWC3_GCTL_PWRDNSCALEMASK);
+		reg |= DWC3_GCTL_PWRDNSCALE(2);
+		reg &= ~(DWC3_GCTL_SOFITPSYNC);
 		dwc3_writel(dwc->regs, DWC3_GCTL, reg);
 	}
 }
@@ -315,13 +337,13 @@
 		dev_dbg(otg->phy->dev, "%s: set gadget %s\n",
 					__func__, gadget->name);
 		otg->gadget = gadget;
-		schedule_work(&dotg->sm_work);
+		queue_delayed_work(system_nrt_wq, &dotg->sm_work, 0);
 	} else {
 		if (otg->phy->state == OTG_STATE_B_PERIPHERAL) {
 			dwc3_otg_start_peripheral(otg, 0);
 			otg->gadget = NULL;
 			otg->phy->state = OTG_STATE_UNDEFINED;
-			schedule_work(&dotg->sm_work);
+			queue_delayed_work(system_nrt_wq, &dotg->sm_work, 0);
 		} else {
 			otg->gadget = NULL;
 		}
@@ -346,7 +368,7 @@
 	 * STOP chg_det as part of !BSV handling would reset the chg_det flags
 	 */
 	if (test_bit(B_SESS_VLD, &dotg->inputs))
-		schedule_work(&dotg->sm_work);
+		queue_delayed_work(system_nrt_wq, &dotg->sm_work, 0);
 }
 
 /**
@@ -385,7 +407,7 @@
 
 	/* Flush processing any pending events before handling new ones */
 	if (init)
-		flush_work(&dotg->sm_work);
+		flush_delayed_work(&dotg->sm_work);
 
 	if (event == DWC3_EVENT_PHY_RESUME) {
 		if (!pm_runtime_status_suspended(phy->dev)) {
@@ -432,15 +454,16 @@
 
 		if (!init) {
 			init = true;
-			if (!work_busy(&dotg->sm_work))
-				schedule_work(&dotg->sm_work);
+			if (!work_busy(&dotg->sm_work.work))
+				queue_delayed_work(system_nrt_wq,
+							&dotg->sm_work, 0);
 
 			complete(&dotg->dwc3_xcvr_vbus_init);
 			dev_dbg(phy->dev, "XCVR: BSV init complete\n");
 			return;
 		}
 
-		schedule_work(&dotg->sm_work);
+		queue_delayed_work(system_nrt_wq, &dotg->sm_work, 0);
 	}
 }
 
@@ -589,7 +612,7 @@
 			handled_irqs |= DWC3_OEVTEN_OTGBDEVVBUSCHNGEVNT;
 		}
 
-		schedule_work(&dotg->sm_work);
+		queue_delayed_work(system_nrt_wq, &dotg->sm_work, 0);
 
 		ret = IRQ_HANDLED;
 
@@ -650,10 +673,12 @@
  */
 static void dwc3_otg_sm_work(struct work_struct *w)
 {
-	struct dwc3_otg *dotg = container_of(w, struct dwc3_otg, sm_work);
+	struct dwc3_otg *dotg = container_of(w, struct dwc3_otg, sm_work.work);
 	struct usb_phy *phy = dotg->otg.phy;
 	struct dwc3_charger *charger = dotg->charger;
 	bool work = 0;
+	int ret = 0;
+	int delay = 0;
 
 	pm_runtime_resume(phy->dev);
 	dev_dbg(phy->dev, "%s state\n", otg_state_string(phy->state));
@@ -796,10 +821,23 @@
 		if (test_bit(ID, &dotg->inputs)) {
 			dev_dbg(phy->dev, "id\n");
 			phy->state = OTG_STATE_B_IDLE;
+			dotg->vbus_retry_count = 0;
 			work = 1;
 		} else {
 			phy->state = OTG_STATE_A_HOST;
-			if (dwc3_otg_start_host(&dotg->otg, 1)) {
+			ret = dwc3_otg_start_host(&dotg->otg, 1);
+			if ((ret == -EPROBE_DEFER) &&
+						dotg->vbus_retry_count < 3) {
+				/*
+				 * Get regulator failed as regulator driver is
+				 * not up yet. Will try to start host after 1sec
+				 */
+				phy->state = OTG_STATE_A_IDLE;
+				dev_dbg(phy->dev, "Unable to get vbus regulator. Retrying...\n");
+				delay = VBUS_REG_CHECK_DELAY;
+				work = 1;
+				dotg->vbus_retry_count++;
+			} else if (ret) {
 				/*
 				 * Probably set_host was not called yet.
 				 * We will re-try as soon as it will be called
@@ -818,6 +856,7 @@
 			dev_dbg(phy->dev, "id\n");
 			dwc3_otg_start_host(&dotg->otg, 0);
 			phy->state = OTG_STATE_B_IDLE;
+			dotg->vbus_retry_count = 0;
 			work = 1;
 		}
 		break;
@@ -828,7 +867,7 @@
 	}
 
 	if (work)
-		schedule_work(&dotg->sm_work);
+		queue_delayed_work(system_nrt_wq, &dotg->sm_work, delay);
 }
 
 
@@ -847,7 +886,8 @@
 	 * OCFG[1] - HNPCap = 0
 	 * OCFG[0] - SRPCap = 0
 	 */
-	dwc3_writel(dotg->regs, DWC3_OCFG, 0x4);
+	if (ext_xceiv && !ext_xceiv->otg_capability)
+		dwc3_writel(dotg->regs, DWC3_OCFG, 0x4);
 
 	/*
 	 * OCTL[6] - PeriMode = 1
@@ -859,7 +899,8 @@
 	 * OCTL[0] - HstSetHNPEn = 0
 	 */
 	if (!once) {
-		dwc3_writel(dotg->regs, DWC3_OCTL, 0x40);
+		if (ext_xceiv && !ext_xceiv->otg_capability)
+			dwc3_writel(dotg->regs, DWC3_OCTL, 0x40);
 		once++;
 	}
 
@@ -950,7 +991,7 @@
 	dotg->otg.phy->state = OTG_STATE_UNDEFINED;
 
 	init_completion(&dotg->dwc3_xcvr_vbus_init);
-	INIT_WORK(&dotg->sm_work, dwc3_otg_sm_work);
+	INIT_DELAYED_WORK(&dotg->sm_work, dwc3_otg_sm_work);
 
 	ret = request_irq(dotg->irq, dwc3_otg_interrupt, IRQF_SHARED,
 				"dwc3_otg", dotg);
@@ -965,7 +1006,7 @@
 	return 0;
 
 err3:
-	cancel_work_sync(&dotg->sm_work);
+	cancel_delayed_work_sync(&dotg->sm_work);
 	usb_set_transceiver(NULL);
 err2:
 	kfree(dotg->otg.phy);
@@ -990,7 +1031,7 @@
 	if (dotg) {
 		if (dotg->charger)
 			dotg->charger->start_detection(dotg->charger, false);
-		cancel_work_sync(&dotg->sm_work);
+		cancel_delayed_work_sync(&dotg->sm_work);
 		usb_set_transceiver(NULL);
 		pm_runtime_put(dwc->dev);
 		free_irq(dotg->irq, dotg);
diff --git a/drivers/usb/dwc3/dwc3_otg.h b/drivers/usb/dwc3/dwc3_otg.h
index 7adf874..3a75b0a 100644
--- a/drivers/usb/dwc3/dwc3_otg.h
+++ b/drivers/usb/dwc3/dwc3_otg.h
@@ -41,7 +41,7 @@
 	struct dwc3		*dwc;
 	void __iomem		*regs;
 	struct regulator	*vbus_otg;
-	struct work_struct	sm_work;
+	struct delayed_work	sm_work;
 	struct dwc3_charger	*charger;
 	struct dwc3_ext_xceiv	*ext_xceiv;
 #define ID		0
@@ -51,6 +51,7 @@
 	struct completion	dwc3_xcvr_vbus_init;
 	int			host_bus_suspend;
 	int			charger_retry_count;
+	int			vbus_retry_count;
 };
 
 /**
diff --git a/drivers/usb/dwc3/gadget.c b/drivers/usb/dwc3/gadget.c
index acda980..8fa4774 100644
--- a/drivers/usb/dwc3/gadget.c
+++ b/drivers/usb/dwc3/gadget.c
@@ -36,7 +36,6 @@
  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  */
 
-#include <linux/module.h>
 #include <linux/kernel.h>
 #include <linux/delay.h>
 #include <linux/slab.h>
@@ -58,10 +57,8 @@
 #include "debug.h"
 #include "io.h"
 
-static bool tx_fifo_resize_enable;
-module_param(tx_fifo_resize_enable, bool, S_IRUGO|S_IWUSR);
-MODULE_PARM_DESC(tx_fifo_resize_enable,
-			"Enable allocating Tx fifo for endpoints");
+static void dwc3_gadget_usb2_phy_suspend(struct dwc3 *dwc, int suspend);
+static void dwc3_gadget_usb3_phy_suspend(struct dwc3 *dwc, int suspend);
 
 /**
  * dwc3_gadget_set_test_mode - Enables USB2 Test Modes
@@ -185,7 +182,7 @@
 	int		mdwidth;
 	int		num;
 
-	if (!dwc->needs_fifo_resize && !tx_fifo_resize_enable)
+	if (!dwc->needs_fifo_resize)
 		return 0;
 
 	ram1_depth = DWC3_RAM1_DEPTH(dwc->hwparams.hwparams7);
@@ -230,6 +227,17 @@
 		 * packets
 		 */
 		tmp = mult * (dep->endpoint.maxpacket + mdwidth);
+
+		if (dwc->tx_fifo_size &&
+				(usb_endpoint_xfer_bulk(dep->endpoint.desc)
+				|| usb_endpoint_xfer_isoc(dep->endpoint.desc)))
+			/*
+			 * Allocate 3KB fifo size for bulk and isochronous TX
+			 * endpoints irrespective of speed. For interrupt
+			 * endpoint, allocate fifo size of endpoint maxpacket.
+			 */
+			tmp = 3 * (1024 + mdwidth);
+
 		tmp += mdwidth;
 
 		fifo_size = DIV_ROUND_UP(tmp, mdwidth);
@@ -239,10 +247,21 @@
 		dev_vdbg(dwc->dev, "%s: Fifo Addr %04x Size %d\n",
 				dep->name, last_fifo_depth, fifo_size & 0xffff);
 
+		last_fifo_depth += (fifo_size & 0xffff);
+		if (dwc->tx_fifo_size &&
+				(last_fifo_depth >= dwc->tx_fifo_size)) {
+			/*
+			 * Fifo size allocated exceeded available RAM size.
+			 * Hence return error.
+			 */
+			dev_err(dwc->dev, "Fifosize(%d) > available RAM(%d)\n",
+					last_fifo_depth, dwc->tx_fifo_size);
+			return -ENOMEM;
+		}
+
 		dwc3_writel(dwc->regs, DWC3_GTXFIFOSIZ(fifo_number),
 				fifo_size);
 
-		last_fifo_depth += (fifo_size & 0xffff);
 	}
 
 	return 0;
@@ -322,6 +341,16 @@
 {
 	u32		timeout = 500;
 	u32		reg;
+	bool hsphy_suspend_enabled;
+	int ret;
+
+	/* Commands to controller will work only if PHY is not suspended */
+	hsphy_suspend_enabled = (dwc3_readl(dwc->regs, DWC3_GUSB2PHYCFG(0)) &
+						DWC3_GUSB2PHYCFG_SUSPHY);
+
+	/* Disable suspend of the USB2 PHY */
+	if (hsphy_suspend_enabled)
+		dwc3_gadget_usb2_phy_suspend(dwc, false);
 
 	dwc3_writel(dwc->regs, DWC3_DGCMDPAR, param);
 	dwc3_writel(dwc->regs, DWC3_DGCMD, cmd | DWC3_DGCMD_CMDACT);
@@ -331,7 +360,8 @@
 		if (!(reg & DWC3_DGCMD_CMDACT)) {
 			dev_vdbg(dwc->dev, "Command Complete --> %d\n",
 					DWC3_DGCMD_STATUS(reg));
-			return 0;
+			ret = 0;
+			break;
 		}
 
 		/*
@@ -339,10 +369,18 @@
 		 * interrupt context.
 		 */
 		timeout--;
-		if (!timeout)
-			return -ETIMEDOUT;
+		if (!timeout) {
+			ret = -ETIMEDOUT;
+			break;
+		}
 		udelay(1);
 	} while (1);
+
+	/* Enable suspend of the USB2 PHY */
+	if (hsphy_suspend_enabled)
+		dwc3_gadget_usb2_phy_suspend(dwc, true);
+
+	return ret;
 }
 
 int dwc3_send_gadget_ep_cmd(struct dwc3 *dwc, unsigned ep,
@@ -351,12 +389,22 @@
 	struct dwc3_ep		*dep = dwc->eps[ep];
 	u32			timeout = 500;
 	u32			reg;
+	bool hsphy_suspend_enabled;
+	int ret;
 
 	dev_vdbg(dwc->dev, "%s: cmd '%s' params %08x %08x %08x\n",
 			dep->name,
 			dwc3_gadget_ep_cmd_string(cmd), params->param0,
 			params->param1, params->param2);
 
+	/* Commands to controller will work only if PHY is not suspended */
+	hsphy_suspend_enabled = (dwc3_readl(dwc->regs, DWC3_GUSB2PHYCFG(0)) &
+						DWC3_GUSB2PHYCFG_SUSPHY);
+
+	/* Disable suspend of the USB2 PHY */
+	if (hsphy_suspend_enabled)
+		dwc3_gadget_usb2_phy_suspend(dwc, false);
+
 	dwc3_writel(dwc->regs, DWC3_DEPCMDPAR0(ep), params->param0);
 	dwc3_writel(dwc->regs, DWC3_DEPCMDPAR1(ep), params->param1);
 	dwc3_writel(dwc->regs, DWC3_DEPCMDPAR2(ep), params->param2);
@@ -374,9 +422,10 @@
 			 * event. Hence return error in this case.
 			 */
 			if (reg & 0x2000)
-				return -EAGAIN;
+				ret = -EAGAIN;
 			else
-				return 0;
+				ret = 0;
+			break;
 		}
 
 		/*
@@ -384,11 +433,19 @@
 		 * interrupt context.
 		 */
 		timeout--;
-		if (!timeout)
-			return -ETIMEDOUT;
+		if (!timeout) {
+			ret = -ETIMEDOUT;
+			break;
+		}
 
 		udelay(1);
 	} while (1);
+
+	/* Enable suspend of the USB2 PHY */
+	if (hsphy_suspend_enabled)
+		dwc3_gadget_usb2_phy_suspend(dwc, true);
+
+	return ret;
 }
 
 dma_addr_t dwc3_trb_dma_offset(struct dwc3_ep *dep,
@@ -1677,6 +1734,9 @@
 		reg |= DWC3_DCTL_HIRD_THRES(28);
 
 		dwc3_writel(dwc->regs, DWC3_DCTL, reg);
+
+		dwc3_gadget_usb2_phy_suspend(dwc, true);
+		dwc3_gadget_usb3_phy_suspend(dwc, true);
 	}
 
 	reg = dwc3_readl(dwc->regs, DWC3_DCFG);
@@ -2572,6 +2632,32 @@
 	dev_vdbg(dwc->dev, "%s link %d\n", __func__, dwc->link_state);
 }
 
+static void dwc3_dump_reg_info(struct dwc3 *dwc)
+{
+	dbg_event(0xFF, "REGDUMP", 0);
+
+	dbg_print_reg("GUSB3PIPCTL", dwc3_readl(dwc->regs,
+							DWC3_GUSB3PIPECTL(0)));
+	dbg_print_reg("GUSB2PHYCONFIG", dwc3_readl(dwc->regs,
+							DWC3_GUSB2PHYCFG(0)));
+	dbg_print_reg("GCTL", dwc3_readl(dwc->regs, DWC3_GCTL));
+	dbg_print_reg("GUCTL", dwc3_readl(dwc->regs, DWC3_GUCTL));
+	dbg_print_reg("GDBGLTSSM", dwc3_readl(dwc->regs, DWC3_GDBGLTSSM));
+	dbg_print_reg("DCFG", dwc3_readl(dwc->regs, DWC3_DCFG));
+	dbg_print_reg("DCTL", dwc3_readl(dwc->regs, DWC3_DCTL));
+	dbg_print_reg("DEVTEN", dwc3_readl(dwc->regs, DWC3_DEVTEN));
+	dbg_print_reg("DSTS", dwc3_readl(dwc->regs, DWC3_DSTS));
+	dbg_print_reg("DALPENA", dwc3_readl(dwc->regs, DWC3_DALEPENA));
+	dbg_print_reg("DGCMD", dwc3_readl(dwc->regs, DWC3_DGCMD));
+
+	dbg_print_reg("OCFG", dwc3_readl(dwc->regs, DWC3_OCFG));
+	dbg_print_reg("OCTL", dwc3_readl(dwc->regs, DWC3_OCTL));
+	dbg_print_reg("OEVT", dwc3_readl(dwc->regs, DWC3_OEVT));
+	dbg_print_reg("OSTS", dwc3_readl(dwc->regs, DWC3_OSTS));
+
+	dwc3_notify_event(dwc, DWC3_CONTROLLER_ERROR_EVENT);
+}
+
 static void dwc3_gadget_interrupt(struct dwc3 *dwc,
 		const struct dwc3_event_devt *event)
 {
@@ -2600,6 +2686,7 @@
 	case DWC3_DEVICE_EVENT_ERRATIC_ERROR:
 		dbg_event(0xFF, "ERROR", 0);
 		dev_vdbg(dwc->dev, "Erratic Error\n");
+		dwc3_dump_reg_info(dwc);
 		break;
 	case DWC3_DEVICE_EVENT_CMD_CMPL:
 		dev_vdbg(dwc->dev, "Command Complete\n");
@@ -2824,8 +2911,8 @@
 
 		dwc3_writel(dwc->regs, DWC3_DCTL, reg);
 
-		dwc3_gadget_usb2_phy_suspend(dwc, false);
-		dwc3_gadget_usb3_phy_suspend(dwc, false);
+		dwc3_gadget_usb2_phy_suspend(dwc, true);
+		dwc3_gadget_usb3_phy_suspend(dwc, true);
 	}
 
 	ret = device_register(&dwc->gadget.dev);
diff --git a/drivers/usb/gadget/android.c b/drivers/usb/gadget/android.c
index 38b1967..bbb206d 100644
--- a/drivers/usb/gadget/android.c
+++ b/drivers/usb/gadget/android.c
@@ -388,22 +388,30 @@
 	}
 }
 
-static void android_enable(struct android_dev *dev)
+static int android_enable(struct android_dev *dev)
 {
 	struct usb_composite_dev *cdev = dev->cdev;
 	struct android_configuration *conf;
+	int err = 0;
 
 	if (WARN_ON(!dev->disable_depth))
-		return;
+		return err;
 
 	if (--dev->disable_depth == 0) {
 
-		list_for_each_entry(conf, &dev->configs, list_item)
-			usb_add_config(cdev, &conf->usb_config,
+		list_for_each_entry(conf, &dev->configs, list_item) {
+			err = usb_add_config(cdev, &conf->usb_config,
 						android_bind_config);
-
+			if (err < 0) {
+				pr_err("%s: usb_add_config failed : err: %d\n",
+						__func__, err);
+				return err;
+			}
+		}
 		usb_gadget_connect(cdev->gadget);
 	}
+
+	return err;
 }
 
 static void android_disable(struct android_dev *dev)
@@ -1768,11 +1776,18 @@
 	config->fsg.nluns = 1;
 	name[0] = "lun";
 	if (dev->pdata && dev->pdata->cdrom) {
-		config->fsg.nluns = 2;
-		config->fsg.luns[1].cdrom = 1;
-		config->fsg.luns[1].ro = 1;
-		config->fsg.luns[1].removable = 0;
-		name[1] = "lun0";
+		config->fsg.luns[config->fsg.nluns].cdrom = 1;
+		config->fsg.luns[config->fsg.nluns].ro = 1;
+		config->fsg.luns[config->fsg.nluns].removable = 0;
+		name[config->fsg.nluns] = "lun0";
+		config->fsg.nluns++;
+	}
+	if (dev->pdata && dev->pdata->internal_ums) {
+		config->fsg.luns[config->fsg.nluns].cdrom = 0;
+		config->fsg.luns[config->fsg.nluns].ro = 0;
+		config->fsg.luns[config->fsg.nluns].removable = 1;
+		name[config->fsg.nluns] = "lun1";
+		config->fsg.nluns++;
 	}
 
 	config->fsg.luns[0].removable = 1;
@@ -2130,7 +2145,18 @@
 	list_for_each_entry(f_holder, &conf->enabled_functions, enabled_list) {
 		ret = f_holder->f->bind_config(f_holder->f, c);
 		if (ret) {
-			pr_err("%s: %s failed", __func__, f_holder->f->name);
+			pr_err("%s: %s failed\n", __func__, f_holder->f->name);
+			while (!list_empty(&c->functions)) {
+				struct usb_function		*f;
+
+				f = list_first_entry(&c->functions,
+					struct usb_function, list);
+				list_del(&f->list);
+				if (f->unbind)
+					f->unbind(c, f);
+			}
+			if (c->unbind)
+				c->unbind(c);
 			return ret;
 		}
 	}
@@ -2347,7 +2373,7 @@
 	int enabled = 0;
 	bool audio_enabled = false;
 	static DEFINE_RATELIMIT_STATE(rl, 10*HZ, 1);
-
+	int err = 0;
 
 	if (!cdev)
 		return -ENODEV;
@@ -2382,7 +2408,14 @@
 			}
 		if (audio_enabled)
 			msleep(100);
-		android_enable(dev);
+		err = android_enable(dev);
+		if (err < 0) {
+			pr_err("%s: android_enable failed\n", __func__);
+			dev->connected = 0;
+			dev->enabled = false;
+			mutex_unlock(&dev->mutex);
+			return size;
+		}
 		dev->enabled = true;
 	} else if (!enabled && dev->enabled) {
 		android_disable(dev);
@@ -2873,6 +2906,8 @@
 				&pdata->swfi_latency);
 		pdata->cdrom = of_property_read_bool(pdev->dev.of_node,
 				"qcom,android-usb-cdrom");
+		pdata->internal_ums = of_property_read_bool(pdev->dev.of_node,
+				"qcom,android-usb-internal-ums");
 	} else {
 		pdata = pdev->dev.platform_data;
 	}
diff --git a/drivers/usb/gadget/composite.c b/drivers/usb/gadget/composite.c
index 27d67e3..e4fb26a 100644
--- a/drivers/usb/gadget/composite.c
+++ b/drivers/usb/gadget/composite.c
@@ -824,6 +824,11 @@
 
 	spin_lock_irqsave(&cdev->lock, flags);
 
+	if (WARN_ON(!config->cdev)) {
+		spin_unlock_irqrestore(&cdev->lock, flags);
+		return 0;
+	}
+
 	if (cdev->config == config)
 		reset_config(cdev);
 
@@ -1220,6 +1225,15 @@
 			break;
 		if (w_value && !f->set_alt)
 			break;
+		/*
+		 * We put interfaces in default settings (alt 0)
+		 * upon set config#1. Call set_alt for non-zero
+		 * alternate setting.
+		 */
+		if (!w_value && cdev->config) {
+			value = 0;
+			break;
+		}
 		value = f->set_alt(f, w_index, w_value);
 		if (value == USB_GADGET_DELAYED_STATUS) {
 			DBG(cdev,
diff --git a/drivers/usb/gadget/f_diag.c b/drivers/usb/gadget/f_diag.c
index d1b911a..bccc504 100644
--- a/drivers/usb/gadget/f_diag.c
+++ b/drivers/usb/gadget/f_diag.c
@@ -626,6 +626,7 @@
 		struct usb_function *f)
 {
 	struct diag_context *ctxt = func_to_diag(f);
+	unsigned long flags;
 
 	if (gadget_is_superspeed(c->cdev->gadget))
 		usb_free_descriptors(f->ss_descriptors);
@@ -643,7 +644,9 @@
 		ctxt->ch->priv_usb = NULL;
 	list_del(&ctxt->list_item);
 	/* Free any pending USB requests from last session */
+	spin_lock_irqsave(&ctxt->lock, flags);
 	free_reqs(ctxt);
+	spin_unlock_irqrestore(&ctxt->lock, flags);
 	kfree(ctxt);
 }
 
diff --git a/drivers/usb/gadget/f_mtp.c b/drivers/usb/gadget/f_mtp.c
index a4192ca..6d7dd3d 100644
--- a/drivers/usb/gadget/f_mtp.c
+++ b/drivers/usb/gadget/f_mtp.c
@@ -151,7 +151,7 @@
 	.bDescriptorType =	USB_DT_SS_ENDPOINT_COMP,
 
 	/* the following 2 values can be tweaked if necessary */
-	/* .bMaxBurst =		0, */
+	.bMaxBurst =		2,
 	/* .bmAttributes =	0, */
 };
 
@@ -168,7 +168,7 @@
 	.bDescriptorType =	USB_DT_SS_ENDPOINT_COMP,
 
 	/* the following 2 values can be tweaked if necessary */
-	/* .bMaxBurst =		0, */
+	 .bMaxBurst =		2,
 	/* .bmAttributes =	0, */
 };
 
diff --git a/drivers/usb/gadget/f_qdss.c b/drivers/usb/gadget/f_qdss.c
index f90967f..f649248 100644
--- a/drivers/usb/gadget/f_qdss.c
+++ b/drivers/usb/gadget/f_qdss.c
@@ -395,6 +395,7 @@
 			goto fail;
 		}
 	}
+	dwc3_tx_fifo_resize_request(qdss->data, true);
 
 	return 0;
 fail:
@@ -406,8 +407,11 @@
 
 static void qdss_unbind(struct usb_configuration *c, struct usb_function *f)
 {
+	struct f_qdss  *qdss = func_to_qdss(f);
+
 	pr_debug("qdss_unbind\n");
 
+	dwc3_tx_fifo_resize_request(qdss->data, false);
 	clear_eps(f);
 	clear_desc(c->cdev->gadget, f);
 }
@@ -441,6 +445,10 @@
 
 	pr_debug("usb_qdss_disconnect_work\n");
 
+	status = uninit_data(qdss->data);
+	if (status)
+		pr_err("%s: uninit_data error\n", __func__);
+
 	/* notify qdss to cancell all active transfers*/
 	if (qdss->ch.notify) {
 		qdss->ch.notify(qdss->ch.priv, USB_QDSS_DISCONNECT, NULL,
@@ -458,22 +466,22 @@
 {
 	struct f_qdss	*qdss = func_to_qdss(f);
 	unsigned long flags;
-	int status;
 
 	pr_debug("qdss_disable\n");
 
 	spin_lock_irqsave(&qdss->lock, flags);
+	if (!qdss->usb_connected) {
+		spin_unlock_irqrestore(&qdss->lock, flags);
+		return;
+	}
+
 	qdss->usb_connected = 0;
 	spin_unlock_irqrestore(&qdss->lock, flags);
 
 	/*cancell all active xfers*/
 	qdss_eps_disable(f);
 
-	status = uninit_data(qdss->data);
-	if (status)
-		pr_err("%s: uninit_data error\n", __func__);
-
-	schedule_work(&qdss->disconnect_w);
+	queue_work(qdss->wq, &qdss->disconnect_w);
 }
 
 static void usb_qdss_connect_work(struct work_struct *work)
@@ -521,6 +529,7 @@
 	if (gadget->speed != USB_SPEED_SUPER &&
 		gadget->speed != USB_SPEED_HIGH) {
 			pr_err("qdss_st_alt: qdss supportes HS or SS only\n");
+			ret = -EINVAL;
 			goto fail;
 	}
 
@@ -562,7 +571,7 @@
 		qdss->usb_connected = 1;
 
 	if (qdss->usb_connected && ch->app_conn)
-		schedule_work(&qdss->connect_w);
+		queue_work(qdss->wq, &qdss->connect_w);
 
 	return 0;
 fail:
@@ -610,7 +619,13 @@
 			spin_unlock_irqrestore(&d_lock, flags);
 			return -ENOMEM;
 		}
-
+		spin_unlock_irqrestore(&d_lock, flags);
+		qdss->wq = create_singlethread_workqueue(name);
+		if (!qdss->wq) {
+			kfree(qdss);
+			return -ENOMEM;
+		}
+		spin_lock_irqsave(&d_lock, flags);
 		ch = &qdss->ch;
 		ch->name = name;
 		list_add_tail(&ch->list, &usb_qdss_ch_list);
@@ -765,6 +780,13 @@
 			spin_unlock_irqrestore(&d_lock, flags);
 			return ERR_PTR(-ENOMEM);
 		}
+		spin_unlock_irqrestore(&d_lock, flags);
+		qdss->wq = create_singlethread_workqueue(name);
+		if (!qdss->wq) {
+			kfree(qdss);
+			return ERR_PTR(-ENOMEM);
+		}
+		spin_lock_irqsave(&d_lock, flags);
 		ch = &qdss->ch;
 		list_add_tail(&ch->list, &usb_qdss_ch_list);
 	} else {
@@ -781,7 +803,7 @@
 
 	/* the case USB cabel was connected befor qdss called  qdss_open*/
 	if (qdss->usb_connected == 1)
-		schedule_work(&qdss->connect_w);
+		queue_work(qdss->wq, &qdss->connect_w);
 
 	return ch;
 }
@@ -819,7 +841,7 @@
 		_ch = list_entry(act, struct usb_qdss_ch, list);
 		qdss = container_of(_ch, struct f_qdss, ch);
 		spin_lock_irqsave(&d_lock, flags);
-
+		destroy_workqueue(qdss->wq);
 		if (!_ch->priv) {
 			list_del(&_ch->list);
 			kfree(qdss);
diff --git a/drivers/usb/gadget/f_qdss.h b/drivers/usb/gadget/f_qdss.h
index 93b5b1f..dcc80b7 100644
--- a/drivers/usb/gadget/f_qdss.h
+++ b/drivers/usb/gadget/f_qdss.h
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2012, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2012-2013, The Linux Foundation. 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 and
@@ -38,6 +38,7 @@
 	unsigned int data_enabled:1;
 	unsigned int ctrl_in_enabled:1;
 	unsigned int ctrl_out_enabled:1;
+	struct workqueue_struct *wq;
 };
 
 #endif
diff --git a/drivers/usb/gadget/u_ether.c b/drivers/usb/gadget/u_ether.c
index 325c2b5..9e789c5 100644
--- a/drivers/usb/gadget/u_ether.c
+++ b/drivers/usb/gadget/u_ether.c
@@ -553,6 +553,7 @@
 				}
 
 				new_req->length = length;
+				new_req->complete = tx_complete;
 				retval = usb_ep_queue(in, new_req, GFP_ATOMIC);
 				switch (retval) {
 				default:
diff --git a/drivers/usb/host/ehci-msm-hsic.c b/drivers/usb/host/ehci-msm-hsic.c
index cfc5961..5d58f16 100644
--- a/drivers/usb/host/ehci-msm-hsic.c
+++ b/drivers/usb/host/ehci-msm-hsic.c
@@ -342,7 +342,7 @@
 
 #define HSIC_DBG1_REG		0x38
 
-static const int vdd_val[VDD_TYPE_MAX][VDD_VAL_MAX] = {
+static int vdd_val[VDD_TYPE_MAX][VDD_VAL_MAX] = {
 		{   /* VDD_CX CORNER Voting */
 			[VDD_NONE]	= RPM_VREG_CORNER_NONE,
 			[VDD_MIN]	= RPM_VREG_CORNER_NOMINAL,
@@ -359,6 +359,8 @@
 {
 	int ret = 0;
 	int none_vol, min_vol, max_vol;
+	u32 tmp[3];
+	int len = 0;
 
 	if (!mehci->hsic_vddcx) {
 		mehci->vdd_type = VDDCX_CORNER;
@@ -373,6 +375,22 @@
 			}
 			mehci->vdd_type = VDDCX;
 		}
+
+		if (mehci->dev->of_node) {
+			of_get_property(mehci->dev->of_node,
+					"hsic,vdd-voltage-level",
+					&len);
+			if (len == sizeof(tmp)) {
+				of_property_read_u32_array(mehci->dev->of_node,
+						"hsic,vdd-voltage-level",
+						tmp, len/sizeof(*tmp));
+				vdd_val[mehci->vdd_type][VDD_NONE] = tmp[0];
+				vdd_val[mehci->vdd_type][VDD_MIN] = tmp[1];
+				vdd_val[mehci->vdd_type][VDD_MAX] = tmp[2];
+			} else {
+				dev_dbg(mehci->dev, "Use default vdd config\n");
+			}
+		}
 	}
 
 	none_vol = vdd_val[mehci->vdd_type][VDD_NONE];
@@ -1881,6 +1899,8 @@
 
 	pdata->phy_sof_workaround = of_property_read_bool(node,
 					"qcom,phy-sof-workaround");
+	pdata->phy_susp_sof_workaround = of_property_read_bool(node,
+					"qcom,phy-susp-sof-workaround");
 	pdata->ignore_cal_pad_config = of_property_read_bool(node,
 					"hsic,ignore-cal-pad-config");
 	of_property_read_u32(node, "hsic,strobe-pad-offset",
@@ -1987,9 +2007,13 @@
 	spin_lock_init(&mehci->wakeup_lock);
 
 	if (pdata->phy_sof_workaround) {
+		/* Enable ALL workarounds related to PHY SOF bugs */
 		mehci->ehci.susp_sof_bug = 1;
 		mehci->ehci.reset_sof_bug = 1;
 		mehci->ehci.resume_sof_bug = 1;
+	} else if (pdata->phy_susp_sof_workaround) {
+		/* Only SUSP SOF hardware bug exists, rest all not present */
+		mehci->ehci.susp_sof_bug = 1;
 	}
 
 	if (pdata->reset_delay)
diff --git a/drivers/usb/host/ehci-msm2.c b/drivers/usb/host/ehci-msm2.c
index 0aecaad..dd04f49 100644
--- a/drivers/usb/host/ehci-msm2.c
+++ b/drivers/usb/host/ehci-msm2.c
@@ -40,6 +40,7 @@
 #include <mach/msm_xo.h>
 #include <mach/msm_iomap.h>
 #include <linux/debugfs.h>
+#include <mach/rpm-regulator.h>
 
 #define MSM_USB_BASE (hcd->regs)
 
@@ -76,6 +77,7 @@
 	int					wakeup_int_cnt;
 	bool					wakeup_irq_enabled;
 	int					wakeup_irq;
+	enum usb_vdd_type			vdd_type;
 };
 
 static inline struct msm_hcd *hcd_to_mhcd(struct usb_hcd *hcd)
@@ -96,26 +98,87 @@
 #define HSUSB_PHY_1P8_VOL_MAX		1800000 /* uV */
 #define HSUSB_PHY_1P8_HPM_LOAD		50000	/* uA */
 
+#define HSUSB_PHY_VDD_DIG_VOL_NONE	0	/* uV */
 #define HSUSB_PHY_VDD_DIG_VOL_MIN	1045000	/* uV */
 #define HSUSB_PHY_VDD_DIG_VOL_MAX	1320000	/* uV */
 #define HSUSB_PHY_VDD_DIG_LOAD		49360	/* uA */
 
+#define HSUSB_PHY_SUSP_DIG_VOL_P50  500000
+#define HSUSB_PHY_SUSP_DIG_VOL_P75  750000
+enum hsusb_vdd_value {
+	VDD_MIN_NONE = 0,
+	VDD_MIN_P50,
+	VDD_MIN_P75,
+	VDD_MIN_OP,
+	VDD_MAX_OP,
+	VDD_VAL_MAX_OP,
+};
+
+static int hsusb_vdd_val[VDD_TYPE_MAX][VDD_VAL_MAX_OP] = {
+		{   /* VDD_CX CORNER Voting */
+			[VDD_MIN_NONE]	= RPM_VREG_CORNER_NONE,
+			[VDD_MIN_P50]	= RPM_VREG_CORNER_NONE,
+			[VDD_MIN_P75]	= RPM_VREG_CORNER_NONE,
+			[VDD_MIN_OP]	= RPM_VREG_CORNER_NOMINAL,
+			[VDD_MAX_OP]	= RPM_VREG_CORNER_HIGH,
+		},
+		{   /* VDD_CX Voltage Voting */
+			[VDD_MIN_NONE]	= HSUSB_PHY_VDD_DIG_VOL_NONE,
+			[VDD_MIN_P50]	= HSUSB_PHY_SUSP_DIG_VOL_P50,
+			[VDD_MIN_P75]	= HSUSB_PHY_SUSP_DIG_VOL_P75,
+			[VDD_MIN_OP]	= HSUSB_PHY_VDD_DIG_VOL_MIN,
+			[VDD_MAX_OP]	= HSUSB_PHY_VDD_DIG_VOL_MAX,
+		},
+};
+
 static int msm_ehci_init_vddcx(struct msm_hcd *mhcd, int init)
 {
 	int ret = 0;
+	int none_vol, min_vol, max_vol;
+	u32 tmp[5];
+	int len = 0;
 
-	if (!init)
+	if (!init) {
+		none_vol = hsusb_vdd_val[mhcd->vdd_type][VDD_MIN_NONE];
+		max_vol = hsusb_vdd_val[mhcd->vdd_type][VDD_MAX_OP];
 		goto disable_reg;
-
-	mhcd->hsusb_vddcx = devm_regulator_get(mhcd->dev, "HSUSB_VDDCX");
-	if (IS_ERR(mhcd->hsusb_vddcx)) {
-		dev_err(mhcd->dev, "unable to get ehci vddcx\n");
-		return PTR_ERR(mhcd->hsusb_vddcx);
 	}
 
-	ret = regulator_set_voltage(mhcd->hsusb_vddcx,
-			HSUSB_PHY_VDD_DIG_VOL_MIN,
-			HSUSB_PHY_VDD_DIG_VOL_MAX);
+	mhcd->vdd_type = VDDCX_CORNER;
+	mhcd->hsusb_vddcx = devm_regulator_get(mhcd->dev, "hsusb_vdd_dig");
+	if (IS_ERR(mhcd->hsusb_vddcx)) {
+		mhcd->hsusb_vddcx = devm_regulator_get(mhcd->dev,
+							"HSUSB_VDDCX");
+		if (IS_ERR(mhcd->hsusb_vddcx)) {
+			dev_err(mhcd->dev, "unable to get ehci vddcx\n");
+			return PTR_ERR(mhcd->hsusb_vddcx);
+		}
+		mhcd->vdd_type = VDDCX;
+	}
+
+	if (mhcd->dev->of_node) {
+		of_get_property(mhcd->dev->of_node,
+				"qcom,vdd-voltage-level",
+				&len);
+		if (len == sizeof(tmp)) {
+			of_property_read_u32_array(mhcd->dev->of_node,
+					"qcom,vdd-voltage-level",
+					tmp, len/sizeof(*tmp));
+			hsusb_vdd_val[mhcd->vdd_type][VDD_MIN_NONE] = tmp[0];
+			hsusb_vdd_val[mhcd->vdd_type][VDD_MIN_P50] = tmp[1];
+			hsusb_vdd_val[mhcd->vdd_type][VDD_MIN_P75] = tmp[2];
+			hsusb_vdd_val[mhcd->vdd_type][VDD_MIN_OP] = tmp[3];
+			hsusb_vdd_val[mhcd->vdd_type][VDD_MAX_OP] = tmp[4];
+		} else {
+			dev_dbg(mhcd->dev, "Use default vdd config\n");
+		}
+	}
+
+	none_vol = hsusb_vdd_val[mhcd->vdd_type][VDD_MIN_NONE];
+	min_vol = hsusb_vdd_val[mhcd->vdd_type][VDD_MIN_OP];
+	max_vol = hsusb_vdd_val[mhcd->vdd_type][VDD_MAX_OP];
+
+	ret = regulator_set_voltage(mhcd->hsusb_vddcx, min_vol, max_vol);
 	if (ret) {
 		dev_err(mhcd->dev, "unable to set the voltage"
 				"for ehci vddcx\n");
@@ -143,8 +206,7 @@
 reg_enable_err:
 	regulator_set_optimum_mode(mhcd->hsusb_vddcx, 0);
 reg_optimum_mode_err:
-	regulator_set_voltage(mhcd->hsusb_vddcx, 0,
-				HSUSB_PHY_VDD_DIG_VOL_MIN);
+	regulator_set_voltage(mhcd->hsusb_vddcx, none_vol, max_vol);
 	return ret;
 
 }
@@ -194,24 +256,22 @@
 }
 
 #ifdef CONFIG_PM_SLEEP
-#define HSUSB_PHY_SUSP_DIG_VOL_P50  500000
-#define HSUSB_PHY_SUSP_DIG_VOL_P75  750000
 static int msm_ehci_config_vddcx(struct msm_hcd *mhcd, int high)
 {
 	struct msm_usb_host_platform_data *pdata;
-	int max_vol = HSUSB_PHY_VDD_DIG_VOL_MAX;
+	int max_vol = hsusb_vdd_val[mhcd->vdd_type][VDD_MAX_OP];
 	int min_vol;
 	int ret;
 
 	pdata = mhcd->dev->platform_data;
 
 	if (high)
-		min_vol = HSUSB_PHY_VDD_DIG_VOL_MIN;
+		min_vol = hsusb_vdd_val[mhcd->vdd_type][VDD_MIN_OP];
 	else if (pdata && pdata->dock_connect_irq &&
 			!irq_read_line(pdata->dock_connect_irq))
-		min_vol = HSUSB_PHY_SUSP_DIG_VOL_P75;
+		min_vol = hsusb_vdd_val[mhcd->vdd_type][VDD_MIN_P75];
 	else
-		min_vol = HSUSB_PHY_SUSP_DIG_VOL_P50;
+		min_vol = hsusb_vdd_val[mhcd->vdd_type][VDD_MIN_P50];
 
 	ret = regulator_set_voltage(mhcd->hsusb_vddcx, min_vol, max_vol);
 	if (ret) {
diff --git a/drivers/usb/otg/msm_otg.c b/drivers/usb/otg/msm_otg.c
index 06e3a1b..f71f54c 100644
--- a/drivers/usb/otg/msm_otg.c
+++ b/drivers/usb/otg/msm_otg.c
@@ -363,6 +363,8 @@
 	if (cnt >= ULPI_IO_TIMEOUT_USEC) {
 		dev_err(phy->dev, "ulpi_read: timeout %08x\n",
 			readl(USB_ULPI_VIEWPORT));
+		dev_err(phy->dev, "PORTSC: %08x USBCMD: %08x\n",
+			readl_relaxed(USB_PORTSC), readl_relaxed(USB_USBCMD));
 		return -ETIMEDOUT;
 	}
 	return ULPI_DATA_READ(readl(USB_ULPI_VIEWPORT));
@@ -388,6 +390,8 @@
 
 	if (cnt >= ULPI_IO_TIMEOUT_USEC) {
 		dev_err(phy->dev, "ulpi_write: timeout\n");
+		dev_err(phy->dev, "PORTSC: %08x USBCMD: %08x\n",
+			readl_relaxed(USB_PORTSC), readl_relaxed(USB_USBCMD));
 		return -ETIMEDOUT;
 	}
 	return 0;
@@ -460,45 +464,19 @@
 	return ret;
 }
 
-static int msm_otg_phy_clk_reset(struct msm_otg *motg)
-{
-	int ret;
-
-	if (IS_ERR(motg->phy_reset_clk))
-		return 0;
-
-	ret = clk_reset(motg->phy_reset_clk, CLK_RESET_ASSERT);
-	if (ret) {
-		dev_err(motg->phy.dev, "usb phy clk assert failed\n");
-		return ret;
-	}
-	usleep_range(10000, 12000);
-	ret = clk_reset(motg->phy_reset_clk, CLK_RESET_DEASSERT);
-	if (ret)
-		dev_err(motg->phy.dev, "usb phy clk deassert failed\n");
-	return ret;
-}
-
 static int msm_otg_phy_reset(struct msm_otg *motg)
 {
 	u32 val;
 	int ret;
-	int retries;
 	struct msm_otg_platform_data *pdata = motg->pdata;
 
 	ret = msm_otg_link_clk_reset(motg, 1);
 	if (ret)
 		return ret;
-	ret = msm_otg_phy_clk_reset(motg);
-	if (ret)
-		return ret;
 
-	/*
-	 * 10 usec delay is required according to spec. Using larger value
-	 * since the exact value proved to not work 100% of the time.
-	 */
-	if (IS_ERR(motg->phy_reset_clk))
-		usleep_range(100, 120);
+	/* wait for 1ms delay as suggested in HPG. */
+	usleep_range(1000, 1200);
+
 	ret = msm_otg_link_clk_reset(motg, 0);
 	if (ret)
 		return ret;
@@ -509,34 +487,6 @@
 	val = readl(USB_PORTSC) & ~PORTSC_PTS_MASK;
 	writel(val | PORTSC_PTS_ULPI, USB_PORTSC);
 
-	for (retries = 3; retries > 0; retries--) {
-		ret = ulpi_write(&motg->phy, ULPI_FUNC_CTRL_SUSPENDM,
-				ULPI_CLR(ULPI_FUNC_CTRL));
-		if (!ret)
-			break;
-		ret = msm_otg_phy_clk_reset(motg);
-		if (ret)
-			return ret;
-	}
-	if (!retries)
-		return -ETIMEDOUT;
-
-	/* This reset calibrates the phy, if the above write succeeded */
-	ret = msm_otg_phy_clk_reset(motg);
-	if (ret)
-		return ret;
-
-	for (retries = 3; retries > 0; retries--) {
-		ret = ulpi_read(&motg->phy, ULPI_DEBUG);
-		if (ret != -ETIMEDOUT)
-			break;
-		ret = msm_otg_phy_clk_reset(motg);
-		if (ret)
-			return ret;
-	}
-	if (!retries)
-		return -ETIMEDOUT;
-
 	dev_info(motg->phy.dev, "phy_reset: success\n");
 	return 0;
 }
@@ -568,6 +518,32 @@
 	return 0;
 }
 
+static void usb_phy_reset(struct msm_otg *motg)
+{
+	u32 val;
+
+	if (motg->pdata->phy_type != SNPS_28NM_INTEGRATED_PHY)
+		return;
+
+	/* Assert USB PHY_PON */
+	val =  readl_relaxed(USB_PHY_CTRL);
+	val &= ~PHY_POR_BIT_MASK;
+	val |= PHY_POR_ASSERT;
+	writel_relaxed(val, USB_PHY_CTRL);
+
+	/* wait for minimum 10 microseconds as suggested in HPG. */
+	usleep_range(10, 15);
+
+	/* Deassert USB PHY_PON */
+	val =  readl_relaxed(USB_PHY_CTRL);
+	val &= ~PHY_POR_BIT_MASK;
+	val |= PHY_POR_DEASSERT;
+	writel_relaxed(val, USB_PHY_CTRL);
+
+	/* Ensure that RESET operation is completed. */
+	mb();
+}
+
 static int msm_otg_reset(struct usb_phy *phy)
 {
 	struct msm_otg *motg = container_of(phy, struct msm_otg, phy);
@@ -602,12 +578,20 @@
 		dev_err(phy->dev, "link reset failed\n");
 		return ret;
 	}
+
 	msleep(100);
 
+	/* Reset USB PHY after performing USB Link RESET */
+	usb_phy_reset(motg);
+
+	/* Program USB PHY Override registers. */
 	ulpi_init(motg);
 
-	/* Ensure that RESET operation is completed before turning off clock */
-	mb();
+	/*
+	 * It is recommended in HPG to reset USB PHY after programming
+	 * USB PHY Override registers.
+	 */
+	usb_phy_reset(motg);
 
 	if (!IS_ERR(motg->clk))
 		clk_disable_unprepare(motg->clk);
@@ -2630,8 +2614,11 @@
 			motg->chg_state = USB_CHG_STATE_UNDEFINED;
 			motg->chg_type = USB_INVALID_CHARGER;
 			msm_otg_notify_charger(motg, 0);
-			if (dcp)
+			if (dcp) {
 				msm_otg_wait_for_ext_chg_done(motg);
+				/* Turn off VDP_SRC */
+				ulpi_write(otg->phy, 0x2, 0x86);
+			}
 			msm_otg_reset(otg->phy);
 			/*
 			 * There is a small window where ID interrupt
@@ -4241,11 +4228,6 @@
 	/* initialize reset counter */
 	motg->reset_counter = 0;
 
-	/* Some targets don't support PHY clock. */
-	motg->phy_reset_clk = clk_get(&pdev->dev, "phy_clk");
-	if (IS_ERR(motg->phy_reset_clk))
-		dev_err(&pdev->dev, "failed to get phy_clk\n");
-
 	/*
 	 * Targets on which link uses asynchronous reset methodology,
 	 * free running clock is not required during the reset.
@@ -4292,11 +4274,27 @@
 		goto put_core_clk;
 	}
 
+	/*
+	 * On few platforms USB PHY is fed with sleep clk.
+	 * Hence don't fail probe.
+	 */
+	motg->sleep_clk = devm_clk_get(&pdev->dev, "sleep_clk");
+	if (IS_ERR(motg->sleep_clk)) {
+		dev_dbg(&pdev->dev, "failed to get sleep_clk\n");
+	} else {
+		ret = clk_prepare_enable(motg->sleep_clk);
+		if (ret) {
+			dev_err(&pdev->dev, "%s failed to vote sleep_clk%d\n",
+							__func__, ret);
+			goto put_pclk;
+		}
+	}
+
 	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
 	if (!res) {
 		dev_err(&pdev->dev, "failed to get platform resource mem\n");
 		ret = -ENODEV;
-		goto put_pclk;
+		goto disable_sleep_clk;
 	}
 
 	motg->io_res = res;
@@ -4304,7 +4302,7 @@
 	if (!motg->regs) {
 		dev_err(&pdev->dev, "ioremap failed\n");
 		ret = -ENOMEM;
-		goto put_pclk;
+		goto disable_sleep_clk;
 	}
 	dev_info(&pdev->dev, "OTG regs = %p\n", motg->regs);
 
@@ -4603,6 +4601,9 @@
 		msm_xo_put(motg->xo_handle);
 free_regs:
 	iounmap(motg->regs);
+disable_sleep_clk:
+	if (!IS_ERR(motg->sleep_clk))
+		clk_disable_unprepare(motg->sleep_clk);
 put_pclk:
 	clk_put(motg->pclk);
 put_core_clk:
@@ -4610,8 +4611,6 @@
 put_clk:
 	if (!IS_ERR(motg->clk))
 		clk_put(motg->clk);
-	if (!IS_ERR(motg->phy_reset_clk))
-		clk_put(motg->phy_reset_clk);
 devote_bus_bw:
 	if (motg->bus_perf_client) {
 		msm_otg_bus_vote(motg, USB_NO_PERF_VOTE);
@@ -4697,6 +4696,10 @@
 	} else {
 		msm_xo_put(motg->xo_handle);
 	}
+
+	if (!IS_ERR(motg->sleep_clk))
+		clk_disable_unprepare(motg->sleep_clk);
+
 	msm_hsusb_ldo_enable(motg, USB_PHY_REG_OFF);
 	msm_hsusb_ldo_init(motg, 0);
 	regulator_disable(hsusb_vdd);
@@ -4707,8 +4710,6 @@
 	iounmap(motg->regs);
 	pm_runtime_set_suspended(&pdev->dev);
 
-	if (!IS_ERR(motg->phy_reset_clk))
-		clk_put(motg->phy_reset_clk);
 	clk_put(motg->pclk);
 	if (!IS_ERR(motg->clk))
 		clk_put(motg->clk);
diff --git a/drivers/usb/serial/usb_wwan.c b/drivers/usb/serial/usb_wwan.c
index 1c8664c..ebe8c6e 100644
--- a/drivers/usb/serial/usb_wwan.c
+++ b/drivers/usb/serial/usb_wwan.c
@@ -516,7 +516,6 @@
 	/* explicitly set the driver mode to raw */
 	tty->raw = 1;
 	tty->real_raw = 1;
-	tty->update_room_in_ldisc = 1;
 
 	set_bit(TTY_NO_WRITE_SPLIT, &tty->flags);
 	dbg("%s", __func__);
diff --git a/drivers/video/msm/mdss/Makefile b/drivers/video/msm/mdss/Makefile
index 017fa8e..ba14d67 100644
--- a/drivers/video/msm/mdss/Makefile
+++ b/drivers/video/msm/mdss/Makefile
@@ -16,7 +16,7 @@
 obj-$(CONFIG_DEBUG_FS) += mdss_debug.o
 endif
 
-dsi-v2-objs = dsi_v2.o dsi_host_v2.o dsi_io_v2.o dsi_panel_v2.o
+dsi-v2-objs = dsi_v2.o dsi_host_v2.o dsi_io_v2.o
 obj-$(CONFIG_FB_MSM_MDSS) += dsi-v2.o
 
 mdss-dsi-objs := mdss_dsi.o mdss_dsi_host.o
diff --git a/drivers/video/msm/mdss/dsi_host_v2.c b/drivers/video/msm/mdss/dsi_host_v2.c
index f2de17d..5264005 100644
--- a/drivers/video/msm/mdss/dsi_host_v2.c
+++ b/drivers/video/msm/mdss/dsi_host_v2.c
@@ -25,6 +25,7 @@
 #include "dsi_v2.h"
 #include "dsi_io_v2.h"
 #include "dsi_host_v2.h"
+#include "mdss_debug.h"
 
 #define DSI_POLL_SLEEP_US 1000
 #define DSI_POLL_TIMEOUT_US 16000
@@ -38,7 +39,10 @@
 
 	int irq_no;
 	unsigned char *dsi_base;
+	size_t dsi_reg_size;
 	struct device dis_dev;
+
+	void (*debug_enable_clk)(int on);
 };
 
 static struct dsi_host_v2_private *dsi_host_private;
@@ -320,7 +324,7 @@
 	wmb();
 }
 
-void msm_dsi_set_tx_power_mode(int mode)
+void dsi_set_tx_power_mode(int mode)
 {
 	u32 data;
 	unsigned char *ctrl_base = dsi_host_private->dsi_base;
@@ -478,6 +482,8 @@
 	if (rc == 0) {
 		pr_err("DSI command transaction time out\n");
 		rc = -ETIME;
+	} else if (!IS_ERR_VALUE(rc)) {
+		rc = 0;
 	}
 
 	dma_unmap_single(&dsi_host_private->dis_dev, tp->dmap, size,
@@ -520,7 +526,7 @@
 {
 	struct dsi_cmd_desc *cm;
 	u32 dsi_ctrl, ctrl;
-	int i, video_mode;
+	int i, video_mode, rc = 0;
 	unsigned char *ctrl_base = dsi_host_private->dsi_base;
 
 	/* turn on cmd mode
@@ -542,8 +548,13 @@
 		dsi_buf_init(tp);
 		dsi_cmd_dma_add(tp, cm);
 		msm_dsi_cmd_dma_tx(tp);
-		if (cm->wait)
-			msleep(cm->wait);
+		rc = msm_dsi_cmd_dma_tx(tp);
+		if (IS_ERR_VALUE(rc)) {
+			pr_err("%s: failed to call cmd_dma_tx\n", __func__);
+			break;
+		}
+		if (cm->dchdr.wait)
+			msleep(cm->dchdr.wait);
 		cm++;
 	}
 
@@ -551,15 +562,15 @@
 
 	if (video_mode)
 		MIPI_OUTP(ctrl_base + DSI_CTRL, dsi_ctrl);
-	return 0;
+	return rc;
 }
 
 /* MDSS_DSI_MRPS, Maximum Return Packet Size */
 static char max_pktsize[2] = {0x00, 0x00}; /* LSB tx first, 10 bytes */
 
 static struct dsi_cmd_desc pkt_size_cmd[] = {
-	{DTYPE_MAX_PKTSIZE, 1, 0, 0, 0,
-		sizeof(max_pktsize), max_pktsize}
+	{{DTYPE_MAX_PKTSIZE, 1, 0, 0, 0,
+		sizeof(max_pktsize)}, max_pktsize}
 };
 
 /*
@@ -578,7 +589,7 @@
 			struct dsi_buf *tp, struct dsi_buf *rp,
 			struct dsi_cmd_desc *cmds, int rlen)
 {
-	int cnt, len, diff, pkt_size;
+	int cnt, len, diff, pkt_size, rc = 0;
 	char cmd;
 
 	if (pdata->panel_info.mipi.no_max_pkt_size)
@@ -590,8 +601,8 @@
 	if (len <= 2) {
 		cnt = 4;	/* short read */
 	} else {
-		if (len > DSI_LEN)
-			len = DSI_LEN;	/* 8 bytes at most */
+		if (len > MDSS_DSI_LEN)
+			len = MDSS_DSI_LEN;	/* 8 bytes at most */
 
 		len = ALIGN(len, 4); /* len 4 bytes align */
 		diff = len - rlen;
@@ -614,7 +625,13 @@
 		max_pktsize[0] = pkt_size;
 		dsi_buf_init(tp);
 		dsi_cmd_dma_add(tp, pkt_size_cmd);
-		msm_dsi_cmd_dma_tx(tp);
+		rc = msm_dsi_cmd_dma_tx(tp);
+		if (IS_ERR_VALUE(rc)) {
+			msm_dsi_disable_irq();
+			pr_err("%s: dma_tx failed\n", __func__);
+			rp->len = 0;
+			goto end;
+		}
 		pr_debug("%s: Max packet size sent\n", __func__);
 	}
 
@@ -623,6 +640,12 @@
 
 	/* transmit read comamnd to client */
 	msm_dsi_cmd_dma_tx(tp);
+	if (IS_ERR_VALUE(rc)) {
+		msm_dsi_disable_irq();
+		pr_err("%s: dma_tx failed\n", __func__);
+		rp->len = 0;
+		goto end;
+	}
 	/*
 	 * once cmd_dma_done interrupt received,
 	 * return data from client is ready and stored
@@ -676,6 +699,7 @@
 		break;
 	}
 
+end:
 	return rp->len;
 }
 
@@ -739,12 +763,18 @@
 	u32 dummy_xres, dummy_yres;
 	u32 bitclk_rate = 0, byteclk_rate = 0, pclk_rate = 0, dsiclk_rate = 0;
 	unsigned char *ctrl_base = dsi_host_private->dsi_base;
+	struct mdss_dsi_ctrl_pdata *ctrl_pdata = NULL;
 
 	pr_debug("msm_dsi_on\n");
 
 	pinfo = &pdata->panel_info;
 
-	ret = msm_dsi_regulator_enable();
+	ctrl_pdata = container_of(pdata, struct mdss_dsi_ctrl_pdata,
+				panel_data);
+
+	ret = msm_dss_enable_vreg(
+		ctrl_pdata->power_data.vreg_config,
+		ctrl_pdata->power_data.num_vreg, 1);
 	if (ret) {
 		pr_err("%s: DSI power on failed\n", __func__);
 		return ret;
@@ -839,6 +869,16 @@
 static int msm_dsi_off(struct mdss_panel_data *pdata)
 {
 	int ret = 0;
+	struct mdss_dsi_ctrl_pdata *ctrl_pdata = NULL;
+
+	if (pdata == NULL) {
+		pr_err("%s: Invalid input data\n", __func__);
+		ret = -EINVAL;
+		return ret;
+	}
+
+	ctrl_pdata = container_of(pdata, struct mdss_dsi_ctrl_pdata,
+				panel_data);
 
 	pr_debug("msm_dsi_off\n");
 	msm_dsi_controller_cfg(0);
@@ -848,7 +888,9 @@
 	msm_dsi_phy_off(dsi_host_private->dsi_base);
 	msm_dsi_ahb_ctrl(0);
 
-	ret = msm_dsi_regulator_disable();
+	ret = msm_dss_enable_vreg(
+		ctrl_pdata->power_data.vreg_config,
+		ctrl_pdata->power_data.num_vreg, 0);
 	if (ret) {
 		pr_err("%s: Panel power off failed\n", __func__);
 		return ret;
@@ -861,11 +903,24 @@
 {
 	struct mdss_panel_info *pinfo;
 	int ret = 0;
+	struct mdss_dsi_ctrl_pdata *ctrl_pdata = NULL;
+
+	if (pdata == NULL) {
+		pr_err("%s: Invalid input data\n", __func__);
+		ret = -EINVAL;
+		return ret;
+	}
+
 
 	pr_debug("%s:\n", __func__);
 
+	ctrl_pdata = container_of(pdata, struct mdss_dsi_ctrl_pdata,
+				panel_data);
+
 	pinfo = &pdata->panel_info;
-	ret = msm_dsi_regulator_enable();
+	ret = msm_dss_enable_vreg(
+		ctrl_pdata->power_data.vreg_config,
+		ctrl_pdata->power_data.num_vreg, 1);
 	if (ret) {
 		pr_err("%s: DSI power on failed\n", __func__);
 		return ret;
@@ -877,10 +932,140 @@
 	return 0;
 }
 
+static void msm_dsi_debug_enable_clock(int on)
+{
+	if (dsi_host_private->debug_enable_clk)
+		dsi_host_private->debug_enable_clk(on);
+
+	if (on)
+		msm_dsi_ahb_ctrl(1);
+	else
+		msm_dsi_ahb_ctrl(0);
+}
+
+static int msm_dsi_debug_init(void)
+{
+	int rc;
+
+	if (!mdss_res)
+		return 0;
+
+	dsi_host_private->debug_enable_clk =
+			mdss_res->debug_inf.debug_enable_clock;
+
+	mdss_res->debug_inf.debug_enable_clock = msm_dsi_debug_enable_clock;
+
+
+	rc = mdss_debug_register_base("dsi0",
+				dsi_host_private->dsi_base,
+				dsi_host_private->dsi_reg_size);
+
+	return rc;
+}
+
+static int dsi_get_panel_cfg(char *panel_cfg)
+{
+	int rc;
+	struct mdss_panel_cfg *pan_cfg = NULL;
+
+	if (!panel_cfg)
+		return MDSS_PANEL_INTF_INVALID;
+
+	pan_cfg = mdp3_panel_intf_type(MDSS_PANEL_INTF_DSI);
+	if (IS_ERR(pan_cfg)) {
+		panel_cfg[0] = 0;
+		return PTR_ERR(pan_cfg);
+	} else if (!pan_cfg) {
+		panel_cfg[0] = 0;
+		return 0;
+	}
+
+	pr_debug("%s:%d: cfg:[%s]\n", __func__, __LINE__,
+		 pan_cfg->arg_cfg);
+	rc = strlcpy(panel_cfg, pan_cfg->arg_cfg,
+				MDSS_MAX_PANEL_LEN);
+	return rc;
+}
+
+/**
+ * dsi_find_panel_of_node(): find device node of dsi panel
+ * @pdev: platform_device of the dsi ctrl node
+ * @panel_cfg: string containing intf specific config data
+ *
+ * Function finds the panel device node using the interface
+ * specific configuration data. This configuration data is
+ * could be derived from the result of bootloader's GCDB
+ * panel detection mechanism. If such config data doesn't
+ * exist then this panel returns the default panel configured
+ * in the device tree.
+ *
+ * returns pointer to panel node on success, NULL on error.
+ */
+static struct device_node *dsi_find_panel_of_node(
+		struct platform_device *pdev, char *panel_cfg)
+{
+	int l;
+	char *panel_name;
+	struct device_node *dsi_pan_node = NULL, *mdss_node = NULL;
+
+	if (!panel_cfg)
+		return NULL;
+
+	l = strlen(panel_cfg);
+	if (!l) {
+		/* no panel cfg chg, parse dt */
+		pr_debug("%s:%d: no cmd line cfg present\n",
+			 __func__, __LINE__);
+		dsi_pan_node = of_parse_phandle(
+			pdev->dev.of_node,
+			"qcom,dsi-pref-prim-pan", 0);
+		if (!dsi_pan_node) {
+			pr_err("%s:can't find panel phandle\n",
+			       __func__);
+			return NULL;
+		}
+	} else {
+		if (panel_cfg[0] != '0') {
+			pr_err("%s:%d:ctrl id=[%d] not supported\n",
+			       __func__, __LINE__, panel_cfg[0]);
+			return NULL;
+		}
+		/*
+		 * skip first two chars '<dsi_ctrl_id>' and
+		 * ':' to get to the panel name
+		 */
+		panel_name = panel_cfg + 2;
+		pr_debug("%s:%d:%s:%s\n", __func__, __LINE__,
+			 panel_cfg, panel_name);
+
+		mdss_node = of_parse_phandle(pdev->dev.of_node,
+					     "qcom,mdss-mdp", 0);
+
+		if (!mdss_node) {
+			pr_err("%s: %d: mdss_node null\n",
+			       __func__, __LINE__);
+			return NULL;
+		}
+		dsi_pan_node = of_find_node_by_name(mdss_node,
+						    panel_name);
+		if (!dsi_pan_node) {
+			pr_err("%s: invalid pan node\n",
+			       __func__);
+			return NULL;
+		}
+	}
+	return dsi_pan_node;
+}
+
 static int __devinit msm_dsi_probe(struct platform_device *pdev)
 {
 	struct dsi_interface intf;
+	char panel_cfg[MDSS_MAX_PANEL_LEN];
+	struct mdss_dsi_ctrl_pdata *ctrl_pdata = NULL;
 	int rc = 0;
+	struct device_node *dsi_pan_node = NULL;
+	bool cmd_cfg_cont_splash = false;
+	struct resource *mdss_dsi_mres;
 
 	pr_debug("%s\n", __func__);
 
@@ -888,59 +1073,103 @@
 	if (rc)
 		return rc;
 
-	if (pdev->dev.of_node) {
-		struct resource *mdss_dsi_mres;
-		pdev->id = 0;
-		mdss_dsi_mres = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-		if (!mdss_dsi_mres) {
-			pr_err("%s:%d unable to get the MDSS reg resources",
-				__func__, __LINE__);
-			return -ENOMEM;
-		} else {
-			dsi_host_private->dsi_base = ioremap(
-						mdss_dsi_mres->start,
-						resource_size(mdss_dsi_mres));
-			if (!dsi_host_private->dsi_base) {
-				pr_err("%s:%d unable to remap dsi resources",
-					__func__, __LINE__);
-				return -ENOMEM;
-			}
-		}
-
-		mdss_dsi_mres = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
-		if (!mdss_dsi_mres || mdss_dsi_mres->start == 0) {
-			pr_err("%s:%d unable to get the MDSS irq resources",
-				__func__, __LINE__);
-			rc = -ENODEV;
-			goto dsi_probe_error;
-		} else {
-			rc = msm_dsi_irq_init(&pdev->dev, mdss_dsi_mres->start);
-			if (rc) {
-				dev_err(&pdev->dev,
-					"%s: failed to init irq, rc=%d\n",
-							__func__, rc);
-				goto dsi_probe_error;
-			}
-		}
-
-		rc = msm_dsi_io_init(pdev);
-		if (rc) {
-			dev_err(&pdev->dev,
-				"%s: failed to init DSI IO, rc=%d\n",
-							__func__, rc);
-			goto dsi_probe_error;
-		}
-
-		rc = of_platform_populate(pdev->dev.of_node,
-					NULL, NULL, &pdev->dev);
-		if (rc) {
-			dev_err(&pdev->dev,
-				"%s: failed to add child nodes, rc=%d\n",
-							__func__, rc);
-			goto dsi_probe_error;
-		}
-
+	if (!pdev->dev.of_node) {
+		pr_err("%s: Device node is not accessible\n", __func__);
+		rc = -ENODEV;
+		goto error_no_mem;
 	}
+	pdev->id = 0;
+
+	ctrl_pdata = platform_get_drvdata(pdev);
+	if (!ctrl_pdata) {
+		ctrl_pdata = devm_kzalloc(&pdev->dev,
+			sizeof(struct mdss_dsi_ctrl_pdata), GFP_KERNEL);
+		if (!ctrl_pdata) {
+			pr_err("%s: FAILED: cannot alloc dsi ctrl\n", __func__);
+			rc = -ENOMEM;
+			goto error_no_mem;
+		}
+		platform_set_drvdata(pdev, ctrl_pdata);
+	}
+
+	mdss_dsi_mres = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+	if (!mdss_dsi_mres) {
+		pr_err("%s:%d unable to get the MDSS reg resources",
+							__func__, __LINE__);
+		rc = -ENOMEM;
+		goto error_io_resource;
+	} else {
+		dsi_host_private->dsi_reg_size = resource_size(mdss_dsi_mres);
+		dsi_host_private->dsi_base = ioremap(mdss_dsi_mres->start,
+						dsi_host_private->dsi_reg_size);
+		if (!dsi_host_private->dsi_base) {
+			pr_err("%s:%d unable to remap dsi resources",
+							__func__, __LINE__);
+			rc = -ENOMEM;
+			goto error_io_resource;
+		}
+	}
+
+	mdss_dsi_mres = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
+	if (!mdss_dsi_mres || mdss_dsi_mres->start == 0) {
+		pr_err("%s:%d unable to get the MDSS irq resources",
+							__func__, __LINE__);
+		rc = -ENODEV;
+		goto error_irq_resource;
+	} else {
+		rc = msm_dsi_irq_init(&pdev->dev, mdss_dsi_mres->start);
+		if (rc) {
+			dev_err(&pdev->dev, "%s: failed to init irq, rc=%d\n",
+								__func__, rc);
+			goto error_irq_resource;
+		}
+	}
+
+	rc = of_platform_populate(pdev->dev.of_node, NULL, NULL, &pdev->dev);
+	if (rc) {
+		dev_err(&pdev->dev, "%s: failed to add child nodes, rc=%d\n",
+								__func__, rc);
+		goto error_platform_pop;
+	}
+
+	/* DSI panels can be different between controllers */
+	rc = dsi_get_panel_cfg(panel_cfg);
+	if (!rc)
+		/* dsi panel cfg not present */
+		pr_warn("%s:%d:dsi specific cfg not present\n",
+							 __func__, __LINE__);
+
+	/* find panel device node */
+	dsi_pan_node = dsi_find_panel_of_node(pdev, panel_cfg);
+	if (!dsi_pan_node) {
+		pr_err("%s: can't find panel node %s\n", __func__,
+								panel_cfg);
+		goto error_pan_node;
+	}
+
+	cmd_cfg_cont_splash = mdp3_panel_get_boot_cfg() ? true : false;
+
+	rc = mdss_dsi_panel_init(dsi_pan_node, ctrl_pdata, cmd_cfg_cont_splash);
+	if (rc) {
+		pr_err("%s: dsi panel init failed\n", __func__);
+		goto error_pan_node;
+	}
+
+	rc = dsi_ctrl_config_init(pdev, ctrl_pdata);
+	if (rc) {
+		dev_err(&pdev->dev, "%s: failed to parse mdss dtsi rc=%d\n",
+								__func__, rc);
+		goto error_pan_node;
+	}
+
+	rc = msm_dsi_io_init(pdev, &(ctrl_pdata->power_data));
+	if (rc) {
+		dev_err(&pdev->dev, "%s: failed to init DSI IO, rc=%d\n",
+								__func__, rc);
+		goto error_io_init;
+	}
+
+	pr_debug("%s: Dsi Ctrl->0 initialized\n", __func__);
 
 	dsi_host_private->dis_dev = pdev->dev;
 	intf.on = msm_dsi_on;
@@ -952,25 +1181,53 @@
 	intf.index = 0;
 	intf.private = NULL;
 	dsi_register_interface(&intf);
+
+	msm_dsi_debug_init();
+
+	rc = dsi_panel_device_register_v2(pdev, ctrl_pdata);
+	if (rc) {
+		pr_err("%s: dsi panel dev reg failed\n", __func__);
+		goto error_device_register;
+	}
 	pr_debug("%s success\n", __func__);
 	return 0;
-dsi_probe_error:
+error_device_register:
+	msm_dsi_io_deinit(pdev, &(ctrl_pdata->power_data));
+error_io_init:
+	dsi_ctrl_config_deinit(pdev, ctrl_pdata);
+error_pan_node:
+	of_node_put(dsi_pan_node);
+error_platform_pop:
+	msm_dsi_disable_irq();
+error_irq_resource:
 	if (dsi_host_private->dsi_base) {
 		iounmap(dsi_host_private->dsi_base);
 		dsi_host_private->dsi_base = NULL;
 	}
-	msm_dsi_io_deinit();
+error_io_resource:
+	devm_kfree(&pdev->dev, ctrl_pdata);
+error_no_mem:
 	msm_dsi_deinit();
+
 	return rc;
 }
 
 static int __devexit msm_dsi_remove(struct platform_device *pdev)
 {
+	struct mdss_dsi_ctrl_pdata *ctrl_pdata = platform_get_drvdata(pdev);
+	if (!ctrl_pdata) {
+		pr_err("%s: no driver data\n", __func__);
+		return -ENODEV;
+	}
+
 	msm_dsi_disable_irq();
-	msm_dsi_io_deinit();
+	msm_dsi_io_deinit(pdev, &(ctrl_pdata->power_data));
+	dsi_ctrl_config_deinit(pdev, ctrl_pdata);
 	iounmap(dsi_host_private->dsi_base);
 	dsi_host_private->dsi_base = NULL;
 	msm_dsi_deinit();
+	devm_kfree(&pdev->dev, ctrl_pdata);
+
 	return 0;
 }
 
diff --git a/drivers/video/msm/mdss/dsi_io_v2.c b/drivers/video/msm/mdss/dsi_io_v2.c
index f0ad511..2c2b3d1 100644
--- a/drivers/video/msm/mdss/dsi_io_v2.c
+++ b/drivers/video/msm/mdss/dsi_io_v2.c
@@ -24,7 +24,6 @@
 #include "dsi_host_v2.h"
 
 struct msm_dsi_io_private {
-	struct regulator *vdda_vreg;
 	struct clk *dsi_byte_clk;
 	struct clk *dsi_esc_clk;
 	struct clk *dsi_pixel_clk;
@@ -41,23 +40,17 @@
 void msm_dsi_ahb_ctrl(int enable)
 {
 	if (enable) {
-		if (dsi_io_private->msm_dsi_ahb_clk_on) {
-			pr_debug("ahb clks already ON\n");
-			return;
-		}
-		clk_enable(dsi_io_private->dsi_ahb_clk);
-		dsi_io_private->msm_dsi_ahb_clk_on = 1;
+		dsi_io_private->msm_dsi_ahb_clk_on++;
+		if (dsi_io_private->msm_dsi_ahb_clk_on == 1)
+			clk_enable(dsi_io_private->dsi_ahb_clk);
 	} else {
-		if (dsi_io_private->msm_dsi_ahb_clk_on == 0) {
-			pr_debug("ahb clk already OFF\n");
-			return;
-		}
-		clk_disable(dsi_io_private->dsi_ahb_clk);
-		dsi_io_private->msm_dsi_ahb_clk_on = 0;
+		dsi_io_private->msm_dsi_ahb_clk_on--;
+		if (dsi_io_private->msm_dsi_ahb_clk_on == 0)
+			clk_disable(dsi_io_private->dsi_ahb_clk);
 	}
 }
 
-int msm_dsi_io_init(struct platform_device *dev)
+int msm_dsi_io_init(struct platform_device *pdev, struct dss_module_power *mp)
 {
 	int rc;
 
@@ -70,25 +63,29 @@
 		}
 	}
 
-	rc = msm_dsi_clk_init(dev);
+	rc = msm_dsi_clk_init(pdev);
 	if (rc) {
 		pr_err("fail to initialize DSI clock\n");
 		return rc;
 	}
 
-	rc = msm_dsi_regulator_init(dev);
+	rc = msm_dss_config_vreg(&pdev->dev, mp->vreg_config,
+						mp->num_vreg, 1);
 	if (rc) {
 		pr_err("fail to initialize DSI regulator\n");
 		return rc;
 	}
+
 	return 0;
 }
 
-void msm_dsi_io_deinit(void)
+void msm_dsi_io_deinit(struct platform_device *pdev,
+				 struct dss_module_power *mp)
 {
 	if (dsi_io_private) {
 		msm_dsi_clk_deinit();
-		msm_dsi_regulator_deinit();
+		msm_dss_config_vreg(&pdev->dev, mp->vreg_config,
+					mp->num_vreg, 0);
 		kfree(dsi_io_private);
 		dsi_io_private = NULL;
 	}
@@ -248,61 +245,6 @@
 	return 0;
 }
 
-int msm_dsi_regulator_init(struct platform_device *dev)
-{
-	int ret = 0;
-
-	dsi_io_private->vdda_vreg = devm_regulator_get(&dev->dev, "vdda");
-	if (IS_ERR(dsi_io_private->vdda_vreg)) {
-		ret = PTR_ERR(dsi_io_private->vdda_vreg);
-		pr_err("could not get vdda 8110_l4, ret=%d\n", ret);
-		return ret;
-	}
-
-	ret = regulator_set_voltage(dsi_io_private->vdda_vreg, DSI_VDDA_VOLTAGE,
-					DSI_VDDA_VOLTAGE);
-	if (ret)
-		pr_err("vdd_io_vreg->set_voltage failed, ret=%d\n", ret);
-
-	return ret;
-}
-
-void msm_dsi_regulator_deinit(void)
-{
-	if (!IS_ERR(dsi_io_private->vdda_vreg)) {
-		devm_regulator_put(dsi_io_private->vdda_vreg);
-		dsi_io_private->vdda_vreg = NULL;
-	}
-}
-
-int msm_dsi_regulator_enable(void)
-{
-	int ret;
-
-	ret = regulator_enable(dsi_io_private->vdda_vreg);
-	if (ret) {
-		pr_err("%s: Failed to enable regulator.\n", __func__);
-		return ret;
-	}
-	msleep(20); /*per DSI controller spec*/
-	return ret;
-}
-
-int msm_dsi_regulator_disable(void)
-{
-	int ret;
-
-	ret = regulator_disable(dsi_io_private->vdda_vreg);
-	if (ret) {
-		pr_err("%s: Failed to disable regulator.\n", __func__);
-		return ret;
-	}
-	wmb();
-	msleep(20); /*per DSI controller spec*/
-
-	return ret;
-}
-
 static void msm_dsi_phy_strength_init(unsigned char *ctrl_base,
 					struct mdss_dsi_phy_ctrl *pd)
 {
@@ -368,12 +310,12 @@
 	for (ln = 0; ln < 5; ln++) {
 		unsigned char *off = ctrl_base + 0x0300 + (ln * 0x40);
 		index = ln * 6;
-		MIPI_OUTP(off, pd->laneCfg[index]);
-		MIPI_OUTP(off + 4, pd->laneCfg[index + 1]);
-		MIPI_OUTP(off + 8, pd->laneCfg[index + 2]);
-		MIPI_OUTP(off + 12, pd->laneCfg[index + 3]);
-		MIPI_OUTP(off + 20, pd->laneCfg[index + 4]);
-		MIPI_OUTP(off + 24, pd->laneCfg[index + 5]);
+		MIPI_OUTP(off, pd->lanecfg[index]);
+		MIPI_OUTP(off + 4, pd->lanecfg[index + 1]);
+		MIPI_OUTP(off + 8, pd->lanecfg[index + 2]);
+		MIPI_OUTP(off + 12, pd->lanecfg[index + 3]);
+		MIPI_OUTP(off + 20, pd->lanecfg[index + 4]);
+		MIPI_OUTP(off + 24, pd->lanecfg[index + 5]);
 	}
 	wmb();
 }
@@ -392,9 +334,9 @@
 static void msm_dsi_phy_bist_init(unsigned char *ctrl_base,
 			struct mdss_dsi_phy_ctrl *pd)
 {
-	MIPI_OUTP(ctrl_base + DSI_DSIPHY_BIST_CTRL4, pd->bistCtrl[4]);
-	MIPI_OUTP(ctrl_base + DSI_DSIPHY_BIST_CTRL1, pd->bistCtrl[1]);
-	MIPI_OUTP(ctrl_base + DSI_DSIPHY_BIST_CTRL0, pd->bistCtrl[0]);
+	MIPI_OUTP(ctrl_base + DSI_DSIPHY_BIST_CTRL4, pd->bistctrl[4]);
+	MIPI_OUTP(ctrl_base + DSI_DSIPHY_BIST_CTRL1, pd->bistctrl[1]);
+	MIPI_OUTP(ctrl_base + DSI_DSIPHY_BIST_CTRL0, pd->bistctrl[0]);
 	MIPI_OUTP(ctrl_base + DSI_DSIPHY_BIST_CTRL4, 0);
 	wmb();
 }
@@ -404,7 +346,7 @@
 {
 	struct mdss_dsi_phy_ctrl *pd;
 
-	pd = pdata->panel_info.mipi.dsi_phy_db;
+	pd = &(pdata->panel_info.mipi.dsi_phy_db);
 
 	msm_dsi_phy_strength_init(ctrl_base, pd);
 
diff --git a/drivers/video/msm/mdss/dsi_io_v2.h b/drivers/video/msm/mdss/dsi_io_v2.h
index a7d43a0..fd1c41e 100644
--- a/drivers/video/msm/mdss/dsi_io_v2.h
+++ b/drivers/video/msm/mdss/dsi_io_v2.h
@@ -17,9 +17,11 @@
 
 void msm_dsi_ahb_ctrl(int enable);
 
-int msm_dsi_io_init(struct platform_device *dev);
+int msm_dsi_io_init(struct platform_device *dev,
+				struct dss_module_power *mp);
 
-void msm_dsi_io_deinit(void);
+void msm_dsi_io_deinit(struct platform_device *dev,
+				struct dss_module_power *mp);
 
 int msm_dsi_clk_init(struct platform_device *dev);
 
@@ -38,14 +40,6 @@
 
 int msm_dsi_clk_disable(void);
 
-int msm_dsi_regulator_init(struct platform_device *dev);
-
-void msm_dsi_regulator_deinit(void);
-
-int msm_dsi_regulator_enable(void);
-
-int msm_dsi_regulator_disable(void);
-
 int msm_dsi_phy_init(unsigned char *ctrl_base,
 			struct mdss_panel_data *pdata);
 
diff --git a/drivers/video/msm/mdss/dsi_panel_v2.c b/drivers/video/msm/mdss/dsi_panel_v2.c
deleted file mode 100644
index 022d911..0000000
--- a/drivers/video/msm/mdss/dsi_panel_v2.c
+++ /dev/null
@@ -1,873 +0,0 @@
-/* Copyright (c) 2012-2013, The Linux Foundation. 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 and
- * only 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/interrupt.h>
-#include <linux/of.h>
-#include <linux/of_gpio.h>
-#include <linux/of_device.h>
-#include <linux/qpnp/pin.h>
-#include <linux/gpio.h>
-#include <linux/delay.h>
-#include <linux/slab.h>
-#include <linux/leds.h>
-#include <linux/err.h>
-#include <linux/regulator/consumer.h>
-
-#include "dsi_v2.h"
-
-#define DT_CMD_HDR 6
-
-struct dsi_panel_private {
-	struct dsi_buf dsi_panel_tx_buf;
-	struct dsi_buf dsi_panel_rx_buf;
-
-	int rst_gpio;
-	int disp_en_gpio;
-	int video_mode_gpio;
-	int te_gpio;
-	char bl_ctrl;
-
-	struct regulator *vddio_vreg;
-	struct regulator *vdda_vreg;
-
-	struct dsi_panel_cmds_list *on_cmds_list;
-	struct dsi_panel_cmds_list *off_cmds_list;
-	struct mdss_dsi_phy_ctrl phy_params;
-
-	char *on_cmds;
-	char *off_cmds;
-};
-
-static struct dsi_panel_private *panel_private;
-
-DEFINE_LED_TRIGGER(bl_led_trigger);
-
-int dsi_panel_init(void)
-{
-	int rc;
-
-	if (!panel_private) {
-		panel_private = kzalloc(sizeof(struct dsi_panel_private),
-					GFP_KERNEL);
-		if (!panel_private) {
-			pr_err("fail to alloc dsi panel private data\n");
-			return -ENOMEM;
-		}
-	}
-
-	rc = dsi_buf_alloc(&panel_private->dsi_panel_tx_buf,
-				ALIGN(DSI_BUF_SIZE,
-				SZ_4K));
-	if (rc)
-		return rc;
-
-	rc = dsi_buf_alloc(&panel_private->dsi_panel_rx_buf,
-				ALIGN(DSI_BUF_SIZE,
-				SZ_4K));
-	if (rc)
-		return rc;
-
-	return 0;
-}
-
-void dsi_panel_deinit(void)
-{
-	if (!panel_private)
-		return;
-
-	kfree(panel_private->dsi_panel_tx_buf.start);
-	kfree(panel_private->dsi_panel_rx_buf.start);
-
-	if (!IS_ERR(panel_private->vddio_vreg))
-		devm_regulator_put(panel_private->vddio_vreg);
-
-	if (!IS_ERR(panel_private->vdda_vreg))
-		devm_regulator_put(panel_private->vdda_vreg);
-
-	if (panel_private->on_cmds_list) {
-		kfree(panel_private->on_cmds_list->buf);
-		kfree(panel_private->on_cmds_list);
-	}
-	if (panel_private->off_cmds_list) {
-		kfree(panel_private->off_cmds_list->buf);
-		kfree(panel_private->off_cmds_list);
-	}
-
-	kfree(panel_private->on_cmds);
-	kfree(panel_private->off_cmds);
-
-	kfree(panel_private);
-	panel_private = NULL;
-
-	if (bl_led_trigger) {
-		led_trigger_unregister_simple(bl_led_trigger);
-		bl_led_trigger = NULL;
-	}
-}
-int dsi_panel_power(int enable)
-{
-	int ret;
-	if (enable) {
-		ret = regulator_enable(panel_private->vddio_vreg);
-		if (ret) {
-			pr_err("dsi_panel_power regulator enable vddio fail\n");
-			return ret;
-		}
-		ret = regulator_enable(panel_private->vdda_vreg);
-		if (ret) {
-			pr_err("dsi_panel_power regulator enable vdda fail\n");
-			return ret;
-		}
-	} else {
-		ret = regulator_disable(panel_private->vddio_vreg);
-		if (ret) {
-			pr_err("dsi_panel_power regulator disable vddio fail\n");
-			return ret;
-		}
-		ret = regulator_disable(panel_private->vdda_vreg);
-		if (ret) {
-			pr_err("dsi_panel_power regulator dsiable vdda fail\n");
-			return ret;
-		}
-	}
-	return 0;
-}
-
-void dsi_panel_reset(struct mdss_panel_data *pdata, int enable)
-{
-	if (pdata == NULL) {
-		pr_err("%s: Invalid input data\n", __func__);
-		return;
-	}
-
-	if (!gpio_is_valid(panel_private->disp_en_gpio)) {
-		pr_debug("%s:%d, reset line not configured\n",
-			   __func__, __LINE__);
-	}
-
-	if (!gpio_is_valid(panel_private->rst_gpio)) {
-		pr_debug("%s:%d, reset line not configured\n",
-			   __func__, __LINE__);
-		return;
-	}
-
-	pr_debug("%s: enable = %d\n", __func__, enable);
-
-	if (enable == 2) {
-		dsi_panel_power(1);
-		gpio_request(panel_private->rst_gpio, "panel_reset");
-		if (gpio_is_valid(panel_private->disp_en_gpio)) {
-			gpio_request(panel_private->disp_en_gpio,
-					"panel_enable");
-		}
-		if (gpio_is_valid(panel_private->video_mode_gpio)) {
-			gpio_request(panel_private->video_mode_gpio,
-					"panel_video_mdoe");
-		}
-		if (gpio_is_valid(panel_private->te_gpio))
-			gpio_request(panel_private->te_gpio, "panel_te");
-	} else if (enable == 1) {
-		dsi_panel_power(1);
-		gpio_request(panel_private->rst_gpio, "panel_reset");
-		gpio_set_value(panel_private->rst_gpio, 1);
-		/*
-		 * these delay values are by experiments currently, will need
-		 * to move to device tree late
-		 */
-		msleep(20);
-		gpio_set_value(panel_private->rst_gpio, 0);
-		udelay(200);
-		gpio_set_value(panel_private->rst_gpio, 1);
-		msleep(20);
-		if (gpio_is_valid(panel_private->disp_en_gpio)) {
-			gpio_request(panel_private->disp_en_gpio,
-					"panel_enable");
-			gpio_set_value(panel_private->disp_en_gpio, 1);
-		}
-		if (gpio_is_valid(panel_private->video_mode_gpio)) {
-			gpio_request(panel_private->video_mode_gpio,
-					"panel_video_mdoe");
-			if (pdata->panel_info.mipi.mode == DSI_VIDEO_MODE)
-				gpio_set_value(panel_private->video_mode_gpio,
-						1);
-			else
-				gpio_set_value(panel_private->video_mode_gpio,
-						0);
-		}
-		if (gpio_is_valid(panel_private->te_gpio))
-			gpio_request(panel_private->te_gpio, "panel_te");
-	} else {
-		gpio_set_value(panel_private->rst_gpio, 0);
-		gpio_free(panel_private->rst_gpio);
-
-		if (gpio_is_valid(panel_private->disp_en_gpio)) {
-			gpio_set_value(panel_private->disp_en_gpio, 0);
-			gpio_free(panel_private->disp_en_gpio);
-		}
-
-		if (gpio_is_valid(panel_private->video_mode_gpio))
-			gpio_free(panel_private->video_mode_gpio);
-
-		if (gpio_is_valid(panel_private->te_gpio))
-			gpio_free(panel_private->te_gpio);
-		dsi_panel_power(0);
-	}
-}
-
-static void dsi_panel_bl_ctrl(struct mdss_panel_data *pdata,
-				u32 bl_level)
-{
-	if (panel_private->bl_ctrl) {
-		switch (panel_private->bl_ctrl) {
-		case BL_WLED:
-			led_trigger_event(bl_led_trigger, bl_level);
-			break;
-
-		default:
-			pr_err("%s: Unknown bl_ctrl configuration\n",
-				__func__);
-			break;
-		}
-	} else
-		pr_err("%s:%d, bl_ctrl not configured", __func__, __LINE__);
-}
-
-static int dsi_panel_on(struct mdss_panel_data *pdata)
-{
-	struct mipi_panel_info *mipi;
-
-	mipi  = &pdata->panel_info.mipi;
-
-	pr_debug("%s:%d, debug info (mode) : %d\n", __func__, __LINE__,
-		 mipi->mode);
-
-
-	return dsi_cmds_tx_v2(pdata, &panel_private->dsi_panel_tx_buf,
-					panel_private->on_cmds_list->buf,
-					panel_private->on_cmds_list->size);
-}
-
-static int dsi_panel_off(struct mdss_panel_data *pdata)
-{
-	struct mipi_panel_info *mipi;
-	mipi  = &pdata->panel_info.mipi;
-
-	pr_debug("%s:%d, debug info\n", __func__, __LINE__);
-
-
-	return dsi_cmds_tx_v2(pdata, &panel_private->dsi_panel_tx_buf,
-					panel_private->off_cmds_list->buf,
-					panel_private->off_cmds_list->size);
-}
-
-static int dsi_panel_parse_gpio(struct platform_device *pdev)
-{
-	struct device_node *np = pdev->dev.of_node;
-	panel_private->disp_en_gpio = of_get_named_gpio(np,
-						"qcom,enable-gpio", 0);
-	panel_private->rst_gpio = of_get_named_gpio(np, "qcom,rst-gpio", 0);
-	panel_private->video_mode_gpio = of_get_named_gpio(np,
-						"qcom,mode-selection-gpio", 0);
-	panel_private->te_gpio = of_get_named_gpio(np,
-						"qcom,te-gpio", 0);
-	return 0;
-}
-
-static int dsi_panel_parse_regulator(struct platform_device *pdev)
-{
-	int ret;
-	panel_private->vddio_vreg = devm_regulator_get(&pdev->dev, "vddio");
-	if (IS_ERR(panel_private->vddio_vreg)) {
-		pr_err("%s: could not get vddio vreg, rc=%ld\n",
-			__func__, PTR_ERR(panel_private->vddio_vreg));
-		return PTR_ERR(panel_private->vddio_vreg);
-	}
-	ret = regulator_set_voltage(panel_private->vddio_vreg,
-					1800000,
-					1800000);
-	if (ret) {
-		pr_err("%s: set voltage failed on vddio_vreg, rc=%d\n",
-			__func__, ret);
-		return ret;
-	}
-	panel_private->vdda_vreg = devm_regulator_get(&pdev->dev, "vdda");
-	if (IS_ERR(panel_private->vdda_vreg)) {
-		pr_err("%s: could not get vdda_vreg , rc=%ld\n",
-			__func__, PTR_ERR(panel_private->vdda_vreg));
-		return PTR_ERR(panel_private->vdda_vreg);
-	}
-	ret = regulator_set_voltage(panel_private->vdda_vreg,
-					2850000,
-					2850000);
-	if (ret) {
-		pr_err("%s: set voltage failed on vdda_vreg, rc=%d\n",
-			__func__, ret);
-		return ret;
-	}
-	return 0;
-}
-
-static int dsi_panel_parse_timing(struct platform_device *pdev,
-				struct dsi_panel_common_pdata *panel_data)
-{
-	struct device_node *np = pdev->dev.of_node;
-	u32 res[6], tmp;
-	int rc;
-
-	rc = of_property_read_u32_array(np, "qcom,mdss-pan-res", res, 2);
-	if (rc) {
-		pr_err("%s:%d, panel resolution not specified\n",
-						__func__, __LINE__);
-		return -EINVAL;
-	}
-
-	panel_data->panel_info.xres = (!rc ? res[0] : 480);
-	panel_data->panel_info.yres = (!rc ? res[1] : 800);
-
-	rc = of_property_read_u32_array(np, "qcom,mdss-pan-active-res", res, 2);
-	if (rc == 0) {
-		panel_data->panel_info.lcdc.xres_pad =
-			panel_data->panel_info.xres - res[0];
-		panel_data->panel_info.lcdc.yres_pad =
-			panel_data->panel_info.yres - res[1];
-	}
-
-	rc = of_property_read_u32(np, "qcom,mdss-pan-bpp", &tmp);
-	if (rc) {
-		pr_err("%s:%d, panel bpp not specified\n",
-						__func__, __LINE__);
-		return -EINVAL;
-	}
-	panel_data->panel_info.bpp = (!rc ? tmp : 24);
-
-	rc = of_property_read_u32_array(np,
-		"qcom,mdss-pan-porch-values", res, 6);
-	if (rc) {
-		pr_err("%s:%d, panel porch not specified\n",
-						__func__, __LINE__);
-		return -EINVAL;
-	}
-
-	panel_data->panel_info.lcdc.h_back_porch = (!rc ? res[0] : 6);
-	panel_data->panel_info.lcdc.h_pulse_width = (!rc ? res[1] : 2);
-	panel_data->panel_info.lcdc.h_front_porch = (!rc ? res[2] : 6);
-	panel_data->panel_info.lcdc.v_back_porch = (!rc ? res[3] : 6);
-	panel_data->panel_info.lcdc.v_pulse_width = (!rc ? res[4] : 2);
-	panel_data->panel_info.lcdc.v_front_porch = (!rc ? res[5] : 6);
-
-	return 0;
-}
-
-static int dsi_panel_parse_phy(struct platform_device *pdev,
-				struct dsi_panel_common_pdata *panel_data)
-{
-	struct device_node *np = pdev->dev.of_node;
-	int i, len;
-	const char *data;
-
-	data = of_get_property(np, "qcom,panel-phy-regulatorSettings", &len);
-	if ((!data) || (len != 6)) {
-		pr_err("%s:%d, Unable to read Phy regulator settings",
-			__func__, __LINE__);
-		return -EINVAL;
-	}
-	for (i = 0; i < len; i++)
-		panel_private->phy_params.regulator[i] = data[i];
-
-	data = of_get_property(np, "qcom,panel-phy-timingSettings", &len);
-	if ((!data) || (len != 12)) {
-		pr_err("%s:%d, Unable to read Phy timing settings",
-			__func__, __LINE__);
-		return -EINVAL;
-	}
-	for (i = 0; i < len; i++)
-		panel_private->phy_params.timing[i] = data[i];
-
-	data = of_get_property(np, "qcom,panel-phy-strengthCtrl", &len);
-	if ((!data) || (len != 2)) {
-		pr_err("%s:%d, Unable to read Phy Strength ctrl settings",
-			__func__, __LINE__);
-		return -EINVAL;
-	}
-	panel_private->phy_params.strength[0] = data[0];
-	panel_private->phy_params.strength[1] = data[1];
-
-	data = of_get_property(np, "qcom,panel-phy-bistCtrl", &len);
-	if ((!data) || (len != 6)) {
-		pr_err("%s:%d, Unable to read Phy Bist Ctrl settings",
-			__func__, __LINE__);
-		return -EINVAL;
-	}
-	for (i = 0; i < len; i++)
-		panel_private->phy_params.bistCtrl[i] = data[i];
-
-	data = of_get_property(np, "qcom,panel-phy-laneConfig", &len);
-	if ((!data) || (len != 30)) {
-		pr_err("%s:%d, Unable to read Phy lane configure settings",
-			__func__, __LINE__);
-		return -EINVAL;
-	}
-	for (i = 0; i < len; i++)
-		panel_private->phy_params.laneCfg[i] = data[i];
-
-	panel_data->panel_info.mipi.dsi_phy_db = &panel_private->phy_params;
-	return 0;
-}
-
-static int dsi_panel_parse_init_cmds(struct platform_device *pdev,
-				struct dsi_panel_common_pdata *panel_data)
-{
-	struct device_node *np = pdev->dev.of_node;
-	int i, len;
-	int cmd_plen, data_offset;
-	const char *data;
-	const char *on_cmds_state, *off_cmds_state;
-	int num_of_on_cmds = 0, num_of_off_cmds = 0;
-
-	data = of_get_property(np, "qcom,panel-on-cmds", &len);
-	if (!data) {
-		pr_err("%s:%d, Unable to read ON cmds", __func__, __LINE__);
-		return -EINVAL;
-	}
-
-	panel_private->on_cmds = kzalloc(sizeof(char) * len, GFP_KERNEL);
-	if (!panel_private->on_cmds)
-		return -ENOMEM;
-
-	memcpy(panel_private->on_cmds, data, len);
-
-	data_offset = 0;
-	cmd_plen = 0;
-	while ((len - data_offset) >= DT_CMD_HDR) {
-		data_offset += (DT_CMD_HDR - 1);
-		cmd_plen = panel_private->on_cmds[data_offset++];
-		data_offset += cmd_plen;
-		num_of_on_cmds++;
-	}
-	if (!num_of_on_cmds) {
-		pr_err("%s:%d, No ON cmds specified", __func__, __LINE__);
-		return -EINVAL;
-	}
-
-	panel_private->on_cmds_list =
-		kzalloc(sizeof(struct dsi_panel_cmds_list), GFP_KERNEL);
-	if (!panel_private->on_cmds_list)
-		return -ENOMEM;
-
-	panel_private->on_cmds_list->buf =
-		kzalloc((num_of_on_cmds * sizeof(struct dsi_cmd_desc)),
-			GFP_KERNEL);
-	if (!panel_private->on_cmds_list->buf)
-		return -ENOMEM;
-
-	data_offset = 0;
-	for (i = 0; i < num_of_on_cmds; i++) {
-		panel_private->on_cmds_list->buf[i].dtype =
-					panel_private->on_cmds[data_offset++];
-		panel_private->on_cmds_list->buf[i].last =
-					panel_private->on_cmds[data_offset++];
-		panel_private->on_cmds_list->buf[i].vc =
-					panel_private->on_cmds[data_offset++];
-		panel_private->on_cmds_list->buf[i].ack =
-					panel_private->on_cmds[data_offset++];
-		panel_private->on_cmds_list->buf[i].wait =
-					panel_private->on_cmds[data_offset++];
-		panel_private->on_cmds_list->buf[i].dlen =
-					panel_private->on_cmds[data_offset++];
-		panel_private->on_cmds_list->buf[i].payload =
-					&panel_private->on_cmds[data_offset];
-		data_offset += (panel_private->on_cmds_list->buf[i].dlen);
-	}
-
-	if (data_offset != len) {
-		pr_err("%s:%d, Incorrect ON command entries",
-						__func__, __LINE__);
-		return -EINVAL;
-	}
-
-	panel_private->on_cmds_list->size = num_of_on_cmds;
-
-	on_cmds_state = of_get_property(pdev->dev.of_node,
-					"qcom,on-cmds-dsi-state", NULL);
-	if (!strncmp(on_cmds_state, "DSI_LP_MODE", 11)) {
-		panel_private->on_cmds_list->ctrl_state = DSI_LP_MODE;
-	} else if (!strncmp(on_cmds_state, "DSI_HS_MODE", 11)) {
-		panel_private->on_cmds_list->ctrl_state = DSI_HS_MODE;
-	} else {
-		pr_debug("%s: ON cmds state not specified. Set Default\n",
-							__func__);
-		panel_private->on_cmds_list->ctrl_state = DSI_LP_MODE;
-	}
-
-	panel_data->dsi_panel_on_cmds = panel_private->on_cmds_list;
-
-	data = of_get_property(np, "qcom,panel-off-cmds", &len);
-	if (!data) {
-		pr_err("%s:%d, Unable to read OFF cmds", __func__, __LINE__);
-		return -EINVAL;
-	}
-
-	panel_private->off_cmds = kzalloc(sizeof(char) * len, GFP_KERNEL);
-	if (!panel_private->off_cmds)
-		return -ENOMEM;
-
-	memcpy(panel_private->off_cmds, data, len);
-
-	data_offset = 0;
-	cmd_plen = 0;
-	while ((len - data_offset) >= DT_CMD_HDR) {
-		data_offset += (DT_CMD_HDR - 1);
-		cmd_plen = panel_private->off_cmds[data_offset++];
-		data_offset += cmd_plen;
-		num_of_off_cmds++;
-	}
-	if (!num_of_off_cmds) {
-		pr_err("%s:%d, No OFF cmds specified", __func__, __LINE__);
-		return -ENOMEM;
-	}
-
-	panel_private->off_cmds_list =
-		kzalloc(sizeof(struct dsi_panel_cmds_list), GFP_KERNEL);
-	if (!panel_private->off_cmds_list)
-		return -ENOMEM;
-
-	panel_private->off_cmds_list->buf = kzalloc(num_of_off_cmds
-					* sizeof(struct dsi_cmd_desc),
-						GFP_KERNEL);
-	if (!panel_private->off_cmds_list->buf)
-		return -ENOMEM;
-
-	data_offset = 0;
-	for (i = 0; i < num_of_off_cmds; i++) {
-		panel_private->off_cmds_list->buf[i].dtype =
-					panel_private->off_cmds[data_offset++];
-		panel_private->off_cmds_list->buf[i].last =
-					panel_private->off_cmds[data_offset++];
-		panel_private->off_cmds_list->buf[i].vc =
-					panel_private->off_cmds[data_offset++];
-		panel_private->off_cmds_list->buf[i].ack =
-					panel_private->off_cmds[data_offset++];
-		panel_private->off_cmds_list->buf[i].wait =
-					panel_private->off_cmds[data_offset++];
-		panel_private->off_cmds_list->buf[i].dlen =
-					panel_private->off_cmds[data_offset++];
-		panel_private->off_cmds_list->buf[i].payload =
-					&panel_private->off_cmds[data_offset];
-		data_offset += (panel_private->off_cmds_list->buf[i].dlen);
-	}
-
-	if (data_offset != len) {
-		pr_err("%s:%d, Incorrect OFF command entries",
-						__func__, __LINE__);
-		return -EINVAL;
-	}
-
-	panel_private->off_cmds_list->size = num_of_off_cmds;
-	off_cmds_state = of_get_property(pdev->dev.of_node,
-				"qcom,off-cmds-dsi-state", NULL);
-	if (!strncmp(off_cmds_state, "DSI_LP_MODE", 11)) {
-		panel_private->off_cmds_list->ctrl_state =
-						DSI_LP_MODE;
-	} else if (!strncmp(off_cmds_state, "DSI_HS_MODE", 11)) {
-		panel_private->off_cmds_list->ctrl_state = DSI_HS_MODE;
-	} else {
-		pr_debug("%s: ON cmds state not specified. Set Default\n",
-							__func__);
-		panel_private->off_cmds_list->ctrl_state = DSI_LP_MODE;
-	}
-
-	panel_data->dsi_panel_off_cmds = panel_private->off_cmds_list;
-
-	return 0;
-}
-
-static int dsi_panel_parse_backlight(struct platform_device *pdev,
-				struct dsi_panel_common_pdata *panel_data,
-				char *bl_ctrl)
-{
-	int rc;
-	u32 res[6];
-	static const char *bl_ctrl_type;
-
-	bl_ctrl_type = of_get_property(pdev->dev.of_node,
-				  "qcom,mdss-pan-bl-ctrl", NULL);
-	if ((bl_ctrl_type) && (!strncmp(bl_ctrl_type, "bl_ctrl_wled", 12))) {
-		led_trigger_register_simple("bkl-trigger", &bl_led_trigger);
-		pr_debug("%s: SUCCESS-> WLED TRIGGER register\n", __func__);
-		*bl_ctrl = BL_WLED;
-	}
-
-	rc = of_property_read_u32_array(pdev->dev.of_node,
-		"qcom,mdss-pan-bl-levels", res, 2);
-	panel_data->panel_info.bl_min = (!rc ? res[0] : 0);
-	panel_data->panel_info.bl_max = (!rc ? res[1] : 255);
-	return rc;
-}
-
-static int dsi_panel_parse_other(struct platform_device *pdev,
-				struct dsi_panel_common_pdata *panel_data)
-{
-	const char *pdest;
-	u32 tmp;
-	int rc;
-
-	pdest = of_get_property(pdev->dev.of_node,
-				"qcom,mdss-pan-dest", NULL);
-	if (strlen(pdest) != 9) {
-		pr_err("%s: Unknown pdest specified\n", __func__);
-		return -EINVAL;
-	}
-	if (!strncmp(pdest, "display_1", 9)) {
-		panel_data->panel_info.pdest = DISPLAY_1;
-	} else if (!strncmp(pdest, "display_2", 9)) {
-		panel_data->panel_info.pdest = DISPLAY_2;
-	} else {
-		pr_debug("%s: pdest not specified. Set Default\n",
-							__func__);
-		panel_data->panel_info.pdest = DISPLAY_1;
-	}
-
-	rc = of_property_read_u32(pdev->dev.of_node,
-		"qcom,mdss-pan-underflow-clr", &tmp);
-	panel_data->panel_info.lcdc.underflow_clr = (!rc ? tmp : 0xff);
-
-	return rc;
-}
-
-static int dsi_panel_parse_host_cfg(struct platform_device *pdev,
-				struct dsi_panel_common_pdata *panel_data)
-{
-	struct device_node *np = pdev->dev.of_node;
-	u32 res[6], tmp;
-	int rc;
-
-	rc = of_property_read_u32(np, "qcom,mdss-pan-dsi-mode", &tmp);
-	panel_data->panel_info.mipi.mode = (!rc ? tmp : DSI_VIDEO_MODE);
-
-	rc = of_property_read_u32(np,
-		"qcom,mdss-pan-dsi-h-pulse-mode", &tmp);
-	panel_data->panel_info.mipi.pulse_mode_hsa_he = (!rc ? tmp : false);
-
-	rc = of_property_read_u32_array(np,
-		"qcom,mdss-pan-dsi-h-power-stop", res, 3);
-	panel_data->panel_info.mipi.hbp_power_stop = (!rc ? res[0] : false);
-	panel_data->panel_info.mipi.hsa_power_stop = (!rc ? res[1] : false);
-	panel_data->panel_info.mipi.hfp_power_stop = (!rc ? res[2] : false);
-
-	rc = of_property_read_u32_array(np,
-		"qcom,mdss-pan-dsi-bllp-power-stop", res, 2);
-	panel_data->panel_info.mipi.bllp_power_stop =
-					(!rc ? res[0] : false);
-	panel_data->panel_info.mipi.eof_bllp_power_stop =
-					(!rc ? res[1] : false);
-
-	rc = of_property_read_u32(np,
-		"qcom,mdss-pan-dsi-traffic-mode", &tmp);
-	panel_data->panel_info.mipi.traffic_mode =
-			(!rc ? tmp : DSI_NON_BURST_SYNCH_PULSE);
-
-	rc = of_property_read_u32(np,
-		"qcom,mdss-pan-dsi-dst-format", &tmp);
-	panel_data->panel_info.mipi.dst_format =
-			(!rc ? tmp : DSI_VIDEO_DST_FORMAT_RGB888);
-
-	rc = of_property_read_u32(np, "qcom,mdss-pan-dsi-vc", &tmp);
-	panel_data->panel_info.mipi.vc = (!rc ? tmp : 0);
-
-	rc = of_property_read_u32(np, "qcom,mdss-pan-dsi-rgb-swap", &tmp);
-	panel_data->panel_info.mipi.rgb_swap = (!rc ? tmp : DSI_RGB_SWAP_RGB);
-
-	rc = of_property_read_u32_array(np,
-		"qcom,mdss-pan-dsi-data-lanes", res, 4);
-	panel_data->panel_info.mipi.data_lane0 = (!rc ? res[0] : true);
-	panel_data->panel_info.mipi.data_lane1 = (!rc ? res[1] : false);
-	panel_data->panel_info.mipi.data_lane2 = (!rc ? res[2] : false);
-	panel_data->panel_info.mipi.data_lane3 = (!rc ? res[3] : false);
-
-	rc = of_property_read_u32(np, "qcom,mdss-pan-dsi-dlane-swap", &tmp);
-	panel_data->panel_info.mipi.dlane_swap = (!rc ? tmp : 0);
-
-	rc = of_property_read_u32_array(np, "qcom,mdss-pan-dsi-t-clk", res, 2);
-	panel_data->panel_info.mipi.t_clk_pre = (!rc ? res[0] : 0x24);
-	panel_data->panel_info.mipi.t_clk_post = (!rc ? res[1] : 0x03);
-
-	rc = of_property_read_u32(np, "qcom,mdss-pan-dsi-stream", &tmp);
-	panel_data->panel_info.mipi.stream = (!rc ? tmp : 0);
-
-	rc = of_property_read_u32(np, "qcom,mdss-pan-te-sel", &tmp);
-	panel_data->panel_info.mipi.te_sel = (!rc ? tmp : 1);
-
-	rc = of_property_read_u32(np, "qcom,mdss-pan-insert-dcs-cmd", &tmp);
-	panel_data->panel_info.mipi.insert_dcs_cmd = (!rc ? tmp : 1);
-
-	rc = of_property_read_u32(np, "qcom,mdss-pan-wr-mem-continue", &tmp);
-	panel_data->panel_info.mipi.wr_mem_continue = (!rc ? tmp : 0x3c);
-	rc = of_property_read_u32(np, "qcom,mdss-pan-wr-mem-start", &tmp);
-	panel_data->panel_info.mipi.wr_mem_start = (!rc ? tmp : 0x2c);
-
-	rc = of_property_read_u32(np, "qcom,mdss-pan-dsi-mdp-tr", &tmp);
-	panel_data->panel_info.mipi.mdp_trigger =
-			(!rc ? tmp : DSI_CMD_TRIGGER_SW);
-	if (panel_data->panel_info.mipi.mdp_trigger > 6) {
-		pr_err("%s:%d, Invalid mdp trigger. Forcing to sw trigger",
-						 __func__, __LINE__);
-		panel_data->panel_info.mipi.mdp_trigger =
-					DSI_CMD_TRIGGER_SW;
-	}
-
-	rc = of_property_read_u32(np, "qcom,mdss-pan-dsi-dma-tr", &tmp);
-	panel_data->panel_info.mipi.dma_trigger =
-			(!rc ? tmp : DSI_CMD_TRIGGER_SW);
-	if (panel_data->panel_info.mipi.dma_trigger > 6) {
-		pr_err("%s:%d, Invalid dma trigger. Forcing to sw trigger",
-						 __func__, __LINE__);
-		panel_data->panel_info.mipi.dma_trigger =
-					DSI_CMD_TRIGGER_SW;
-	}
-
-	rc = of_property_read_u32(np, "qcom,mdss-pan-dsi-frame-rate", &tmp);
-	panel_data->panel_info.mipi.frame_rate = (!rc ? tmp : 60);
-	return rc;
-}
-
-static int dsi_panel_parse_dt(struct platform_device *pdev,
-				struct dsi_panel_common_pdata *panel_data,
-				char *bl_ctrl)
-{
-	int rc;
-
-	rc = dsi_panel_parse_gpio(pdev);
-	if (rc) {
-		pr_err("fail to parse panel GPIOs\n");
-		return rc;
-	}
-
-	rc = dsi_panel_parse_regulator(pdev);
-	if (rc) {
-		pr_err("fail to parse panel regulators\n");
-		return rc;
-	}
-
-	rc = dsi_panel_parse_timing(pdev, panel_data);
-	if (rc) {
-		pr_err("fail to parse panel timing\n");
-		return rc;
-	}
-
-	rc = dsi_panel_parse_phy(pdev, panel_data);
-	if (rc) {
-		pr_err("fail to parse DSI PHY settings\n");
-		return rc;
-	}
-
-	rc = dsi_panel_parse_backlight(pdev, panel_data, bl_ctrl);
-	if (rc) {
-		pr_err("fail to parse DSI backlight\n");
-		return rc;
-	}
-
-	rc = dsi_panel_parse_other(pdev, panel_data);
-	if (rc) {
-		pr_err("fail to parse DSI panel destination\n");
-		return rc;
-	}
-
-	rc = dsi_panel_parse_host_cfg(pdev, panel_data);
-	if (rc) {
-		pr_err("fail to parse DSI host configs\n");
-		return rc;
-	}
-
-	rc = dsi_panel_parse_init_cmds(pdev, panel_data);
-	if (rc) {
-		pr_err("fail to parse DSI init commands\n");
-		return rc;
-	}
-
-	return 0;
-}
-
-static int __devinit dsi_panel_probe(struct platform_device *pdev)
-{
-	int rc = 0;
-	static struct dsi_panel_common_pdata vendor_pdata;
-	static const char *panel_name;
-
-	pr_debug("%s:%d, debug info id=%d", __func__, __LINE__, pdev->id);
-	if (!pdev->dev.of_node)
-		return -ENODEV;
-
-	panel_name = of_get_property(pdev->dev.of_node, "label", NULL);
-	if (!panel_name)
-		pr_debug("%s:%d, panel name not specified\n",
-						__func__, __LINE__);
-	else
-		pr_debug("%s: Panel Name = %s\n", __func__, panel_name);
-
-	rc = dsi_panel_init();
-	if (rc) {
-		pr_err("dsi_panel_init failed %d\n", rc);
-		goto dsi_panel_probe_error;
-
-	}
-	rc = dsi_panel_parse_dt(pdev, &vendor_pdata, &panel_private->bl_ctrl);
-	if (rc) {
-		pr_err("dsi_panel_parse_dt failed %d\n", rc);
-		goto dsi_panel_probe_error;
-	}
-
-	vendor_pdata.on = dsi_panel_on;
-	vendor_pdata.off = dsi_panel_off;
-	vendor_pdata.reset = dsi_panel_reset;
-	vendor_pdata.bl_fnc = dsi_panel_bl_ctrl;
-
-	rc = dsi_panel_device_register_v2(pdev, &vendor_pdata,
-					panel_private->bl_ctrl);
-
-	if (rc) {
-		pr_err("dsi_panel_device_register_v2 failed %d\n", rc);
-		goto dsi_panel_probe_error;
-	}
-
-	return 0;
-dsi_panel_probe_error:
-	dsi_panel_deinit();
-	return rc;
-}
-
-static int __devexit dsi_panel_remove(struct platform_device *pdev)
-{
-	dsi_panel_deinit();
-	return 0;
-}
-
-
-static const struct of_device_id dsi_panel_match[] = {
-	{.compatible = "qcom,dsi-panel-v2"},
-	{}
-};
-
-static struct platform_driver this_driver = {
-	.probe  = dsi_panel_probe,
-	.remove = __devexit_p(dsi_panel_remove),
-	.driver = {
-		.name = "dsi_v2_panel",
-		.of_match_table = dsi_panel_match,
-	},
-};
-
-static int __init dsi_panel_module_init(void)
-{
-	return platform_driver_register(&this_driver);
-}
-module_init(dsi_panel_module_init);
diff --git a/drivers/video/msm/mdss/dsi_v2.c b/drivers/video/msm/mdss/dsi_v2.c
index 686ec01..9ca3461 100644
--- a/drivers/video/msm/mdss/dsi_v2.c
+++ b/drivers/video/msm/mdss/dsi_v2.c
@@ -16,12 +16,12 @@
 #include <linux/slab.h>
 #include <linux/iopoll.h>
 #include <linux/of_device.h>
+#include <linux/of_gpio.h>
 
-#include "mdss_panel.h"
 #include "dsi_v2.h"
 
-static struct dsi_panel_common_pdata *panel_common_data;
 static struct dsi_interface dsi_intf;
+static struct dsi_buf dsi_panel_tx_buf;
 
 static int dsi_off(struct mdss_panel_data *pdata)
 {
@@ -52,20 +52,24 @@
 	}
 	return rc;
 }
+
 static int dsi_panel_handler(struct mdss_panel_data *pdata, int enable)
 {
 	int rc = 0;
+	struct mdss_dsi_ctrl_pdata *ctrl_pdata = NULL;
 
 	pr_debug("dsi_panel_handler enable=%d\n", enable);
-	if (!panel_common_data || !pdata)
+	if (!pdata)
 		return -ENODEV;
+	ctrl_pdata = container_of(pdata, struct mdss_dsi_ctrl_pdata,
+				panel_data);
 
 	if (enable) {
-		if (panel_common_data->reset)
-			panel_common_data->reset(pdata, 1);
+		mdss_dsi_panel_reset(pdata, 1);
 
-		if (panel_common_data->on)
-			rc = panel_common_data->on(pdata);
+		rc = dsi_cmds_tx_v2(pdata, &dsi_panel_tx_buf,
+					ctrl_pdata->on_cmds.cmds,
+					ctrl_pdata->on_cmds.cmd_cnt);
 
 		if (rc)
 			pr_err("dsi_panel_handler panel on failed %d\n", rc);
@@ -73,11 +77,11 @@
 		if (dsi_intf.op_mode_config)
 			dsi_intf.op_mode_config(DSI_CMD_MODE, pdata);
 
-		if (panel_common_data->off)
-			panel_common_data->off(pdata);
+		dsi_cmds_tx_v2(pdata, &dsi_panel_tx_buf,
+					ctrl_pdata->off_cmds.cmds,
+					ctrl_pdata->off_cmds.cmd_cnt);
 
-		if (panel_common_data->reset)
-			panel_common_data->reset(pdata, 0);
+		mdss_dsi_panel_reset(pdata, 0);
 	}
 	return rc;
 }
@@ -88,9 +92,6 @@
 
 	pr_debug("%s:\n", __func__);
 
-	if (panel_common_data->reset)
-		panel_common_data->reset(pdata, 2);
-
 	if (dsi_intf.cont_on)
 		rc = dsi_intf.cont_on(pdata);
 
@@ -106,7 +107,7 @@
 {
 	int rc = 0;
 
-	if (!pdata || !panel_common_data) {
+	if (!pdata) {
 		pr_err("%s: Invalid input data\n", __func__);
 		return -ENODEV;
 	}
@@ -134,49 +135,399 @@
 	return rc;
 }
 
-static struct platform_device *get_dsi_platform_device(
-			struct platform_device *dev)
+static int dsi_parse_gpio(struct platform_device *pdev,
+				struct mdss_dsi_ctrl_pdata *ctrl_pdata)
 {
-	struct device_node *dsi_ctrl_np;
-	struct platform_device *ctrl_pdev;
+	struct device_node *np = pdev->dev.of_node;
+	int rc = 0, i = 0;
+	u32 tmp[9];
 
-	dsi_ctrl_np = of_parse_phandle(dev->dev.of_node,
-					"qcom,dsi-ctrl-phandle", 0);
+	ctrl_pdata->disp_en_gpio = of_get_named_gpio(np,
+		"qcom,platform-enable-gpio", 0);
 
-	if (!dsi_ctrl_np)
-		return NULL;
+	if (!gpio_is_valid(ctrl_pdata->disp_en_gpio)) {
+		pr_err("%s:%d, Disp_en gpio not specified\n",
+						__func__, __LINE__);
+	} else {
+		rc = gpio_request(ctrl_pdata->disp_en_gpio, "disp_enable");
+		if (rc) {
+			pr_err("request reset gpio failed, rc=%d\n",
+			       rc);
+			gpio_free(ctrl_pdata->disp_en_gpio);
+			return -ENODEV;
+		}
+	}
 
-	ctrl_pdev = of_find_device_by_node(dsi_ctrl_np);
-	if (!ctrl_pdev)
-		return NULL;
+	if (ctrl_pdata->panel_data.panel_info.mipi.mode == DSI_CMD_MODE) {
+		ctrl_pdata->disp_te_gpio = of_get_named_gpio(np,
+						"qcom,platform-te-gpio", 0);
+		if (!gpio_is_valid(ctrl_pdata->disp_te_gpio)) {
+			pr_err("%s:%d, Disp_te gpio not specified\n",
+							__func__, __LINE__);
+		} else {
+			rc = gpio_request(ctrl_pdata->disp_te_gpio, "disp_te");
+			if (rc) {
+				pr_err("request TE gpio failed, rc=%d\n",
+								       rc);
+				gpio_free(ctrl_pdata->disp_te_gpio);
+				return -ENODEV;
+			}
+			rc = gpio_tlmm_config(GPIO_CFG(
+					ctrl_pdata->disp_te_gpio, 1,
+					GPIO_CFG_INPUT,
+					GPIO_CFG_PULL_DOWN,
+					GPIO_CFG_2MA),
+					GPIO_CFG_ENABLE);
 
-	return ctrl_pdev;
+			if (rc) {
+				pr_err("%s: unable to config tlmm = %d\n",
+					__func__, ctrl_pdata->disp_te_gpio);
+				gpio_free(ctrl_pdata->disp_te_gpio);
+				return -ENODEV;
+			}
+
+			rc = gpio_direction_input(ctrl_pdata->disp_te_gpio);
+			if (rc) {
+				pr_err("set_direction for disp_en gpio failed, rc=%d\n",
+								       rc);
+				gpio_free(ctrl_pdata->disp_te_gpio);
+				if (gpio_is_valid(ctrl_pdata->disp_en_gpio))
+					gpio_free(ctrl_pdata->disp_en_gpio);
+				return -ENODEV;
+			}
+			pr_debug("%s: te_gpio=%d\n", __func__,
+					ctrl_pdata->disp_te_gpio);
+		}
+	}
+
+	rc = of_property_read_u32_array(np,
+		"qcom,platform-reset-sequence", tmp, MDSS_DSI_RST_SEQ_LEN);
+	if (rc)
+		pr_err("%s:%d, unable to read gpio reset sequence\n",
+						__func__, __LINE__);
+	else
+		for (i = 0; i < MDSS_DSI_RST_SEQ_LEN; ++i)
+			ctrl_pdata->rst_seq[i] = tmp[i];
+
+	ctrl_pdata->rst_gpio = of_get_named_gpio(np,
+					"qcom,platform-reset-gpio", 0);
+	if (!gpio_is_valid(ctrl_pdata->rst_gpio)) {
+		pr_err("%s:%d, reset gpio not specified\n",
+						__func__, __LINE__);
+	} else {
+		rc = gpio_request(ctrl_pdata->rst_gpio, "disp_rst_n");
+		if (rc) {
+			pr_err("request reset gpio failed, rc=%d\n",
+				rc);
+			gpio_free(ctrl_pdata->rst_gpio);
+			if (gpio_is_valid(ctrl_pdata->disp_en_gpio))
+				gpio_free(ctrl_pdata->disp_en_gpio);
+			if (gpio_is_valid(ctrl_pdata->disp_te_gpio))
+				gpio_free(ctrl_pdata->disp_te_gpio);
+			return -ENODEV;
+		}
+	}
+
+	if (ctrl_pdata->panel_data.panel_info.mode_gpio_state !=
+						MODE_GPIO_NOT_VALID) {
+		ctrl_pdata->mode_gpio = of_get_named_gpio(np,
+						"qcom,platform-mode-gpio", 0);
+		if (!gpio_is_valid(ctrl_pdata->mode_gpio)) {
+			pr_info("%s:%d, reset gpio not specified\n",
+							__func__, __LINE__);
+		} else {
+			rc = gpio_request(ctrl_pdata->mode_gpio, "panel_mode");
+			if (rc) {
+				pr_err("request panel mode gpio failed,rc=%d\n",
+									rc);
+				gpio_free(ctrl_pdata->mode_gpio);
+				if (gpio_is_valid(ctrl_pdata->disp_en_gpio))
+					gpio_free(ctrl_pdata->disp_en_gpio);
+				if (gpio_is_valid(ctrl_pdata->rst_gpio))
+					gpio_free(ctrl_pdata->rst_gpio);
+				if (gpio_is_valid(ctrl_pdata->disp_te_gpio))
+					gpio_free(ctrl_pdata->disp_te_gpio);
+				return -ENODEV;
+			}
+		}
+	}
+	return 0;
 }
 
+void dsi_ctrl_config_deinit(struct platform_device *pdev,
+				struct mdss_dsi_ctrl_pdata *ctrl_pdata)
+{
+	struct dss_module_power *module_power = &(ctrl_pdata->power_data);
+	if (!module_power) {
+		pr_err("%s: invalid input\n", __func__);
+		return;
+	}
+
+	if (module_power->vreg_config) {
+		devm_kfree(&(pdev->dev), module_power->vreg_config);
+		module_power->vreg_config = NULL;
+	}
+	module_power->num_vreg = 0;
+
+	if (gpio_is_valid(ctrl_pdata->disp_en_gpio))
+		gpio_free(ctrl_pdata->disp_en_gpio);
+	if (gpio_is_valid(ctrl_pdata->rst_gpio))
+		gpio_free(ctrl_pdata->rst_gpio);
+	if (gpio_is_valid(ctrl_pdata->disp_te_gpio))
+		gpio_free(ctrl_pdata->disp_te_gpio);
+	if (gpio_is_valid(ctrl_pdata->mode_gpio))
+		gpio_free(ctrl_pdata->mode_gpio);
+}
+
+static int dsi_parse_vreg(struct device *dev, struct dss_module_power *mp)
+{
+	int i = 0, rc = 0;
+	u32 tmp = 0;
+	struct device_node *supply_node = NULL;
+	struct device_node *np = NULL;
+
+	if (!dev || !mp) {
+		pr_err("%s: invalid input\n", __func__);
+		rc = -EINVAL;
+		goto error;
+	}
+
+	np = dev->of_node;
+
+	mp->num_vreg = 0;
+	for_each_child_of_node(np, supply_node) {
+		if (!strncmp(supply_node->name, "qcom,platform-supply-entry",
+					strlen("qcom,platform-supply-entry")))
+			++mp->num_vreg;
+	}
+	if (mp->num_vreg == 0) {
+		pr_err("%s: no vreg\n", __func__);
+		goto novreg;
+	} else {
+		pr_debug("%s: vreg found. count=%d\n", __func__, mp->num_vreg);
+	}
+
+	mp->vreg_config = devm_kzalloc(dev, sizeof(struct dss_vreg) *
+		mp->num_vreg, GFP_KERNEL);
+	if (!mp->vreg_config) {
+		pr_err("%s: can't alloc vreg mem\n", __func__);
+		rc = -ENOMEM;
+		goto error;
+	}
+
+	for_each_child_of_node(np, supply_node) {
+		if (!strncmp(supply_node->name, "qcom,platform-supply-entry",
+					strlen("qcom,platform-supply-entry"))) {
+			const char *st = NULL;
+			/* vreg-name */
+			rc = of_property_read_string(supply_node,
+				"qcom,supply-name", &st);
+			if (rc) {
+				pr_err("%s: error reading name. rc=%d\n",
+					__func__, rc);
+				goto error;
+			}
+			strlcpy(mp->vreg_config[i].vreg_name, st,
+				sizeof(mp->vreg_config[i].vreg_name));
+			/* vreg-min-voltage */
+			rc = of_property_read_u32(supply_node,
+				"qcom,supply-min-voltage", &tmp);
+			if (rc) {
+				pr_err("%s: error reading min volt. rc=%d\n",
+					__func__, rc);
+				goto error;
+			}
+			mp->vreg_config[i].min_voltage = tmp;
+
+			/* vreg-max-voltage */
+			rc = of_property_read_u32(supply_node,
+				"qcom,supply-max-voltage", &tmp);
+			if (rc) {
+				pr_err("%s: error reading max volt. rc=%d\n",
+					__func__, rc);
+				goto error;
+			}
+			mp->vreg_config[i].max_voltage = tmp;
+
+			/* enable-load */
+			rc = of_property_read_u32(supply_node,
+				"qcom,supply-enable-load", &tmp);
+			if (rc) {
+				pr_err("%s: error reading enable load. rc=%d\n",
+					__func__, rc);
+				goto error;
+			}
+			mp->vreg_config[i].enable_load = tmp;
+
+			/* disable-load */
+			rc = of_property_read_u32(supply_node,
+				"qcom,supply-disable-load", &tmp);
+			if (rc) {
+				pr_err("%s: error reading disable load. rc=%d\n",
+					__func__, rc);
+				goto error;
+			}
+			mp->vreg_config[i].disable_load = tmp;
+
+			/* pre-sleep */
+			rc = of_property_read_u32(supply_node,
+				"qcom,supply-pre-on-sleep", &tmp);
+			if (rc) {
+				pr_debug("%s: error reading supply pre sleep value. rc=%d\n",
+					__func__, rc);
+			}
+			mp->vreg_config[i].pre_on_sleep = (!rc ? tmp : 0);
+
+			rc = of_property_read_u32(supply_node,
+				"qcom,supply-pre-off-sleep", &tmp);
+			if (rc) {
+				pr_debug("%s: error reading supply pre sleep value. rc=%d\n",
+					__func__, rc);
+			}
+			mp->vreg_config[i].pre_off_sleep = (!rc ? tmp : 0);
+
+			/* post-sleep */
+			rc = of_property_read_u32(supply_node,
+				"qcom,supply-post-on-sleep", &tmp);
+			if (rc) {
+				pr_debug("%s: error reading supply post sleep value. rc=%d\n",
+					__func__, rc);
+			}
+			mp->vreg_config[i].post_on_sleep = (!rc ? tmp : 0);
+
+			rc = of_property_read_u32(supply_node,
+				"qcom,supply-post-off-sleep", &tmp);
+			if (rc) {
+				pr_debug("%s: error reading supply post sleep value. rc=%d\n",
+					__func__, rc);
+			}
+			mp->vreg_config[i].post_off_sleep = (!rc ? tmp : 0);
+
+			pr_debug("%s: %s min=%d, max=%d, enable=%d, disable=%d, preonsleep=%d, postonsleep=%d, preoffsleep=%d, postoffsleep=%d\n",
+				__func__,
+				mp->vreg_config[i].vreg_name,
+				mp->vreg_config[i].min_voltage,
+				mp->vreg_config[i].max_voltage,
+				mp->vreg_config[i].enable_load,
+				mp->vreg_config[i].disable_load,
+				mp->vreg_config[i].pre_on_sleep,
+				mp->vreg_config[i].post_on_sleep,
+				mp->vreg_config[i].pre_off_sleep,
+				mp->vreg_config[i].post_off_sleep
+				);
+			++i;
+		}
+	}
+
+	return 0;
+
+error:
+	if (mp->vreg_config) {
+		devm_kfree(dev, mp->vreg_config);
+		mp->vreg_config = NULL;
+	}
+novreg:
+	mp->num_vreg = 0;
+
+	return rc;
+}
+
+static int dsi_parse_phy(struct platform_device *pdev,
+				struct mdss_dsi_ctrl_pdata *ctrl_pdata)
+{
+	struct device_node *np = pdev->dev.of_node;
+	int i, len;
+	const char *data;
+	struct mdss_dsi_phy_ctrl *phy_db
+		= &(ctrl_pdata->panel_data.panel_info.mipi.dsi_phy_db);
+
+	data = of_get_property(np, "qcom,platform-regulator-settings", &len);
+	if ((!data) || (len != 6)) {
+		pr_err("%s:%d, Unable to read Phy regulator settings",
+			__func__, __LINE__);
+		return -EINVAL;
+	}
+	for (i = 0; i < len; i++)
+		phy_db->regulator[i] = data[i];
+
+	data = of_get_property(np, "qcom,platform-strength-ctrl", &len);
+	if ((!data) || (len != 2)) {
+		pr_err("%s:%d, Unable to read Phy Strength ctrl settings",
+			__func__, __LINE__);
+		return -EINVAL;
+	}
+	phy_db->strength[0] = data[0];
+	phy_db->strength[1] = data[1];
+
+	data = of_get_property(np, "qcom,platform-bist-ctrl", &len);
+	if ((!data) || (len != 6)) {
+		pr_err("%s:%d, Unable to read Phy Bist Ctrl settings",
+			__func__, __LINE__);
+		return -EINVAL;
+	}
+	for (i = 0; i < len; i++)
+		phy_db->bistctrl[i] = data[i];
+
+	data = of_get_property(np, "qcom,platform-lane-config", &len);
+	if ((!data) || (len != 30)) {
+		pr_err("%s:%d, Unable to read Phy lane configure settings",
+			__func__, __LINE__);
+		return -EINVAL;
+	}
+	for (i = 0; i < len; i++)
+		phy_db->lanecfg[i] = data[i];
+
+	return 0;
+}
+
+int dsi_ctrl_config_init(struct platform_device *pdev,
+				struct mdss_dsi_ctrl_pdata *ctrl_pdata)
+{
+	int rc;
+
+	rc = dsi_parse_vreg(&pdev->dev, &ctrl_pdata->power_data);
+	if (rc) {
+		pr_err("%s:%d unable to get the regulator resources",
+			__func__, __LINE__);
+		return rc;
+	}
+
+	rc = dsi_parse_gpio(pdev, ctrl_pdata);
+	if (rc) {
+		pr_err("fail to parse panel GPIOs\n");
+		return rc;
+	}
+
+	rc = dsi_parse_phy(pdev, ctrl_pdata);
+	if (rc) {
+		pr_err("fail to parse DSI PHY settings\n");
+		return rc;
+	}
+
+	return 0;
+}
 int dsi_panel_device_register_v2(struct platform_device *dev,
-				struct dsi_panel_common_pdata *panel_data,
-				char backlight_ctrl)
+				struct mdss_dsi_ctrl_pdata *ctrl_pdata)
 {
 	struct mipi_panel_info *mipi;
-	struct platform_device *ctrl_pdev;
 	int rc;
 	u8 lanes = 0, bpp;
 	u32 h_period, v_period;
-	static struct mdss_panel_data dsi_panel_data;
+	struct mdss_panel_info *pinfo = &(ctrl_pdata->panel_data.panel_info);
 
-	h_period = ((panel_data->panel_info.lcdc.h_pulse_width)
-			+ (panel_data->panel_info.lcdc.h_back_porch)
-			+ (panel_data->panel_info.xres)
-			+ (panel_data->panel_info.lcdc.h_front_porch));
+	h_period = ((pinfo->lcdc.h_pulse_width)
+			+ (pinfo->lcdc.h_back_porch)
+			+ (pinfo->xres)
+			+ (pinfo->lcdc.h_front_porch));
 
-	v_period = ((panel_data->panel_info.lcdc.v_pulse_width)
-			+ (panel_data->panel_info.lcdc.v_back_porch)
-			+ (panel_data->panel_info.yres)
-			+ (panel_data->panel_info.lcdc.v_front_porch));
+	v_period = ((pinfo->lcdc.v_pulse_width)
+			+ (pinfo->lcdc.v_back_porch)
+			+ (pinfo->yres)
+			+ (pinfo->lcdc.v_front_porch));
 
-	mipi  = &panel_data->panel_info.mipi;
+	mipi  = &pinfo->mipi;
 
-	panel_data->panel_info.type =
+	pinfo->type =
 		((mipi->mode == DSI_VIDEO_MODE)
 			? MIPI_VIDEO_PANEL : MIPI_CMD_PANEL);
 
@@ -189,7 +540,6 @@
 	if (mipi->data_lane0)
 		lanes += 1;
 
-
 	if ((mipi->dst_format == DSI_CMD_DST_FORMAT_RGB888)
 		|| (mipi->dst_format == DSI_VIDEO_DST_FORMAT_RGB888)
 		|| (mipi->dst_format == DSI_VIDEO_DST_FORMAT_RGB666_LOOSE))
@@ -200,39 +550,38 @@
 	else
 		bpp = 3; /* Default format set to RGB888 */
 
-	if (panel_data->panel_info.type == MIPI_VIDEO_PANEL &&
-		!panel_data->panel_info.clk_rate) {
-		h_period += panel_data->panel_info.lcdc.xres_pad;
-		v_period += panel_data->panel_info.lcdc.yres_pad;
+	if (pinfo->type == MIPI_VIDEO_PANEL &&
+		!pinfo->clk_rate) {
+		h_period += pinfo->lcdc.xres_pad;
+		v_period += pinfo->lcdc.yres_pad;
 
 		if (lanes > 0) {
-			panel_data->panel_info.clk_rate =
+			pinfo->clk_rate =
 			((h_period * v_period * (mipi->frame_rate) * bpp * 8)
 			   / lanes);
 		} else {
 			pr_err("%s: forcing mdss_dsi lanes to 1\n", __func__);
-			panel_data->panel_info.clk_rate =
+			pinfo->clk_rate =
 				(h_period * v_period
 					 * (mipi->frame_rate) * bpp * 8);
 		}
 	}
 
-	ctrl_pdev = get_dsi_platform_device(dev);
-	if (!ctrl_pdev)
-		return -EPROBE_DEFER;
+	ctrl_pdata->panel_data.event_handler = dsi_event_handler;
 
-	dsi_panel_data.event_handler = dsi_event_handler;
+	rc = dsi_buf_alloc(&dsi_panel_tx_buf,
+				ALIGN(DSI_BUF_SIZE,
+				SZ_4K));
+	if (rc)
+		return rc;
 
-	dsi_panel_data.panel_info = panel_data->panel_info;
-
-	dsi_panel_data.set_backlight = panel_data->bl_fnc;
-	panel_common_data = panel_data;
 	/*
 	 * register in mdp driver
 	 */
-	rc = mdss_register_panel(ctrl_pdev, &dsi_panel_data);
+	rc = mdss_register_panel(dev, &(ctrl_pdata->panel_data));
 	if (rc) {
 		dev_err(&dev->dev, "unable to register MIPI DSI panel\n");
+		kfree(dsi_panel_tx_buf.start);
 		return rc;
 	}
 
@@ -340,15 +689,16 @@
 	char *bp;
 	u32 *hp;
 	int i, len;
+	struct dsi_ctrl_hdr *dchdr = &cm->dchdr;
 
 	bp = dsi_buf_reserve_hdr(dp, DSI_HOST_HDR_SIZE);
 
 	/* fill up payload */
 	if (cm->payload) {
-		len = cm->dlen;
+		len = dchdr->dlen;
 		len += 3;
 		len &= ~0x03; /* multipled by 4 */
-		for (i = 0; i < cm->dlen; i++)
+		for (i = 0; i < dchdr->dlen; i++)
 			*bp++ = cm->payload[i];
 
 		/* append 0xff to the end */
@@ -361,11 +711,11 @@
 	/* fill up header */
 	hp = dp->hdr;
 	*hp = 0;
-	*hp = DSI_HDR_WC(cm->dlen);
-	*hp |= DSI_HDR_VC(cm->vc);
+	*hp = DSI_HDR_WC(dchdr->dlen);
+	*hp |= DSI_HDR_VC(dchdr->vc);
 	*hp |= DSI_HDR_LONG_PKT;
 	*hp |= DSI_HDR_DTYPE(DTYPE_GEN_LWRITE);
-	if (cm->last)
+	if (dchdr->last)
 		*hp |= DSI_HDR_LAST;
 
 	dsi_buf_push(dp, DSI_HOST_HDR_SIZE);
@@ -380,8 +730,9 @@
 {
 	u32 *hp;
 	int len;
+	struct dsi_ctrl_hdr *dchdr = &cm->dchdr;
 
-	if (cm->dlen && cm->payload == 0) {
+	if (dchdr->dlen && cm->payload == 0) {
 		pr_err("%s: NO payload error\n", __func__);
 		return 0;
 	}
@@ -389,11 +740,11 @@
 	dsi_buf_reserve_hdr(dp, DSI_HOST_HDR_SIZE);
 	hp = dp->hdr;
 	*hp = 0;
-	*hp |= DSI_HDR_VC(cm->vc);
-	if (cm->last)
+	*hp |= DSI_HDR_VC(dchdr->vc);
+	if (dchdr->last)
 		*hp |= DSI_HDR_LAST;
 
-	len = (cm->dlen > 2) ? 2 : cm->dlen;
+	len = (dchdr->dlen > 2) ? 2 : dchdr->dlen;
 
 	if (len == 1) {
 		*hp |= DSI_HDR_DTYPE(DTYPE_GEN_WRITE1);
@@ -421,8 +772,9 @@
 {
 	u32 *hp;
 	int len;
+	struct dsi_ctrl_hdr *dchdr = &cm->dchdr;
 
-	if (cm->dlen && cm->payload == 0) {
+	if (dchdr->dlen && cm->payload == 0) {
 		pr_err("%s: NO payload error\n", __func__);
 		return 0;
 	}
@@ -430,12 +782,12 @@
 	dsi_buf_reserve_hdr(dp, DSI_HOST_HDR_SIZE);
 	hp = dp->hdr;
 	*hp = 0;
-	*hp |= DSI_HDR_VC(cm->vc);
+	*hp |= DSI_HDR_VC(dchdr->vc);
 	*hp |= DSI_HDR_BTA;
-	if (cm->last)
+	if (dchdr->last)
 		*hp |= DSI_HDR_LAST;
 
-	len = (cm->dlen > 2) ? 2 : cm->dlen;
+	len = (dchdr->dlen > 2) ? 2 : dchdr->dlen;
 
 	if (len == 1) {
 		*hp |= DSI_HDR_DTYPE(DTYPE_GEN_READ1);
@@ -463,6 +815,7 @@
 	char *bp;
 	u32 *hp;
 	int i, len;
+	struct dsi_ctrl_hdr *dchdr = &cm->dchdr;
 
 	bp = dsi_buf_reserve_hdr(dp, DSI_HOST_HDR_SIZE);
 
@@ -471,10 +824,10 @@
 	 * dcs command byte (first byte) followed by payload
 	 */
 	if (cm->payload) {
-		len = cm->dlen;
+		len = dchdr->dlen;
 		len += 3;
 		len &= ~0x03; /* multipled by 4 */
-		for (i = 0; i < cm->dlen; i++)
+		for (i = 0; i < dchdr->dlen; i++)
 			*bp++ = cm->payload[i];
 
 		/* append 0xff to the end */
@@ -487,11 +840,11 @@
 	/* fill up header */
 	hp = dp->hdr;
 	*hp = 0;
-	*hp = DSI_HDR_WC(cm->dlen);
-	*hp |= DSI_HDR_VC(cm->vc);
+	*hp = DSI_HDR_WC(dchdr->dlen);
+	*hp |= DSI_HDR_VC(dchdr->vc);
 	*hp |= DSI_HDR_LONG_PKT;
 	*hp |= DSI_HDR_DTYPE(DTYPE_DCS_LWRITE);
-	if (cm->last)
+	if (dchdr->last)
 		*hp |= DSI_HDR_LAST;
 
 	dsi_buf_push(dp, DSI_HOST_HDR_SIZE);
@@ -506,6 +859,7 @@
 {
 	u32 *hp;
 	int len;
+	struct dsi_ctrl_hdr *dchdr = &cm->dchdr;
 
 	if (cm->payload == 0) {
 		pr_err("%s: NO payload error\n", __func__);
@@ -515,13 +869,13 @@
 	dsi_buf_reserve_hdr(dp, DSI_HOST_HDR_SIZE);
 	hp = dp->hdr;
 	*hp = 0;
-	*hp |= DSI_HDR_VC(cm->vc);
-	if (cm->ack)
+	*hp |= DSI_HDR_VC(dchdr->vc);
+	if (dchdr->ack)
 		*hp |= DSI_HDR_BTA;
-	if (cm->last)
+	if (dchdr->last)
 		*hp |= DSI_HDR_LAST;
 
-	len = (cm->dlen > 1) ? 1 : cm->dlen;
+	len = (dchdr->dlen > 1) ? 1 : dchdr->dlen;
 
 	*hp |= DSI_HDR_DTYPE(DTYPE_DCS_WRITE);
 	*hp |= DSI_HDR_DATA1(cm->payload[0]); /* dcs command byte */
@@ -537,8 +891,9 @@
 static int dsi_dcs_swrite1(struct dsi_buf *dp, struct dsi_cmd_desc *cm)
 {
 	u32 *hp;
+	struct dsi_ctrl_hdr *dchdr = &cm->dchdr;
 
-	if (cm->dlen < 2 || cm->payload == 0) {
+	if (dchdr->dlen < 2 || cm->payload == 0) {
 		pr_err("%s: NO payload error\n", __func__);
 		return -EINVAL;
 	}
@@ -546,10 +901,10 @@
 	dsi_buf_reserve_hdr(dp, DSI_HOST_HDR_SIZE);
 	hp = dp->hdr;
 	*hp = 0;
-	*hp |= DSI_HDR_VC(cm->vc);
-	if (cm->ack)
+	*hp |= DSI_HDR_VC(dchdr->vc);
+	if (dchdr->ack)
 		*hp |= DSI_HDR_BTA;
-	if (cm->last)
+	if (dchdr->last)
 		*hp |= DSI_HDR_LAST;
 
 	*hp |= DSI_HDR_DTYPE(DTYPE_DCS_WRITE1);
@@ -567,6 +922,7 @@
 static int dsi_dcs_read(struct dsi_buf *dp, struct dsi_cmd_desc *cm)
 {
 	u32 *hp;
+	struct dsi_ctrl_hdr *dchdr = &cm->dchdr;
 
 	if (cm->payload == 0) {
 		pr_err("%s: NO payload error\n", __func__);
@@ -576,10 +932,10 @@
 	dsi_buf_reserve_hdr(dp, DSI_HOST_HDR_SIZE);
 	hp = dp->hdr;
 	*hp = 0;
-	*hp |= DSI_HDR_VC(cm->vc);
+	*hp |= DSI_HDR_VC(dchdr->vc);
 	*hp |= DSI_HDR_BTA;
 	*hp |= DSI_HDR_DTYPE(DTYPE_DCS_READ);
-	if (cm->last)
+	if (dchdr->last)
 		*hp |= DSI_HDR_LAST;
 
 	*hp |= DSI_HDR_DATA1(cm->payload[0]); /* dcs command byte */
@@ -593,13 +949,14 @@
 static int dsi_cm_on(struct dsi_buf *dp, struct dsi_cmd_desc *cm)
 {
 	u32 *hp;
+	struct dsi_ctrl_hdr *dchdr = &cm->dchdr;
 
 	dsi_buf_reserve_hdr(dp, DSI_HOST_HDR_SIZE);
 	hp = dp->hdr;
 	*hp = 0;
-	*hp |= DSI_HDR_VC(cm->vc);
+	*hp |= DSI_HDR_VC(dchdr->vc);
 	*hp |= DSI_HDR_DTYPE(DTYPE_CM_ON);
-	if (cm->last)
+	if (dchdr->last)
 		*hp |= DSI_HDR_LAST;
 
 	dsi_buf_push(dp, DSI_HOST_HDR_SIZE);
@@ -610,13 +967,14 @@
 static int dsi_cm_off(struct dsi_buf *dp, struct dsi_cmd_desc *cm)
 {
 	u32 *hp;
+	struct dsi_ctrl_hdr *dchdr = &cm->dchdr;
 
 	dsi_buf_reserve_hdr(dp, DSI_HOST_HDR_SIZE);
 	hp = dp->hdr;
 	*hp = 0;
-	*hp |= DSI_HDR_VC(cm->vc);
+	*hp |= DSI_HDR_VC(dchdr->vc);
 	*hp |= DSI_HDR_DTYPE(DTYPE_CM_OFF);
-	if (cm->last)
+	if (dchdr->last)
 		*hp |= DSI_HDR_LAST;
 
 	dsi_buf_push(dp, DSI_HOST_HDR_SIZE);
@@ -627,13 +985,14 @@
 static int dsi_peripheral_on(struct dsi_buf *dp, struct dsi_cmd_desc *cm)
 {
 	u32 *hp;
+	struct dsi_ctrl_hdr *dchdr = &cm->dchdr;
 
 	dsi_buf_reserve_hdr(dp, DSI_HOST_HDR_SIZE);
 	hp = dp->hdr;
 	*hp = 0;
-	*hp |= DSI_HDR_VC(cm->vc);
+	*hp |= DSI_HDR_VC(dchdr->vc);
 	*hp |= DSI_HDR_DTYPE(DTYPE_PERIPHERAL_ON);
-	if (cm->last)
+	if (dchdr->last)
 		*hp |= DSI_HDR_LAST;
 
 	dsi_buf_push(dp, DSI_HOST_HDR_SIZE);
@@ -644,13 +1003,14 @@
 static int dsi_peripheral_off(struct dsi_buf *dp, struct dsi_cmd_desc *cm)
 {
 	u32 *hp;
+	struct dsi_ctrl_hdr *dchdr = &cm->dchdr;
 
 	dsi_buf_reserve_hdr(dp, DSI_HOST_HDR_SIZE);
 	hp = dp->hdr;
 	*hp = 0;
-	*hp |= DSI_HDR_VC(cm->vc);
+	*hp |= DSI_HDR_VC(dchdr->vc);
 	*hp |= DSI_HDR_DTYPE(DTYPE_PERIPHERAL_OFF);
-	if (cm->last)
+	if (dchdr->last)
 		*hp |= DSI_HDR_LAST;
 
 	dsi_buf_push(dp, DSI_HOST_HDR_SIZE);
@@ -661,6 +1021,7 @@
 static int dsi_set_max_pktsize(struct dsi_buf *dp, struct dsi_cmd_desc *cm)
 {
 	u32 *hp;
+	struct dsi_ctrl_hdr *dchdr = &cm->dchdr;
 
 	if (cm->payload == 0) {
 		pr_err("%s: NO payload error\n", __func__);
@@ -670,9 +1031,9 @@
 	dsi_buf_reserve_hdr(dp, DSI_HOST_HDR_SIZE);
 	hp = dp->hdr;
 	*hp = 0;
-	*hp |= DSI_HDR_VC(cm->vc);
+	*hp |= DSI_HDR_VC(dchdr->vc);
 	*hp |= DSI_HDR_DTYPE(DTYPE_MAX_PKTSIZE);
-	if (cm->last)
+	if (dchdr->last)
 		*hp |= DSI_HDR_LAST;
 
 	*hp |= DSI_HDR_DATA1(cm->payload[0]);
@@ -686,15 +1047,16 @@
 static int dsi_null_pkt(struct dsi_buf *dp, struct dsi_cmd_desc *cm)
 {
 	u32 *hp;
+	struct dsi_ctrl_hdr *dchdr = &cm->dchdr;
 
 	dsi_buf_reserve_hdr(dp, DSI_HOST_HDR_SIZE);
 	hp = dp->hdr;
 	*hp = 0;
-	*hp = DSI_HDR_WC(cm->dlen);
+	*hp = DSI_HDR_WC(dchdr->dlen);
 	*hp |= DSI_HDR_LONG_PKT;
-	*hp |= DSI_HDR_VC(cm->vc);
+	*hp |= DSI_HDR_VC(dchdr->vc);
 	*hp |= DSI_HDR_DTYPE(DTYPE_NULL_PKT);
-	if (cm->last)
+	if (dchdr->last)
 		*hp |= DSI_HDR_LAST;
 
 	dsi_buf_push(dp, DSI_HOST_HDR_SIZE);
@@ -705,15 +1067,16 @@
 static int dsi_blank_pkt(struct dsi_buf *dp, struct dsi_cmd_desc *cm)
 {
 	u32 *hp;
+	struct dsi_ctrl_hdr *dchdr = &cm->dchdr;
 
 	dsi_buf_reserve_hdr(dp, DSI_HOST_HDR_SIZE);
 	hp = dp->hdr;
 	*hp = 0;
-	*hp = DSI_HDR_WC(cm->dlen);
+	*hp = DSI_HDR_WC(dchdr->dlen);
 	*hp |= DSI_HDR_LONG_PKT;
-	*hp |= DSI_HDR_VC(cm->vc);
+	*hp |= DSI_HDR_VC(dchdr->vc);
 	*hp |= DSI_HDR_DTYPE(DTYPE_BLANK_PKT);
-	if (cm->last)
+	if (dchdr->last)
 		*hp |= DSI_HDR_LAST;
 
 	dsi_buf_push(dp, DSI_HOST_HDR_SIZE);
@@ -727,8 +1090,9 @@
 int dsi_cmd_dma_add(struct dsi_buf *dp, struct dsi_cmd_desc *cm)
 {
 	int len = 0;
+	struct dsi_ctrl_hdr *dchdr = &cm->dchdr;
 
-	switch (cm->dtype) {
+	switch (dchdr->dtype) {
 	case DTYPE_GEN_WRITE:
 	case DTYPE_GEN_WRITE1:
 	case DTYPE_GEN_WRITE2:
@@ -777,7 +1141,7 @@
 		break;
 	default:
 		pr_debug("%s: dtype=%x NOT supported\n",
-					__func__, cm->dtype);
+					__func__, dchdr->dtype);
 		break;
 
 	}
diff --git a/drivers/video/msm/mdss/dsi_v2.h b/drivers/video/msm/mdss/dsi_v2.h
index 96dd390..a554856 100644
--- a/drivers/video/msm/mdss/dsi_v2.h
+++ b/drivers/video/msm/mdss/dsi_v2.h
@@ -11,190 +11,18 @@
  *
  */
 
-#ifndef MDSS_DSI_H
-#define MDSS_DSI_H
+#ifndef DSI_V2_H
+#define DSI_V2_H
 
 #include <linux/list.h>
 #include <mach/scm-io.h>
 
+#include "mdss_dsi.h"
 #include "mdss_panel.h"
 
-#define MIPI_OUTP(addr, data) writel_relaxed((data), (addr))
-#define MIPI_INP(addr) readl_relaxed(addr)
-
-#define MIPI_DSI_PRIM 1
-#define MIPI_DSI_SECD 2
-
-#define MIPI_DSI_PANEL_VGA	0
-#define MIPI_DSI_PANEL_WVGA	1
-#define MIPI_DSI_PANEL_WVGA_PT	2
-#define MIPI_DSI_PANEL_FWVGA_PT	3
-#define MIPI_DSI_PANEL_WSVGA_PT	4
-#define MIPI_DSI_PANEL_QHD_PT 5
-#define MIPI_DSI_PANEL_WXGA	6
-#define MIPI_DSI_PANEL_WUXGA	7
-#define MIPI_DSI_PANEL_720P_PT	8
-#define DSI_PANEL_MAX	8
-
-enum {
-	DSI_VIDEO_MODE,
-	DSI_CMD_MODE,
-};
-
-enum {
-	ST_DSI_CLK_OFF,
-	ST_DSI_SUSPEND,
-	ST_DSI_RESUME,
-	ST_DSI_PLAYING,
-	ST_DSI_NUM
-};
-
-enum {
-	EV_DSI_UPDATE,
-	EV_DSI_DONE,
-	EV_DSI_TOUT,
-	EV_DSI_NUM
-};
-
-enum {
-	LANDSCAPE = 1,
-	PORTRAIT = 2,
-};
-
-enum {
-	DSI_CMD_MODE_DMA,
-	DSI_CMD_MODE_MDP,
-};
-
-enum {
-	BL_PWM,
-	BL_WLED,
-	BL_DCS_CMD,
-	UNKNOWN_CTRL,
-};
-
-enum {
-	DSI_LP_MODE,
-	DSI_HS_MODE,
-};
-
-#define DSI_NON_BURST_SYNCH_PULSE	0
-#define DSI_NON_BURST_SYNCH_EVENT	1
-#define DSI_BURST_MODE			2
-
-#define DSI_RGB_SWAP_RGB	0
-#define DSI_RGB_SWAP_RBG	1
-#define DSI_RGB_SWAP_BGR	2
-#define DSI_RGB_SWAP_BRG	3
-#define DSI_RGB_SWAP_GRB	4
-#define DSI_RGB_SWAP_GBR	5
-
-#define DSI_VIDEO_DST_FORMAT_RGB565		0
-#define DSI_VIDEO_DST_FORMAT_RGB666		1
-#define DSI_VIDEO_DST_FORMAT_RGB666_LOOSE	2
-#define DSI_VIDEO_DST_FORMAT_RGB888		3
-
-#define DSI_CMD_DST_FORMAT_RGB111	0
-#define DSI_CMD_DST_FORMAT_RGB332	3
-#define DSI_CMD_DST_FORMAT_RGB444	4
-#define DSI_CMD_DST_FORMAT_RGB565	6
-#define DSI_CMD_DST_FORMAT_RGB666	7
-#define DSI_CMD_DST_FORMAT_RGB888	8
-
-#define DSI_CMD_TRIGGER_NONE		0x0	/* mdp trigger */
-#define DSI_CMD_TRIGGER_TE		0x02
-#define DSI_CMD_TRIGGER_SW		0x04
-#define DSI_CMD_TRIGGER_SW_SEOF		0x05	/* cmd dma only */
-#define DSI_CMD_TRIGGER_SW_TE		0x06
-
-#define DSI_HOST_HDR_SIZE	4
-#define DSI_HDR_LAST		BIT(31)
-#define DSI_HDR_LONG_PKT	BIT(30)
-#define DSI_HDR_BTA		BIT(29)
-#define DSI_HDR_VC(vc)		(((vc) & 0x03) << 22)
-#define DSI_HDR_DTYPE(dtype)	(((dtype) & 0x03f) << 16)
-#define DSI_HDR_DATA2(data)	(((data) & 0x0ff) << 8)
-#define DSI_HDR_DATA1(data)	((data) & 0x0ff)
-#define DSI_HDR_WC(wc)		((wc) & 0x0ffff)
-
 #define DSI_BUF_SIZE	1024
 #define DSI_MRPS	0x04  /* Maximum Return Packet Size */
 
-#define DSI_LEN 8 /* 4 x 4 - 6 - 2, bytes dcs header+crc-align  */
-
-struct dsi_buf {
-	u32 *hdr;	/* dsi host header */
-	char *start;	/* buffer start addr */
-	char *end;	/* buffer end addr */
-	int size;	/* size of buffer */
-	char *data;	/* buffer */
-	int len;	/* data length */
-	dma_addr_t dmap; /* mapped dma addr */
-};
-
-/* dcs read/write */
-#define DTYPE_DCS_WRITE		0x05	/* short write, 0 parameter */
-#define DTYPE_DCS_WRITE1	0x15	/* short write, 1 parameter */
-#define DTYPE_DCS_READ		0x06	/* read */
-#define DTYPE_DCS_LWRITE	0x39	/* long write */
-
-/* generic read/write */
-#define DTYPE_GEN_WRITE		0x03	/* short write, 0 parameter */
-#define DTYPE_GEN_WRITE1	0x13	/* short write, 1 parameter */
-#define DTYPE_GEN_WRITE2	0x23	/* short write, 2 parameter */
-#define DTYPE_GEN_LWRITE	0x29	/* long write */
-#define DTYPE_GEN_READ		0x04	/* long read, 0 parameter */
-#define DTYPE_GEN_READ1		0x14	/* long read, 1 parameter */
-#define DTYPE_GEN_READ2		0x24	/* long read, 2 parameter */
-
-#define DTYPE_TEAR_ON		0x35	/* set tear on */
-#define DTYPE_MAX_PKTSIZE	0x37	/* set max packet size */
-#define DTYPE_NULL_PKT		0x09	/* null packet, no data */
-#define DTYPE_BLANK_PKT		0x19	/* blankiing packet, no data */
-
-#define DTYPE_CM_ON		0x02	/* color mode off */
-#define DTYPE_CM_OFF		0x12	/* color mode on */
-#define DTYPE_PERIPHERAL_OFF	0x22
-#define DTYPE_PERIPHERAL_ON	0x32
-
-/*
- * dcs response
- */
-#define DTYPE_ACK_ERR_RESP      0x02
-#define DTYPE_EOT_RESP          0x08    /* end of tx */
-#define DTYPE_GEN_READ1_RESP    0x11    /* 1 parameter, short */
-#define DTYPE_GEN_READ2_RESP    0x12    /* 2 parameter, short */
-#define DTYPE_GEN_LREAD_RESP    0x1a
-#define DTYPE_DCS_LREAD_RESP    0x1c
-#define DTYPE_DCS_READ1_RESP    0x21    /* 1 parameter, short */
-#define DTYPE_DCS_READ2_RESP    0x22    /* 2 parameter, short */
-
-struct dsi_cmd_desc {
-	int dtype;
-	int last;
-	int vc;
-	int ack;	/* ask ACK from peripheral */
-	int wait;
-	int dlen;
-	char *payload;
-};
-
-struct dsi_panel_cmds_list {
-	struct dsi_cmd_desc *buf;
-	int size;
-	char ctrl_state;
-};
-
-struct dsi_panel_common_pdata {
-	struct mdss_panel_info panel_info;
-	int (*on) (struct mdss_panel_data *pdata);
-	int (*off) (struct mdss_panel_data *pdata);
-	void (*reset)(struct mdss_panel_data *pdata, int enable);
-	void (*bl_fnc) (struct mdss_panel_data *pdata, u32 bl_level);
-	struct dsi_panel_cmds_list *dsi_panel_on_cmds;
-	struct dsi_panel_cmds_list *dsi_panel_off_cmds;
-};
-
 struct dsi_interface {
 	int (*on)(struct mdss_panel_data *pdata);
 	int (*off)(struct mdss_panel_data *pdata);
@@ -210,8 +38,7 @@
 };
 
 int dsi_panel_device_register_v2(struct platform_device *pdev,
-				struct dsi_panel_common_pdata *panel_data,
-				char bl_ctrl);
+				struct mdss_dsi_ctrl_pdata *ctrl_pdata);
 
 void dsi_register_interface(struct dsi_interface *intf);
 
@@ -235,4 +62,16 @@
 
 int dsi_long_read_resp(struct dsi_buf *rp);
 
-#endif /* MDSS_DSI_H */
+void dsi_set_tx_power_mode(int mode);
+
+void dsi_ctrl_config_deinit(struct platform_device *pdev,
+				struct mdss_dsi_ctrl_pdata *ctrl_pdata);
+
+int dsi_ctrl_config_init(struct platform_device *pdev,
+				struct mdss_dsi_ctrl_pdata *ctrl_pdata);
+
+struct mdss_panel_cfg *mdp3_panel_intf_type(int intf_val);
+
+int mdp3_panel_get_boot_cfg(void);
+
+#endif /* DSI_V2_H */
diff --git a/drivers/video/msm/mdss/mdp3.c b/drivers/video/msm/mdss/mdp3.c
index f6f722e..8a5f1ee 100644
--- a/drivers/video/msm/mdss/mdp3.c
+++ b/drivers/video/msm/mdss/mdp3.c
@@ -15,6 +15,7 @@
 
 #include <linux/clk.h>
 #include <linux/debugfs.h>
+#include <linux/dma-buf.h>
 #include <linux/kernel.h>
 #include <linux/init.h>
 #include <linux/interrupt.h>
@@ -49,6 +50,7 @@
 #include "mdp3_hwio.h"
 #include "mdp3_ctrl.h"
 #include "mdp3_ppp.h"
+#include "mdss_debug.h"
 
 #define MDP_CORE_HW_VERSION	0x03040310
 struct mdp3_hw_resource *mdp3_res;
@@ -91,6 +93,10 @@
 static struct msm_bus_paths
 	mdp_bus_ppp_usecases[ARRAY_SIZE(mdp_bus_ppp_vectors)];
 
+static struct mdss_panel_intf pan_types[] = {
+	{"dsi", MDSS_PANEL_INTF_DSI},
+};
+
 static struct msm_bus_scale_pdata mdp_bus_ppp_scale_table = {
 	.usecase = mdp_bus_ppp_usecases,
 	.num_usecases = ARRAY_SIZE(mdp_bus_ppp_usecases),
@@ -115,8 +121,19 @@
 };
 
 struct mdp3_iommu_domain_map mdp3_iommu_domains[MDP3_IOMMU_DOMAIN_MAX] = {
-	[MDP3_IOMMU_DOMAIN] = {
-		.domain_type = MDP3_IOMMU_DOMAIN,
+	[MDP3_PPP_IOMMU_DOMAIN] = {
+		.domain_type = MDP3_PPP_IOMMU_DOMAIN,
+		.client_name = "mdp_ppp",
+		.partitions = {
+			{
+				.start = SZ_128K,
+				.size = SZ_1G - SZ_128K,
+			},
+		},
+		.npartitions = 1,
+	},
+	[MDP3_DMA_IOMMU_DOMAIN] = {
+		.domain_type = MDP3_DMA_IOMMU_DOMAIN,
 		.client_name = "mdp_dma",
 		.partitions = {
 			{
@@ -131,27 +148,27 @@
 struct mdp3_iommu_ctx_map mdp3_iommu_contexts[MDP3_IOMMU_CTX_MAX] = {
 	[MDP3_IOMMU_CTX_PPP_0] = {
 		.ctx_type = MDP3_IOMMU_CTX_PPP_0,
-		.domain = &mdp3_iommu_domains[MDP3_IOMMU_DOMAIN],
+		.domain = &mdp3_iommu_domains[MDP3_PPP_IOMMU_DOMAIN],
 		.ctx_name = "mdpe_0",
 		.attached = 0,
 	},
 	[MDP3_IOMMU_CTX_PPP_1] = {
 		.ctx_type = MDP3_IOMMU_CTX_PPP_1,
-		.domain = &mdp3_iommu_domains[MDP3_IOMMU_DOMAIN],
+		.domain = &mdp3_iommu_domains[MDP3_PPP_IOMMU_DOMAIN],
 		.ctx_name = "mdpe_1",
 		.attached = 0,
 	},
 
 	[MDP3_IOMMU_CTX_DMA_0] = {
 		.ctx_type = MDP3_IOMMU_CTX_DMA_0,
-		.domain = &mdp3_iommu_domains[MDP3_IOMMU_DOMAIN],
+		.domain = &mdp3_iommu_domains[MDP3_DMA_IOMMU_DOMAIN],
 		.ctx_name = "mdps_0",
 		.attached = 0,
 	},
 
 	[MDP3_IOMMU_CTX_DMA_1] = {
 		.ctx_type = MDP3_IOMMU_CTX_DMA_1,
-		.domain = &mdp3_iommu_domains[MDP3_IOMMU_DOMAIN],
+		.domain = &mdp3_iommu_domains[MDP3_DMA_IOMMU_DOMAIN],
 		.ctx_name = "mdps_1",
 		.attached = 0,
 	},
@@ -378,7 +395,7 @@
 
 static int mdp3_clk_update(u32 clk_idx, u32 enable)
 {
-	int ret = -EINVAL;
+	int ret = 0;
 	struct clk *clk;
 	int count = 0;
 
@@ -680,6 +697,8 @@
 {
 	int ret;
 
+	mutex_init(&mdp3_res->iommu_lock);
+
 	ret = mdp3_iommu_domain_init();
 	if (ret) {
 		pr_err("mdp3 iommu domain init fails\n");
@@ -806,9 +825,191 @@
 		devm_free_irq(&mdp3_res->pdev->dev, mdp3_res->irq, mdp3_res);
 }
 
+static int mdp3_get_pan_intf(const char *pan_intf)
+{
+	int i, rc = MDSS_PANEL_INTF_INVALID;
+
+	if (!pan_intf)
+		return rc;
+
+	for (i = 0; i < ARRAY_SIZE(pan_types); i++) {
+		if (!strncmp(pan_intf, pan_types[i].name,
+				strlen(pan_types[i].name))) {
+			rc = pan_types[i].type;
+			break;
+		}
+	}
+
+	return rc;
+}
+
+static int mdp3_parse_dt_pan_intf(struct platform_device *pdev)
+{
+	int rc;
+	struct mdp3_hw_resource *mdata = platform_get_drvdata(pdev);
+	const char *prim_intf = NULL;
+
+	rc = of_property_read_string(pdev->dev.of_node,
+				"qcom,mdss-pref-prim-intf", &prim_intf);
+	if (rc)
+		return -ENODEV;
+
+	rc = mdp3_get_pan_intf(prim_intf);
+	if (rc < 0) {
+		mdata->pan_cfg.pan_intf = MDSS_PANEL_INTF_INVALID;
+	} else {
+		mdata->pan_cfg.pan_intf = rc;
+		rc = 0;
+	}
+	return rc;
+}
+
+static int mdp3_get_pan_cfg(struct mdss_panel_cfg *pan_cfg)
+{
+	char *t = NULL;
+	char pan_intf_str[MDSS_MAX_PANEL_LEN];
+	int rc, i;
+	char pan_name[MDSS_MAX_PANEL_LEN];
+
+	if (!pan_cfg)
+		return -EINVAL;
+
+	strlcpy(pan_name, &pan_cfg->arg_cfg[0], sizeof(pan_cfg->arg_cfg));
+	if (pan_name[0] == '0') {
+		pan_cfg->lk_cfg = false;
+	} else if (pan_name[0] == '1') {
+		pan_cfg->lk_cfg = true;
+	} else {
+		/* read from dt */
+		pan_cfg->lk_cfg = true;
+		pan_cfg->pan_intf = MDSS_PANEL_INTF_INVALID;
+		return -EINVAL;
+	}
+
+	/* skip lk cfg and delimiter; ex: "0:" */
+	strlcpy(pan_name, &pan_name[2], MDSS_MAX_PANEL_LEN);
+	t = strnstr(pan_name, ":", MDSS_MAX_PANEL_LEN);
+	if (!t) {
+		pr_err("%s: pan_name=[%s] invalid\n",
+			__func__, pan_name);
+		pan_cfg->pan_intf = MDSS_PANEL_INTF_INVALID;
+		return -EINVAL;
+	}
+
+	for (i = 0; ((pan_name + i) < t) && (i < 4); i++)
+		pan_intf_str[i] = *(pan_name + i);
+	pan_intf_str[i] = 0;
+	pr_debug("%s:%d panel intf %s\n", __func__, __LINE__, pan_intf_str);
+	/* point to the start of panel name */
+	t = t + 1;
+	strlcpy(&pan_cfg->arg_cfg[0], t, sizeof(pan_cfg->arg_cfg));
+	pr_debug("%s:%d: t=[%s] panel name=[%s]\n", __func__, __LINE__,
+		t, pan_cfg->arg_cfg);
+	rc = mdp3_get_pan_intf(pan_intf_str);
+	pan_cfg->pan_intf = (rc < 0) ?  MDSS_PANEL_INTF_INVALID : rc;
+	return 0;
+}
+
+static int mdp3_parse_bootarg(struct platform_device *pdev)
+{
+	struct device_node *chosen_node;
+	static const char *cmd_line;
+	char *disp_idx, *end_idx;
+	int rc, len = 0, name_len, cmd_len;
+	int *intf_type;
+	char *panel_name;
+	struct mdss_panel_cfg *pan_cfg;
+	struct mdp3_hw_resource *mdata = platform_get_drvdata(pdev);
+
+	mdata->pan_cfg.arg_cfg[MDSS_MAX_PANEL_LEN] = 0;
+	pan_cfg = &mdata->pan_cfg;
+	panel_name = &pan_cfg->arg_cfg[0];
+	intf_type = &pan_cfg->pan_intf;
+
+	/* reads from dt by default */
+	pan_cfg->lk_cfg = true;
+
+	chosen_node = of_find_node_by_name(NULL, "chosen");
+	if (!chosen_node) {
+		pr_err("%s: get chosen node failed\n", __func__);
+		rc = -ENODEV;
+		goto get_dt_pan;
+	}
+
+	cmd_line = of_get_property(chosen_node, "bootargs", &len);
+	if (!cmd_line || len <= 0) {
+		pr_err("%s: get bootargs failed\n", __func__);
+		rc = -ENODEV;
+		goto get_dt_pan;
+	}
+
+	name_len = strlen("mdss_mdp.panel=");
+	cmd_len = strlen(cmd_line);
+	disp_idx = strnstr(cmd_line, "mdss_mdp.panel=", cmd_len);
+	if (!disp_idx) {
+		pr_err("%s:%d:cmdline panel not set disp_idx=[%p]\n",
+				__func__, __LINE__, disp_idx);
+		memset(panel_name, 0x00, MDSS_MAX_PANEL_LEN);
+		*intf_type = MDSS_PANEL_INTF_INVALID;
+		rc = MDSS_PANEL_INTF_INVALID;
+		goto get_dt_pan;
+	}
+
+	disp_idx += name_len;
+
+	end_idx = strnstr(disp_idx, " ", MDSS_MAX_PANEL_LEN);
+	pr_debug("%s:%d: pan_name=[%s] end=[%s]\n", __func__, __LINE__,
+		 disp_idx, end_idx);
+	if (!end_idx) {
+		end_idx = disp_idx + strlen(disp_idx) + 1;
+		pr_warn("%s:%d: pan_name=[%s] end=[%s]\n", __func__,
+		       __LINE__, disp_idx, end_idx);
+	}
+
+	if (end_idx <= disp_idx) {
+		pr_err("%s:%d:cmdline pan incorrect end=[%p] disp=[%p]\n",
+			__func__, __LINE__, end_idx, disp_idx);
+		memset(panel_name, 0x00, MDSS_MAX_PANEL_LEN);
+		*intf_type = MDSS_PANEL_INTF_INVALID;
+		rc = MDSS_PANEL_INTF_INVALID;
+		goto get_dt_pan;
+	}
+
+	*end_idx = 0;
+	len = end_idx - disp_idx + 1;
+	if (len <= 0) {
+		pr_warn("%s: panel name not rx", __func__);
+		rc = -EINVAL;
+		goto get_dt_pan;
+	}
+
+	strlcpy(panel_name, disp_idx, min(++len, MDSS_MAX_PANEL_LEN));
+	pr_debug("%s:%d panel:[%s]", __func__, __LINE__, panel_name);
+	of_node_put(chosen_node);
+
+	rc = mdp3_get_pan_cfg(pan_cfg);
+	if (!rc)
+		pan_cfg->init_done = true;
+
+	return rc;
+
+get_dt_pan:
+	rc = mdp3_parse_dt_pan_intf(pdev);
+	/* if pref pan intf is not present */
+	if (rc)
+		pr_err("%s:unable to parse device tree for pan intf\n",
+			__func__);
+	else
+		pan_cfg->init_done = true;
+
+	of_node_put(chosen_node);
+	return rc;
+}
+
 static int mdp3_parse_dt(struct platform_device *pdev)
 {
 	struct resource *res;
+	int rc;
 
 	res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "mdp_phys");
 	if (!res) {
@@ -835,20 +1036,345 @@
 	}
 	mdp3_res->irq = res->start;
 
+	rc = mdp3_parse_bootarg(pdev);
+	if (rc) {
+		pr_err("%s: Error in panel override:rc=[%d]\n",
+		       __func__, rc);
+		return rc;
+	}
+
 	return 0;
 }
 
-int mdp3_put_img(struct mdp3_img_data *data)
+static void mdp3_iommu_heap_unmap_iommu(struct mdp3_iommu_meta *meta)
+{
+	unsigned int domain_num;
+	unsigned int partition_num = 0;
+	struct iommu_domain *domain;
+
+	domain_num = (mdp3_res->domains + MDP3_PPP_IOMMU_DOMAIN)->domain_idx;
+	domain = msm_get_iommu_domain(domain_num);
+
+	if (!domain) {
+		pr_err("Could not get domain %d. Corruption?\n", domain_num);
+		return;
+	}
+
+	iommu_unmap_range(domain, meta->iova_addr, meta->mapped_size);
+	msm_free_iova_address(meta->iova_addr, domain_num, partition_num,
+		meta->mapped_size);
+
+	return;
+}
+
+static void mdp3_iommu_meta_destroy(struct kref *kref)
+{
+	struct mdp3_iommu_meta *meta =
+			container_of(kref, struct mdp3_iommu_meta, ref);
+
+	rb_erase(&meta->node, &mdp3_res->iommu_root);
+	mdp3_iommu_heap_unmap_iommu(meta);
+	dma_buf_put(meta->dbuf);
+	kfree(meta);
+}
+
+
+static void mdp3_iommu_meta_put(struct mdp3_iommu_meta *meta)
+{
+	/* Need to lock here to prevent race against map/unmap */
+	mutex_lock(&mdp3_res->iommu_lock);
+	kref_put(&meta->ref, mdp3_iommu_meta_destroy);
+	mutex_unlock(&mdp3_res->iommu_lock);
+}
+
+static struct mdp3_iommu_meta *mdp3_iommu_meta_lookup(struct sg_table *table)
+{
+	struct rb_root *root = &mdp3_res->iommu_root;
+	struct rb_node **p = &root->rb_node;
+	struct rb_node *parent = NULL;
+	struct mdp3_iommu_meta *entry = NULL;
+
+	while (*p) {
+		parent = *p;
+		entry = rb_entry(parent, struct mdp3_iommu_meta, node);
+
+		if (table < entry->table)
+			p = &(*p)->rb_left;
+		else if (table > entry->table)
+			p = &(*p)->rb_right;
+		else
+			return entry;
+	}
+	return NULL;
+}
+
+void mdp3_unmap_iommu(struct ion_client *client, struct ion_handle *handle)
+{
+	struct mdp3_iommu_meta *meta;
+	struct sg_table *table;
+
+	table = ion_sg_table(client, handle);
+
+	mutex_lock(&mdp3_res->iommu_lock);
+	meta = mdp3_iommu_meta_lookup(table);
+	if (!meta) {
+		WARN(1, "%s: buffer was never mapped for %p\n", __func__,
+				handle);
+		mutex_unlock(&mdp3_res->iommu_lock);
+		goto out;
+	}
+	mutex_unlock(&mdp3_res->iommu_lock);
+
+	mdp3_iommu_meta_put(meta);
+out:
+	return;
+}
+
+static void mdp3_iommu_meta_add(struct mdp3_iommu_meta *meta)
+{
+	struct rb_root *root = &mdp3_res->iommu_root;
+	struct rb_node **p = &root->rb_node;
+	struct rb_node *parent = NULL;
+	struct mdp3_iommu_meta *entry;
+
+	while (*p) {
+		parent = *p;
+		entry = rb_entry(parent, struct mdp3_iommu_meta, node);
+
+		if (meta->table < entry->table) {
+			p = &(*p)->rb_left;
+		} else if (meta->table > entry->table) {
+			p = &(*p)->rb_right;
+		} else {
+			pr_err("%s: handle %p already exists\n", __func__,
+				entry->handle);
+			BUG();
+		}
+	}
+
+	rb_link_node(&meta->node, parent, p);
+	rb_insert_color(&meta->node, root);
+}
+
+static int mdp3_iommu_map_iommu(struct mdp3_iommu_meta *meta,
+	unsigned long align, unsigned long iova_length,
+	unsigned int padding, unsigned long flags)
+{
+	struct iommu_domain *domain;
+	int ret = 0;
+	unsigned long size;
+	unsigned long unmap_size;
+	struct sg_table *table;
+	int prot = IOMMU_WRITE | IOMMU_READ;
+	unsigned int domain_num = (mdp3_res->domains +
+			MDP3_PPP_IOMMU_DOMAIN)->domain_idx;
+	unsigned int partition_num = 0;
+
+	size = meta->size;
+	table = meta->table;
+
+	/* Use the biggest alignment to allow bigger IOMMU mappings.
+	 * Use the first entry since the first entry will always be the
+	 * biggest entry. To take advantage of bigger mapping sizes both the
+	 * VA and PA addresses have to be aligned to the biggest size.
+	 */
+	if (sg_dma_len(table->sgl) > align)
+		align = sg_dma_len(table->sgl);
+
+	ret = msm_allocate_iova_address(domain_num, partition_num,
+			meta->mapped_size, align, &meta->iova_addr);
+
+	if (ret)
+		goto out;
+
+	domain = msm_get_iommu_domain(domain_num);
+
+	if (!domain) {
+		ret = -ENOMEM;
+		goto out1;
+	}
+
+	/* Adding padding to before buffer */
+	if (padding) {
+		unsigned long phys_addr = sg_phys(table->sgl);
+		ret = msm_iommu_map_extra(domain, meta->iova_addr, phys_addr,
+				padding, SZ_4K, prot);
+		if (ret)
+			goto out1;
+	}
+
+	/* Mapping actual buffer */
+	ret = iommu_map_range(domain, meta->iova_addr + padding,
+			table->sgl, size, prot);
+	if (ret) {
+		pr_err("%s: could not map %lx in domain %p\n",
+			__func__, meta->iova_addr, domain);
+			unmap_size = padding;
+		goto out2;
+	}
+
+	/* Adding padding to end of buffer */
+	if (padding) {
+		unsigned long phys_addr = sg_phys(table->sgl);
+		unsigned long extra_iova_addr = meta->iova_addr +
+				padding + size;
+		ret = msm_iommu_map_extra(domain, extra_iova_addr, phys_addr,
+				padding, SZ_4K, prot);
+		if (ret) {
+			unmap_size = padding + size;
+			goto out2;
+		}
+	}
+	return ret;
+
+out2:
+	iommu_unmap_range(domain, meta->iova_addr, unmap_size);
+out1:
+	msm_free_iova_address(meta->iova_addr, domain_num, partition_num,
+				iova_length);
+
+out:
+	return ret;
+}
+
+static struct mdp3_iommu_meta *mdp3_iommu_meta_create(struct ion_client *client,
+	struct ion_handle *handle, struct sg_table *table, unsigned long size,
+	unsigned long align, unsigned long iova_length, unsigned int padding,
+	unsigned long flags, unsigned long *iova)
+{
+	struct mdp3_iommu_meta *meta;
+	int ret;
+
+	meta = kzalloc(sizeof(*meta), GFP_KERNEL);
+
+	if (!meta)
+		return ERR_PTR(-ENOMEM);
+
+	meta->handle = handle;
+	meta->table = table;
+	meta->size = size;
+	meta->mapped_size = iova_length;
+	meta->dbuf = ion_share_dma_buf(client, handle);
+	kref_init(&meta->ref);
+
+	ret = mdp3_iommu_map_iommu(meta,
+		align, iova_length, padding, flags);
+	if (ret < 0)	{
+		pr_err("%s: Unable to map buffer\n", __func__);
+		goto out;
+	}
+
+	*iova = meta->iova_addr;
+	mdp3_iommu_meta_add(meta);
+
+	return meta;
+out:
+	kfree(meta);
+	return ERR_PTR(ret);
+}
+
+/*
+ * PPP hw reads in tiles of 16 which might be outside mapped region
+ * need to map buffers ourseleve to add extra padding
+ */
+int mdp3_self_map_iommu(struct ion_client *client, struct ion_handle *handle,
+	unsigned long align, unsigned long padding, unsigned long *iova,
+	unsigned long *buffer_size, unsigned long flags,
+	unsigned long iommu_flags)
+{
+	struct mdp3_iommu_meta *iommu_meta = NULL;
+	struct sg_table *table;
+	struct scatterlist *sg;
+	unsigned long size = 0, iova_length = 0;
+	int ret = 0;
+	int i;
+
+	table = ion_sg_table(client, handle);
+	if (IS_ERR_OR_NULL(table))
+		return PTR_ERR(table);
+
+	for_each_sg(table->sgl, sg, table->nents, i)
+		size += sg_dma_len(sg);
+
+	padding = PAGE_ALIGN(padding);
+
+	/* Adding 16 lines padding before and after buffer */
+	iova_length = size + 2 * padding;
+
+	if (size & ~PAGE_MASK) {
+		pr_debug("%s: buffer size %lx is not aligned to %lx", __func__,
+			size, PAGE_SIZE);
+		ret = -EINVAL;
+		goto out;
+	}
+
+	if (iova_length & ~PAGE_MASK) {
+		pr_debug("%s: iova_length %lx is not aligned to %lx", __func__,
+			iova_length, PAGE_SIZE);
+		ret = -EINVAL;
+		goto out;
+	}
+
+	mutex_lock(&mdp3_res->iommu_lock);
+	iommu_meta = mdp3_iommu_meta_lookup(table);
+
+	if (!iommu_meta) {
+		iommu_meta = mdp3_iommu_meta_create(client, handle, table, size,
+				align, iova_length, padding, flags, iova);
+		if (!IS_ERR_OR_NULL(iommu_meta)) {
+			iommu_meta->flags = iommu_flags;
+			ret = 0;
+		} else {
+			ret = PTR_ERR(iommu_meta);
+			goto out_unlock;
+		}
+	} else {
+		if (iommu_meta->flags != iommu_flags) {
+			pr_err("%s: handle %p is already mapped with diff flag\n",
+				__func__, handle);
+			ret = -EINVAL;
+			goto out_unlock;
+		} else if (iommu_meta->mapped_size != iova_length) {
+			pr_err("%s: handle %p is already mapped with diff len\n",
+				__func__, handle);
+			ret = -EINVAL;
+			goto out_unlock;
+		} else {
+			kref_get(&iommu_meta->ref);
+			*iova = iommu_meta->iova_addr;
+		}
+	}
+	BUG_ON(iommu_meta->size != size);
+	mutex_unlock(&mdp3_res->iommu_lock);
+
+	*iova = *iova + padding;
+	*buffer_size = size;
+	return ret;
+
+out_unlock:
+	mutex_unlock(&mdp3_res->iommu_lock);
+out:
+	mdp3_iommu_meta_put(iommu_meta);
+	return ret;
+}
+
+int mdp3_put_img(struct mdp3_img_data *data, int client)
 {
 	struct ion_client *iclient = mdp3_res->ion_client;
-	int dom = (mdp3_res->domains + MDP3_IOMMU_DOMAIN)->domain_idx;
+	int dom;
 
 	 if (data->flags & MDP_MEMORY_ID_TYPE_FB) {
 		pr_info("mdp3_put_img fb mem buf=0x%x\n", data->addr);
 		fput_light(data->srcp_file, data->p_need);
 		data->srcp_file = NULL;
 	} else if (!IS_ERR_OR_NULL(data->srcp_ihdl)) {
-		ion_unmap_iommu(iclient, data->srcp_ihdl, dom, 0);
+		if (client == MDP3_CLIENT_DMA_P) {
+			dom = (mdp3_res->domains +
+				MDP3_DMA_IOMMU_DOMAIN)->domain_idx;
+			ion_unmap_iommu(iclient, data->srcp_ihdl, dom, 0);
+		} else {
+			mdp3_unmap_iommu(iclient, data->srcp_ihdl);
+		}
 		ion_free(iclient, data->srcp_ihdl);
 		data->srcp_ihdl = NULL;
 	} else {
@@ -857,14 +1383,15 @@
 	return 0;
 }
 
-int mdp3_get_img(struct msmfb_data *img, struct mdp3_img_data *data)
+int mdp3_get_img(struct msmfb_data *img, struct mdp3_img_data *data,
+		int client)
 {
 	struct file *file;
 	int ret = -EINVAL;
 	int fb_num;
 	unsigned long *start, *len;
 	struct ion_client *iclient = mdp3_res->ion_client;
-	int dom = (mdp3_res->domains + MDP3_IOMMU_DOMAIN)->domain_idx;
+	int dom;
 
 	start = (unsigned long *) &data->addr;
 	len = (unsigned long *) &data->len;
@@ -906,10 +1433,15 @@
 			data->srcp_ihdl = NULL;
 			return ret;
 		}
-
-		ret = ion_map_iommu(iclient, data->srcp_ihdl, dom,
-		    0, SZ_4K, 0, start, len, 0, 0);
-
+		if (client == MDP3_CLIENT_DMA_P) {
+			dom = (mdp3_res->domains +
+					MDP3_DMA_IOMMU_DOMAIN)->domain_idx;
+			ret = ion_map_iommu(iclient, data->srcp_ihdl, dom,
+					0, SZ_4K, 0, start, len, 0, 0);
+		} else {
+			ret = mdp3_self_map_iommu(iclient, data->srcp_ihdl,
+				SZ_4K, data->padding, start, len, 0, 0);
+		}
 		if (IS_ERR_VALUE(ret)) {
 			ion_free(iclient, data->srcp_ihdl);
 			pr_err("failed to map ion handle (%d)\n", ret);
@@ -924,7 +1456,7 @@
 		pr_debug("mem=%d ihdl=%p buf=0x%x len=0x%x\n", img->memory_id,
 			 data->srcp_ihdl, data->addr, data->len);
 	} else {
-		mdp3_put_img(data);
+		mdp3_put_img(data, client);
 		return -EINVAL;
 	}
 
@@ -997,14 +1529,6 @@
 		return xres * bpp;
 }
 
-void mdp3_fbmem_clear(void)
-{
-	if (mdp3_res->ion_handle && mdp3_res->virt) {
-		pr_debug("mdp3_fbmem_clear\n");
-		memset(mdp3_res->virt, 0, mdp3_res->size);
-	}
-}
-
 static int mdp3_alloc(size_t size, void **virt, unsigned long *phys)
 {
 	int ret = 0;
@@ -1057,76 +1581,16 @@
 	return -ENOMEM;
 }
 
-static int mdp3_fbmem_alloc(struct msm_fb_data_type *mfd)
-{
-	int ret = -ENOMEM, dom;
-	void *virt = NULL;
-	unsigned long phys = 0;
-	size_t size;
-	u32 yres = mfd->fbi->var.yres_virtual;
-
-	size = PAGE_ALIGN(mfd->fbi->fix.line_length * yres);
-
-	if (mfd->index != 0) {
-		mfd->fbi->screen_base = virt;
-		mfd->fbi->fix.smem_start = phys;
-		mfd->fbi->fix.smem_len = 0;
-		return 0;
-	}
-
-	ret = mdp3_alloc(size, &virt, &phys);
-	if (ret) {
-		pr_err("fail to allocate fb memory\n");
-		return ret;
-	}
-
-	dom = (mdp3_res->domains + MDP3_IOMMU_DOMAIN)->domain_idx;
-
-	ret = ion_map_iommu(mdp3_res->ion_client, mdp3_res->ion_handle,
-			dom, 0, SZ_4K, 0, &mfd->iova,
-			(unsigned long *)&size, 0, 0);
-
-	if (ret) {
-		pr_err("%s map IOMMU error\n", __func__);
-		goto ion_map_iommu_err;
-	}
-
-	pr_debug("allocating %u bytes at %p (%lx phys) for fb %d\n",
-			size, virt, phys, mfd->index);
-
-	mfd->fbi->screen_base = virt;
-	mfd->fbi->fix.smem_start = phys;
-	mfd->fbi->fix.smem_len = size;
-	return 0;
-
-ion_map_iommu_err:
-	ion_unmap_kernel(mdp3_res->ion_client, mdp3_res->ion_handle);
-	ion_free(mdp3_res->ion_client, mdp3_res->ion_handle);
-	mdp3_res->ion_handle = NULL;
-	mdp3_res->virt = NULL;
-	mdp3_res->phys = 0;
-	mdp3_res->size = 0;
-	return -ENOMEM;
-}
-
-void mdp3_fbmem_free(struct msm_fb_data_type *mfd)
+void mdp3_free(void)
 {
 	pr_debug("mdp3_fbmem_free\n");
 	if (mdp3_res->ion_handle) {
-		int dom = (mdp3_res->domains + MDP3_IOMMU_DOMAIN)->domain_idx;
-
 		ion_unmap_kernel(mdp3_res->ion_client, mdp3_res->ion_handle);
-		ion_unmap_iommu(mdp3_res->ion_client,  mdp3_res->ion_handle,
-				dom, 0);
 		ion_free(mdp3_res->ion_client, mdp3_res->ion_handle);
 		mdp3_res->ion_handle = NULL;
 		mdp3_res->virt = NULL;
 		mdp3_res->phys = 0;
 		mdp3_res->size = 0;
-		mfd->fbi->screen_base = 0;
-		mfd->fbi->fix.smem_start = 0;
-		mfd->fbi->fix.smem_len = 0;
-		mfd->iova = 0;
 	}
 }
 
@@ -1162,7 +1626,7 @@
 {
 	if (!mdp3_res)
 		return -ENODEV;
-	return mdp3_res->domains[MDP3_IOMMU_DOMAIN].domain_idx;
+	return mdp3_res->domains[MDP3_DMA_IOMMU_DOMAIN].domain_idx;
 }
 
 int mdp3_continuous_splash_copy(struct mdss_panel_data *pdata)
@@ -1173,6 +1637,11 @@
 	size_t size;
 	int rc;
 
+	if (pdata->panel_info.type != MIPI_VIDEO_PANEL) {
+		pr_debug("cmd mode panel, no need to copy splash image\n");
+		return 0;
+	}
+
 	rgb_size = MDP3_REG_READ(MDP3_REG_DMA_P_SIZE);
 	stride = MDP3_REG_READ(MDP3_REG_DMA_P_IBUF_Y_STRIDE);
 	stride = stride & 0x3FFF;
@@ -1180,7 +1649,7 @@
 
 	height = (rgb_size >> 16) & 0xffff;
 	width  = rgb_size & 0xffff;
-	size = PAGE_ALIGN(height * stride * 2);
+	size = PAGE_ALIGN(height * stride);
 	pr_debug("splash_height=%d splash_width=%d Buffer size=%d\n",
 		height, width, size);
 
@@ -1210,8 +1679,9 @@
 		status = MDP3_REG_READ(MDP3_REG_DSI_VIDEO_EN);
 		rc = status & 0x1;
 	} else {
-		status = MDP3_REG_READ(MDP3_REG_DMA_P_START);
-		rc = status & 01;
+		status = MDP3_REG_READ(MDP3_REG_DMA_P_CONFIG);
+		status &= 0x180000;
+		rc = (status == 0x080000);
 	}
 
 	mdp3_clk_update(MDP3_CLK_AHB, 0);
@@ -1271,7 +1741,8 @@
 	return 0;
 
 splash_on_err:
-	mdp3_clk_enable(0);
+	if (mdp3_clk_enable(0))
+		pr_err("%s: Unable to disable mdp3 clocks\n", __func__);
 	return rc;
 }
 
@@ -1285,17 +1756,62 @@
 			return 0;
 		}
 		rc = mdp3_continuous_splash_on(pdata);
+	} else {
+		if (mdp3_is_display_on(pdata)) {
+			pr_err("lk continuous splash, but kerenl not\n");
+			rc = mdp3_continuous_splash_on(pdata);
+		}
 	}
 	return rc;
 }
 
+static void mdp3_debug_enable_clock(int on)
+{
+	if (on)
+		mdp3_clk_enable(1);
+	else
+		mdp3_clk_enable(0);
+}
+
+static int mdp3_debug_init(struct platform_device *pdev)
+{
+	int rc;
+	struct mdss_data_type *mdata;
+
+	mdata = devm_kzalloc(&pdev->dev, sizeof(*mdata), GFP_KERNEL);
+	if (!mdata)
+		return -ENOMEM;
+
+	mdss_res = mdata;
+
+	mdata->debug_inf.debug_dump_stats = NULL;
+	mdata->debug_inf.debug_enable_clock = mdp3_debug_enable_clock;
+
+	rc = mdss_debugfs_init(mdata);
+	if (rc)
+		return rc;
+
+	rc = mdss_debug_register_base(NULL, mdp3_res->mdp_base ,
+					mdp3_res->mdp_reg_size);
+
+	return rc;
+}
+
+static void mdp3_debug_deinit(struct platform_device *pdev)
+{
+	if (mdss_res) {
+		mdss_debugfs_remove(mdss_res);
+		devm_kfree(&pdev->dev, mdss_res);
+		mdss_res = NULL;
+	}
+}
+
 static int mdp3_probe(struct platform_device *pdev)
 {
 	int rc;
 	static struct msm_mdp_interface mdp3_interface = {
 	.init_fnc = mdp3_init,
 	.fb_mem_get_iommu_domain = mdp3_fb_mem_get_iommu_domain,
-	.fb_mem_alloc_fnc = mdp3_fbmem_alloc,
 	.panel_register_done = mdp3_panel_register_done,
 	.fb_stride = mdp3_fb_stride,
 	};
@@ -1337,6 +1853,12 @@
 		goto probe_done;
 	}
 
+	rc = mdp3_debug_init(pdev);
+	if (rc) {
+		pr_err("unable to initialize mdp debugging\n");
+		goto probe_done;
+	}
+
 	rc = mdss_fb_register_mdp_instance(&mdp3_interface);
 	if (rc)
 		pr_err("unable to register mdp instance\n");
@@ -1350,11 +1872,41 @@
 
 		devm_kfree(&pdev->dev, mdp3_res);
 		mdp3_res = NULL;
+
+		if (mdss_res) {
+			devm_kfree(&pdev->dev, mdss_res);
+			mdss_res = NULL;
+		}
 	}
 
 	return rc;
 }
 
+struct mdss_panel_cfg *mdp3_panel_intf_type(int intf_val)
+{
+	if (!mdp3_res || !mdp3_res->pan_cfg.init_done)
+		return ERR_PTR(-EPROBE_DEFER);
+
+	if (mdp3_res->pan_cfg.pan_intf == intf_val)
+		return &mdp3_res->pan_cfg;
+	else
+		return NULL;
+}
+EXPORT_SYMBOL(mdp3_panel_intf_type);
+
+int mdp3_panel_get_boot_cfg(void)
+{
+	int rc;
+
+	if (!mdp3_res || !mdp3_res->pan_cfg.init_done)
+		rc = -EPROBE_DEFER;
+	if (mdp3_res->pan_cfg.lk_cfg)
+		rc = 1;
+	else
+		rc = 0;
+	return rc;
+}
+
 static  int mdp3_suspend_sub(struct mdp3_hw_resource *mdata)
 {
 	return 0;
@@ -1398,6 +1950,7 @@
 	pm_runtime_disable(&pdev->dev);
 	mdp3_bus_scale_unregister();
 	mdp3_clk_remove();
+	mdp3_debug_deinit(pdev);
 	return 0;
 }
 
diff --git a/drivers/video/msm/mdss/mdp3.h b/drivers/video/msm/mdss/mdp3.h
index 03416c7..2f73c42 100644
--- a/drivers/video/msm/mdss/mdp3.h
+++ b/drivers/video/msm/mdss/mdp3.h
@@ -41,8 +41,9 @@
 };
 
 enum {
-	MDP3_IOMMU_DOMAIN,
-	MDP3_IOMMU_DOMAIN_MAX
+	MDP3_DMA_IOMMU_DOMAIN,
+	MDP3_PPP_IOMMU_DOMAIN,
+	MDP3_IOMMU_DOMAIN_MAX,
 };
 
 enum {
@@ -58,6 +59,12 @@
 	MDP3_CLIENT_PPP,
 };
 
+enum {
+	DI_PARTITION_NUM = 0,
+	DI_DOMAIN_NUM = 1,
+	DI_MAX,
+};
+
 struct mdp3_bus_handle_map {
 	struct msm_bus_vectors *bus_vector;
 	struct msm_bus_paths *usecases;
@@ -83,6 +90,19 @@
 	int attached;
 };
 
+struct mdp3_iommu_meta {
+	struct rb_node node;
+	struct ion_handle *handle;
+	struct rb_root iommu_maps;
+	struct kref ref;
+	struct sg_table *table;
+	struct dma_buf *dbuf;
+	int mapped_size;
+	unsigned long size;
+	unsigned long iova_addr;
+	unsigned long flags;
+};
+
 #define MDP3_MAX_INTR 28
 
 struct mdp3_intr_cb {
@@ -111,6 +131,8 @@
 	struct mdp3_iommu_domain_map *domains;
 	struct mdp3_iommu_ctx_map *iommu_contexts;
 	struct ion_handle *ion_handle;
+	struct mutex iommu_lock;
+	struct rb_root iommu_root;
 	void *virt;
 	unsigned long phys;
 	size_t size;
@@ -126,11 +148,13 @@
 	int irq_registered;
 
 	struct early_suspend suspend_handler;
+	struct mdss_panel_cfg pan_cfg;
 };
 
 struct mdp3_img_data {
 	u32 addr;
 	u32 len;
+	u32 padding;
 	u32 flags;
 	int p_need;
 	struct file *srcp_file;
@@ -150,14 +174,13 @@
 int mdp3_clk_set_rate(int clk_type, unsigned long clk_rate, int client);
 int mdp3_clk_enable(int enable);
 int mdp3_bus_scale_set_quota(int client, u64 ab_quota, u64 ib_quota);
-int mdp3_put_img(struct mdp3_img_data *data);
-int mdp3_get_img(struct msmfb_data *img, struct mdp3_img_data *data);
+int mdp3_put_img(struct mdp3_img_data *data, int client);
+int mdp3_get_img(struct msmfb_data *img, struct mdp3_img_data *data,
+		int client);
 int mdp3_iommu_enable(int client);
 int mdp3_iommu_disable(int client);
 int mdp3_iommu_is_attached(int client);
-void mdp3_fbmem_free(struct msm_fb_data_type *mfd);
-void mdp3_fbmem_clear(void);
-
+void mdp3_free(void);
 
 #define MDP3_REG_WRITE(addr, val) writel_relaxed(val, mdp3_res->mdp_base + addr)
 #define MDP3_REG_READ(addr) readl_relaxed(mdp3_res->mdp_base + addr)
diff --git a/drivers/video/msm/mdss/mdp3_ctrl.c b/drivers/video/msm/mdss/mdp3_ctrl.c
index f77a2b3..ac3fd3a 100644
--- a/drivers/video/msm/mdss/mdp3_ctrl.c
+++ b/drivers/video/msm/mdss/mdp3_ctrl.c
@@ -50,7 +50,7 @@
 	while (count--) {
 		struct mdp3_img_data *data = &bufq->img_data[bufq->pop_idx];
 		bufq->pop_idx = (bufq->pop_idx + 1) % MDP3_MAX_BUF_QUEUE;
-		mdp3_put_img(data);
+		mdp3_put_img(data, MDP3_CLIENT_DMA_P);
 	}
 	bufq->count = 0;
 	bufq->push_idx = 0;
@@ -88,20 +88,11 @@
 	return bufq->count;
 }
 
-static void mdp3_dispatch_vsync(struct work_struct *work)
-{
-	struct mdp3_session_data *mdp3_session;
-	mdp3_session = container_of(work, struct mdp3_session_data, vsync_work);
-	if (mdp3_session && mdp3_session->mfd)
-		sysfs_notify(&mdp3_session->mfd->fbi->dev->kobj, NULL,
-				"vsync_event");
-}
-
 void vsync_notify_handler(void *arg)
 {
 	struct mdp3_session_data *session = (struct mdp3_session_data *)arg;
 	session->vsync_time = ktime_get();
-	schedule_work(&session->vsync_work);
+	sysfs_notify_dirent(session->vsync_event_sd);
 }
 
 static int mdp3_ctrl_vsync_enable(struct msm_fb_data_type *mfd, int enable)
@@ -370,6 +361,14 @@
 	struct mdp3_dma_output_config outputConfig;
 	struct mdp3_dma_source sourceConfig;
 	int frame_rate = mfd->panel_info->mipi.frame_rate;
+	int vbp, vfp, vspw;
+	int vtotal, vporch;
+
+	vbp = panel_info->lcdc.v_back_porch;
+	vfp = panel_info->lcdc.v_front_porch;
+	vspw = panel_info->lcdc.v_pulse_width;
+	vporch = vbp + vfp + vspw;
+	vtotal = vporch + panel_info->yres;
 
 	fix = &fbi->fix;
 	var = &fbi->var;
@@ -381,8 +380,9 @@
 	sourceConfig.y = 0;
 	sourceConfig.stride = fix->line_length;
 	sourceConfig.buf = (void *)mfd->iova;
+	sourceConfig.vporch = vporch;
 	sourceConfig.vsync_count =
-		MDP_VSYNC_CLK_RATE / (frame_rate * sourceConfig.width);
+		MDP_VSYNC_CLK_RATE / (frame_rate * vtotal);
 
 	outputConfig.dither_en = 0;
 	outputConfig.out_sel = mdp3_ctrl_get_intf_type(mfd);
@@ -473,11 +473,6 @@
 		goto on_error;
 	}
 
-	mdp3_fbmem_clear();
-
-	if (panel->set_backlight)
-		panel->set_backlight(panel, panel->panel_info.bl_max);
-
 	pr_debug("mdp3_ctrl_on dma start\n");
 	if (mfd->fbi->screen_base) {
 		rc = mdp3_session->dma->start(mdp3_session->dma,
@@ -520,18 +515,16 @@
 
 	mdp3_histogram_stop(mdp3_session, MDP_BLOCK_DMA_P);
 
-	pr_debug("mdp3_ctrl_off turn panel off\n");
-	if (panel->set_backlight)
-		panel->set_backlight(panel, 0);
+	rc = mdp3_session->dma->stop(mdp3_session->dma, mdp3_session->intf);
+	if (rc)
+		pr_debug("fail to stop the MDP3 dma\n");
 
 	if (panel->event_handler)
 		rc = panel->event_handler(panel, MDSS_EVENT_PANEL_OFF, NULL);
 	if (rc)
 		pr_err("fail to turn off the panel\n");
 
-	rc = mdp3_session->dma->stop(mdp3_session->dma, mdp3_session->intf);
-	if (rc)
-		pr_err("fail to stop the MDP3 dma\n");
+
 
 	mdp3_irq_deregister();
 
@@ -564,6 +557,88 @@
 	return 0;
 }
 
+static int mdp3_ctrl_reset(struct msm_fb_data_type *mfd)
+{
+	int rc = 0;
+	struct mdp3_session_data *mdp3_session;
+	struct mdp3_dma *mdp3_dma;
+	struct mdss_panel_data *panel;
+	struct mdp3_vsync_notification vsync_client;
+
+	pr_debug("mdp3_ctrl_reset\n");
+	mdp3_session = (struct mdp3_session_data *)mfd->mdp.private1;
+	if (!mdp3_session || !mdp3_session->panel || !mdp3_session->dma ||
+		!mdp3_session->intf) {
+		pr_err("mdp3_ctrl_reset no device");
+		return -ENODEV;
+	}
+
+	panel = mdp3_session->panel;
+	mdp3_dma = mdp3_session->dma;
+	mutex_lock(&mdp3_session->lock);
+
+	vsync_client = mdp3_dma->vsync_client;
+
+	rc = mdp3_dma->stop(mdp3_dma, mdp3_session->intf);
+	if (rc) {
+		pr_err("fail to stop the MDP3 dma\n");
+		goto reset_error;
+	}
+
+	rc = panel->event_handler(panel, MDSS_EVENT_PANEL_OFF, NULL);
+	if (rc)
+		pr_err("fail to turn off panel\n");
+
+	rc = mdp3_ctrl_res_req_clk(mfd, 0);
+	if (rc) {
+		pr_err("fail to release mdp clocks\n");
+		goto reset_error;
+	}
+
+	rc = panel->event_handler(panel, MDSS_EVENT_BLANK, NULL);
+	if (rc) {
+		pr_err("fail to blank the panel\n");
+		goto reset_error;
+	}
+
+	rc = mdp3_iommu_enable(MDP3_CLIENT_DMA_P);
+	if (rc) {
+		pr_err("fail to attach dma iommu\n");
+		goto reset_error;
+	}
+
+	rc = panel->event_handler(panel, MDSS_EVENT_UNBLANK, NULL);
+	if (rc) {
+		pr_err("fail to unblank the panel\n");
+		goto reset_error;
+	}
+
+	rc = panel->event_handler(panel, MDSS_EVENT_PANEL_ON, NULL);
+	if (rc) {
+		pr_err("fail to turn on the panel\n");
+		goto reset_error;
+	}
+
+	rc = mdp3_ctrl_res_req_clk(mfd, 1);
+	if (rc) {
+		pr_err("fail to turn on mdp clks\n");
+		goto reset_error;
+	}
+
+	mdp3_ctrl_intf_init(mfd, mdp3_session->intf);
+	mdp3_ctrl_dma_init(mfd, mdp3_dma);
+
+	if (vsync_client.handler)
+		mdp3_dma->vsync_enable(mdp3_dma, &vsync_client);
+
+	if (mfd->fbi->screen_base)
+		rc = mdp3_dma->start(mdp3_dma, mdp3_session->intf);
+
+reset_error:
+	mutex_unlock(&mdp3_session->lock);
+	return rc;
+}
+
 static int mdp3_overlay_get(struct msm_fb_data_type *mfd,
 				struct mdp_overlay *req)
 {
@@ -590,15 +665,15 @@
 
 	mutex_lock(&mdp3_session->lock);
 
-	if (mdp3_session->overlay.id == req->id) {
-		mdp3_session->overlay = *req;
-		if (req->id == MSMFB_NEW_REQUEST) {
-			mdp3_session->overlay.id = 1;
-			req->id = 1;
-		}
-	} else {
-		rc = -EINVAL;
+	if (mdp3_session->overlay.id != req->id)
+		pr_err("overlay was not released, continue to recover\n");
+
+	mdp3_session->overlay = *req;
+	if (req->id == MSMFB_NEW_REQUEST) {
+		mdp3_session->overlay.id = 1;
+		req->id = 1;
 	}
+
 	mutex_unlock(&mdp3_session->lock);
 
 	return rc;
@@ -631,7 +706,7 @@
 	struct msmfb_data *img = &req->data;
 	struct mdp3_img_data data;
 
-	rc = mdp3_get_img(img, &data);
+	rc = mdp3_get_img(img, &data, MDP3_CLIENT_DMA_P);
 	if (rc) {
 		pr_err("fail to get overlay buffer\n");
 		return rc;
@@ -640,7 +715,7 @@
 	rc = mdp3_bufq_push(&mdp3_session->bufq_in, &data);
 	if (rc) {
 		pr_err("fail to queue the overlay buffer, buffer drop\n");
-		mdp3_put_img(&data);
+		mdp3_put_img(&data, MDP3_CLIENT_DMA_P);
 		return rc;
 	}
 	return 0;
@@ -680,19 +755,20 @@
 	if (!mdp3_session || !mdp3_session->dma)
 		return -EINVAL;
 
-	if (!mdp3_session->status) {
-		pr_err("%s, display off!\n", __func__);
-		return -EPERM;
-	}
-
 	if (!mdp3_iommu_is_attached(MDP3_CLIENT_DMA_P)) {
 		pr_debug("continuous splash screen, IOMMU not attached\n");
-		mdp3_ctrl_off(mfd);
-		mdp3_ctrl_on(mfd);
+		mdp3_ctrl_reset(mfd);
+		mdp3_free();
 	}
 
 	mutex_lock(&mdp3_session->lock);
 
+	if (!mdp3_session->status) {
+		pr_err("%s, display off!\n", __func__);
+		mutex_unlock(&mdp3_session->lock);
+		return -EPERM;
+	}
+
 	data = mdp3_bufq_pop(&mdp3_session->bufq_in);
 	if (data) {
 		mdp3_session->dma->update(mdp3_session->dma,
@@ -703,10 +779,7 @@
 
 	if (mdp3_bufq_count(&mdp3_session->bufq_out) > 2) {
 		data = mdp3_bufq_pop(&mdp3_session->bufq_out);
-		mdp3_put_img(data);
-
-		if (mfd->fbi->screen_base)
-			mdp3_fbmem_free(mfd);
+		mdp3_put_img(data, MDP3_CLIENT_DMA_P);
 	}
 	mutex_unlock(&mdp3_session->lock);
 
@@ -730,11 +803,6 @@
 	if (!mdp3_session || !mdp3_session->dma)
 		return;
 
-	if (!mdp3_session->status) {
-		pr_err("mdp3_ctrl_pan_display, display off!\n");
-		return;
-	}
-
 	if (!mdp3_iommu_is_attached(MDP3_CLIENT_DMA_P)) {
 		pr_debug("continuous splash screen, IOMMU not attached\n");
 		mdp3_ctrl_off(mfd);
@@ -742,6 +810,12 @@
 	}
 
 	mutex_lock(&mdp3_session->lock);
+
+	if (!mdp3_session->status) {
+		pr_err("mdp3_ctrl_pan_display, display off!\n");
+		goto pan_error;
+	}
+
 	fbi = mfd->fbi;
 
 	bpp = fbi->var.bits_per_pixel / 8;
@@ -789,6 +863,64 @@
 	return ret;
 }
 
+int mdp3_validate_start_req(struct mdp_histogram_start_req *req)
+{
+	if (req->frame_cnt >= MDP_HISTOGRAM_FRAME_COUNT_MAX) {
+		pr_err("%s invalid req frame_cnt\n", __func__);
+		return -EINVAL;
+	}
+	if (req->bit_mask >= MDP_HISTOGRAM_BIT_MASK_MAX) {
+		pr_err("%s invalid req bit mask\n", __func__);
+		return -EINVAL;
+	}
+	if (req->block != MDP_BLOCK_DMA_P ||
+		req->num_bins != MDP_HISTOGRAM_BIN_NUM) {
+		pr_err("mdp3_histogram_start invalid request\n");
+		return -EINVAL;
+	}
+	return 0;
+}
+
+int mdp3_validate_scale_config(struct mdp_bl_scale_data *data)
+{
+	if (data->scale > MDP_HISTOGRAM_BL_SCALE_MAX) {
+		pr_err("%s invalid bl_scale\n", __func__);
+		return -EINVAL;
+	}
+	if (data->min_lvl > MDP_HISTOGRAM_BL_LEVEL_MAX) {
+		pr_err("%s invalid bl_min_lvl\n", __func__);
+		return -EINVAL;
+	}
+	return 0;
+}
+
+int mdp3_validate_csc_data(struct mdp_csc_cfg_data *data)
+{
+	int i;
+	for (i = 0; i < 9; i++) {
+		if (data->csc_data.csc_mv[i] >=
+				MDP_HISTOGRAM_CSC_MATRIX_MAX)
+			return -EINVAL;
+	}
+	for (i = 0; i < 3; i++) {
+		if (data->csc_data.csc_pre_bv[i] >=
+				MDP_HISTOGRAM_CSC_VECTOR_MAX)
+			return -EINVAL;
+		if (data->csc_data.csc_post_bv[i] >=
+				MDP_HISTOGRAM_CSC_VECTOR_MAX)
+			return -EINVAL;
+	}
+	for (i = 0; i < 6; i++) {
+		if (data->csc_data.csc_pre_lv[i] >=
+				MDP_HISTOGRAM_CSC_VECTOR_MAX)
+			return -EINVAL;
+		if (data->csc_data.csc_post_lv[i] >=
+				MDP_HISTOGRAM_CSC_VECTOR_MAX)
+			return -EINVAL;
+	}
+	return 0;
+}
+
 static int mdp3_histogram_start(struct mdp3_session_data *session,
 					struct mdp_histogram_start_req *req)
 {
@@ -796,11 +928,10 @@
 	struct mdp3_dma_histogram_config histo_config;
 
 	pr_debug("mdp3_histogram_start\n");
-	if (req->block != MDP_BLOCK_DMA_P ||
-		req->num_bins != MDP_HISTOGRAM_BIN_NUM) {
-		pr_err("mdp3_histogram_start invalid request\n");
-		return -EINVAL;
-	}
+
+	ret = mdp3_validate_start_req(req);
+	if (ret)
+		return ret;
 
 	if (!session->dma->histo_op ||
 		!session->dma->config_histo) {
@@ -1000,10 +1131,20 @@
 
 	switch (mdp_pp.op) {
 	case mdp_bl_scale_cfg:
+		ret = mdp3_validate_scale_config(&mdp_pp.data.bl_scale_data);
+		if (ret) {
+			pr_err("%s: invalid scale config\n", __func__);
+			break;
+		}
 		ret = mdp3_bl_scale_config(mfd, (struct mdp_bl_scale_data *)
 						&mdp_pp.data.bl_scale_data);
 		break;
 	case mdp_op_csc_cfg:
+		ret = mdp3_validate_csc_data(&(mdp_pp.data.csc_cfg_data));
+		if (ret) {
+			pr_err("%s: invalid csc data\n", __func__);
+			break;
+		}
 		ret = mdp3_csc_config(mdp3_session,
 						&(mdp_pp.data.csc_cfg_data));
 		break;
@@ -1078,7 +1219,8 @@
 	if (!mdp3_session->dma->config_lut)
 		return -EINVAL;
 
-	if (cmap->start + cmap->len > MDP_LUT_SIZE) {
+	if (cmap->start > MDP_LUT_SIZE || cmap->len > MDP_LUT_SIZE ||
+			(cmap->start + cmap->len > MDP_LUT_SIZE)) {
 		pr_err("mdp3_ctrl_lut_update invalid arguments\n");
 		return  -EINVAL;
 	}
@@ -1235,7 +1377,6 @@
 	}
 	memset(mdp3_session, 0, sizeof(struct mdp3_session_data));
 	mutex_init(&mdp3_session->lock);
-	INIT_WORK(&mdp3_session->vsync_work, mdp3_dispatch_vsync);
 	mutex_init(&mdp3_session->histo_lock);
 	mdp3_session->dma = mdp3_get_dma_pipe(MDP3_DMA_CAP_ALL);
 	if (!mdp3_session->dma) {
@@ -1261,6 +1402,7 @@
 		goto init_done;
 	}
 
+	mdp3_session->dma->output_config.out_sel = intf_type;
 	mdp3_session->mfd = mfd;
 	mdp3_session->panel = dev_get_platdata(&mfd->pdev->dev);
 	mdp3_session->status = 0;
@@ -1282,6 +1424,14 @@
 		goto init_done;
 	}
 
+	mdp3_session->vsync_event_sd = sysfs_get_dirent(dev->kobj.sd, NULL,
+							"vsync_event");
+	if (!mdp3_session->vsync_event_sd) {
+		pr_err("vsync_event sysfs lookup failed\n");
+		rc = -ENODEV;
+		goto init_done;
+	}
+
 	kobject_uevent(&dev->kobj, KOBJ_ADD);
 	pr_debug("vsync kobject_uevent(KOBJ_ADD)\n");
 
diff --git a/drivers/video/msm/mdss/mdp3_ctrl.h b/drivers/video/msm/mdss/mdp3_ctrl.h
index 9ea1c91..eb32797 100644
--- a/drivers/video/msm/mdss/mdp3_ctrl.h
+++ b/drivers/video/msm/mdss/mdp3_ctrl.h
@@ -43,10 +43,10 @@
 	ktime_t vsync_time;
 	struct timer_list vsync_timer;
 	int vsync_period;
+	struct sysfs_dirent *vsync_event_sd;
 	struct mdp_overlay overlay;
 	struct mdp3_buffer_queue bufq_in;
 	struct mdp3_buffer_queue bufq_out;
-	struct work_struct vsync_work;
 	int histo_status;
 	struct mutex histo_lock;
 	int lut_sel;
diff --git a/drivers/video/msm/mdss/mdp3_dma.c b/drivers/video/msm/mdss/mdp3_dma.c
index 88eedb9..5874286 100644
--- a/drivers/video/msm/mdss/mdp3_dma.c
+++ b/drivers/video/msm/mdss/mdp3_dma.c
@@ -18,7 +18,7 @@
 #include "mdp3_hwio.h"
 
 #define DMA_STOP_POLL_SLEEP_US 1000
-#define DMA_STOP_POLL_TIMEOUT_US 16000
+#define DMA_STOP_POLL_TIMEOUT_US 32000
 #define DMA_HISTO_RESET_TIMEOUT_MS 40
 #define DMA_LUT_CONFIG_MASK 0xfffffbe8
 #define DMA_CCS_CONFIG_MASK 0xfffffc17
@@ -247,16 +247,22 @@
 	pr_debug("mdp3_dma_sync_config\n");
 
 	if (dma->output_config.out_sel == MDP3_DMA_OUTPUT_SEL_DSI_CMD) {
-		sync_config = (source_config->height - 1) << 21;
+		int porch = source_config->vporch;
+		int height = source_config->height;
+		int vtotal = height + porch;
+		sync_config = vtotal << 21;
 		sync_config |= source_config->vsync_count;
 		sync_config |= BIT(19);
 		sync_config |= BIT(20);
 
 		MDP3_REG_WRITE(MDP3_REG_SYNC_CONFIG_0 + dma_sel, sync_config);
 		MDP3_REG_WRITE(MDP3_REG_VSYNC_SEL, 0x024);
-		MDP3_REG_WRITE(MDP3_REG_PRIMARY_VSYNC_INIT_VAL + dma_sel, 0);
-		MDP3_REG_WRITE(MDP3_REG_SYNC_THRESH_0 + dma_sel, 0x00100000);
-		MDP3_REG_WRITE(MDP3_REG_PRIMARY_START_P0S + dma_sel, 0x0);
+		MDP3_REG_WRITE(MDP3_REG_PRIMARY_VSYNC_INIT_VAL + dma_sel,
+				height);
+		MDP3_REG_WRITE(MDP3_REG_PRIMARY_RD_PTR_IRQ, 0x5);
+		MDP3_REG_WRITE(MDP3_REG_SYNC_THRESH_0 + dma_sel, (4 << 16 | 2));
+		MDP3_REG_WRITE(MDP3_REG_PRIMARY_START_P0S + dma_sel, porch);
+		MDP3_REG_WRITE(MDP3_REG_TEAR_CHECK_EN, 0x1);
 	}
 	return 0;
 }
@@ -286,12 +292,7 @@
 	MDP3_REG_WRITE(MDP3_REG_DMA_P_IBUF_Y_STRIDE, source_config->stride);
 	MDP3_REG_WRITE(MDP3_REG_DMA_P_OUT_XY, dma_p_out_xy);
 
-	/*
-	 * NOTE: MDP_DMA_P_FETCH_CFG: max_burst_size need to use value 4, not
-	 * the default 16 for MDP hang issue workaround
-	 */
-	MDP3_REG_WRITE(MDP3_REG_DMA_P_FETCH_CFG, 0x20);
-	MDP3_REG_WRITE(MDP3_REG_PRIMARY_RD_PTR_IRQ, 0x10);
+	MDP3_REG_WRITE(MDP3_REG_DMA_P_FETCH_CFG, 0x40);
 
 	dma->source_config = *source_config;
 	dma->output_config = *output_config;
@@ -497,7 +498,7 @@
 			struct mdp3_dma_histogram_config *histo_config)
 {
 	unsigned long flag;
-	u32 histo_bit_mask, histo_control;
+	u32 histo_bit_mask = 0, histo_control = 0;
 	u32 histo_isr_mask = MDP3_DMA_P_HIST_INTR_HIST_DONE_BIT |
 			MDP3_DMA_P_HIST_INTR_RESET_DONE_BIT;
 
@@ -530,7 +531,7 @@
 	pr_debug("mdp3_dmap_update\n");
 
 	if (dma->output_config.out_sel == MDP3_DMA_OUTPUT_SEL_DSI_CMD) {
-		cb_type |= MDP3_DMA_CALLBACK_TYPE_DMA_DONE;
+		cb_type = MDP3_DMA_CALLBACK_TYPE_DMA_DONE;
 		if (intf->active)
 			wait_for_completion_killable(&dma->dma_comp);
 	}
@@ -553,7 +554,8 @@
 
 	mdp3_dma_callback_enable(dma, cb_type);
 	pr_debug("mdp3_dmap_update wait for vsync_comp in\n");
-	wait_for_completion_killable(&dma->vsync_comp);
+	if (dma->output_config.out_sel == MDP3_DMA_OUTPUT_SEL_DSI_VIDEO)
+		wait_for_completion_killable(&dma->vsync_comp);
 	pr_debug("mdp3_dmap_update wait for vsync_comp out\n");
 	return 0;
 }
@@ -565,7 +567,7 @@
 	int cb_type = MDP3_DMA_CALLBACK_TYPE_VSYNC;
 
 	if (dma->output_config.out_sel == MDP3_DMA_OUTPUT_SEL_DSI_CMD) {
-		cb_type |= MDP3_DMA_CALLBACK_TYPE_DMA_DONE;
+		cb_type = MDP3_DMA_CALLBACK_TYPE_DMA_DONE;
 		if (intf->active)
 			wait_for_completion_killable(&dma->dma_comp);
 	}
@@ -586,7 +588,8 @@
 	spin_unlock_irqrestore(&dma->dma_lock, flag);
 
 	mdp3_dma_callback_enable(dma, cb_type);
-	wait_for_completion_killable(&dma->vsync_comp);
+	if (dma->output_config.out_sel == MDP3_DMA_OUTPUT_SEL_DSI_VIDEO)
+		wait_for_completion_killable(&dma->vsync_comp);
 	return 0;
 }
 
@@ -631,7 +634,7 @@
 		return ret;
 
 	if (dma->histo_state != MDP3_DMA_HISTO_STATE_READY) {
-		pr_err("mdp3_dmap_histo_get after dma shut down\n");
+		pr_debug("mdp3_dmap_histo_get after dma shut down\n");
 		return -EPERM;
 	}
 
@@ -694,9 +697,6 @@
 	unsigned long flag;
 	int ret;
 
-	if (dma->histo_state == MDP3_DMA_HISTO_STATE_START)
-		return -EINVAL;
-
 	spin_lock_irqsave(&dma->histo_lock, flag);
 
 	init_completion(&dma->histo_comp);
@@ -826,6 +826,7 @@
 					MDP3_DMA_CALLBACK_TYPE_DMA_DONE);
 
 	init_completion(&dma->dma_comp);
+	dma->vsync_client.handler = NULL;
 	return ret;
 }
 
diff --git a/drivers/video/msm/mdss/mdp3_dma.h b/drivers/video/msm/mdss/mdp3_dma.h
index e4a28dc..6983e55 100644
--- a/drivers/video/msm/mdss/mdp3_dma.h
+++ b/drivers/video/msm/mdss/mdp3_dma.h
@@ -16,6 +16,12 @@
 
 #include <linux/sched.h>
 
+#define MDP_HISTOGRAM_BL_SCALE_MAX 1024
+#define MDP_HISTOGRAM_BL_LEVEL_MAX 255
+#define MDP_HISTOGRAM_FRAME_COUNT_MAX 0x20
+#define MDP_HISTOGRAM_BIT_MASK_MAX 0x4
+#define MDP_HISTOGRAM_CSC_MATRIX_MAX 0x2000
+#define MDP_HISTOGRAM_CSC_VECTOR_MAX 0x200
 #define MDP_HISTOGRAM_BIN_NUM	32
 #define MDP_LUT_SIZE 256
 
@@ -145,6 +151,7 @@
 	void *buf;
 	int stride;
 	int vsync_count;
+	int vporch;
 };
 
 struct mdp3_dma_output_config {
diff --git a/drivers/video/msm/mdss/mdp3_ppp.c b/drivers/video/msm/mdss/mdp3_ppp.c
index 924ec5a..e1f2d10 100644
--- a/drivers/video/msm/mdss/mdp3_ppp.c
+++ b/drivers/video/msm/mdss/mdp3_ppp.c
@@ -119,11 +119,22 @@
 		struct mdp3_img_data *data)
 {
 	struct msmfb_data fb_data;
+	uint32_t stride;
+	int bpp = ppp_bpp(img->format);
+
+	if (bpp <= 0) {
+		pr_err("%s incorrect format %d\n", __func__, img->format);
+		return -EINVAL;
+	}
+
 	fb_data.flags = img->priv;
 	fb_data.memory_id = img->memory_id;
 	fb_data.offset = 0;
 
-	return mdp3_get_img(&fb_data, data);
+	stride = img->width * bpp;
+	data->padding = 16 * stride;
+
+	return mdp3_get_img(&fb_data, data, MDP3_CLIENT_PPP);
 }
 
 /* Check format */
@@ -344,8 +355,9 @@
 int mdp3_ppp_turnon(struct msm_fb_data_type *mfd, int on_off)
 {
 	struct mdss_panel_info *panel_info = mfd->panel_info;
-	int ab = 0, ib = 0;
+	uint64_t ab = 0, ib = 0;
 	int rate = 0;
+	int rc;
 
 	if (on_off) {
 		rate = MDP_BLIT_CLK_RATE;
@@ -357,8 +369,17 @@
 		ib = (ab * 3) / 2;
 	}
 	mdp3_clk_set_rate(MDP3_CLK_CORE, rate, MDP3_CLIENT_PPP);
-	mdp3_clk_enable(on_off);
-	mdp3_bus_scale_set_quota(MDP3_CLIENT_PPP, ab, ib);
+	rc = mdp3_clk_enable(on_off);
+	if (rc < 0) {
+		pr_err("%s: mdp3_clk_enable failed\n", __func__);
+		return rc;
+	}
+	rc = mdp3_bus_scale_set_quota(MDP3_CLIENT_PPP, ab, ib);
+	if (rc < 0) {
+		mdp3_clk_enable(!on_off);
+		pr_err("%s: scale_set_quota failed\n", __func__);
+		return rc;
+	}
 	ppp_stat->bw_on = on_off;
 	return 0;
 }
@@ -909,10 +930,14 @@
 static void mdp3_free_bw_wq_handler(struct work_struct *work)
 {
 	struct msm_fb_data_type *mfd = ppp_stat->mfd;
+	int rc;
+
 	mutex_lock(&ppp_stat->config_ppp_mutex);
 	if (ppp_stat->bw_on) {
 		mdp3_ppp_turnon(mfd, 0);
-		mdp3_iommu_disable(MDP3_CLIENT_PPP);
+		rc = mdp3_iommu_disable(MDP3_CLIENT_PPP);
+		if (rc < 0)
+			WARN(1, "Unable to disable ppp iommu\n");
 	}
 	mutex_unlock(&ppp_stat->config_ppp_mutex);
 }
@@ -931,8 +956,19 @@
 	}
 
 	if (!ppp_stat->bw_on) {
-		mdp3_iommu_enable(MDP3_CLIENT_PPP);
+		rc = mdp3_iommu_enable(MDP3_CLIENT_PPP);
+		if (rc < 0) {
+			mutex_unlock(&ppp_stat->config_ppp_mutex);
+			pr_err("%s: mdp3_iommu_enable failed\n", __func__);
+			return;
+		}
 		mdp3_ppp_turnon(mfd, 1);
+		if (rc < 0) {
+			mdp3_iommu_disable(MDP3_CLIENT_PPP);
+			mutex_unlock(&ppp_stat->config_ppp_mutex);
+			pr_err("%s: Enable ppp resources failed\n", __func__);
+			return;
+		}
 	}
 	while (req) {
 		mdp3_ppp_wait_for_fence(req);
@@ -945,8 +981,10 @@
 						&req->src_data[i],
 						&req->dst_data[i]);
 				}
-				mdp3_put_img(&req->src_data[i]);
-				mdp3_put_img(&req->dst_data[i]);
+				mdp3_put_img(&req->src_data[i],
+					MDP3_CLIENT_PPP);
+				mdp3_put_img(&req->dst_data[i],
+					MDP3_CLIENT_PPP);
 			}
 		}
 		/* Signal to release fence */
@@ -1017,7 +1055,7 @@
 		rc = mdp3_ppp_get_img(&req->req_list[i].dst,
 				&req->req_list[i], &req->dst_data[i]);
 		if (rc < 0 || req->dst_data[i].len == 0) {
-			mdp3_put_img(&req->src_data[i]);
+			mdp3_put_img(&req->src_data[i], MDP3_CLIENT_PPP);
 			pr_err("mdp_ppp: couldn't retrieve dest img from mem\n");
 			goto parse_err_1;
 		}
@@ -1060,8 +1098,8 @@
 	put_unused_fd(req->cur_rel_fen_fd);
 parse_err_1:
 	for (i--; i >= 0; i--) {
-		mdp3_put_img(&req->src_data[i]);
-		mdp3_put_img(&req->dst_data[i]);
+		mdp3_put_img(&req->src_data[i], MDP3_CLIENT_PPP);
+		mdp3_put_img(&req->dst_data[i], MDP3_CLIENT_PPP);
 	}
 	mdp3_ppp_deinit_buf_sync(req);
 	mutex_unlock(&ppp_stat->req_mutex);
diff --git a/drivers/video/msm/mdss/mdp3_ppp_hwio.c b/drivers/video/msm/mdss/mdp3_ppp_hwio.c
index 199387f..a051037 100644
--- a/drivers/video/msm/mdss/mdp3_ppp_hwio.c
+++ b/drivers/video/msm/mdss/mdp3_ppp_hwio.c
@@ -361,38 +361,6 @@
 	return rgb;
 }
 
-uint8_t *mdp_bg_adjust_rot_addr(struct ppp_blit_op *iBuf,
-	uint8_t *addr, uint32_t bpp, uint32_t uv)
-{
-	uint32_t dest_ystride = iBuf->bg.prop.width * bpp;
-	uint32_t h_slice = 1, min_val;
-
-	if (uv && ((iBuf->bg.color_fmt == MDP_Y_CBCR_H2V2) ||
-		(iBuf->bg.color_fmt == MDP_Y_CRCB_H2V2)))
-		h_slice = 2;
-
-	if (((iBuf->mdp_op & MDPOP_ROT90) == MDPOP_ROT90) ^
-		((iBuf->mdp_op & MDPOP_LR) == MDPOP_LR)) {
-		min_val = (iBuf->bg.roi.width + iBuf->bg.roi.x) % 16;
-		if (!min_val)
-			min_val = 16;
-		addr +=
-		    (iBuf->bg.roi.width -
-			    MIN(min_val, iBuf->bg.roi.width)) * bpp;
-	}
-	if ((iBuf->mdp_op & MDPOP_UD) == MDPOP_UD) {
-		min_val = (iBuf->bg.roi.height + iBuf->bg.roi.y) % 16;
-		if (!min_val)
-			min_val = 16;
-		addr +=
-			((iBuf->bg.roi.height -
-			MIN(min_val, iBuf->bg.roi.height))/h_slice) *
-			dest_ystride;
-	}
-
-	return addr;
-}
-
 uint8_t *mdp_dst_adjust_rot_addr(struct ppp_blit_op *iBuf,
 	uint8_t *addr, uint32_t bpp, uint32_t uv)
 {
@@ -434,9 +402,7 @@
 		img->p0 += (x + y * ALIGN(width, 128)) * bpp;
 	else
 		img->p0 += (x + y * width) * bpp;
-	if (layer == 1)
-		img->p0 = mdp_bg_adjust_rot_addr(blit_op, img->p0, bpp, 0);
-	else if (layer == 2)
+	if (layer != 0)
 		img->p0 = mdp_dst_adjust_rot_addr(blit_op, img->p0, bpp, 0);
 
 	if (img->p1) {
@@ -454,13 +420,9 @@
 			img->p1 += ((x / h_slice) * h_slice +
 			((y == 0) ? 0 : ((y + 1) / v_slice - 1) * width)) * bpp;
 
-		if (layer == 1) {
-			img->p0 = mdp_bg_adjust_rot_addr(blit_op,
-					img->p0, bpp, 0);
-		} else if (layer == 2) {
+		if (layer != 0)
 			img->p0 = mdp_dst_adjust_rot_addr(blit_op,
 					img->p0, bpp, 0);
-		}
 	}
 }
 
diff --git a/drivers/video/msm/mdss/mdss.h b/drivers/video/msm/mdss/mdss.h
index 840af17..dd1a95b 100644
--- a/drivers/video/msm/mdss/mdss.h
+++ b/drivers/video/msm/mdss/mdss.h
@@ -23,6 +23,8 @@
 
 #include <mach/iommu_domains.h>
 
+#include "mdss_panel.h"
+
 #define MDSS_REG_WRITE(addr, val) writel_relaxed(val, mdss_res->mdp_base + addr)
 #define MDSS_REG_READ(addr) readl_relaxed(mdss_res->mdp_base + addr)
 
@@ -56,6 +58,12 @@
 	u32 val;
 };
 
+struct mdss_debug_inf {
+	void *debug_data;
+	int (*debug_dump_stats)(void *data, char *buf, int len);
+	void (*debug_enable_clock)(int on);
+};
+
 struct mdss_data_type {
 	u32 mdp_rev;
 	struct clk *mdp_clk[MDSS_MAX_CLK];
@@ -74,6 +82,7 @@
 	u32 has_bwc;
 	u32 has_decimation;
 	u8 has_wfd_blk;
+	u8 has_wb_ad;
 
 	u32 mdp_irq_mask;
 	u32 mdp_hist_irq_mask;
@@ -112,6 +121,7 @@
 	void *video_intf;
 	u32 nintf;
 
+	u32 pp_bus_hdl;
 	struct mdss_ad_info *ad_cfgs;
 	u32 nad_cfgs;
 	struct workqueue_struct *ad_calc_wq;
@@ -121,9 +131,10 @@
 	struct mdss_iommu_map_type *iommu_map;
 
 	struct early_suspend early_suspend;
-	void *debug_data;
+	struct mdss_debug_inf debug_inf;
 	int current_bus_idx;
 	bool mixer_switched;
+	struct mdss_panel_cfg pan_cfg;
 };
 extern struct mdss_data_type *mdss_res;
 
diff --git a/drivers/video/msm/mdss/mdss_debug.c b/drivers/video/msm/mdss/mdss_debug.c
index 13fba26..f933c8e 100644
--- a/drivers/video/msm/mdss/mdss_debug.c
+++ b/drivers/video/msm/mdss/mdss_debug.c
@@ -128,11 +128,12 @@
 		const char __user *user_buf, size_t count, loff_t *ppos)
 {
 	struct mdss_debug_base *dbg = file->private_data;
+	struct mdss_data_type *mdata = mdss_res;
 	size_t off;
 	u32 data, cnt;
 	char buf[24];
 
-	if (!dbg)
+	if (!dbg || !mdata)
 		return -ENODEV;
 
 	if (count >= sizeof(buf))
@@ -151,9 +152,13 @@
 	if (off >= dbg->max_offset)
 		return -EFAULT;
 
-	mdss_mdp_clk_ctrl(MDP_BLOCK_POWER_ON, false);
+	if (mdata->debug_inf.debug_enable_clock)
+		mdata->debug_inf.debug_enable_clock(1);
+
 	writel_relaxed(data, dbg->base + off);
-	mdss_mdp_clk_ctrl(MDP_BLOCK_POWER_OFF, false);
+
+	if (mdata->debug_inf.debug_enable_clock)
+		mdata->debug_inf.debug_enable_clock(0);
 
 	pr_debug("addr=%x data=%x\n", off, data);
 
@@ -164,9 +169,10 @@
 			char __user *user_buf, size_t count, loff_t *ppos)
 {
 	struct mdss_debug_base *dbg = file->private_data;
+	struct mdss_data_type *mdata = mdss_res;
 	size_t len;
 
-	if (!dbg) {
+	if (!dbg || !mdata) {
 		pr_err("invalid handle\n");
 		return -ENODEV;
 	}
@@ -188,7 +194,9 @@
 		ptr = dbg->base + dbg->off;
 		tot = 0;
 
-		mdss_mdp_clk_ctrl(MDP_BLOCK_POWER_ON, false);
+		if (mdata->debug_inf.debug_enable_clock)
+			mdata->debug_inf.debug_enable_clock(1);
+
 		for (cnt = dbg->cnt; cnt > 0; cnt -= ROW_BYTES) {
 			hex_dump_to_buffer(ptr, min(cnt, ROW_BYTES),
 					   ROW_BYTES, GROUP_BYTES, dump_buf,
@@ -203,7 +211,8 @@
 			if (tot >= dbg->buf_len)
 				break;
 		}
-		mdss_mdp_clk_ctrl(MDP_BLOCK_POWER_OFF, false);
+		if (mdata->debug_inf.debug_enable_clock)
+			mdata->debug_inf.debug_enable_clock(0);
 
 		dbg->buf_len = tot;
 	}
@@ -246,10 +255,10 @@
 	char dn[80] = "";
 	int prefix_len = 0;
 
-	if (!mdata || !mdata->debug_data)
+	if (!mdata || !mdata->debug_inf.debug_data)
 		return -ENODEV;
 
-	mdd = mdata->debug_data;
+	mdd = mdata->debug_inf.debug_data;
 
 	dbg = kzalloc(sizeof(*dbg), GFP_KERNEL);
 	if (!dbg)
@@ -301,33 +310,11 @@
 	return 0;
 }
 
-static int mdss_debug_stat_ctl_dump(struct mdss_mdp_ctl *ctl,
-		char *bp, int len)
-{
-	int tot = 0;
-
-	if (!ctl->ref_cnt)
-		return 0;
-
-	if (ctl->intf_num) {
-		tot = scnprintf(bp, len,
-			"intf%d: play: %08u \tvsync: %08u \tunderrun: %08u\n",
-				ctl->intf_num, ctl->play_cnt,
-				ctl->vsync_cnt, ctl->underrun_cnt);
-	} else {
-		tot = scnprintf(bp, len, "wb: \tmode=%x \tplay: %08u\n",
-				ctl->opmode, ctl->play_cnt);
-	}
-
-	return tot;
-}
-
 static ssize_t mdss_debug_stat_read(struct file *file, char __user *buff,
 		size_t count, loff_t *ppos)
 {
 	struct mdss_data_type *mdata = file->private_data;
-	struct mdss_mdp_pipe *pipe;
-	int i, len, tot;
+	int len, tot;
 	char bp[512];
 
 	if (*ppos)
@@ -337,30 +324,11 @@
 
 	tot = scnprintf(bp, len, "\nmdp:\n");
 
-	for (i = 0; i < mdata->nctl; i++)
-		tot += mdss_debug_stat_ctl_dump(mdata->ctl_off + i,
-				bp + tot, len - tot);
-	tot += scnprintf(bp + tot, len - tot, "\n");
+	if (mdata->debug_inf.debug_dump_stats)
+		tot += mdata->debug_inf.debug_dump_stats(mdata,
+						bp + tot, len - tot);
 
-	for (i = 0; i < mdata->nvig_pipes; i++) {
-		pipe = mdata->vig_pipes + i;
-		tot += scnprintf(bp + tot, len - tot,
-			"VIG%d :   %08u\t", i, pipe->play_cnt);
-	}
-	tot += scnprintf(bp + tot, len - tot, "\n");
 
-	for (i = 0; i < mdata->nrgb_pipes; i++) {
-		pipe = mdata->rgb_pipes + i;
-		tot += scnprintf(bp + tot, len - tot,
-			"RGB%d :   %08u\t", i, pipe->play_cnt);
-	}
-	tot += scnprintf(bp + tot, len - tot, "\n");
-
-	for (i = 0; i < mdata->ndma_pipes; i++) {
-		pipe = mdata->dma_pipes + i;
-		tot += scnprintf(bp + tot, len - tot,
-			"DMA%d :   %08u\t", i, pipe->play_cnt);
-	}
 	tot += scnprintf(bp + tot, len - tot, "\n");
 
 	if (copy_to_user(buff, bp, tot))
@@ -401,7 +369,7 @@
 {
 	struct mdss_debug_data *mdd;
 
-	if (mdata->debug_data) {
+	if (mdata->debug_inf.debug_data) {
 		pr_warn("mdss debugfs already initialized\n");
 		return -EBUSY;
 	}
@@ -424,18 +392,19 @@
 	debugfs_create_file("stat", 0644, mdd->root, mdata, &mdss_stat_fops);
 
 	debugfs_create_u32("min_mdp_clk", 0644, mdd->root,
-		(u32 *)&mdata->min_mdp_clk);
+			(u32 *)&mdata->min_mdp_clk);
 
-	mdata->debug_data = mdd;
+	mdata->debug_inf.debug_data = mdd;
 
 	return 0;
 }
 
 int mdss_debugfs_remove(struct mdss_data_type *mdata)
 {
-	struct mdss_debug_data *mdd = mdata->debug_data;
+	struct mdss_debug_data *mdd = mdata->debug_inf.debug_data;
 
 	mdss_debugfs_cleanup(mdd);
+	mdata->debug_inf.debug_data = NULL;
 
 	return 0;
 }
diff --git a/drivers/video/msm/mdss/mdss_dsi.c b/drivers/video/msm/mdss/mdss_dsi.c
index a575d6d..e156116 100644
--- a/drivers/video/msm/mdss/mdss_dsi.c
+++ b/drivers/video/msm/mdss/mdss_dsi.c
@@ -262,6 +262,29 @@
 	return rc;
 }
 
+static int mdss_dsi_get_panel_cfg(char *panel_cfg)
+{
+	int rc;
+	struct mdss_panel_cfg *pan_cfg = NULL;
+
+	if (!panel_cfg)
+		return MDSS_PANEL_INTF_INVALID;
+
+	pan_cfg = mdss_panel_intf_type(MDSS_PANEL_INTF_DSI);
+	if (IS_ERR(pan_cfg)) {
+		return PTR_ERR(pan_cfg);
+	} else if (!pan_cfg) {
+		panel_cfg[0] = 0;
+		return 0;
+	}
+
+	pr_debug("%s:%d: cfg:[%s]\n", __func__, __LINE__,
+		 pan_cfg->arg_cfg);
+	rc = strlcpy(panel_cfg, pan_cfg->arg_cfg,
+		     sizeof(pan_cfg->arg_cfg));
+	return rc;
+}
+
 static int mdss_dsi_off(struct mdss_panel_data *pdata)
 {
 	int ret = 0;
@@ -636,98 +659,212 @@
 	return rc;
 }
 
+/**
+ * mdss_dsi_find_panel_of_node(): find device node of dsi panel
+ * @pdev: platform_device of the dsi ctrl node
+ * @panel_cfg: string containing intf specific config data
+ *
+ * Function finds the panel device node using the interface
+ * specific configuration data. This configuration data is
+ * could be derived from the result of bootloader's GCDB
+ * panel detection mechanism. If such config data doesn't
+ * exist then this panel returns the default panel configured
+ * in the device tree.
+ *
+ * returns pointer to panel node on success, NULL on error.
+ */
+static struct device_node *mdss_dsi_find_panel_of_node(
+		struct platform_device *pdev, char *panel_cfg)
+{
+	int l;
+	int ctrl_id = -1;
+	char *panel_name;
+	struct device_node *dsi_pan_node = NULL, *mdss_node = NULL;
+
+	l = strlen(panel_cfg);
+	if (!l) {
+		/* no panel cfg chg, parse dt */
+		pr_debug("%s:%d: no cmd line cfg present\n",
+			 __func__, __LINE__);
+		dsi_pan_node = of_parse_phandle(
+			pdev->dev.of_node,
+			"qcom,dsi-pref-prim-pan", 0);
+		if (!dsi_pan_node) {
+			pr_err("%s:can't find panel phandle\n",
+			       __func__);
+			return NULL;
+		}
+	} else {
+		if (panel_cfg[0] == '0') {
+			pr_debug("%s:%d: DSI ctrl 1\n", __func__, __LINE__);
+			ctrl_id = 0;
+		} else if (panel_cfg[0] == '1') {
+			pr_debug("%s:%d: DSI ctrl 2\n", __func__, __LINE__);
+			ctrl_id = 1;
+		}
+		if ((pdev->id - 1) != ctrl_id) {
+			pr_err("%s:%d:pdev_ID=[%d]\n",
+			       __func__, __LINE__, pdev->id);
+			return NULL;
+		}
+		/*
+		 * skip first two chars '<dsi_ctrl_id>' and
+		 * ':' to get to the panel name
+		 */
+		panel_name = panel_cfg + 2;
+		pr_debug("%s:%d:%s:%s\n", __func__, __LINE__,
+			 panel_cfg, panel_name);
+
+		mdss_node = of_parse_phandle(pdev->dev.of_node,
+					     "qcom,mdss-mdp", 0);
+
+		if (!mdss_node) {
+			pr_err("%s: %d: mdss_node null\n",
+			       __func__, __LINE__);
+			return NULL;
+		}
+		dsi_pan_node = of_find_node_by_name(mdss_node,
+						    panel_name);
+		if (!dsi_pan_node) {
+			pr_err("%s: invalid pan node\n",
+			       __func__);
+			return NULL;
+		}
+	}
+	return dsi_pan_node;
+}
+
 static int __devinit mdss_dsi_ctrl_probe(struct platform_device *pdev)
 {
 	int rc = 0;
 	u32 index;
 	struct mdss_dsi_ctrl_pdata *ctrl_pdata = NULL;
+	struct device_node *dsi_pan_node = NULL;
+	char panel_cfg[MDSS_MAX_PANEL_LEN];
+	struct resource *mdss_dsi_mres;
+	const char *ctrl_name;
+	bool cmd_cfg_cont_splash = true;
 
-	if (pdev->dev.of_node) {
-		struct resource *mdss_dsi_mres;
-		const char *ctrl_name;
+	if (!mdss_is_ready()) {
+		pr_err("%s: MDP not probed yet!\n", __func__);
+		return -EPROBE_DEFER;
+	}
 
-		ctrl_pdata = platform_get_drvdata(pdev);
+	if (!pdev->dev.of_node) {
+		pr_err("DSI driver only supports device tree probe\n");
+		return -ENOTSUPP;
+	}
+
+	ctrl_pdata = platform_get_drvdata(pdev);
+	if (!ctrl_pdata) {
+		ctrl_pdata = devm_kzalloc(&pdev->dev,
+					  sizeof(struct mdss_dsi_ctrl_pdata),
+					  GFP_KERNEL);
 		if (!ctrl_pdata) {
-			ctrl_pdata = devm_kzalloc(&pdev->dev,
-				sizeof(struct mdss_dsi_ctrl_pdata), GFP_KERNEL);
-			if (!ctrl_pdata) {
-				pr_err("%s: FAILED: cannot alloc dsi ctrl\n",
-					__func__);
-				rc = -ENOMEM;
-				goto error_no_mem;
-			}
-			platform_set_drvdata(pdev, ctrl_pdata);
-		}
-
-		ctrl_name = of_get_property(pdev->dev.of_node, "label", NULL);
-		if (!ctrl_name)
-			pr_info("%s:%d, DSI Ctrl name not specified\n",
-						__func__, __LINE__);
-		else
-			pr_info("%s: DSI Ctrl name = %s\n",
-				__func__, ctrl_name);
-
-		rc = of_property_read_u32(pdev->dev.of_node,
-					  "cell-index", &index);
-		if (rc) {
-			dev_err(&pdev->dev,
-				"%s: Cell-index not specified, rc=%d\n",
-							__func__, rc);
-			goto error_no_mem;
-		}
-
-		if (index == 0)
-			pdev->id = 1;
-		else
-			pdev->id = 2;
-
-		mdss_dsi_mres = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-		if (!mdss_dsi_mres) {
-			pr_err("%s:%d unable to get the MDSS resources",
-				       __func__, __LINE__);
+			pr_err("%s: FAILED: cannot alloc dsi ctrl\n",
+			       __func__);
 			rc = -ENOMEM;
 			goto error_no_mem;
 		}
-		if (mdss_dsi_mres) {
-			mdss_dsi_base = ioremap(mdss_dsi_mres->start,
-				resource_size(mdss_dsi_mres));
-			if (!mdss_dsi_base) {
-				pr_err("%s:%d unable to remap dsi resources",
-					       __func__, __LINE__);
-				rc = -ENOMEM;
-				goto error_no_mem;
-			}
-		}
-
-		rc = of_platform_populate(pdev->dev.of_node,
-					NULL, NULL, &pdev->dev);
-		if (rc) {
-			dev_err(&pdev->dev,
-				"%s: failed to add child nodes, rc=%d\n",
-							__func__, rc);
-			goto error_ioremap;
-		}
-
-		/* Parse the regulator information */
-		rc = mdss_dsi_get_dt_vreg_data(&pdev->dev,
-			&ctrl_pdata->power_data);
-		if (rc) {
-			pr_err("%s: failed to get vreg data from dt. rc=%d\n",
-				__func__, rc);
-			goto error_vreg;
-		}
-
-		pr_debug("%s: Dsi Ctrl->%d initialized\n", __func__, index);
+		platform_set_drvdata(pdev, ctrl_pdata);
 	}
 
+	ctrl_name = of_get_property(pdev->dev.of_node, "label", NULL);
+	if (!ctrl_name)
+		pr_info("%s:%d, DSI Ctrl name not specified\n",
+			__func__, __LINE__);
+	else
+		pr_info("%s: DSI Ctrl name = %s\n",
+			__func__, ctrl_name);
+
+	rc = of_property_read_u32(pdev->dev.of_node,
+				  "cell-index", &index);
+	if (rc) {
+		dev_err(&pdev->dev,
+			"%s: Cell-index not specified, rc=%d\n",
+			__func__, rc);
+		goto error_no_mem;
+	}
+
+	if (index == 0)
+		pdev->id = 1;
+	else
+		pdev->id = 2;
+
+	mdss_dsi_mres = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+	if (!mdss_dsi_mres) {
+		pr_err("%s:%d unable to get the MDSS resources",
+		       __func__, __LINE__);
+		rc = -ENOMEM;
+		goto error_no_mem;
+	}
+
+	mdss_dsi_base = ioremap(mdss_dsi_mres->start,
+				resource_size(mdss_dsi_mres));
+	if (!mdss_dsi_base) {
+		pr_err("%s:%d unable to remap dsi resources",
+		       __func__, __LINE__);
+		rc = -ENOMEM;
+		goto error_no_mem;
+	}
+
+	rc = of_platform_populate(pdev->dev.of_node,
+				  NULL, NULL, &pdev->dev);
+	if (rc) {
+		dev_err(&pdev->dev,
+			"%s: failed to add child nodes, rc=%d\n",
+			__func__, rc);
+		goto error_ioremap;
+	}
+
+	/* Parse the regulator information */
+	rc = mdss_dsi_get_dt_vreg_data(&pdev->dev,
+				       &ctrl_pdata->power_data);
+	if (rc) {
+		pr_err("%s: failed to get vreg data from dt. rc=%d\n",
+		       __func__, rc);
+		goto error_vreg;
+	}
+
+	/* DSI panels can be different between controllers */
+	rc = mdss_dsi_get_panel_cfg(panel_cfg);
+	if (!rc)
+		/* dsi panel cfg not present */
+		pr_warn("%s:%d:dsi specific cfg not present\n",
+			__func__, __LINE__);
+
+	/* find panel device node */
+	dsi_pan_node = mdss_dsi_find_panel_of_node(pdev, panel_cfg);
+	if (!dsi_pan_node) {
+		pr_err("%s: can't find panel node %s\n", __func__, panel_cfg);
+		goto error_pan_node;
+	}
+
+	cmd_cfg_cont_splash = mdss_panel_get_boot_cfg() ? true : false;
+
+	rc = mdss_dsi_panel_init(dsi_pan_node, ctrl_pdata, cmd_cfg_cont_splash);
+	if (rc) {
+		pr_err("%s: dsi panel init failed\n", __func__);
+		goto error_pan_node;
+	}
+
+	rc = dsi_panel_device_register(dsi_pan_node, ctrl_pdata);
+	if (rc) {
+		pr_err("%s: dsi panel dev reg failed\n", __func__);
+		goto error_pan_node;
+	}
+
+	pr_debug("%s: Dsi Ctrl->%d initialized\n", __func__, index);
 	return 0;
 
+error_pan_node:
+	of_node_put(dsi_pan_node);
+error_vreg:
+	mdss_dsi_put_dt_vreg_data(&pdev->dev, &ctrl_pdata->power_data);
 error_ioremap:
 	iounmap(mdss_dsi_base);
 error_no_mem:
 	devm_kfree(&pdev->dev, ctrl_pdata);
-error_vreg:
-	mdss_dsi_put_dt_vreg_data(&pdev->dev, &ctrl_pdata->power_data);
 
 	return rc;
 }
@@ -810,33 +947,32 @@
 	return 0;
 }
 
-
-int dsi_panel_device_register(struct platform_device *pdev,
-			      struct mdss_panel_common_pdata *panel_data)
+int dsi_panel_device_register(struct device_node *pan_node,
+				struct mdss_dsi_ctrl_pdata *ctrl_pdata)
 {
 	struct mipi_panel_info *mipi;
 	int rc, i, len;
 	u8 lanes = 0, bpp;
 	u32 h_period, v_period, dsi_pclk_rate, tmp[9];
-	struct mdss_dsi_ctrl_pdata *ctrl_pdata;
 	struct device_node *dsi_ctrl_np = NULL;
 	struct platform_device *ctrl_pdev = NULL;
-	bool cont_splash_enabled = false;
 	const char *data;
+	struct mdss_panel_info *pinfo = &(ctrl_pdata->panel_data.panel_info);
 
-	h_period = ((panel_data->panel_info.lcdc.h_pulse_width)
-			+ (panel_data->panel_info.lcdc.h_back_porch)
-			+ (panel_data->panel_info.xres)
-			+ (panel_data->panel_info.lcdc.h_front_porch));
+	h_period = ((pinfo->lcdc.h_pulse_width)
+			+ (pinfo->lcdc.h_back_porch)
+			+ (pinfo->xres)
+			+ (pinfo->lcdc.h_front_porch));
 
-	v_period = ((panel_data->panel_info.lcdc.v_pulse_width)
-			+ (panel_data->panel_info.lcdc.v_back_porch)
-			+ (panel_data->panel_info.yres)
-			+ (panel_data->panel_info.lcdc.v_front_porch));
+	v_period = ((pinfo->lcdc.v_pulse_width)
+			+ (pinfo->lcdc.v_back_porch)
+			+ (pinfo->yres)
+			+ (pinfo->lcdc.v_front_porch));
 
-	mipi  = &panel_data->panel_info.mipi;
+	mipi  = &pinfo->mipi;
+	mipi  = &(pinfo->mipi);
 
-	panel_data->panel_info.type =
+	pinfo->type =
 		((mipi->mode == DSI_VIDEO_MODE)
 			? MIPI_VIDEO_PANEL : MIPI_CMD_PANEL);
 
@@ -860,22 +996,22 @@
 	else
 		bpp = 3;		/* Default format set to RGB888 */
 
-	if (!panel_data->panel_info.clk_rate) {
-		h_period += panel_data->panel_info.lcdc.xres_pad;
-		v_period += panel_data->panel_info.lcdc.yres_pad;
+	if (!pinfo->clk_rate) {
+		h_period += pinfo->lcdc.xres_pad;
+		v_period += pinfo->lcdc.yres_pad;
 
 		if (lanes > 0) {
-			panel_data->panel_info.clk_rate =
+			pinfo->clk_rate =
 			((h_period * v_period * (mipi->frame_rate) * bpp * 8)
 			   / lanes);
 		} else {
 			pr_err("%s: forcing mdss_dsi lanes to 1\n", __func__);
-			panel_data->panel_info.clk_rate =
+			pinfo->clk_rate =
 				(h_period * v_period
 					 * (mipi->frame_rate) * bpp * 8);
 		}
 	}
-	pll_divider_config.clk_rate = panel_data->panel_info.clk_rate;
+	pll_divider_config.clk_rate = pinfo->clk_rate;
 
 	rc = mdss_dsi_clk_div_config(bpp, lanes, &dsi_pclk_rate);
 	if (rc) {
@@ -887,7 +1023,7 @@
 		dsi_pclk_rate = 35000000;
 	mipi->dsi_pclk_rate = dsi_pclk_rate;
 
-	dsi_ctrl_np = of_parse_phandle(pdev->dev.of_node,
+	dsi_ctrl_np = of_parse_phandle(pan_node,
 				"qcom,mdss-dsi-panel-controller", 0);
 	if (!dsi_ctrl_np) {
 		pr_err("%s: Dsi controller node not initialized\n", __func__);
@@ -895,16 +1031,10 @@
 	}
 
 	ctrl_pdev = of_find_device_by_node(dsi_ctrl_np);
-	ctrl_pdata = platform_get_drvdata(ctrl_pdev);
-	if (!ctrl_pdata) {
-		pr_err("%s: no dsi ctrl driver data\n", __func__);
-		return -EINVAL;
-	}
 
 	rc = mdss_dsi_regulator_init(ctrl_pdev);
 	if (rc) {
-		dev_err(&pdev->dev,
-			"%s: failed to init regulator, rc=%d\n",
+		pr_err("%s: failed to init regulator, rc=%d\n",
 						__func__, rc);
 		return rc;
 	}
@@ -916,8 +1046,8 @@
 			__func__, __LINE__);
 		return -EINVAL;
 	}
-	(panel_data->panel_info.mipi.dsi_phy_db)->strength[0] = data[0];
-	(panel_data->panel_info.mipi.dsi_phy_db)->strength[1] = data[1];
+	pinfo->mipi.dsi_phy_db.strength[0] = data[0];
+	pinfo->mipi.dsi_phy_db.strength[1] = data[1];
 
 	data = of_get_property(ctrl_pdev->dev.of_node,
 		"qcom,platform-regulator-settings", &len);
@@ -927,7 +1057,7 @@
 		return -EINVAL;
 	}
 	for (i = 0; i < len; i++) {
-		(panel_data->panel_info.mipi.dsi_phy_db)->regulator[i]
+		pinfo->mipi.dsi_phy_db.regulator[i]
 			= data[i];
 	}
 
@@ -939,7 +1069,7 @@
 		return -EINVAL;
 	}
 	for (i = 0; i < len; i++) {
-		(panel_data->panel_info.mipi.dsi_phy_db)->bistCtrl[i]
+		pinfo->mipi.dsi_phy_db.bistctrl[i]
 			= data[i];
 	}
 
@@ -951,15 +1081,16 @@
 		return -EINVAL;
 	}
 	for (i = 0; i < len; i++) {
-		(panel_data->panel_info.mipi.dsi_phy_db)->laneCfg[i] =
+		pinfo->mipi.dsi_phy_db.lanecfg[i] =
 			data[i];
 	}
 
 	ctrl_pdata->shared_pdata.broadcast_enable = of_property_read_bool(
-		pdev->dev.of_node, "qcom,mdss-dsi-panel-broadcast-mode");
+		pan_node, "qcom,mdss-dsi-panel-broadcast-mode");
 
 	ctrl_pdata->disp_en_gpio = of_get_named_gpio(ctrl_pdev->dev.of_node,
 		"qcom,platform-enable-gpio", 0);
+
 	if (!gpio_is_valid(ctrl_pdata->disp_en_gpio)) {
 		pr_err("%s:%d, Disp_en gpio not specified\n",
 						__func__, __LINE__);
@@ -973,12 +1104,16 @@
 		}
 	}
 
-	ctrl_pdata->disp_te_gpio = of_get_named_gpio(ctrl_pdev->dev.of_node,
+	if (pinfo->type == MIPI_CMD_PANEL) {
+		ctrl_pdata->disp_te_gpio = of_get_named_gpio(ctrl_pdev->dev.of_node,
 						"qcom,platform-te-gpio", 0);
-	if (!gpio_is_valid(ctrl_pdata->disp_te_gpio)) {
-		pr_err("%s:%d, Disp_te gpio not specified\n",
+		if (!gpio_is_valid(ctrl_pdata->disp_te_gpio)) {
+			pr_err("%s:%d, Disp_te gpio not specified\n",
 						__func__, __LINE__);
-	} else {
+		}
+	}
+
+	if (gpio_is_valid(ctrl_pdata->disp_te_gpio)) {
 		rc = gpio_request(ctrl_pdata->disp_te_gpio, "disp_te");
 		if (rc) {
 			pr_err("request TE gpio failed, rc=%d\n",
@@ -1037,13 +1172,38 @@
 		}
 	}
 
+	if (pinfo->mode_gpio_state != MODE_GPIO_NOT_VALID) {
+
+		ctrl_pdata->mode_gpio = of_get_named_gpio(
+					ctrl_pdev->dev.of_node,
+					"qcom,platform-mode-gpio", 0);
+		if (!gpio_is_valid(ctrl_pdata->mode_gpio)) {
+			pr_info("%s:%d, mode gpio not specified\n",
+							__func__, __LINE__);
+		} else {
+			rc = gpio_request(ctrl_pdata->mode_gpio, "panel_mode");
+			if (rc) {
+				pr_err("request panel mode gpio failed,rc=%d\n",
+									rc);
+				gpio_free(ctrl_pdata->mode_gpio);
+				if (gpio_is_valid(ctrl_pdata->disp_en_gpio))
+					gpio_free(ctrl_pdata->disp_en_gpio);
+				if (gpio_is_valid(ctrl_pdata->rst_gpio))
+					gpio_free(ctrl_pdata->rst_gpio);
+				if (gpio_is_valid(ctrl_pdata->disp_te_gpio))
+					gpio_free(ctrl_pdata->disp_te_gpio);
+				return -ENODEV;
+			}
+		}
+	}
+
 	if (mdss_dsi_clk_init(ctrl_pdev, ctrl_pdata)) {
 		pr_err("%s: unable to initialize Dsi ctrl clks\n", __func__);
 		return -EPERM;
 	}
 
 	if (mdss_dsi_retrieve_ctrl_resources(ctrl_pdev,
-					     panel_data->panel_info.pdest,
+					     pinfo->pdest,
 					     ctrl_pdata)) {
 		pr_err("%s: unable to get Dsi controller res\n", __func__);
 		return -EPERM;
@@ -1051,20 +1211,6 @@
 
 	ctrl_pdata->panel_data.event_handler = mdss_dsi_event_handler;
 
-	ctrl_pdata->on_cmds = panel_data->on_cmds;
-	ctrl_pdata->off_cmds = panel_data->off_cmds;
-
-	memcpy(&((ctrl_pdata->panel_data).panel_info),
-				&(panel_data->panel_info),
-				       sizeof(struct mdss_panel_info));
-
-	ctrl_pdata->panel_data.set_backlight = panel_data->bl_fnc;
-	ctrl_pdata->bklt_ctrl = panel_data->panel_info.bklt_ctrl;
-	ctrl_pdata->pwm_pmic_gpio = panel_data->panel_info.pwm_pmic_gpio;
-	ctrl_pdata->pwm_period = panel_data->panel_info.pwm_period;
-	ctrl_pdata->pwm_lpg_chan = panel_data->panel_info.pwm_lpg_chan;
-	ctrl_pdata->bklt_max = panel_data->panel_info.bl_max;
-
 	if (ctrl_pdata->bklt_ctrl == BL_PWM)
 		mdss_dsi_panel_pwm_cfg(ctrl_pdata);
 
@@ -1074,24 +1220,14 @@
 	 */
 
 	ctrl_pdata->pclk_rate = dsi_pclk_rate;
-	ctrl_pdata->byte_clk_rate = panel_data->panel_info.clk_rate / 8;
+	ctrl_pdata->byte_clk_rate = pinfo->clk_rate / 8;
 	pr_debug("%s: pclk=%d, bclk=%d\n", __func__,
 			ctrl_pdata->pclk_rate, ctrl_pdata->byte_clk_rate);
 
 	ctrl_pdata->ctrl_state = CTRL_STATE_UNKNOWN;
-	cont_splash_enabled = of_property_read_bool(pdev->dev.of_node,
-			"qcom,cont-splash-enabled");
-	if (!cont_splash_enabled) {
-		pr_info("%s:%d Continuous splash flag not found.\n",
-				__func__, __LINE__);
-		ctrl_pdata->panel_data.panel_info.cont_splash_enabled = 0;
-		ctrl_pdata->panel_data.panel_info.panel_power_on = 0;
-	} else {
-		pr_info("%s:%d Continuous splash flag enabled.\n",
-				__func__, __LINE__);
 
-		ctrl_pdata->panel_data.panel_info.cont_splash_enabled = 1;
-		ctrl_pdata->panel_data.panel_info.panel_power_on = 1;
+	if (pinfo->cont_splash_enabled) {
+		pinfo->panel_power_on = 1;
 		rc = mdss_dsi_panel_power_on(&(ctrl_pdata->panel_data), 1);
 		if (rc) {
 			pr_err("%s: Panel power on failed\n", __func__);
@@ -1101,11 +1237,13 @@
 		mdss_dsi_clk_ctrl(ctrl_pdata, 1);
 		ctrl_pdata->ctrl_state |=
 			(CTRL_STATE_PANEL_INIT | CTRL_STATE_MDP_ACTIVE);
+	} else {
+		pinfo->panel_power_on = 0;
 	}
 
 	rc = mdss_register_panel(ctrl_pdev, &(ctrl_pdata->panel_data));
 	if (rc) {
-		dev_err(&pdev->dev, "unable to register MIPI DSI panel\n");
+		pr_err("%s: unable to register MIPI DSI panel\n", __func__);
 		if (ctrl_pdata->rst_gpio)
 			gpio_free(ctrl_pdata->rst_gpio);
 		if (gpio_is_valid(ctrl_pdata->disp_en_gpio))
@@ -1113,10 +1251,7 @@
 		return rc;
 	}
 
-	ctrl_pdata->on = panel_data->on;
-	ctrl_pdata->off = panel_data->off;
-
-	if (panel_data->panel_info.pdest == DISPLAY_1) {
+	if (pinfo->pdest == DISPLAY_1) {
 		mdss_debug_register_base("dsi0",
 			ctrl_pdata->ctrl_base, ctrl_pdata->reg_size);
 		ctrl_pdata->ndx = 0;
@@ -1126,7 +1261,7 @@
 		ctrl_pdata->ndx = 1;
 	}
 
-	pr_debug("%s: Panal data initialized\n", __func__);
+	pr_debug("%s: Panel data initialized\n", __func__);
 	return 0;
 }
 
diff --git a/drivers/video/msm/mdss/mdss_dsi.h b/drivers/video/msm/mdss/mdss_dsi.h
index a8c34f3..2d63532 100644
--- a/drivers/video/msm/mdss/mdss_dsi.h
+++ b/drivers/video/msm/mdss/mdss_dsi.h
@@ -296,16 +296,6 @@
 	void *data;
 };
 
-struct mdss_panel_common_pdata {
-	struct mdss_panel_info panel_info;
-	int (*on) (struct mdss_panel_data *pdata);
-	int (*off) (struct mdss_panel_data *pdata);
-	void (*bl_fnc) (struct mdss_panel_data *pdata, u32 bl_level);
-
-	struct dsi_panel_cmds on_cmds;
-	struct dsi_panel_cmds off_cmds;
-};
-
 struct dsi_drv_cm_data {
 	struct regulator *vdd_vreg;
 	struct regulator *vdd_io_vreg;
@@ -333,11 +323,13 @@
 	struct clk *esc_clk;
 	struct clk *pixel_clk;
 	u8 ctrl_state;
+	int panel_mode;
 	int irq_cnt;
 	int mdss_dsi_clk_on;
 	int rst_gpio;
 	int disp_en_gpio;
 	int disp_te_gpio;
+	int mode_gpio;
 	int bklt_ctrl;	/* backlight ctrl */
 	int pwm_period;
 	int pwm_pmic_gpio;
@@ -369,8 +361,8 @@
 	struct dsi_buf rx_buf;
 };
 
-int dsi_panel_device_register(struct platform_device *pdev,
-			      struct mdss_panel_common_pdata *panel_data);
+int dsi_panel_device_register(struct device_node *pan_node,
+				struct mdss_dsi_ctrl_pdata *ctrl_pdata);
 
 char *mdss_dsi_buf_reserve_hdr(struct dsi_buf *dp, int hlen);
 char *mdss_dsi_buf_init(struct dsi_buf *dp);
@@ -428,4 +420,7 @@
 struct dcs_cmd_req *mdss_dsi_cmdlist_get(struct mdss_dsi_ctrl_pdata *ctrl);
 void mdss_dsi_cmdlist_kickoff(int intf);
 
+int mdss_dsi_panel_init(struct device_node *node,
+		struct mdss_dsi_ctrl_pdata *ctrl_pdata,
+		bool cmd_cfg_cont_splash);
 #endif /* MDSS_DSI_H */
diff --git a/drivers/video/msm/mdss/mdss_dsi_host.c b/drivers/video/msm/mdss/mdss_dsi_host.c
index e48d0d2..62bc7e6 100644
--- a/drivers/video/msm/mdss/mdss_dsi_host.c
+++ b/drivers/video/msm/mdss/mdss_dsi_host.c
@@ -25,6 +25,8 @@
 #include "mdss.h"
 #include "mdss_dsi.h"
 
+#define VSYNC_PERIOD 17
+
 static struct mdss_dsi_ctrl_pdata *left_ctrl_pdata;
 
 static struct mdss_dsi_ctrl_pdata *ctrl_list[DSI_CTRL_MAX];
@@ -766,6 +768,8 @@
 
 	pinfo->rgb_swap = DSI_RGB_SWAP_RGB;
 
+	ctrl_pdata->panel_mode = pinfo->mode;
+
 	if (pinfo->mode == DSI_VIDEO_MODE) {
 		data = 0;
 		if (pinfo->pulse_mode_hsa_he)
@@ -1135,6 +1139,8 @@
 	return 4;
 }
 
+static int mdss_dsi_wait4video_eng_busy(struct mdss_dsi_ctrl_pdata *ctrl);
+
 static int mdss_dsi_cmd_dma_tx(struct mdss_dsi_ctrl_pdata *ctrl,
 					struct dsi_buf *tp);
 
@@ -1147,7 +1153,7 @@
 	struct dsi_buf *tp;
 	struct dsi_cmd_desc *cm;
 	struct dsi_ctrl_hdr *dchdr;
-	int len, tot = 0;
+	int len, wait, tot = 0;
 
 	tp = &ctrl->tx_buf;
 	mdss_dsi_buf_init(tp);
@@ -1164,6 +1170,9 @@
 		tot += len;
 		if (dchdr->last) {
 			tp->data = tp->start; /* begin of buf */
+
+			wait = mdss_dsi_wait4video_eng_busy(ctrl);
+
 			mdss_dsi_enable_irq(ctrl, DSI_CMD_TERM);
 			len = mdss_dsi_cmd_dma_tx(ctrl, tp);
 			if (IS_ERR_VALUE(len)) {
@@ -1172,7 +1181,8 @@
 					__func__,  cmds->payload[0]);
 				return -EINVAL;
 			}
-			if (dchdr->wait)
+
+			if (!wait || dchdr->wait > VSYNC_PERIOD)
 				usleep(dchdr->wait * 1000);
 
 			mdss_dsi_buf_init(tp);
@@ -1357,6 +1367,9 @@
 			rp->len = 0;
 			goto end;
 		}
+
+		mdss_dsi_wait4video_eng_busy(ctrl);
+
 		mdss_dsi_enable_irq(ctrl, DSI_CMD_TERM);
 		ret = mdss_dsi_cmd_dma_tx(ctrl, tp);
 		if (IS_ERR_VALUE(ret)) {
@@ -1377,6 +1390,8 @@
 		goto end;
 	}
 
+	mdss_dsi_wait4video_eng_busy(ctrl);
+
 	mdss_dsi_enable_irq(ctrl, DSI_CMD_TERM);
 	/* transmit read comamnd to client */
 	ret = mdss_dsi_cmd_dma_tx(ctrl, tp);
@@ -1541,7 +1556,6 @@
 	return rlen;
 }
 
-#define VSYNC_PERIOD 17
 
 void mdss_dsi_wait4video_done(struct mdss_dsi_ctrl_pdata *ctrl)
 {
@@ -1567,11 +1581,21 @@
 	MIPI_OUTP((ctrl->ctrl_base) + 0x0110, data);
 }
 
-static void mdss_dsi_wait4video_eng_busy(struct mdss_dsi_ctrl_pdata *ctrl)
+static int mdss_dsi_wait4video_eng_busy(struct mdss_dsi_ctrl_pdata *ctrl)
 {
-	mdss_dsi_wait4video_done(ctrl);
-	/* delay 4 ms to skip BLLP */
-	usleep(4000);
+	int ret = 0;
+
+	if (ctrl->panel_mode == DSI_CMD_MODE)
+		return ret;
+
+	if (ctrl->ctrl_state & CTRL_STATE_MDP_ACTIVE) {
+		mdss_dsi_wait4video_done(ctrl);
+		/* delay 4 ms to skip BLLP */
+		usleep(4000);
+		ret = 1;
+	}
+
+	return ret;
 }
 
 void mdss_dsi_cmd_mdp_start(struct mdss_dsi_ctrl_pdata *ctrl)
@@ -1638,7 +1662,6 @@
 void mdss_dsi_cmdlist_commit(struct mdss_dsi_ctrl_pdata *ctrl, int from_mdp)
 {
 	struct dcs_cmd_req *req;
-	u32 data;
 
 	mutex_lock(&ctrl->cmd_mutex);
 	req = mdss_dsi_cmdlist_get(ctrl);
@@ -1646,26 +1669,14 @@
 	/* make sure dsi_cmd_mdp is idle */
 	mdss_dsi_cmd_mdp_busy(ctrl);
 
+	pr_debug("%s:  from_mdp=%d pid=%d\n", __func__, from_mdp, current->pid);
+
 	if (req == NULL)
 		goto need_lock;
 
 	pr_debug("%s:  from_mdp=%d pid=%d\n", __func__, from_mdp, current->pid);
 	mdss_dsi_clk_ctrl(ctrl, 1);
 
-	data = MIPI_INP((ctrl->ctrl_base) + 0x0004);
-	if (data & 0x02) {
-		/* video mode, make sure video engine is busy
-		 * so dcs command will be sent at start of BLLP
-		 */
-		mdss_dsi_wait4video_eng_busy(ctrl);
-	} else {
-		/* command mode */
-		if (!from_mdp) { /* cmdlist_put */
-			/* make sure dsi_cmd_mdp is idle */
-			mdss_dsi_cmd_mdp_busy(ctrl);
-		}
-	}
-
 	if (req->flags & CMD_REQ_RX)
 		mdss_dsi_cmdlist_rx(ctrl, req);
 	else
diff --git a/drivers/video/msm/mdss/mdss_dsi_panel.c b/drivers/video/msm/mdss/mdss_dsi_panel.c
index 9a019f9..203900c 100644
--- a/drivers/video/msm/mdss/mdss_dsi_panel.c
+++ b/drivers/video/msm/mdss/mdss_dsi_panel.c
@@ -28,8 +28,6 @@
 
 DEFINE_LED_TRIGGER(bl_led_trigger);
 
-static struct mdss_dsi_phy_ctrl phy_params;
-
 void mdss_dsi_panel_pwm_cfg(struct mdss_dsi_ctrl_pdata *ctrl)
 {
 	int ret;
@@ -158,6 +156,7 @@
 void mdss_dsi_panel_reset(struct mdss_panel_data *pdata, int enable)
 {
 	struct mdss_dsi_ctrl_pdata *ctrl_pdata = NULL;
+	struct mdss_panel_info *pinfo = NULL;
 	int i;
 
 	if (pdata == NULL) {
@@ -180,6 +179,7 @@
 	}
 
 	pr_debug("%s: enable = %d\n", __func__, enable);
+	pinfo = &(ctrl_pdata->panel_data.panel_info);
 
 	if (enable) {
 		for (i = 0; i < MDSS_DSI_RST_SEQ_LEN; ++i) {
@@ -189,6 +189,13 @@
 		}
 		if (gpio_is_valid(ctrl_pdata->disp_en_gpio))
 			gpio_set_value((ctrl_pdata->disp_en_gpio), 1);
+
+		if (gpio_is_valid(ctrl_pdata->mode_gpio)) {
+			if (pinfo->mode_gpio_state == MODE_GPIO_HIGH)
+				gpio_set_value((ctrl_pdata->mode_gpio), 1);
+			else if (pinfo->mode_gpio_state == MODE_GPIO_LOW)
+				gpio_set_value((ctrl_pdata->mode_gpio), 0);
+		}
 		if (ctrl_pdata->ctrl_state & CTRL_STATE_PANEL_INIT) {
 			pr_debug("%s: Panel Not properly turned OFF\n",
 						__func__);
@@ -485,14 +492,14 @@
 }
 
 
-static int mdss_panel_parse_dt(struct platform_device *pdev,
-			      struct mdss_panel_common_pdata *panel_data)
+static int mdss_panel_parse_dt(struct device_node *np,
+			struct mdss_dsi_ctrl_pdata *ctrl_pdata)
 {
-	struct device_node *np = pdev->dev.of_node;
 	u32 tmp;
 	int rc, i, len;
 	const char *data;
 	static const char *pdest;
+	struct mdss_panel_info *pinfo = &(ctrl_pdata->panel_data.panel_info);
 
 	rc = of_property_read_u32(np, "qcom,mdss-dsi-panel-width", &tmp);
 	if (rc) {
@@ -500,7 +507,7 @@
 						__func__, __LINE__);
 		return -EINVAL;
 	}
-	panel_data->panel_info.xres = (!rc ? tmp : 640);
+	pinfo->xres = (!rc ? tmp : 640);
 
 	rc = of_property_read_u32(np, "qcom,mdss-dsi-panel-height", &tmp);
 	if (rc) {
@@ -508,75 +515,82 @@
 						__func__, __LINE__);
 		return -EINVAL;
 	}
-	panel_data->panel_info.yres = (!rc ? tmp : 480);
+	pinfo->yres = (!rc ? tmp : 480);
 
+	rc = of_property_read_u32(np,
+		"qcom,mdss-pan-physical-width-dimension", &tmp);
+	pinfo->physical_width = (!rc ? tmp : 0);
+	rc = of_property_read_u32(np,
+		"qcom,mdss-pan-physical-height-dimension", &tmp);
+	pinfo->physical_height = (!rc ? tmp : 0);
 	rc = of_property_read_u32(np, "qcom,mdss-dsi-h-left-border", &tmp);
-	panel_data->panel_info.lcdc.xres_pad = (!rc ? tmp : 0);
+	pinfo->lcdc.xres_pad = (!rc ? tmp : 0);
 	rc = of_property_read_u32(np, "qcom,mdss-dsi-h-right-border", &tmp);
 	if (!rc)
-		panel_data->panel_info.lcdc.xres_pad += tmp;
+		pinfo->lcdc.xres_pad += tmp;
 	rc = of_property_read_u32(np, "qcom,mdss-dsi-v-top-border", &tmp);
-	panel_data->panel_info.lcdc.yres_pad = (!rc ? tmp : 0);
+	pinfo->lcdc.yres_pad = (!rc ? tmp : 0);
 	rc = of_property_read_u32(np, "qcom,mdss-dsi-v-bottom-border", &tmp);
 	if (!rc)
-		panel_data->panel_info.lcdc.yres_pad += tmp;
+		pinfo->lcdc.yres_pad += tmp;
 	rc = of_property_read_u32(np, "qcom,mdss-dsi-bpp", &tmp);
 	if (rc) {
 		pr_err("%s:%d, bpp not specified\n", __func__, __LINE__);
 		return -EINVAL;
 	}
-	panel_data->panel_info.bpp = (!rc ? tmp : 24);
-	panel_data->panel_info.mipi.mode = DSI_VIDEO_MODE;
+	pinfo->bpp = (!rc ? tmp : 24);
+	pinfo->mipi.mode = DSI_VIDEO_MODE;
 	data = of_get_property(np, "qcom,mdss-dsi-panel-type", NULL);
 	if (data && !strncmp(data, "dsi_cmd_mode", 12))
-		panel_data->panel_info.mipi.mode = DSI_CMD_MODE;
+		pinfo->mipi.mode = DSI_CMD_MODE;
 	rc = of_property_read_u32(np, "qcom,mdss-dsi-pixel-packing", &tmp);
 	tmp = (!rc ? tmp : 0);
-	rc = mdss_panel_dt_get_dst_fmt(panel_data->panel_info.bpp,
-		panel_data->panel_info.mipi.mode, tmp,
-		&(panel_data->panel_info.mipi.dst_format));
+	rc = mdss_panel_dt_get_dst_fmt(pinfo->bpp,
+		pinfo->mipi.mode, tmp,
+		&(pinfo->mipi.dst_format));
 	if (rc) {
 		pr_debug("%s: problem determining dst format. Set Default\n",
 			__func__);
-		panel_data->panel_info.mipi.dst_format =
+		pinfo->mipi.dst_format =
 			DSI_VIDEO_DST_FORMAT_RGB888;
 	}
-	pdest = of_get_property(pdev->dev.of_node,
+	pdest = of_get_property(np,
 		"qcom,mdss-dsi-panel-destination", NULL);
+
 	if (strlen(pdest) != 9) {
 		pr_err("%s: Unknown pdest specified\n", __func__);
 		return -EINVAL;
 	}
 	if (!strncmp(pdest, "display_1", 9))
-		panel_data->panel_info.pdest = DISPLAY_1;
+		pinfo->pdest = DISPLAY_1;
 	else if (!strncmp(pdest, "display_2", 9))
-		panel_data->panel_info.pdest = DISPLAY_2;
+		pinfo->pdest = DISPLAY_2;
 	else {
 		pr_debug("%s: pdest not specified. Set Default\n",
 							__func__);
-		panel_data->panel_info.pdest = DISPLAY_1;
+		pinfo->pdest = DISPLAY_1;
 	}
 	rc = of_property_read_u32(np, "qcom,mdss-dsi-h-front-porch", &tmp);
-	panel_data->panel_info.lcdc.h_front_porch = (!rc ? tmp : 6);
+	pinfo->lcdc.h_front_porch = (!rc ? tmp : 6);
 	rc = of_property_read_u32(np, "qcom,mdss-dsi-h-back-porch", &tmp);
-	panel_data->panel_info.lcdc.h_back_porch = (!rc ? tmp : 6);
+	pinfo->lcdc.h_back_porch = (!rc ? tmp : 6);
 	rc = of_property_read_u32(np, "qcom,mdss-dsi-h-pulse-width", &tmp);
-	panel_data->panel_info.lcdc.h_pulse_width = (!rc ? tmp : 2);
+	pinfo->lcdc.h_pulse_width = (!rc ? tmp : 2);
 	rc = of_property_read_u32(np, "qcom,mdss-dsi-h-sync-skew", &tmp);
-	panel_data->panel_info.lcdc.hsync_skew = (!rc ? tmp : 0);
+	pinfo->lcdc.hsync_skew = (!rc ? tmp : 0);
 	rc = of_property_read_u32(np, "qcom,mdss-dsi-v-back-porch", &tmp);
-	panel_data->panel_info.lcdc.v_back_porch = (!rc ? tmp : 6);
+	pinfo->lcdc.v_back_porch = (!rc ? tmp : 6);
 	rc = of_property_read_u32(np, "qcom,mdss-dsi-v-front-porch", &tmp);
-	panel_data->panel_info.lcdc.v_front_porch = (!rc ? tmp : 6);
+	pinfo->lcdc.v_front_porch = (!rc ? tmp : 6);
 	rc = of_property_read_u32(np, "qcom,mdss-dsi-v-pulse-width", &tmp);
-	panel_data->panel_info.lcdc.v_pulse_width = (!rc ? tmp : 2);
+	pinfo->lcdc.v_pulse_width = (!rc ? tmp : 2);
 	rc = of_property_read_u32(np,
 		"qcom,mdss-dsi-underflow-color", &tmp);
-	panel_data->panel_info.lcdc.underflow_clr = (!rc ? tmp : 0xff);
+	pinfo->lcdc.underflow_clr = (!rc ? tmp : 0xff);
 	rc = of_property_read_u32(np,
 		"qcom,mdss-dsi-border-color", &tmp);
-	panel_data->panel_info.lcdc.border_clr = (!rc ? tmp : 0);
-	panel_data->panel_info.bklt_ctrl = UNKNOWN_CTRL;
+	pinfo->lcdc.border_clr = (!rc ? tmp : 0);
+	pinfo->bklt_ctrl = UNKNOWN_CTRL;
 	data = of_get_property(np, "qcom,mdss-dsi-bl-pmic-control-type", NULL);
 	if (data) {
 		if (!strncmp(data, "bl_ctrl_wled", 12)) {
@@ -584,9 +598,9 @@
 				&bl_led_trigger);
 			pr_debug("%s: SUCCESS-> WLED TRIGGER register\n",
 				__func__);
-			panel_data->panel_info.bklt_ctrl = BL_WLED;
+			ctrl_pdata->bklt_ctrl = BL_WLED;
 		} else if (!strncmp(data, "bl_ctrl_pwm", 11)) {
-			panel_data->panel_info.bklt_ctrl = BL_PWM;
+			ctrl_pdata->bklt_ctrl = BL_PWM;
 			rc = of_property_read_u32(np,
 				"qcom,mdss-dsi-bl-pmic-pwm-frequency", &tmp);
 			if (rc) {
@@ -594,7 +608,7 @@
 						__func__, __LINE__);
 				return -EINVAL;
 			}
-			panel_data->panel_info.pwm_period = tmp;
+			ctrl_pdata->pwm_period = tmp;
 			rc = of_property_read_u32(np,
 				"qcom,mdss-dsi-bl-pmic-bank-select", &tmp);
 			if (rc) {
@@ -602,108 +616,119 @@
 						__func__, __LINE__);
 				return -EINVAL;
 			}
-			panel_data->panel_info.pwm_lpg_chan = tmp;
+			ctrl_pdata->pwm_lpg_chan = tmp;
 			tmp = of_get_named_gpio(np,
 				"qcom,mdss-dsi-pwm-gpio", 0);
-			panel_data->panel_info.pwm_pmic_gpio = tmp;
+			ctrl_pdata->pwm_pmic_gpio = tmp;
 		} else if (!strncmp(data, "bl_ctrl_dcs", 11)) {
-			panel_data->panel_info.bklt_ctrl = BL_DCS_CMD;
+			ctrl_pdata->bklt_ctrl = BL_DCS_CMD;
 		}
 	}
 	rc = of_property_read_u32(np, "qcom,mdss-dsi-bl-min-level", &tmp);
-	panel_data->panel_info.bl_min = (!rc ? tmp : 0);
+	pinfo->bl_min = (!rc ? tmp : 0);
 	rc = of_property_read_u32(np, "qcom,mdss-dsi-bl-max-level", &tmp);
-	panel_data->panel_info.bl_max = (!rc ? tmp : 255);
+	pinfo->bl_max = (!rc ? tmp : 255);
+	ctrl_pdata->bklt_max = pinfo->bl_max;
 
 	rc = of_property_read_u32(np, "qcom,mdss-dsi-interleave-mode", &tmp);
-	panel_data->panel_info.mipi.interleave_mode = (!rc ? tmp : 0);
+	pinfo->mipi.interleave_mode = (!rc ? tmp : 0);
 
-	panel_data->panel_info.mipi.vsync_enable = of_property_read_bool(np,
+	pinfo->mipi.vsync_enable = of_property_read_bool(np,
 		"qcom,mdss-dsi-te-check-enable");
-	panel_data->panel_info.mipi.hw_vsync_mode = of_property_read_bool(np,
+	pinfo->mipi.hw_vsync_mode = of_property_read_bool(np,
 		"qcom,mdss-dsi-te-using-te-pin");
 
 	rc = of_property_read_u32(np,
 		"qcom,mdss-dsi-h-sync-pulse", &tmp);
-	panel_data->panel_info.mipi.pulse_mode_hsa_he = (!rc ? tmp : false);
+	pinfo->mipi.pulse_mode_hsa_he = (!rc ? tmp : false);
 
-	panel_data->panel_info.mipi.hfp_power_stop = of_property_read_bool(np,
+	pinfo->mipi.hfp_power_stop = of_property_read_bool(np,
 		"qcom,mdss-dsi-hfp-power-mode");
-	panel_data->panel_info.mipi.hsa_power_stop = of_property_read_bool(np,
+	pinfo->mipi.hsa_power_stop = of_property_read_bool(np,
 		"qcom,mdss-dsi-hsa-power-mode");
-	panel_data->panel_info.mipi.hbp_power_stop = of_property_read_bool(np,
+	pinfo->mipi.hbp_power_stop = of_property_read_bool(np,
 		"qcom,mdss-dsi-hbp-power-mode");
-	panel_data->panel_info.mipi.bllp_power_stop = of_property_read_bool(np,
+	pinfo->mipi.bllp_power_stop = of_property_read_bool(np,
 		"qcom,mdss-dsi-bllp-power-mode");
-	panel_data->panel_info.mipi.eof_bllp_power_stop = of_property_read_bool(
+	pinfo->mipi.eof_bllp_power_stop = of_property_read_bool(
 		np, "qcom,mdss-dsi-bllp-eof-power-mode");
 	rc = of_property_read_u32(np,
 		"qcom,mdss-dsi-traffic-mode", &tmp);
-	panel_data->panel_info.mipi.traffic_mode =
+	pinfo->mipi.traffic_mode =
 			(!rc ? tmp : DSI_NON_BURST_SYNCH_PULSE);
 	rc = of_property_read_u32(np,
 		"qcom,mdss-dsi-te-dcs-command", &tmp);
-	panel_data->panel_info.mipi.insert_dcs_cmd =
+	pinfo->mipi.insert_dcs_cmd =
 			(!rc ? tmp : 1);
 	rc = of_property_read_u32(np,
 		"qcom,mdss-dsi-te-v-sync-continue-lines", &tmp);
-	panel_data->panel_info.mipi.wr_mem_continue =
+	pinfo->mipi.wr_mem_continue =
 			(!rc ? tmp : 0x3c);
 	rc = of_property_read_u32(np,
 		"qcom,mdss-dsi-te-v-sync-rd-ptr-irq-line", &tmp);
-	panel_data->panel_info.mipi.wr_mem_start =
+	pinfo->mipi.wr_mem_start =
 			(!rc ? tmp : 0x2c);
 	rc = of_property_read_u32(np,
 		"qcom,mdss-dsi-te-pin-select", &tmp);
-	panel_data->panel_info.mipi.te_sel =
+	pinfo->mipi.te_sel =
 			(!rc ? tmp : 1);
 	rc = of_property_read_u32(np, "qcom,mdss-dsi-virtual-channel-id", &tmp);
-	panel_data->panel_info.mipi.vc = (!rc ? tmp : 0);
+	pinfo->mipi.vc = (!rc ? tmp : 0);
 	rc = of_property_read_u32(np, "qcom,mdss-dsi-color-order", &tmp);
-	panel_data->panel_info.mipi.rgb_swap = (!rc ? tmp : DSI_RGB_SWAP_RGB);
-	panel_data->panel_info.mipi.data_lane0 = of_property_read_bool(np,
+	pinfo->mipi.rgb_swap = (!rc ? tmp : DSI_RGB_SWAP_RGB);
+	pinfo->mipi.data_lane0 = of_property_read_bool(np,
 		"qcom,mdss-dsi-lane-0-state");
-	panel_data->panel_info.mipi.data_lane1 = of_property_read_bool(np,
+	pinfo->mipi.data_lane1 = of_property_read_bool(np,
 		"qcom,mdss-dsi-lane-1-state");
-	panel_data->panel_info.mipi.data_lane2 = of_property_read_bool(np,
+	pinfo->mipi.data_lane2 = of_property_read_bool(np,
 		"qcom,mdss-dsi-lane-2-state");
-	panel_data->panel_info.mipi.data_lane3 = of_property_read_bool(np,
+	pinfo->mipi.data_lane3 = of_property_read_bool(np,
 		"qcom,mdss-dsi-lane-3-state");
 
 	rc = of_property_read_u32(np, "qcom,mdss-dsi-lane-map", &tmp);
-	panel_data->panel_info.mipi.dlane_swap = (!rc ? tmp : 0);
+	pinfo->mipi.dlane_swap = (!rc ? tmp : 0);
 
 	rc = of_property_read_u32(np, "qcom,mdss-dsi-t-clk-pre", &tmp);
-	panel_data->panel_info.mipi.t_clk_pre = (!rc ? tmp : 0x24);
+	pinfo->mipi.t_clk_pre = (!rc ? tmp : 0x24);
 	rc = of_property_read_u32(np, "qcom,mdss-dsi-t-clk-post", &tmp);
-	panel_data->panel_info.mipi.t_clk_post = (!rc ? tmp : 0x03);
+	pinfo->mipi.t_clk_post = (!rc ? tmp : 0x03);
 
 	rc = of_property_read_u32(np, "qcom,mdss-dsi-stream", &tmp);
-	panel_data->panel_info.mipi.stream = (!rc ? tmp : 0);
+	pinfo->mipi.stream = (!rc ? tmp : 0);
 
 	rc = of_property_read_u32(np, "qcom,mdss-dsi-mdp-trigger", &tmp);
-	panel_data->panel_info.mipi.mdp_trigger =
+	pinfo->mipi.mdp_trigger =
 			(!rc ? tmp : DSI_CMD_TRIGGER_SW);
-	if (panel_data->panel_info.mipi.mdp_trigger > 6) {
+	if (pinfo->mipi.mdp_trigger > 6) {
 		pr_err("%s:%d, Invalid mdp trigger. Forcing to sw trigger",
 						 __func__, __LINE__);
-		panel_data->panel_info.mipi.mdp_trigger =
+		pinfo->mipi.mdp_trigger =
 					DSI_CMD_TRIGGER_SW;
 	}
 
 	rc = of_property_read_u32(np, "qcom,mdss-dsi-dma-trigger", &tmp);
-	panel_data->panel_info.mipi.dma_trigger =
+	pinfo->mipi.dma_trigger =
 			(!rc ? tmp : DSI_CMD_TRIGGER_SW);
-	if (panel_data->panel_info.mipi.dma_trigger > 6) {
+	if (pinfo->mipi.dma_trigger > 6) {
 		pr_err("%s:%d, Invalid dma trigger. Forcing to sw trigger",
 						 __func__, __LINE__);
-		panel_data->panel_info.mipi.dma_trigger =
+		pinfo->mipi.dma_trigger =
 					DSI_CMD_TRIGGER_SW;
 	}
+	data = of_get_property(np, "qcom,mdss-dsi-panel-mode-gpio-state", &tmp);
+	if (data) {
+		if (!strcmp(data, "high"))
+			pinfo->mode_gpio_state = MODE_GPIO_HIGH;
+		else if (!strcmp(data, "low"))
+			pinfo->mode_gpio_state = MODE_GPIO_LOW;
+	} else {
+		pinfo->mode_gpio_state = MODE_GPIO_NOT_VALID;
+	}
+
 	rc = of_property_read_u32(np, "qcom,mdss-dsi-panel-frame-rate", &tmp);
-	panel_data->panel_info.mipi.frame_rate = (!rc ? tmp : 60);
+	pinfo->mipi.frame_rate = (!rc ? tmp : 60);
 	rc = of_property_read_u32(np, "qcom,mdss-dsi-panel-clock-rate", &tmp);
-	panel_data->panel_info.clk_rate = (!rc ? tmp : 0);
+	pinfo->clk_rate = (!rc ? tmp : 0);
 	data = of_get_property(np, "qcom,mdss-dsi-panel-timings", &len);
 	if ((!data) || (len != 12)) {
 		pr_err("%s:%d, Unable to read Phy timing settings",
@@ -711,16 +736,14 @@
 		goto error;
 	}
 	for (i = 0; i < len; i++)
-		phy_params.timing[i] = data[i];
+		pinfo->mipi.dsi_phy_db.timing[i] = data[i];
 
-	panel_data->panel_info.mipi.dsi_phy_db = &phy_params;
+	mdss_dsi_parse_fbc_params(np, pinfo);
 
-	mdss_dsi_parse_fbc_params(np, &panel_data->panel_info);
-
-	mdss_dsi_parse_dcs_cmds(np, &panel_data->on_cmds,
+	mdss_dsi_parse_dcs_cmds(np, &ctrl_pdata->on_cmds,
 		"qcom,mdss-dsi-on-command", "qcom,mdss-dsi-on-command-state");
 
-	mdss_dsi_parse_dcs_cmds(np, &panel_data->off_cmds,
+	mdss_dsi_parse_dcs_cmds(np, &ctrl_pdata->off_cmds,
 		"qcom,mdss-dsi-off-command", "qcom,mdss-dsi-off-command-state");
 
 	return 0;
@@ -729,53 +752,52 @@
 	return -EINVAL;
 }
 
-static int __devinit mdss_dsi_panel_probe(struct platform_device *pdev)
+int mdss_dsi_panel_init(struct device_node *node,
+	struct mdss_dsi_ctrl_pdata *ctrl_pdata,
+	bool cmd_cfg_cont_splash)
 {
 	int rc = 0;
-	static struct mdss_panel_common_pdata vendor_pdata;
 	static const char *panel_name;
-	pr_debug("%s:%d, debug info id=%d", __func__, __LINE__, pdev->id);
-	if (!pdev->dev.of_node)
-		return -ENODEV;
+	bool cont_splash_enabled;
 
-	panel_name = of_get_property(pdev->dev.of_node,
-		"qcom,mdss-dsi-panel-name", NULL);
+	if (!node) {
+		pr_err("%s: no panel node\n", __func__);
+		return -ENODEV;
+	}
+
+	pr_debug("%s:%d\n", __func__, __LINE__);
+	panel_name = of_get_property(node, "qcom,mdss-dsi-panel-name", NULL);
 	if (!panel_name)
-		pr_info("%s:%d, panel name not specified\n",
+		pr_info("%s:%d, Panel name not specified\n",
 						__func__, __LINE__);
 	else
 		pr_info("%s: Panel Name = %s\n", __func__, panel_name);
 
-	rc = mdss_panel_parse_dt(pdev, &vendor_pdata);
-	if (rc)
+	rc = mdss_panel_parse_dt(node, ctrl_pdata);
+	if (rc) {
+		pr_err("%s:%d panel dt parse failed\n", __func__, __LINE__);
 		return rc;
+	}
 
-	vendor_pdata.on = mdss_dsi_panel_on;
-	vendor_pdata.off = mdss_dsi_panel_off;
-	vendor_pdata.bl_fnc = mdss_dsi_panel_bl_ctrl;
+	if (cmd_cfg_cont_splash)
+		cont_splash_enabled = of_property_read_bool(node,
+				"qcom,cont-splash-enabled");
+	else
+		cont_splash_enabled = false;
+	if (!cont_splash_enabled) {
+		pr_info("%s:%d Continuous splash flag not found.\n",
+				__func__, __LINE__);
+		ctrl_pdata->panel_data.panel_info.cont_splash_enabled = 0;
+	} else {
+		pr_info("%s:%d Continuous splash flag enabled.\n",
+				__func__, __LINE__);
 
-	rc = dsi_panel_device_register(pdev, &vendor_pdata);
-	if (rc)
-		return rc;
+		ctrl_pdata->panel_data.panel_info.cont_splash_enabled = 1;
+	}
+
+	ctrl_pdata->on = mdss_dsi_panel_on;
+	ctrl_pdata->off = mdss_dsi_panel_off;
+	ctrl_pdata->panel_data.set_backlight = mdss_dsi_panel_bl_ctrl;
 
 	return 0;
 }
-
-static const struct of_device_id mdss_dsi_panel_match[] = {
-	{.compatible = "qcom,mdss-dsi-panel"},
-	{}
-};
-
-static struct platform_driver this_driver = {
-	.probe  = mdss_dsi_panel_probe,
-	.driver = {
-		.name   = "dsi_panel",
-		.of_match_table = mdss_dsi_panel_match,
-	},
-};
-
-static int __init mdss_dsi_panel_init(void)
-{
-	return platform_driver_register(&this_driver);
-}
-module_init(mdss_dsi_panel_init);
diff --git a/drivers/video/msm/mdss/mdss_edp.c b/drivers/video/msm/mdss/mdss_edp.c
index 3e0bc6d..64caaf5 100644
--- a/drivers/video/msm/mdss/mdss_edp.c
+++ b/drivers/video/msm/mdss/mdss_edp.c
@@ -753,6 +753,20 @@
 {
 	int ret;
 	struct mdss_edp_drv_pdata *edp_drv;
+	struct mdss_panel_cfg *pan_cfg = NULL;
+
+	if (!mdss_is_ready()) {
+		pr_err("%s: MDP not probed yet!\n", __func__);
+		return -EPROBE_DEFER;
+	}
+
+	pan_cfg = mdss_panel_intf_type(MDSS_PANEL_INTF_EDP);
+	if (IS_ERR(pan_cfg)) {
+		return PTR_ERR(pan_cfg);
+	} else if (!pan_cfg) {
+		pr_debug("%s: not configured as prim\n", __func__);
+		return -ENODEV;
+	}
 
 	if (!pdev->dev.of_node) {
 		pr_err("%s: Failed\n", __func__);
diff --git a/drivers/video/msm/mdss/mdss_fb.c b/drivers/video/msm/mdss/mdss_fb.c
index ac87cbd..793cbd7 100644
--- a/drivers/video/msm/mdss/mdss_fb.c
+++ b/drivers/video/msm/mdss/mdss_fb.c
@@ -242,12 +242,28 @@
 	return ret;
 }
 
+static ssize_t mdss_mdp_show_blank_event(struct device *dev,
+		struct device_attribute *attr, char *buf)
+{
+	struct fb_info *fbi = dev_get_drvdata(dev);
+	struct msm_fb_data_type *mfd = (struct msm_fb_data_type *)fbi->par;
+	int ret;
+
+	pr_debug("fb%d panel_power_on = %d\n", mfd->index, mfd->panel_power_on);
+	ret = scnprintf(buf, PAGE_SIZE, "panel_power_on = %d\n",
+						mfd->panel_power_on);
+
+	return ret;
+}
+
 static DEVICE_ATTR(msm_fb_type, S_IRUGO, mdss_fb_get_type, NULL);
 static DEVICE_ATTR(msm_fb_split, S_IRUGO, mdss_fb_get_split, NULL);
+static DEVICE_ATTR(show_blank_event, S_IRUGO, mdss_mdp_show_blank_event, NULL);
 
 static struct attribute *mdss_fb_attrs[] = {
 	&dev_attr_msm_fb_type.attr,
 	&dev_attr_msm_fb_split.attr,
+	&dev_attr_show_blank_event.attr,
 	NULL,
 };
 
@@ -274,8 +290,8 @@
 {
 	struct msm_fb_data_type *mfd = platform_get_drvdata(pdev);
 
-	if (mfd->ref_cnt > 1)
-		mfd->ref_cnt = 1;
+	for (; mfd->ref_cnt > 1; mfd->ref_cnt--)
+		pm_runtime_put(mfd->fbi->dev);
 
 	mdss_fb_release(mfd->fbi, 0);
 }
@@ -313,6 +329,7 @@
 	mfd->index = fbi_list_index;
 	mfd->mdp_fb_page_protection = MDP_FB_PAGE_PROTECTION_WRITECOMBINE;
 
+	mfd->ext_ad_ctrl = -1;
 	mfd->bl_level = 0;
 	mfd->bl_scale = 1024;
 	mfd->bl_min_lvl = 30;
@@ -322,6 +339,7 @@
 	if (pdata->next)
 		mfd->split_display = true;
 	mfd->mdp = *mdp_instance;
+	INIT_LIST_HEAD(&mfd->proc_list);
 
 	mutex_init(&mfd->lock);
 	mutex_init(&mfd->bl_lock);
@@ -573,9 +591,23 @@
 static void mdss_fb_scale_bl(struct msm_fb_data_type *mfd, u32 *bl_lvl)
 {
 	u32 temp = *bl_lvl;
+
 	pr_debug("input = %d, scale = %d", temp, mfd->bl_scale);
 	if (temp >= mfd->bl_min_lvl) {
-		/* bl_scale is the numerator of scaling fraction (x/1024)*/
+		if (temp > mfd->panel_info->bl_max) {
+			pr_warn("%s: invalid bl level\n",
+				__func__);
+			temp = mfd->panel_info->bl_max;
+		}
+		if (mfd->bl_scale > 1024) {
+			pr_warn("%s: invalid bl scale\n",
+				__func__);
+			mfd->bl_scale = 1024;
+		}
+		/*
+		 * bl_scale is the numerator of
+		 * scaling fraction (x/1024)
+		 */
 		temp = (temp * mfd->bl_scale) / 1024;
 
 		/*if less than minimum level, use min level*/
@@ -591,6 +623,7 @@
 void mdss_fb_set_backlight(struct msm_fb_data_type *mfd, u32 bkl_lvl)
 {
 	struct mdss_panel_data *pdata;
+	int (*update_ad_input)(struct msm_fb_data_type *mfd);
 	u32 temp = bkl_lvl;
 
 	if ((!mfd->panel_power_on || !bl_updated) && !IS_CALIB_MODE_BL(mfd)) {
@@ -622,9 +655,10 @@
 		bl_level_old = temp;
 
 		if (mfd->mdp.update_ad_input) {
+			update_ad_input = mfd->mdp.update_ad_input;
 			mutex_unlock(&mfd->bl_lock);
 			/* Will trigger ad_setup which will grab bl_lock */
-			mfd->mdp.update_ad_input(mfd);
+			update_ad_input(mfd);
 			mutex_lock(&mfd->bl_lock);
 		}
 	}
@@ -688,11 +722,8 @@
 
 			mfd->op_enable = false;
 			curr_pwr_state = mfd->panel_power_on;
-			mutex_lock(&mfd->bl_lock);
-			mdss_fb_set_backlight(mfd, 0);
 			mfd->panel_power_on = false;
 			bl_updated = 0;
-			mutex_unlock(&mfd->bl_lock);
 
 			ret = mfd->mdp.off_fnc(mfd);
 			if (ret)
@@ -1007,6 +1038,10 @@
 		fix->line_length = var->xres * bpp;
 
 	var->yres = panel_info->yres;
+	if (panel_info->physical_width)
+		var->width = panel_info->physical_width;
+	if (panel_info->physical_height)
+		var->height = panel_info->physical_height;
 	var->xres_virtual = var->xres;
 	var->yres_virtual = panel_info->yres * mfd->fb_page;
 	var->bits_per_pixel = bpp * 8;	/* FrameBuffer color depth */
@@ -1083,24 +1118,44 @@
 static int mdss_fb_open(struct fb_info *info, int user)
 {
 	struct msm_fb_data_type *mfd = (struct msm_fb_data_type *)info->par;
+	struct mdss_fb_proc_info *pinfo = NULL;
 	int result;
+	int pid = current->tgid;
+
+	list_for_each_entry(pinfo, &mfd->proc_list, list) {
+		if (pinfo->pid == pid)
+			break;
+	}
+
+	if ((pinfo == NULL) || (pinfo->pid != pid)) {
+		pinfo = kmalloc(sizeof(*pinfo), GFP_KERNEL);
+		if (!pinfo) {
+			pr_err("unable to alloc process info\n");
+			return -ENOMEM;
+		}
+		pinfo->pid = pid;
+		pinfo->ref_cnt = 0;
+		list_add(&pinfo->list, &mfd->proc_list);
+		pr_debug("new process entry pid=%d\n", pinfo->pid);
+	}
 
 	result = pm_runtime_get_sync(info->dev);
 
 	if (result < 0)
 		pr_err("pm_runtime: fail to wake up\n");
 
-
 	if (!mfd->ref_cnt) {
 		result = mdss_fb_blank_sub(FB_BLANK_UNBLANK, info,
 					   mfd->op_enable);
 		if (result) {
 			pm_runtime_put(info->dev);
-			pr_err("mdss_fb_open: can't turn on display!\n");
+			pr_err("can't turn on fb%d! rc=%d\n", mfd->index,
+				result);
 			return result;
 		}
 	}
 
+	pinfo->ref_cnt++;
 	mfd->ref_cnt++;
 	return 0;
 }
@@ -1108,7 +1163,9 @@
 static int mdss_fb_release(struct fb_info *info, int user)
 {
 	struct msm_fb_data_type *mfd = (struct msm_fb_data_type *)info->par;
+	struct mdss_fb_proc_info *pinfo = NULL;
 	int ret = 0;
+	int pid = current->tgid;
 
 	if (!mfd->ref_cnt) {
 		pr_info("try to close unopened fb %d!\n", mfd->index);
@@ -1118,12 +1175,36 @@
 	mdss_fb_pan_idle(mfd);
 	mfd->ref_cnt--;
 
+	list_for_each_entry(pinfo, &mfd->proc_list, list) {
+		if (pinfo->pid == pid)
+			break;
+	}
+
+	if (!pinfo || (pinfo->pid != pid)) {
+		pr_warn("unable to find process info for fb%d pid=%d\n",
+				mfd->index, pid);
+	} else {
+		pr_debug("found process entry pid=%d ref=%d\n",
+				pinfo->pid, pinfo->ref_cnt);
+
+		pinfo->ref_cnt--;
+		if (pinfo->ref_cnt == 0) {
+			if (mfd->mdp.release_fnc) {
+				ret = mfd->mdp.release_fnc(mfd);
+				if (ret)
+					pr_err("error releasing fb%d pid=%d\n",
+						mfd->index, pinfo->pid);
+			}
+			list_del(&pinfo->list);
+			kfree(pinfo);
+		}
+	}
+
 	if (!mfd->ref_cnt) {
 		ret = mdss_fb_blank_sub(FB_BLANK_POWERDOWN, info,
 				       mfd->op_enable);
 		if (ret) {
-			pr_err("can't turn off display attached to fb%d!\n",
-				mfd->index);
+			pr_err("can't turn off fb%d! rc=%d\n", mfd->index, ret);
 			return ret;
 		}
 	}
diff --git a/drivers/video/msm/mdss/mdss_fb.h b/drivers/video/msm/mdss/mdss_fb.h
index 030fd67..fd96e63 100644
--- a/drivers/video/msm/mdss/mdss_fb.h
+++ b/drivers/video/msm/mdss/mdss_fb.h
@@ -61,6 +61,8 @@
 	int (*init_fnc)(struct msm_fb_data_type *mfd);
 	int (*on_fnc)(struct msm_fb_data_type *mfd);
 	int (*off_fnc)(struct msm_fb_data_type *mfd);
+	/* called to release resources associated to the process */
+	int (*release_fnc)(struct msm_fb_data_type *mfd);
 	int (*kickoff_fnc)(struct msm_fb_data_type *mfd);
 	int (*ioctl_handler)(struct msm_fb_data_type *mfd, u32 cmd, void *arg);
 	void (*dma_fnc)(struct msm_fb_data_type *mfd);
@@ -81,6 +83,12 @@
 					/ (2 * max_bright);\
 					} while (0)
 
+struct mdss_fb_proc_info {
+	int pid;
+	u32 ref_cnt;
+	struct list_head list;
+};
+
 struct msm_fb_data_type {
 	u32 key;
 	u32 index;
@@ -110,6 +118,7 @@
 	unsigned long cursor_buf_phys;
 	unsigned long cursor_buf_iova;
 
+	int ext_ad_ctrl;
 	u32 ext_bl_ctrl;
 	u32 calib_mode;
 	u32 bl_level;
@@ -148,6 +157,7 @@
 	u32 is_power_setting;
 
 	u32 dcm_state;
+	struct list_head proc_list;
 };
 
 struct msm_fb_backup_type {
diff --git a/drivers/video/msm/mdss/mdss_hdmi_cec.c b/drivers/video/msm/mdss/mdss_hdmi_cec.c
index 2cf47fc..b74f074 100644
--- a/drivers/video/msm/mdss/mdss_hdmi_cec.c
+++ b/drivers/video/msm/mdss/mdss_hdmi_cec.c
@@ -22,6 +22,7 @@
 
 /* Reference: HDMI 1.4a Specification section 7.1 */
 #define RETRANSMIT_MAX_NUM	5
+#define MAX_OPERAND_SIZE	15
 
 /*
  * Ref. HDMI 1.4a: Supplement-1 CEC Section 6, 7
@@ -30,7 +31,7 @@
 	u8 sender_id;
 	u8 recvr_id;
 	u8 opcode;
-	u8 operand[15];
+	u8 operand[MAX_OPERAND_SIZE];
 	u8 frame_size;
 	u8 retransmit;
 };
@@ -738,6 +739,10 @@
 	}
 	spin_unlock_irqrestore(&cec_ctrl->lock, flags);
 
+	if (msg->frame_size > MAX_OPERAND_SIZE) {
+		DEV_ERR("%s: msg frame too big!\n", __func__);
+		return -EINVAL;
+	}
 	rc = hdmi_cec_msg_send(cec_ctrl, msg);
 	if (rc) {
 		DEV_ERR("%s: hdmi_cec_msg_send failed\n", __func__);
diff --git a/drivers/video/msm/mdss/mdss_hdmi_tx.c b/drivers/video/msm/mdss/mdss_hdmi_tx.c
index ad134a0..0fd3655 100644
--- a/drivers/video/msm/mdss/mdss_hdmi_tx.c
+++ b/drivers/video/msm/mdss/mdss_hdmi_tx.c
@@ -430,7 +430,7 @@
 static ssize_t hdmi_tx_sysfs_wta_vendor_name(struct device *dev,
 	struct device_attribute *attr, const char *buf, size_t count)
 {
-	ssize_t ret;
+	ssize_t ret, sz;
 	u8 *s = (u8 *) buf;
 	u8 *d = NULL;
 	struct hdmi_tx_ctrl *hdmi_ctrl =
@@ -445,7 +445,8 @@
 	ret = strnlen(buf, PAGE_SIZE);
 	ret = (ret > 8) ? 8 : ret;
 
-	memset(hdmi_ctrl->spd_vendor_name, 0, 8);
+	sz = sizeof(hdmi_ctrl->spd_vendor_name);
+	memset(hdmi_ctrl->spd_vendor_name, 0, sz);
 	while (*s) {
 		if (*s & 0x60 && *s ^ 0x7f) {
 			*d = *s;
@@ -459,6 +460,7 @@
 
 		d++;
 	}
+	hdmi_ctrl->spd_vendor_name[sz - 1] = 0;
 
 	DEV_DBG("%s: '%s'\n", __func__, hdmi_ctrl->spd_vendor_name);
 
@@ -486,7 +488,7 @@
 static ssize_t hdmi_tx_sysfs_wta_product_description(struct device *dev,
 	struct device_attribute *attr, const char *buf, size_t count)
 {
-	ssize_t ret;
+	ssize_t ret, sz;
 	u8 *s = (u8 *) buf;
 	u8 *d = NULL;
 	struct hdmi_tx_ctrl *hdmi_ctrl =
@@ -501,7 +503,8 @@
 	ret = strnlen(buf, PAGE_SIZE);
 	ret = (ret > 16) ? 16 : ret;
 
-	memset(hdmi_ctrl->spd_product_description, 0, 16);
+	sz = sizeof(hdmi_ctrl->spd_product_description);
+	memset(hdmi_ctrl->spd_product_description, 0, sz);
 	while (*s) {
 		if (*s & 0x60 && *s ^ 0x7f) {
 			*d = *s;
@@ -515,6 +518,7 @@
 
 		d++;
 	}
+	hdmi_ctrl->spd_product_description[sz - 1] = 0;
 
 	DEV_DBG("%s: '%s'\n", __func__, hdmi_ctrl->spd_product_description);
 
diff --git a/drivers/video/msm/mdss/mdss_hdmi_tx.h b/drivers/video/msm/mdss/mdss_hdmi_tx.h
index 18ee782..fd95582 100644
--- a/drivers/video/msm/mdss/mdss_hdmi_tx.h
+++ b/drivers/video/msm/mdss/mdss_hdmi_tx.h
@@ -79,8 +79,8 @@
 	bool hdcp_feature_on;
 	u32 present_hdcp;
 
-	u8 spd_vendor_name[8];
-	u8 spd_product_description[16];
+	u8 spd_vendor_name[9];
+	u8 spd_product_description[17];
 
 	struct hdmi_tx_ddc_ctrl ddc_ctrl;
 
diff --git a/drivers/video/msm/mdss/mdss_io_util.c b/drivers/video/msm/mdss/mdss_io_util.c
index c862e78..6a1e7f7c 100644
--- a/drivers/video/msm/mdss/mdss_io_util.c
+++ b/drivers/video/msm/mdss/mdss_io_util.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2012, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2012-2013, The Linux Foundation. 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 and
@@ -211,7 +211,8 @@
 					in_vreg[i].vreg_name, rc);
 				goto vreg_set_opt_mode_fail;
 			}
-			msleep(in_vreg[i].pre_on_sleep);
+			if (in_vreg[i].pre_on_sleep)
+				msleep(in_vreg[i].pre_on_sleep);
 			rc = regulator_set_optimum_mode(in_vreg[i].vreg,
 				in_vreg[i].enable_load);
 			if (rc < 0) {
@@ -221,7 +222,8 @@
 				goto vreg_set_opt_mode_fail;
 			}
 			rc = regulator_enable(in_vreg[i].vreg);
-			msleep(in_vreg[i].post_on_sleep);
+			if (in_vreg[i].post_on_sleep)
+				msleep(in_vreg[i].post_on_sleep);
 			if (rc < 0) {
 				DEV_ERR("%pS->%s: %s enable failed\n",
 					__builtin_return_address(0), __func__,
@@ -232,11 +234,13 @@
 	} else {
 		for (i = num_vreg-1; i >= 0; i--)
 			if (regulator_is_enabled(in_vreg[i].vreg)) {
-				msleep(in_vreg[i].pre_off_sleep);
+				if (in_vreg[i].pre_off_sleep)
+					msleep(in_vreg[i].pre_off_sleep);
 				regulator_set_optimum_mode(in_vreg[i].vreg,
 					in_vreg[i].disable_load);
 				regulator_disable(in_vreg[i].vreg);
-				msleep(in_vreg[i].post_off_sleep);
+				if (in_vreg[i].post_off_sleep)
+					msleep(in_vreg[i].post_off_sleep);
 			}
 	}
 	return rc;
@@ -246,11 +250,13 @@
 
 vreg_set_opt_mode_fail:
 	for (i--; i >= 0; i--) {
-		msleep(in_vreg[i].pre_off_sleep);
+		if (in_vreg[i].pre_off_sleep)
+			msleep(in_vreg[i].pre_off_sleep);
 		regulator_set_optimum_mode(in_vreg[i].vreg,
 			in_vreg[i].disable_load);
 		regulator_disable(in_vreg[i].vreg);
-		msleep(in_vreg[i].post_off_sleep);
+		if (in_vreg[i].post_off_sleep)
+			msleep(in_vreg[i].post_off_sleep);
 	}
 
 	return rc;
diff --git a/drivers/video/msm/mdss/mdss_mdp.c b/drivers/video/msm/mdss/mdss_mdp.c
index 6f9c98e..3107e38 100644
--- a/drivers/video/msm/mdss/mdss_mdp.c
+++ b/drivers/video/msm/mdss/mdss_mdp.c
@@ -52,6 +52,7 @@
 #include "mdss.h"
 #include "mdss_fb.h"
 #include "mdss_mdp.h"
+#include "mdss_panel.h"
 #include "mdss_debug.h"
 
 struct mdss_data_type *mdss_res;
@@ -92,6 +93,13 @@
 	MDP_BUS_VECTOR_ENTRY(SZ_256M, SZ_512M),
 };
 static struct msm_bus_paths mdp_bus_usecases[ARRAY_SIZE(mdp_bus_vectors)];
+
+static struct mdss_panel_intf pan_types[] = {
+	{"dsi", MDSS_PANEL_INTF_DSI},
+	{"edp", MDSS_PANEL_INTF_EDP},
+	{"hdmi", MDSS_PANEL_INTF_HDMI},
+};
+
 static struct msm_bus_scale_pdata mdp_bus_scale_table = {
 	.usecase = mdp_bus_usecases,
 	.num_usecases = ARRAY_SIZE(mdp_bus_usecases),
@@ -133,7 +141,6 @@
 struct mdss_hw *mdss_irq_handlers[MDSS_MAX_HW_BLK];
 
 static void mdss_mdp_footswitch_ctrl(struct mdss_data_type *mdata, int on);
-static inline int mdss_mdp_suspend_sub(struct mdss_data_type *mdata);
 static int mdss_mdp_parse_dt(struct platform_device *pdev);
 static int mdss_mdp_parse_dt_pipe(struct platform_device *pdev);
 static int mdss_mdp_parse_dt_mixer(struct platform_device *pdev);
@@ -167,9 +174,10 @@
 
 	spin_lock(&mdss_lock);
 	hw = mdss_irq_handlers[hw_ndx];
+	spin_unlock(&mdss_lock);
+
 	if (hw)
 		rc = hw->irq_handler(irq, hw->ptr);
-	spin_unlock(&mdss_lock);
 
 	return rc;
 }
@@ -808,10 +816,75 @@
 	return 0;
 }
 
+static int mdss_debug_stat_ctl_dump(struct mdss_mdp_ctl *ctl,
+		char *bp, int len)
+{
+	int total = 0;
+
+	if (!ctl->ref_cnt)
+		return 0;
+
+	if (ctl->intf_num) {
+		total = scnprintf(bp, len,
+			"intf%d: play: %08u \tvsync: %08u \tunderrun: %08u\n",
+				ctl->intf_num, ctl->play_cnt,
+				ctl->vsync_cnt, ctl->underrun_cnt);
+	} else {
+		total = scnprintf(bp, len, "wb: \tmode=%x \tplay: %08u\n",
+				ctl->opmode, ctl->play_cnt);
+	}
+
+	return total;
+}
+
+static int mdss_debug_dump_stats(void *data, char *buf, int len)
+{
+	struct mdss_data_type *mdata = data;
+	struct mdss_mdp_pipe *pipe;
+	int i, total = 0;
+
+	for (i = 0; i < mdata->nctl; i++)
+		total += mdss_debug_stat_ctl_dump(mdata->ctl_off + i, buf, len);
+
+	total += scnprintf(buf + total, len - total, "\n");
+
+	for (i = 0; i < mdata->nvig_pipes; i++) {
+		pipe = mdata->vig_pipes + i;
+		total += scnprintf(buf + total, len - total,
+			"VIG%d :   %08u\t", i, pipe->play_cnt);
+	}
+	total += scnprintf(buf + total, len - total, "\n");
+
+	for (i = 0; i < mdata->nrgb_pipes; i++) {
+		pipe = mdata->rgb_pipes + i;
+		total += scnprintf(buf + total, len - total,
+			"RGB%d :   %08u\t", i, pipe->play_cnt);
+	}
+	total += scnprintf(buf + total, len - total, "\n");
+
+	for (i = 0; i < mdata->ndma_pipes; i++) {
+		pipe = mdata->dma_pipes + i;
+		total += scnprintf(buf + total, len - total,
+			"DMA%d :   %08u\t", i, pipe->play_cnt);
+	}
+	return total;
+}
+
+static void mdss_debug_enable_clock(int on)
+{
+	if (on)
+		mdss_mdp_clk_ctrl(MDP_BLOCK_POWER_ON, false);
+	else
+		mdss_mdp_clk_ctrl(MDP_BLOCK_POWER_OFF, false);
+}
+
 static int mdss_mdp_debug_init(struct mdss_data_type *mdata)
 {
 	int rc;
 
+	mdata->debug_inf.debug_dump_stats = mdss_debug_dump_stats;
+	mdata->debug_inf.debug_enable_clock = mdss_debug_enable_clock;
+
 	rc = mdss_debugfs_init(mdata);
 	if (rc)
 		return rc;
@@ -831,6 +904,10 @@
 	mdata->mdp_rev = MDSS_MDP_REG_READ(MDSS_MDP_REG_HW_VERSION);
 	pr_info_once("MDP Rev=%x\n", mdata->mdp_rev);
 
+	/* disable hw underrun recovery */
+	writel_relaxed(0x0, mdata->mdp_base +
+			MDSS_MDP_REG_VIDEO_INTF_UNDERFLOW_CTL);
+
 	if (mdata->hw_settings) {
 		struct mdss_hw_settings *hws = mdata->hw_settings;
 
@@ -911,18 +988,6 @@
 	}
 }
 
-static void mdss_mdp_shutdown(struct platform_device *pdev)
-{
-	struct mdss_data_type *mdata = platform_get_drvdata(pdev);
-
-	if (!mdata)
-		return;
-
-	pr_debug("display shutdown\n");
-
-	mdss_mdp_suspend_sub(mdata);
-}
-
 static int mdss_mdp_probe(struct platform_device *pdev)
 {
 	struct resource *res;
@@ -1040,8 +1105,8 @@
 probe_done:
 	if (IS_ERR_VALUE(rc)) {
 		mdss_mdp_hw.ptr = NULL;
-		mdss_res = NULL;
 		mdss_mdp_pp_term(&pdev->dev);
+		mdss_res = NULL;
 	}
 
 	return rc;
@@ -1105,6 +1170,185 @@
 	return 0;
 }
 
+static int mdss_mdp_get_pan_intf(const char *pan_intf)
+{
+	int i, rc = MDSS_PANEL_INTF_INVALID;
+
+	if (!pan_intf)
+		return rc;
+
+	for (i = 0; i < ARRAY_SIZE(pan_types); i++) {
+		if (!strncmp(pan_intf, pan_types[i].name, MDSS_MAX_PANEL_LEN)) {
+			rc = pan_types[i].type;
+			break;
+		}
+	}
+	return rc;
+}
+
+static int mdss_mdp_get_pan_cfg(struct mdss_panel_cfg *pan_cfg)
+{
+	char *t = NULL;
+	char pan_intf_str[MDSS_MAX_PANEL_LEN];
+	int rc, i;
+	char pan_name[MDSS_MAX_PANEL_LEN];
+
+	if (!pan_cfg)
+		return -EINVAL;
+
+	strlcpy(pan_name, &pan_cfg->arg_cfg[0], sizeof(pan_cfg->arg_cfg));
+	if (pan_name[0] == '0') {
+		pan_cfg->lk_cfg = false;
+	} else if (pan_name[0] == '1') {
+		pan_cfg->lk_cfg = true;
+	} else {
+		/* read from dt */
+		pan_cfg->lk_cfg = true;
+		pan_cfg->pan_intf = MDSS_PANEL_INTF_INVALID;
+		return -EINVAL;
+	}
+
+	/* skip lk cfg and delimiter; ex: "0:" */
+	strlcpy(pan_name, &pan_name[2], MDSS_MAX_PANEL_LEN);
+	t = strnstr(pan_name, ":", MDSS_MAX_PANEL_LEN);
+	if (!t) {
+		pr_err("%s: pan_name=[%s] invalid\n",
+			__func__, pan_name);
+		pan_cfg->pan_intf = MDSS_PANEL_INTF_INVALID;
+		return -EINVAL;
+	}
+
+	for (i = 0; ((pan_name + i) < t) && (i < 4); i++)
+		pan_intf_str[i] = *(pan_name + i);
+	pan_intf_str[i] = 0;
+	pr_debug("%s:%d panel intf %s\n", __func__, __LINE__, pan_intf_str);
+	/* point to the start of panel name */
+	t = t + 1;
+	strlcpy(&pan_cfg->arg_cfg[0], t, sizeof(pan_cfg->arg_cfg));
+	pr_debug("%s:%d: t=[%s] panel name=[%s]\n", __func__, __LINE__,
+		t, pan_cfg->arg_cfg);
+	rc = mdss_mdp_get_pan_intf(pan_intf_str);
+	pan_cfg->pan_intf = (rc < 0) ?  MDSS_PANEL_INTF_INVALID : rc;
+	return 0;
+}
+
+static int mdss_mdp_parse_dt_pan_intf(struct platform_device *pdev)
+{
+	int rc;
+	struct mdss_data_type *mdata = platform_get_drvdata(pdev);
+	const char *prim_intf = NULL;
+
+	rc = of_property_read_string(pdev->dev.of_node,
+				"qcom,mdss-pref-prim-intf", &prim_intf);
+	if (rc)
+		return -ENODEV;
+
+	rc = mdss_mdp_get_pan_intf(prim_intf);
+	if (rc < 0) {
+		mdata->pan_cfg.pan_intf = MDSS_PANEL_INTF_INVALID;
+	} else {
+		mdata->pan_cfg.pan_intf = rc;
+		rc = 0;
+	}
+	return rc;
+}
+
+static int mdss_mdp_parse_bootarg(struct platform_device *pdev)
+{
+	struct device_node *chosen_node;
+	static const char *cmd_line;
+	char *disp_idx, *end_idx;
+	int rc, len = 0, name_len, cmd_len;
+	int *intf_type;
+	char *panel_name;
+	struct mdss_panel_cfg *pan_cfg;
+	struct mdss_data_type *mdata = platform_get_drvdata(pdev);
+
+	mdata->pan_cfg.arg_cfg[MDSS_MAX_PANEL_LEN] = 0;
+	pan_cfg = &mdata->pan_cfg;
+	panel_name = &pan_cfg->arg_cfg[0];
+	intf_type = &pan_cfg->pan_intf;
+
+	/* reads from dt by default */
+	pan_cfg->lk_cfg = true;
+
+	chosen_node = of_find_node_by_name(NULL, "chosen");
+	if (!chosen_node) {
+		pr_err("%s: get chosen node failed\n", __func__);
+		rc = -ENODEV;
+		goto get_dt_pan;
+	}
+
+	cmd_line = of_get_property(chosen_node, "bootargs", &len);
+	if (!cmd_line || len <= 0) {
+		pr_err("%s: get bootargs failed\n", __func__);
+		rc = -ENODEV;
+		goto get_dt_pan;
+	}
+
+	name_len = strlen("mdss_mdp.panel=");
+	cmd_len = strlen(cmd_line);
+	disp_idx = strnstr(cmd_line, "mdss_mdp.panel=", cmd_len);
+	if (!disp_idx) {
+		pr_err("%s:%d:cmdline panel not set disp_idx=[%p]\n",
+				__func__, __LINE__, disp_idx);
+		memset(panel_name, 0x00, MDSS_MAX_PANEL_LEN);
+		*intf_type = MDSS_PANEL_INTF_INVALID;
+		rc = MDSS_PANEL_INTF_INVALID;
+		goto get_dt_pan;
+	}
+
+	disp_idx += name_len;
+
+	end_idx = strnstr(disp_idx, " ", MDSS_MAX_PANEL_LEN);
+	pr_debug("%s:%d: pan_name=[%s] end=[%s]\n", __func__, __LINE__,
+		 disp_idx, end_idx);
+	if (!end_idx) {
+		end_idx = disp_idx + strlen(disp_idx) + 1;
+		pr_warn("%s:%d: pan_name=[%s] end=[%s]\n", __func__,
+		       __LINE__, disp_idx, end_idx);
+	}
+
+	if (end_idx <= disp_idx) {
+		pr_err("%s:%d:cmdline pan incorrect end=[%p] disp=[%p]\n",
+			__func__, __LINE__, end_idx, disp_idx);
+		memset(panel_name, 0x00, MDSS_MAX_PANEL_LEN);
+		*intf_type = MDSS_PANEL_INTF_INVALID;
+		rc = MDSS_PANEL_INTF_INVALID;
+		goto get_dt_pan;
+	}
+
+	*end_idx = 0;
+	len = end_idx - disp_idx + 1;
+	if (len <= 0) {
+		pr_warn("%s: panel name not rx", __func__);
+		rc = -EINVAL;
+		goto get_dt_pan;
+	}
+
+	strlcpy(panel_name, disp_idx, min(++len, MDSS_MAX_PANEL_LEN));
+	pr_debug("%s:%d panel:[%s]", __func__, __LINE__, panel_name);
+	of_node_put(chosen_node);
+
+	rc = mdss_mdp_get_pan_cfg(pan_cfg);
+	if (!rc)
+		pan_cfg->init_done = true;
+
+	return rc;
+
+get_dt_pan:
+	rc = mdss_mdp_parse_dt_pan_intf(pdev);
+	/* if pref pan intf is not present */
+	if (rc)
+		pr_err("%s:unable to parse device tree for pan intf\n",
+			__func__);
+	else
+		pan_cfg->init_done = true;
+
+	of_node_put(chosen_node);
+	return rc;
+}
+
 static int mdss_mdp_parse_dt(struct platform_device *pdev)
 {
 	int rc;
@@ -1157,6 +1401,13 @@
 		return rc;
 	}
 
+	rc = mdss_mdp_parse_bootarg(pdev);
+	if (rc) {
+		pr_err("%s: Error in panel override:rc=[%d]\n",
+		       __func__, rc);
+		return rc;
+	}
+
 	return 0;
 }
 
@@ -1570,6 +1821,9 @@
 	if (mdata->nad_cfgs > mdata->nmixers_intf)
 		return -EINVAL;
 
+	mdata->has_wb_ad = of_property_read_bool(pdev->dev.of_node,
+		"qcom,mdss-has-wb-ad");
+
 	ad_offsets = kzalloc(sizeof(u32) * mdata->nad_cfgs, GFP_KERNEL);
 	if (!ad_offsets) {
 		pr_err("no mem assigned: kzalloc fail\n");
@@ -1622,11 +1876,61 @@
 	return len;
 }
 
-struct mdss_data_type *mdss_mdp_get_mdata()
+struct mdss_data_type *mdss_mdp_get_mdata(void)
 {
 	return mdss_res;
 }
 
+/**
+ * mdss_is_ready() - checks if mdss is probed and ready
+ *
+ * Checks if mdss resources have been initialized
+ *
+ * returns true if mdss is ready, else returns false
+ */
+bool mdss_is_ready(void)
+{
+	return mdss_mdp_get_mdata() ? true : false;
+}
+EXPORT_SYMBOL(mdss_mdp_get_mdata);
+
+/**
+ * mdss_panel_intf_type() - checks if a given intf type is primary
+ * @intf_val: panel interface type of the individual controller
+ *
+ * Individual controller queries with MDP to check if it is
+ * configured as the primary interface.
+ *
+ * returns a pointer to the configured structure mdss_panel_cfg
+ * to the controller that's configured as the primary panel interface.
+ * returns NULL on error or if @intf_val is not the configured
+ * controller.
+ */
+struct mdss_panel_cfg *mdss_panel_intf_type(int intf_val)
+{
+	if (!mdss_res || !mdss_res->pan_cfg.init_done)
+		return ERR_PTR(-EPROBE_DEFER);
+
+	if (mdss_res->pan_cfg.pan_intf == intf_val)
+		return &mdss_res->pan_cfg;
+	else
+		return NULL;
+}
+EXPORT_SYMBOL(mdss_panel_intf_type);
+
+int mdss_panel_get_boot_cfg(void)
+{
+	int rc;
+
+	if (!mdss_res || !mdss_res->pan_cfg.init_done)
+		rc = -EPROBE_DEFER;
+	if (mdss_res->pan_cfg.lk_cfg)
+		rc = 1;
+	else
+		rc = 0;
+	return rc;
+}
+
 static void mdss_mdp_footswitch_ctrl(struct mdss_data_type *mdata, int on)
 {
 	if (!mdata->fs)
@@ -1795,7 +2099,7 @@
 	.remove = mdss_mdp_remove,
 	.suspend = mdss_mdp_suspend,
 	.resume = mdss_mdp_resume,
-	.shutdown = mdss_mdp_shutdown,
+	.shutdown = NULL,
 	.driver = {
 		/*
 		 * Driver name must match the device name added in
diff --git a/drivers/video/msm/mdss/mdss_mdp.h b/drivers/video/msm/mdss/mdss_mdp.h
index aba77e3..351d52b 100644
--- a/drivers/video/msm/mdss/mdss_mdp.h
+++ b/drivers/video/msm/mdss/mdss_mdp.h
@@ -39,6 +39,8 @@
 #define MAX_DOWNSCALE_RATIO	4
 #define MAX_UPSCALE_RATIO	20
 #define MAX_DECIMATION		4
+#define MDP_MIN_VBP		4
+#define MAX_FREE_LIST_SIZE	12
 
 #define C3_ALPHA	3	/* alpha */
 #define C2_R_Cr		2	/* R/Cr */
@@ -114,6 +116,7 @@
 
 struct mdss_mdp_vsync_handler {
 	bool enabled;
+	bool cmd_post_flush;
 	mdp_vsync_handler_t vsync_handler;
 	struct list_head list;
 };
@@ -270,6 +273,7 @@
 	struct mutex lock;
 	struct work_struct calc_work;
 	struct msm_fb_data_type *mfd;
+	struct msm_fb_data_type *bl_mfd;
 	struct mdss_mdp_vsync_handler handle;
 	struct completion comp;
 	u32 last_str;
@@ -314,6 +318,7 @@
 	u32 ftch_id;
 	atomic_t ref_cnt;
 	u32 play_cnt;
+	int pid;
 
 	u32 flags;
 	u32 bwc_mode;
@@ -333,6 +338,7 @@
 	u8 mixer_stage;
 	u8 is_fg;
 	u8 alpha;
+	u8 blend_op;
 	u8 overfetch_disable;
 	u32 transp;
 
@@ -361,8 +367,8 @@
 };
 
 struct mdss_overlay_private {
-	int vsync_pending;
 	ktime_t vsync_time;
+	struct sysfs_dirent *vsync_event_sd;
 	int borderfill_enable;
 	int overlay_play_enable;
 	int hw_refresh;
@@ -375,8 +381,12 @@
 	struct list_head overlay_list;
 	struct list_head pipes_used;
 	struct list_head pipes_cleanup;
-	struct work_struct vsync_work;
+	struct list_head rot_proc_list;
 	bool mixer_swap;
+
+	struct mdss_mdp_data free_list[MAX_FREE_LIST_SIZE];
+	int free_list_size;
+	int ad_state;
 };
 
 struct mdss_mdp_perf_params {
diff --git a/drivers/video/msm/mdss/mdss_mdp_ctl.c b/drivers/video/msm/mdss/mdss_mdp_ctl.c
index d1595b3..d2c684f 100644
--- a/drivers/video/msm/mdss/mdss_mdp_ctl.c
+++ b/drivers/video/msm/mdss/mdss_mdp_ctl.c
@@ -212,7 +212,14 @@
 
 	quota = fps * pipe->src.w * src_h;
 	if (pipe->src_fmt->chroma_sample == MDSS_MDP_CHROMA_420)
-		quota = (quota * 3) / 2;
+		/*
+		 * with decimation, chroma is not downsampled, this means we
+		 * need to allocate bw for extra lines that will be fetched
+		 */
+		if (pipe->vert_deci)
+			quota *= 2;
+		else
+			quota = (quota * 3) / 2;
 	else
 		quota *= pipe->src_fmt->bpp;
 
@@ -242,6 +249,7 @@
 				       u32 *clk_rate)
 {
 	struct mdss_mdp_pipe *pipe;
+	struct mdss_panel_info *pinfo = NULL;
 	int fps = DEFAULT_FRAME_RATE;
 	u32 v_total;
 	int i;
@@ -252,22 +260,21 @@
 	*clk_rate = 0;
 
 	if (!mixer->rotator_mode) {
-		int is_writeback = false;
 		if (mixer->type == MDSS_MDP_MIXER_TYPE_INTF) {
-			struct mdss_panel_info *pinfo;
 			pinfo = &mixer->ctl->panel_data->panel_info;
 			fps = mdss_panel_get_framerate(pinfo);
 			v_total = mdss_panel_get_vtotal(pinfo);
 
 			if (pinfo->type == WRITEBACK_PANEL)
-				is_writeback = true;
+				pinfo = NULL;
 		} else {
 			v_total = mixer->height;
-
-			is_writeback = true;
 		}
 		*clk_rate = mixer->width * v_total * fps;
-		if (is_writeback) {
+		if (pinfo && pinfo->lcdc.v_back_porch < MDP_MIN_VBP)
+			*clk_rate = MDSS_MDP_CLK_FUDGE_FACTOR(*clk_rate);
+
+		if (!pinfo) {
 			/* perf for bus writeback */
 			*bus_ab_quota = fps * mixer->width * mixer->height * 3;
 			*bus_ab_quota >>= MDSS_MDP_BUS_FACTOR_SHIFT;
@@ -280,11 +287,6 @@
 		pipe = mixer->stage_pipe[i];
 		if (pipe == NULL)
 			continue;
-		if (pipe->is_fg) {
-			ab_total = 0;
-			ib_total = 0;
-			max_clk_rate = 0;
-		}
 
 		if (mdss_mdp_perf_calc_pipe(pipe, &perf))
 			continue;
@@ -425,6 +427,7 @@
 	ctl->read_line_cnt_fnc = NULL;
 	ctl->add_vsync_handler = NULL;
 	ctl->remove_vsync_handler = NULL;
+	ctl->panel_data = NULL;
 	mutex_unlock(&mdss_mdp_ctl_lock);
 
 	return 0;
@@ -433,7 +436,7 @@
 static struct mdss_mdp_mixer *mdss_mdp_mixer_alloc(
 		struct mdss_mdp_ctl *ctl, u32 type, int mux)
 {
-	struct mdss_mdp_mixer *mixer = NULL;
+	struct mdss_mdp_mixer *mixer = NULL, *alt_mixer = NULL;
 	u32 nmixers_intf;
 	u32 nmixers_wb;
 	u32 i;
@@ -451,6 +454,16 @@
 	case MDSS_MDP_MIXER_TYPE_INTF:
 		mixer_pool = ctl->mdata->mixer_intf;
 		nmixers = nmixers_intf;
+
+		/*
+		 * try to reserve first layer mixer for write back if
+		 * assertive display needs to be supported through wfd
+		 */
+		if (ctl->mdata->has_wb_ad && ctl->intf_num) {
+			alt_mixer = mixer_pool;
+			mixer_pool++;
+			nmixers--;
+		}
 		break;
 
 	case MDSS_MDP_MIXER_TYPE_WRITEBACK:
@@ -489,6 +502,9 @@
 		}
 		mixer = NULL;
 	}
+
+	if (!mixer && alt_mixer && (alt_mixer->ref_cnt == 0))
+		mixer = alt_mixer;
 	mutex_unlock(&mdss_mdp_ctl_lock);
 
 	return mixer;
@@ -520,13 +536,13 @@
 
 	ctl = mdss_mdp_ctl_alloc(mdss_res, mdss_res->nmixers_intf);
 	if (!ctl) {
-		pr_err("unable to allocate wb ctl\n");
+		pr_debug("unable to allocate wb ctl\n");
 		return NULL;
 	}
 
 	mixer = mdss_mdp_mixer_alloc(ctl, MDSS_MDP_MIXER_TYPE_WRITEBACK, false);
 	if (!mixer) {
-		pr_err("unable to allocate wb mixer\n");
+		pr_debug("unable to allocate wb mixer\n");
 		goto error;
 	}
 
@@ -572,6 +588,7 @@
 	struct mdss_mdp_ctl *ctl;
 
 	ctl = mixer->ctl;
+	mixer->rotator_mode = 0;
 
 	pr_debug("destroy ctl=%d mixer=%d\n", ctl->num, mixer->num);
 
@@ -1207,7 +1224,8 @@
 {
 	struct mdss_mdp_pipe *pipe;
 	u32 off, blend_op, blend_stage;
-	u32 mixercfg = 0, blend_color_out = 0, bgalpha = 0;
+	u32 mixercfg = 0, blend_color_out = 0, bg_alpha_enable = 0;
+	u32 fg_alpha = 0, bg_alpha = 0;
 	int stage, secure = 0;
 
 	if (!mixer)
@@ -1227,7 +1245,7 @@
 			mixercfg = 1 << (3 * pipe->num);
 		}
 		if (pipe->src_fmt->alpha_enable)
-			bgalpha = 1;
+			bg_alpha_enable = 1;
 		secure = pipe->flags & MDP_SECURE_OVERLAY_SESSION;
 	}
 
@@ -1244,48 +1262,79 @@
 		blend_stage = stage - MDSS_MDP_STAGE_0;
 		off = MDSS_MDP_REG_LM_BLEND_OFFSET(blend_stage);
 
-		if (pipe->is_fg) {
-			bgalpha = 0;
-			if (!secure)
-				mixercfg = MDSS_MDP_LM_BORDER_COLOR;
+		blend_op = (MDSS_MDP_BLEND_FG_ALPHA_FG_CONST |
+			    MDSS_MDP_BLEND_BG_ALPHA_BG_CONST);
+		fg_alpha = pipe->alpha;
+		bg_alpha = 0xFF - pipe->alpha;
+		/* keep fg alpha */
+		blend_color_out |= 1 << (blend_stage + 1);
+
+		switch (pipe->blend_op) {
+		case BLEND_OP_OPAQUE:
 
 			blend_op = (MDSS_MDP_BLEND_FG_ALPHA_FG_CONST |
 				    MDSS_MDP_BLEND_BG_ALPHA_BG_CONST);
-			/* keep fg alpha */
-			blend_color_out |= 1 << (blend_stage + 1);
 
-			pr_debug("pnum=%d stg=%d alpha=IS_FG\n", pipe->num,
+			pr_debug("pnum=%d stg=%d op=OPAQUE\n", pipe->num,
 					stage);
-		} else if (pipe->src_fmt->alpha_enable) {
-			bgalpha = 0;
-			blend_op = (MDSS_MDP_BLEND_BG_ALPHA_FG_PIXEL |
-				    MDSS_MDP_BLEND_BG_INV_ALPHA);
-			/* keep fg alpha */
-			blend_color_out |= 1 << (blend_stage + 1);
+			break;
 
-			pr_debug("pnum=%d stg=%d alpha=FG PIXEL\n", pipe->num,
+		case BLEND_OP_PREMULTIPLIED:
+			if (pipe->src_fmt->alpha_enable) {
+				blend_op = (MDSS_MDP_BLEND_FG_ALPHA_FG_CONST |
+					    MDSS_MDP_BLEND_BG_ALPHA_FG_PIXEL);
+				if (fg_alpha != 0xff) {
+					bg_alpha = fg_alpha;
+					blend_op |=
+						MDSS_MDP_BLEND_BG_MOD_ALPHA |
+						MDSS_MDP_BLEND_BG_INV_MOD_ALPHA;
+				} else {
+					blend_op |= MDSS_MDP_BLEND_BG_INV_ALPHA;
+				}
+			}
+			pr_debug("pnum=%d stg=%d op=PREMULTIPLIED\n", pipe->num,
 					stage);
-		} else if (bgalpha) {
-			blend_op = (MDSS_MDP_BLEND_BG_ALPHA_BG_PIXEL |
-				    MDSS_MDP_BLEND_FG_ALPHA_BG_PIXEL |
-				    MDSS_MDP_BLEND_FG_INV_ALPHA);
-			/* keep bg alpha */
-			pr_debug("pnum=%d stg=%d alpha=BG_PIXEL\n", pipe->num,
+			break;
+
+		case BLEND_OP_COVERAGE:
+			if (pipe->src_fmt->alpha_enable) {
+				blend_op = (MDSS_MDP_BLEND_FG_ALPHA_FG_PIXEL |
+					    MDSS_MDP_BLEND_BG_ALPHA_FG_PIXEL);
+				if (fg_alpha != 0xff) {
+					bg_alpha = fg_alpha;
+					blend_op |=
+					       MDSS_MDP_BLEND_FG_MOD_ALPHA |
+					       MDSS_MDP_BLEND_FG_INV_MOD_ALPHA |
+					       MDSS_MDP_BLEND_BG_MOD_ALPHA |
+					       MDSS_MDP_BLEND_BG_INV_MOD_ALPHA;
+				} else {
+					blend_op |= MDSS_MDP_BLEND_BG_INV_ALPHA;
+				}
+			}
+			pr_debug("pnum=%d stg=%d op=COVERAGE\n", pipe->num,
 					stage);
-		} else {
+			break;
+
+		default:
 			blend_op = (MDSS_MDP_BLEND_FG_ALPHA_FG_CONST |
 				    MDSS_MDP_BLEND_BG_ALPHA_BG_CONST);
-			pr_debug("pnum=%d stg=%d alpha=CONST\n", pipe->num,
+			pr_debug("pnum=%d stg=%d op=NONE\n", pipe->num,
 					stage);
+			break;
 		}
 
+		if (!pipe->src_fmt->alpha_enable && bg_alpha_enable)
+			blend_color_out = 0;
+
 		mixercfg |= stage << (3 * pipe->num);
 
+		pr_debug("stg=%d op=%x fg_alpha=%x bg_alpha=%x\n", stage,
+					blend_op, fg_alpha, bg_alpha);
 		mdp_mixer_write(mixer, off + MDSS_MDP_REG_LM_OP_MODE, blend_op);
 		mdp_mixer_write(mixer, off + MDSS_MDP_REG_LM_BLEND_FG_ALPHA,
-				   pipe->alpha);
+				   fg_alpha);
 		mdp_mixer_write(mixer, off + MDSS_MDP_REG_LM_BLEND_BG_ALPHA,
-				   0xFF - pipe->alpha);
+				   bg_alpha);
 	}
 
 	if (mixer->cursor_enabled)
diff --git a/drivers/video/msm/mdss/mdss_mdp_formats.h b/drivers/video/msm/mdss/mdss_mdp_formats.h
index f5da8e6..a2edf90 100644
--- a/drivers/video/msm/mdss/mdss_mdp_formats.h
+++ b/drivers/video/msm/mdss/mdss_mdp_formats.h
@@ -165,5 +165,14 @@
 		.bpp = 2,
 		.element = { C1_B_Cb, C0_G_Y, C2_R_Cr, C0_G_Y },
 	},
+	{
+		FMT_YUV_COMMON(MDP_YCBYCR_H2V1),
+		.fetch_planes = MDSS_MDP_PLANE_INTERLEAVED,
+		.chroma_sample = MDSS_MDP_CHROMA_H2V1,
+		.unpack_count = 4,
+		.bpp = 2,
+		.element = { C2_R_Cr, C0_G_Y, C1_B_Cb, C0_G_Y },
+	},
+
 };
 #endif
diff --git a/drivers/video/msm/mdss/mdss_mdp_hwio.h b/drivers/video/msm/mdss/mdss_mdp_hwio.h
index ccd6e56..213368a 100644
--- a/drivers/video/msm/mdss/mdss_mdp_hwio.h
+++ b/drivers/video/msm/mdss/mdss_mdp_hwio.h
@@ -43,6 +43,7 @@
 #define MDSS_MDP_REG_HIST_INTR_STATUS			0x00120
 #define MDSS_MDP_REG_HIST_INTR_CLEAR			0x00124
 
+#define MDSS_MDP_REG_VIDEO_INTF_UNDERFLOW_CTL		0x003E0
 #define MDSS_MDP_REG_SPLIT_DISPLAY_EN			0x003F4
 #define MDSS_MDP_REG_SPLIT_DISPLAY_UPPER_PIPE_CTRL	0x003F8
 #define MDSS_MDP_REG_SPLIT_DISPLAY_LOWER_PIPE_CTRL	0x004F0
diff --git a/drivers/video/msm/mdss/mdss_mdp_intf_cmd.c b/drivers/video/msm/mdss/mdss_mdp_intf_cmd.c
index cb4c1f2..920c231 100644
--- a/drivers/video/msm/mdss/mdss_mdp_intf_cmd.c
+++ b/drivers/video/msm/mdss/mdss_mdp_intf_cmd.c
@@ -34,7 +34,7 @@
 	u8 ref_cnt;
 	struct completion pp_comp;
 	struct completion stop_comp;
-	mdp_vsync_handler_t send_vsync;
+	struct list_head vsync_handlers;
 	int panel_on;
 	int koff_cnt;
 	int clk_enabled;
@@ -232,6 +232,7 @@
 {
 	struct mdss_mdp_ctl *ctl = arg;
 	struct mdss_mdp_cmd_ctx *ctx = ctl->priv_data;
+	struct mdss_mdp_vsync_handler *tmp;
 	ktime_t vsync_time;
 
 	if (!ctx) {
@@ -243,8 +244,10 @@
 	ctl->vsync_cnt++;
 
 	spin_lock(&ctx->clk_lock);
-	if (ctx->send_vsync)
-		ctx->send_vsync(ctl, vsync_time);
+	list_for_each_entry(tmp, &ctx->vsync_handlers, list) {
+		if (tmp->enabled && !tmp->cmd_post_flush)
+			tmp->vsync_handler(ctl, vsync_time);
+	}
 
 	if (!ctx->vsync_enabled) {
 		if (ctx->rdptr_enabled)
@@ -265,6 +268,8 @@
 {
 	struct mdss_mdp_ctl *ctl = arg;
 	struct mdss_mdp_cmd_ctx *ctx = ctl->priv_data;
+	struct mdss_mdp_vsync_handler *tmp;
+	ktime_t vsync_time;
 
 	if (!ctx) {
 		pr_err("%s: invalid ctx\n", __func__);
@@ -272,6 +277,10 @@
 	}
 
 	spin_lock(&ctx->clk_lock);
+	list_for_each_entry(tmp, &ctx->vsync_handlers, list) {
+		if (tmp->enabled && tmp->cmd_post_flush)
+			tmp->vsync_handler(ctl, vsync_time);
+	}
 	mdss_mdp_irq_disable_nosync(MDSS_MDP_IRQ_PING_PONG_COMP, ctx->pp_num);
 
 	complete_all(&ctx->pp_comp);
@@ -318,15 +327,16 @@
 	}
 
 	spin_lock_irqsave(&ctx->clk_lock, flags);
-	if (ctx->vsync_enabled) {
-		spin_unlock_irqrestore(&ctx->clk_lock, flags);
-		return 0;
+	if (!handle->enabled) {
+		handle->enabled = true;
+		list_add(&handle->list, &ctx->vsync_handlers);
+		if (!handle->cmd_post_flush)
+			ctx->vsync_enabled = 1;
 	}
-	ctx->vsync_enabled = 1;
-	ctx->send_vsync = handle->vsync_handler;
 	spin_unlock_irqrestore(&ctx->clk_lock, flags);
 
-	mdss_mdp_cmd_clk_on(ctx);
+	if (!handle->cmd_post_flush)
+		mdss_mdp_cmd_clk_on(ctx);
 
 	return 0;
 }
@@ -337,6 +347,8 @@
 
 	struct mdss_mdp_cmd_ctx *ctx;
 	unsigned long flags;
+	struct mdss_mdp_vsync_handler *tmp;
+	int num_rdptr_vsync = 0;
 
 	ctx = (struct mdss_mdp_cmd_ctx *) ctl->priv_data;
 	if (!ctx) {
@@ -346,13 +358,18 @@
 
 
 	spin_lock_irqsave(&ctx->clk_lock, flags);
-	if (!ctx->vsync_enabled) {
-		spin_unlock_irqrestore(&ctx->clk_lock, flags);
-		return 0;
+	if (handle->enabled) {
+		handle->enabled = false;
+		list_del_init(&handle->list);
 	}
-	ctx->vsync_enabled = 0;
-	ctx->send_vsync = NULL;
-	ctx->rdptr_enabled = VSYNC_EXPIRE_TICK;
+	list_for_each_entry(tmp, &ctx->vsync_handlers, list) {
+		if (!tmp->cmd_post_flush)
+			num_rdptr_vsync++;
+	}
+	if (!num_rdptr_vsync) {
+		ctx->vsync_enabled = 0;
+		ctx->rdptr_enabled = VSYNC_EXPIRE_TICK;
+	}
 	spin_unlock_irqrestore(&ctx->clk_lock, flags);
 	return 0;
 }
@@ -455,6 +472,7 @@
 {
 	struct mdss_mdp_cmd_ctx *ctx;
 	unsigned long flags;
+	struct mdss_mdp_vsync_handler *tmp, *handle;
 	int need_wait = 0;
 	int ret = 0;
 
@@ -468,10 +486,6 @@
 		INIT_COMPLETION(ctx->stop_comp);
 		need_wait = 1;
 	}
-	if (ctx->vsync_enabled) {
-		pr_err("%s: vsync should be disabled\n", __func__);
-		ctx->vsync_enabled = 0;
-	}
 	spin_unlock_irqrestore(&ctx->clk_lock, flags);
 
 	if (need_wait)
@@ -486,6 +500,9 @@
 
 	ctx->panel_on = 0;
 
+	list_for_each_entry_safe(handle, tmp, &ctx->vsync_handlers, list)
+		mdss_mdp_cmd_remove_vsync_handler(ctl, handle);
+
 	mdss_mdp_set_intr_callback(MDSS_MDP_IRQ_PING_PONG_RD_PTR, ctx->pp_num,
 				   NULL, NULL);
 	mdss_mdp_set_intr_callback(MDSS_MDP_IRQ_PING_PONG_COMP, ctx->pp_num,
@@ -550,6 +567,7 @@
 	spin_lock_init(&ctx->clk_lock);
 	mutex_init(&ctx->clk_mtx);
 	INIT_WORK(&ctx->clk_work, clk_ctrl_work);
+	INIT_LIST_HEAD(&ctx->vsync_handlers);
 
 	pr_debug("%s: ctx=%p num=%d mixer=%d\n", __func__,
 				ctx, ctx->pp_num, mixer->num);
diff --git a/drivers/video/msm/mdss/mdss_mdp_intf_video.c b/drivers/video/msm/mdss/mdss_mdp_intf_video.c
index 6fb8883..c78339a 100644
--- a/drivers/video/msm/mdss/mdss_mdp_intf_video.c
+++ b/drivers/video/msm/mdss/mdss_mdp_intf_video.c
@@ -479,9 +479,9 @@
 		mdp_video_write(ctx, MDSS_MDP_REG_INTF_TIMING_ENGINE_EN, 1);
 		wmb();
 
-		rc = wait_for_completion_interruptible_timeout(&ctx->vsync_comp,
+		rc = wait_for_completion_timeout(&ctx->vsync_comp,
 				usecs_to_jiffies(VSYNC_TIMEOUT_US));
-		WARN(rc <= 0, "timeout (%d) enabling timegen on ctl=%d\n",
+		WARN(rc == 0, "timeout (%d) enabling timegen on ctl=%d\n",
 				rc, ctl->num);
 
 		ctx->timegen_en = true;
@@ -536,8 +536,8 @@
 			(unsigned long int)virt, &phys);
 
 	bl_fb_addr_va = (unsigned long *)ioremap(bl_fb_addr, size);
-
 	memcpy(virt, bl_fb_addr_va, size);
+	iounmap(bl_fb_addr_va);
 
 	MDSS_MDP_REG_WRITE(pipe_addr, phys);
 	MDSS_MDP_REG_WRITE(MDSS_MDP_REG_CTL_FLUSH + MDSS_MDP_REG_CTL_OFFSET(0),
diff --git a/drivers/video/msm/mdss/mdss_mdp_intf_writeback.c b/drivers/video/msm/mdss/mdss_mdp_intf_writeback.c
index 0a37573..2b07428 100644
--- a/drivers/video/msm/mdss/mdss_mdp_intf_writeback.c
+++ b/drivers/video/msm/mdss/mdss_mdp_intf_writeback.c
@@ -48,6 +48,8 @@
 
 	void (*callback_fnc) (void *arg);
 	void *callback_arg;
+	spinlock_t wb_lock;
+	struct list_head vsync_handlers;
 };
 
 static struct mdss_mdp_writeback_ctx wb_ctx_list[MDSS_MDP_MAX_WRITEBACK] = {
@@ -293,16 +295,75 @@
 	return mdss_mdp_writeback_format_setup(ctx, format);
 }
 
+static int mdss_mdp_wb_add_vsync_handler(struct mdss_mdp_ctl *ctl,
+		struct mdss_mdp_vsync_handler *handle)
+{
+	struct mdss_mdp_writeback_ctx *ctx;
+	unsigned long flags;
+	int ret = 0;
+
+	if (!handle || !(handle->vsync_handler)) {
+		ret = -EINVAL;
+		goto exit;
+	}
+
+	ctx = (struct mdss_mdp_writeback_ctx *) ctl->priv_data;
+	if (!ctx) {
+		pr_err("invalid ctx for ctl=%d\n", ctl->num);
+		ret = -ENODEV;
+		goto exit;
+	}
+
+	spin_lock_irqsave(&ctx->wb_lock, flags);
+	if (!handle->enabled) {
+		handle->enabled = true;
+		list_add(&handle->list, &ctx->vsync_handlers);
+	}
+	spin_unlock_irqrestore(&ctx->wb_lock, flags);
+exit:
+	return ret;
+}
+
+static int mdss_mdp_wb_remove_vsync_handler(struct mdss_mdp_ctl *ctl,
+		struct mdss_mdp_vsync_handler *handle)
+{
+	struct mdss_mdp_writeback_ctx *ctx;
+	unsigned long flags;
+	int ret = 0;
+	if (!handle || !(handle->vsync_handler)) {
+		ret = -EINVAL;
+		goto exit;
+	}
+	ctx = (struct mdss_mdp_writeback_ctx *) ctl->priv_data;
+	if (!ctx) {
+		pr_err("invalid ctx for ctl=%d\n", ctl->num);
+		ret = -ENODEV;
+		goto exit;
+	}
+	spin_lock_irqsave(&ctx->wb_lock, flags);
+	if (handle->enabled) {
+		handle->enabled = false;
+		list_del_init(&handle->list);
+	}
+	spin_unlock_irqrestore(&ctx->wb_lock, flags);
+exit:
+	return ret;
+}
+
 static int mdss_mdp_writeback_stop(struct mdss_mdp_ctl *ctl)
 {
 	struct mdss_mdp_writeback_ctx *ctx;
+	struct mdss_mdp_vsync_handler *t, *handle;
 
 	pr_debug("stop ctl=%d\n", ctl->num);
 
 	ctx = (struct mdss_mdp_writeback_ctx *) ctl->priv_data;
 	if (ctx) {
+		list_for_each_entry_safe(handle, t, &ctx->vsync_handlers, list)
+			mdss_mdp_wb_remove_vsync_handler(ctl, handle);
+
 		mdss_mdp_set_intr_callback(ctx->intr_type, ctx->intf_num,
-				   NULL, NULL);
+				NULL, NULL);
 
 		ctl->priv_data = NULL;
 		ctx->ref_cnt--;
@@ -313,13 +374,16 @@
 
 static void mdss_mdp_writeback_intr_done(void *arg)
 {
-	struct mdss_mdp_writeback_ctx *ctx;
+	struct mdss_mdp_ctl *ctl = arg;
+	struct mdss_mdp_writeback_ctx *ctx = ctl->priv_data;
+	struct mdss_mdp_vsync_handler *tmp;
+	ktime_t vsync_time;
 
-	ctx = (struct mdss_mdp_writeback_ctx *) arg;
 	if (!ctx) {
 		pr_err("invalid ctx\n");
 		return;
 	}
+	vsync_time = ktime_get();
 
 	pr_debug("intr wb_num=%d\n", ctx->wb_num);
 
@@ -328,6 +392,12 @@
 	if (ctx->callback_fnc)
 		ctx->callback_fnc(ctx->callback_arg);
 
+	spin_lock(&ctx->wb_lock);
+	list_for_each_entry(tmp, &ctx->vsync_handlers, list) {
+		tmp->vsync_handler(ctl, vsync_time);
+	}
+	spin_unlock(&ctx->wb_lock);
+
 	complete_all(&ctx->wb_comp);
 }
 
@@ -345,12 +415,12 @@
 	if (ctx->comp_cnt == 0)
 		return rc;
 
-	rc = wait_for_completion_interruptible_timeout(&ctx->wb_comp,
+	rc = wait_for_completion_timeout(&ctx->wb_comp,
 			KOFF_TIMEOUT);
 	mdss_mdp_set_intr_callback(ctx->intr_type, ctx->intf_num,
 		NULL, NULL);
 
-	if (rc <= 0) {
+	if (rc == 0) {
 		rc = -ENODEV;
 		WARN(1, "writeback kickoff timed out (%d) ctl=%d\n",
 						rc, ctl->num);
@@ -393,7 +463,7 @@
 	}
 
 	mdss_mdp_set_intr_callback(ctx->intr_type, ctx->intf_num,
-		   mdss_mdp_writeback_intr_done, ctx);
+		   mdss_mdp_writeback_intr_done, ctl);
 
 	ctx->callback_fnc = wb_args->callback_fnc;
 	ctx->callback_arg = wb_args->priv_data;
@@ -439,6 +509,8 @@
 	ctx->base = ctl->wb_base;
 	ctx->initialized = false;
 	init_completion(&ctx->wb_comp);
+	spin_lock_init(&ctx->wb_lock);
+	INIT_LIST_HEAD(&ctx->vsync_handlers);
 
 	if (ctx->type == MDSS_MDP_WRITEBACK_TYPE_ROTATOR)
 		ctl->prepare_fnc = mdss_mdp_writeback_prepare_rot;
@@ -447,6 +519,8 @@
 	ctl->stop_fnc = mdss_mdp_writeback_stop;
 	ctl->display_fnc = mdss_mdp_writeback_display;
 	ctl->wait_fnc = mdss_mdp_wb_wait4comp;
+	ctl->add_vsync_handler = mdss_mdp_wb_add_vsync_handler;
+	ctl->remove_vsync_handler = mdss_mdp_wb_remove_vsync_handler;
 
 	return ret;
 }
diff --git a/drivers/video/msm/mdss/mdss_mdp_overlay.c b/drivers/video/msm/mdss/mdss_mdp_overlay.c
index 99b0205..fcc87f6 100644
--- a/drivers/video/msm/mdss/mdss_mdp_overlay.c
+++ b/drivers/video/msm/mdss/mdss_mdp_overlay.c
@@ -25,6 +25,7 @@
 
 #include <mach/iommu_domains.h>
 #include <mach/event_timer.h>
+#include <mach/msm_bus.h>
 
 #include "mdss.h"
 #include "mdss_debug.h"
@@ -37,6 +38,9 @@
 #define CHECK_BOUNDS(offset, size, max_size) \
 	(((size) > (max_size)) || ((offset) > ((max_size) - (size))))
 
+#define PP_CLK_CFG_OFF 0
+#define PP_CLK_CFG_ON 1
+
 static atomic_t ov_active_panels = ATOMIC_INIT(0);
 static int mdss_mdp_overlay_free_fb_pipe(struct msm_fb_data_type *mfd);
 static int mdss_mdp_overlay_fb_parse_dt(struct msm_fb_data_type *mfd);
@@ -241,6 +245,8 @@
 
 	if (req->id == MSMFB_NEW_REQUEST) {
 		rot = mdss_mdp_rotator_session_alloc();
+		rot->pid = current->tgid;
+		list_add(&rot->list, &mdp5_data->rot_proc_list);
 
 		if (!rot) {
 			pr_err("unable to allocate rotator session\n");
@@ -439,6 +445,7 @@
 		mutex_unlock(&mfd->lock);
 		pipe->mixer = mixer;
 		pipe->mfd = mfd;
+		pipe->pid = current->tgid;
 		pipe->play_cnt = 0;
 	} else {
 		pipe = mdss_mdp_pipe_get(mdp5_data->mdata, req->id);
@@ -491,6 +498,16 @@
 	pipe->is_fg = req->is_fg;
 	pipe->alpha = req->alpha;
 	pipe->transp = req->transp_mask;
+	pipe->blend_op = req->blend_op;
+	if (pipe->blend_op == BLEND_OP_NOT_DEFINED)
+		pipe->blend_op = fmt->alpha_enable ?
+					BLEND_OP_PREMULTIPLIED :
+					BLEND_OP_OPAQUE;
+
+	if (!fmt->alpha_enable && (pipe->blend_op != BLEND_OP_OPAQUE))
+		pr_debug("Unintended blend_op %d on layer with no alpha plane\n",
+			pipe->blend_op);
+
 	pipe->overfetch_disable = fmt->is_yuv &&
 			!(pipe->flags & MDP_SOURCE_ROTATED_90);
 
@@ -595,7 +612,8 @@
 	mutex_lock(&mfd->lock);
 	if (pipe->play_cnt == 0) {
 		pr_debug("failed for pipe %d\n", pipe->num);
-		list_del(&pipe->used_list);
+		if (!list_empty(&pipe->used_list))
+			list_del_init(&pipe->used_list);
 		mdss_mdp_pipe_destroy(pipe);
 	}
 
@@ -685,6 +703,45 @@
 	return 0;
 }
 
+/**
+ * __mdss_mdp_overlay_free_list_purge() - clear free list of buffers
+ * @mfd:	Msm frame buffer data structure for the associated fb
+ *
+ * Frees memory and clears current list of buffers which are pending free
+ */
+static void __mdss_mdp_overlay_free_list_purge(struct msm_fb_data_type *mfd)
+{
+	struct mdss_overlay_private *mdp5_data = mfd_to_mdp5_data(mfd);
+	int i;
+
+	pr_debug("purging fb%d free list\n", mfd->index);
+	for (i = 0; i < mdp5_data->free_list_size; i++)
+		mdss_mdp_overlay_free_buf(&mdp5_data->free_list[i]);
+	mdp5_data->free_list_size = 0;
+}
+
+/**
+ * __mdss_mdp_overlay_free_list_add() - add a buffer to free list
+ * @mfd:	Msm frame buffer data structure for the associated fb
+ */
+static void __mdss_mdp_overlay_free_list_add(struct msm_fb_data_type *mfd,
+		struct mdss_mdp_data *buf)
+{
+	struct mdss_overlay_private *mdp5_data = mfd_to_mdp5_data(mfd);
+	int i;
+
+	/* if holding too many buffers free current list */
+	if (mdp5_data->free_list_size >= MAX_FREE_LIST_SIZE) {
+		pr_warn("max free list size for fb%d, purging\n", mfd->index);
+		__mdss_mdp_overlay_free_list_purge(mfd);
+	}
+
+	BUG_ON(mdp5_data->free_list_size >= MAX_FREE_LIST_SIZE);
+	i = mdp5_data->free_list_size++;
+	mdp5_data->free_list[i] = *buf;
+	memset(buf, 0, sizeof(*buf));
+}
+
 static void mdss_mdp_overlay_cleanup(struct msm_fb_data_type *mfd)
 {
 	struct mdss_mdp_pipe *pipe, *tmp;
@@ -692,18 +749,20 @@
 	LIST_HEAD(destroy_pipes);
 
 	mutex_lock(&mfd->lock);
+	__mdss_mdp_overlay_free_list_purge(mfd);
+
 	list_for_each_entry_safe(pipe, tmp, &mdp5_data->pipes_cleanup,
 				cleanup_list) {
 		list_move(&pipe->cleanup_list, &destroy_pipes);
 		mdss_mdp_overlay_free_buf(&pipe->back_buf);
-		mdss_mdp_overlay_free_buf(&pipe->front_buf);
+		__mdss_mdp_overlay_free_list_add(mfd, &pipe->front_buf);
 		pipe->mfd = NULL;
 	}
 
 	list_for_each_entry(pipe, &mdp5_data->pipes_used, used_list) {
 		if (pipe->back_buf.num_planes) {
 			/* make back buffer active */
-			mdss_mdp_overlay_free_buf(&pipe->front_buf);
+			__mdss_mdp_overlay_free_list_add(mfd, &pipe->front_buf);
 			swap(pipe->back_buf, pipe->front_buf);
 		}
 	}
@@ -768,7 +827,7 @@
 int mdss_mdp_overlay_kickoff(struct msm_fb_data_type *mfd)
 {
 	struct mdss_overlay_private *mdp5_data = mfd_to_mdp5_data(mfd);
-	struct mdss_mdp_pipe *pipe, *next;
+	struct mdss_mdp_pipe *pipe;
 	struct mdss_mdp_ctl *ctl = mfd_to_ctl(mfd);
 	struct mdss_mdp_ctl *tmp;
 	int ret;
@@ -788,8 +847,7 @@
 		return ret;
 	}
 
-	list_for_each_entry_safe(pipe, next, &mdp5_data->pipes_used,
-			used_list) {
+	list_for_each_entry(pipe, &mdp5_data->pipes_used, used_list) {
 		struct mdss_mdp_data *buf;
 		/*
 		 * When external is connected and no dedicated wfd is present,
@@ -827,13 +885,6 @@
 			pipe->params_changed++;
 			buf = &pipe->front_buf;
 		} else if (!pipe->params_changed) {
-			if (pipe->mixer) {
-				if (!mdss_mdp_pipe_is_staged(pipe)) {
-					list_del(&pipe->used_list);
-					list_add(&pipe->cleanup_list,
-						 &mdp5_data->pipes_cleanup);
-				}
-			}
 			continue;
 		} else if (pipe->front_buf.num_planes) {
 			buf = &pipe->front_buf;
@@ -892,9 +943,12 @@
 				continue;
 			}
 			mutex_lock(&mfd->lock);
-			list_del(&pipe->used_list);
-			list_add(&pipe->cleanup_list,
-				&mdp5_data->pipes_cleanup);
+			pipe->pid = 0;
+			if (!list_empty(&pipe->used_list)) {
+				list_del_init(&pipe->used_list);
+				list_add(&pipe->cleanup_list,
+					&mdp5_data->pipes_cleanup);
+			}
 			mutex_unlock(&mfd->lock);
 			mdss_mdp_mixer_pipe_unstage(pipe);
 			mdss_mdp_pipe_unmap(pipe);
@@ -940,6 +994,10 @@
 		if (rot) {
 			mdss_mdp_overlay_free_buf(&rot->src_buf);
 			mdss_mdp_overlay_free_buf(&rot->dst_buf);
+
+			rot->pid = 0;
+			if (!list_empty(&rot->list))
+				list_del_init(&rot->list);
 			ret = mdss_mdp_rotator_release(rot);
 		}
 	} else {
@@ -952,18 +1010,31 @@
 	return ret;
 }
 
-static int mdss_mdp_overlay_release_all(struct msm_fb_data_type *mfd)
+/**
+ * mdss_mdp_overlay_release_all() - release any overlays associated with fb dev
+ * @mfd:	Msm frame buffer structure associated with fb device
+ *
+ * Release any resources allocated by calling process, this can be called
+ * on fb_release to release any overlays/rotator sessions left open.
+ */
+static int __mdss_mdp_overlay_release_all(struct msm_fb_data_type *mfd)
 {
 	struct mdss_mdp_pipe *pipe;
+	struct mdss_mdp_rotator_session *rot, *tmp;
 	struct mdss_overlay_private *mdp5_data = mfd_to_mdp5_data(mfd);
 	u32 unset_ndx = 0;
 	int cnt = 0;
+	int pid = current->tgid;
+
+	pr_debug("releasing all resources for fb%d pid=%d\n", mfd->index, pid);
 
 	mutex_lock(&mdp5_data->ov_lock);
 	mutex_lock(&mfd->lock);
 	list_for_each_entry(pipe, &mdp5_data->pipes_used, used_list) {
-		unset_ndx |= pipe->ndx;
-		cnt++;
+		if (pipe->pid == pid) {
+			unset_ndx |= pipe->ndx;
+			cnt++;
+		}
 	}
 
 	if (cnt == 0 && !list_empty(&mdp5_data->pipes_cleanup)) {
@@ -983,6 +1054,14 @@
 	if (cnt)
 		mfd->mdp.kickoff_fnc(mfd);
 
+	list_for_each_entry_safe(rot, tmp, &mdp5_data->rot_proc_list, list) {
+		if (rot->pid == pid) {
+			if (!list_empty(&rot->list))
+				list_del_init(&rot->list);
+			mdss_mdp_rotator_release(rot);
+		}
+	}
+
 	return 0;
 }
 
@@ -1339,15 +1418,6 @@
 	mutex_unlock(&mdp5_data->ov_lock);
 }
 
-static void mdss_mdp_overlay_dispatch_vsync(struct work_struct *work)
-{
-	struct mdss_overlay_private *mdp5_data;
-	mdp5_data = container_of(work, struct mdss_overlay_private, vsync_work);
-	if (mdp5_data->ctl && mdp5_data->ctl->mfd)
-		sysfs_notify(&mdp5_data->ctl->mfd->fbi->dev->kobj, NULL,
-				"vsync_event");
-}
-
 /* function is called in irq context should have minimum processing */
 static void mdss_mdp_overlay_handle_vsync(struct mdss_mdp_ctl *ctl,
 						ktime_t t)
@@ -1364,30 +1434,23 @@
 	pr_debug("vsync on fb%d play_cnt=%d\n", mfd->index, ctl->play_cnt);
 
 	mdp5_data->vsync_time = t;
-	schedule_work(&mdp5_data->vsync_work);
+	sysfs_notify_dirent(mdp5_data->vsync_event_sd);
 }
 
 int mdss_mdp_overlay_vsync_ctrl(struct msm_fb_data_type *mfd, int en)
 {
-	struct mdss_overlay_private *mdp5_data = mfd_to_mdp5_data(mfd);
 	struct mdss_mdp_ctl *ctl = mfd_to_ctl(mfd);
 	int rc;
 
 	if (!ctl)
 		return -ENODEV;
 	if (!ctl->add_vsync_handler || !ctl->remove_vsync_handler)
-		return -ENOTSUPP;
-
-	rc = mutex_lock_interruptible(&ctl->lock);
-	if (rc)
-		return rc;
+		return -EOPNOTSUPP;
 
 	if (!ctl->power_on) {
 		pr_debug("fb%d vsync pending first update en=%d\n",
 				mfd->index, en);
-		mdp5_data->vsync_pending = en;
-		mutex_unlock(&ctl->lock);
-		return 0;
+		return -EPERM;
 	}
 
 	pr_debug("fb%d vsync en=%d\n", mfd->index, en);
@@ -1399,8 +1462,6 @@
 		rc = ctl->remove_vsync_handler(ctl, &ctl->vsync_handler);
 	mdss_mdp_clk_ctrl(MDP_BLOCK_POWER_OFF, false);
 
-	mutex_unlock(&ctl->lock);
-
 	return rc;
 }
 
@@ -1424,15 +1485,81 @@
 	return ret;
 }
 
-static DEVICE_ATTR(vsync_event, S_IRUGO, mdss_mdp_vsync_show_event, NULL);
+static inline int mdss_mdp_ad_is_supported(struct msm_fb_data_type *mfd)
+{
+	struct mdss_mdp_ctl *ctl = mfd_to_ctl(mfd);
+	struct mdss_mdp_mixer *mixer;
 
-static struct attribute *vsync_fs_attrs[] = {
+	if (!ctl) {
+		pr_debug("there is no ctl attached to fb\n");
+		return 0;
+	}
+
+	mixer = mdss_mdp_mixer_get(ctl, MDSS_MDP_MIXER_MUX_LEFT);
+	if (mixer && (mixer->num > ctl->mdata->nad_cfgs)) {
+		if (!mixer)
+			pr_warn("there is no mixer attached to fb\n");
+		else
+			pr_debug("mixer attached (%d) doesnt support ad\n",
+				 mixer->num);
+		return 0;
+	}
+
+	mixer = mdss_mdp_mixer_get(ctl, MDSS_MDP_MIXER_MUX_RIGHT);
+	if (mixer && (mixer->num > ctl->mdata->nad_cfgs))
+		return 0;
+
+	return 1;
+}
+
+static ssize_t mdss_mdp_ad_show(struct device *dev,
+		struct device_attribute *attr, char *buf)
+{
+	struct fb_info *fbi = dev_get_drvdata(dev);
+	struct msm_fb_data_type *mfd = fbi->par;
+	struct mdss_overlay_private *mdp5_data = mfd_to_mdp5_data(mfd);
+	int ret, state;
+
+	state = mdss_mdp_ad_is_supported(mfd) ? mdp5_data->ad_state : -1;
+
+	ret = scnprintf(buf, PAGE_SIZE, "%d", state);
+
+	return ret;
+}
+
+static ssize_t mdss_mdp_ad_store(struct device *dev,
+		struct device_attribute *attr, const char *buf, size_t count)
+{
+	struct fb_info *fbi = dev_get_drvdata(dev);
+	struct msm_fb_data_type *mfd = fbi->par;
+	struct mdss_overlay_private *mdp5_data = mfd_to_mdp5_data(mfd);
+	int ret, ad;
+
+	ret = kstrtoint(buf, 10, &ad);
+	if (ret) {
+		pr_err("Invalid input for ad\n");
+		return -EINVAL;
+	}
+
+	mdp5_data->ad_state = ad;
+	sysfs_notify(&dev->kobj, NULL, "ad");
+
+	return count;
+}
+
+
+static DEVICE_ATTR(vsync_event, S_IRUGO, mdss_mdp_vsync_show_event, NULL);
+static DEVICE_ATTR(ad, S_IRUGO | S_IWUSR | S_IWGRP, mdss_mdp_ad_show,
+	mdss_mdp_ad_store);
+
+static struct attribute *mdp_overlay_sysfs_attrs[] = {
 	&dev_attr_vsync_event.attr,
+	&dev_attr_ad.attr,
 	NULL,
 };
 
-static struct attribute_group vsync_fs_attr_group = {
-	.attrs = vsync_fs_attrs,
+static struct attribute_group mdp_overlay_sysfs_group = {
+	.attrs = mdp_overlay_sysfs_attrs,
 };
 
 static int mdss_mdp_hw_cursor_update(struct msm_fb_data_type *mfd,
@@ -1708,12 +1835,20 @@
 	struct mdp_histogram_start_req hist_req;
 	u32 block;
 	struct mdss_overlay_private *mdp5_data = mfd_to_mdp5_data(mfd);
+	u32 pp_bus_handle;
+	static int req = -1;
 
 	switch (cmd) {
 	case MSMFB_HISTOGRAM_START:
 		if (!mfd->panel_power_on)
 			return -EPERM;
 
+		pp_bus_handle = mdss_mdp_get_mdata()->pp_bus_hdl;
+		req = msm_bus_scale_client_update_request(pp_bus_handle,
+				PP_CLK_CFG_ON);
+		if (req)
+			pr_err("Updated pp_bus_scale failed, ret = %d", req);
+
 		ret = copy_from_user(&hist_req, argp, sizeof(hist_req));
 		if (ret)
 			return ret;
@@ -1727,6 +1862,17 @@
 			return ret;
 
 		ret = mdss_mdp_histogram_stop(mdp5_data->ctl, block);
+		if (ret)
+			return ret;
+
+		if (!req) {
+			pp_bus_handle = mdss_mdp_get_mdata()->pp_bus_hdl;
+			req = msm_bus_scale_client_update_request(pp_bus_handle,
+				 PP_CLK_CFG_OFF);
+			if (req)
+				pr_err("Updated pp_bus_scale failed, ret = %d",
+					req);
+		}
 		break;
 
 	case MSMFB_HISTOGRAM:
@@ -1980,6 +2126,7 @@
 		}
 		ctl->vsync_handler.vsync_handler =
 						mdss_mdp_overlay_handle_vsync;
+		ctl->vsync_handler.cmd_post_flush = false;
 
 		if (mfd->split_display && pdata->next) {
 			/* enable split display */
@@ -1992,10 +2139,11 @@
 		mdp5_data->ctl = ctl;
 	}
 
-	if (!mfd->panel_info->cont_splash_enabled) {
+	if (!mfd->panel_info->cont_splash_enabled &&
+		(mfd->panel_info->type != DTV_PANEL) &&
+		(mfd->panel_info->type != WRITEBACK_PANEL)) {
 		rc = mdss_mdp_overlay_start(mfd);
-		if (!IS_ERR_VALUE(rc) && (mfd->panel_info->type != DTV_PANEL) &&
-			(mfd->panel_info->type != WRITEBACK_PANEL))
+		if (!IS_ERR_VALUE(rc))
 			rc = mdss_mdp_overlay_kickoff(mfd);
 	} else {
 		rc = mdss_mdp_ctl_setup(mdp5_data->ctl);
@@ -2006,11 +2154,7 @@
 	if (IS_ERR_VALUE(rc)) {
 		pr_err("Failed to turn on fb%d\n", mfd->index);
 		mdss_mdp_overlay_off(mfd);
-	} else if (mdp5_data->vsync_pending) {
-		mdp5_data->vsync_pending = 0;
-		mdss_mdp_overlay_vsync_ctrl(mfd, mdp5_data->vsync_pending);
 	}
-
 	return rc;
 }
 
@@ -2019,6 +2163,7 @@
 	int rc;
 	struct mdss_overlay_private *mdp5_data;
 	struct mdss_mdp_mixer *mixer;
+	int need_cleanup;
 
 	if (!mfd)
 		return -ENODEV;
@@ -2046,22 +2191,19 @@
 	if (mixer)
 		mixer->cursor_enabled = 0;
 
-	if (!mfd->ref_cnt) {
-		mdss_mdp_overlay_release_all(mfd);
-	} else {
-		int need_cleanup;
-		mutex_lock(&mfd->lock);
-		need_cleanup = !list_empty(&mdp5_data->pipes_cleanup);
-		mutex_unlock(&mfd->lock);
+	mutex_lock(&mfd->lock);
+	need_cleanup = !list_empty(&mdp5_data->pipes_cleanup);
+	mutex_unlock(&mfd->lock);
 
-		if (need_cleanup) {
-			pr_debug("cleaning up some pipes\n");
-			mdss_mdp_overlay_kickoff(mfd);
-		}
+	if (need_cleanup) {
+		pr_debug("cleaning up pipes on fb%d\n", mfd->index);
+		mdss_mdp_overlay_kickoff(mfd);
 	}
 
 	rc = mdss_mdp_ctl_stop(mdp5_data->ctl);
 	if (rc == 0) {
+		__mdss_mdp_overlay_free_list_purge(mfd);
+
 		if (!mfd->ref_cnt) {
 			mdp5_data->borderfill_enable = false;
 			mdss_mdp_ctl_destroy(mdp5_data->ctl);
@@ -2102,6 +2244,7 @@
 
 	mdp5_interface->on_fnc = mdss_mdp_overlay_on;
 	mdp5_interface->off_fnc = mdss_mdp_overlay_off;
+	mdp5_interface->release_fnc = __mdss_mdp_overlay_release_all;
 	mdp5_interface->do_histogram = NULL;
 	mdp5_interface->cursor_update = mdss_mdp_hw_cursor_update;
 	mdp5_interface->dma_fnc = mdss_mdp_overlay_pan_display;
@@ -2118,7 +2261,7 @@
 
 	INIT_LIST_HEAD(&mdp5_data->pipes_used);
 	INIT_LIST_HEAD(&mdp5_data->pipes_cleanup);
-	INIT_WORK(&mdp5_data->vsync_work, mdss_mdp_overlay_dispatch_vsync);
+	INIT_LIST_HEAD(&mdp5_data->rot_proc_list);
 	mutex_init(&mdp5_data->ov_lock);
 	mdp5_data->hw_refresh = true;
 	mdp5_data->overlay_play_enable = true;
@@ -2135,12 +2278,20 @@
 	if (rc)
 		return rc;
 
-	rc = sysfs_create_group(&dev->kobj, &vsync_fs_attr_group);
+	rc = sysfs_create_group(&dev->kobj, &mdp_overlay_sysfs_group);
 	if (rc) {
 		pr_err("vsync sysfs group creation failed, ret=%d\n", rc);
 		goto init_fail;
 	}
 
+	mdp5_data->vsync_event_sd = sysfs_get_dirent(dev->kobj.sd, NULL,
+						     "vsync_event");
+	if (!mdp5_data->vsync_event_sd) {
+		pr_err("vsync_event sysfs lookup failed\n");
+		rc = -ENODEV;
+		goto init_fail;
+	}
+
 	pm_runtime_set_suspended(&mfd->pdev->dev);
 	pm_runtime_enable(&mfd->pdev->dev);
 
diff --git a/drivers/video/msm/mdss/mdss_mdp_pipe.c b/drivers/video/msm/mdss/mdss_mdp_pipe.c
index 3f75053..16ea7dc 100644
--- a/drivers/video/msm/mdss/mdss_mdp_pipe.c
+++ b/drivers/video/msm/mdss/mdss_mdp_pipe.c
@@ -173,21 +173,39 @@
 			return rc;
 		pr_debug("BWC SMP strides ystride0=%x ystride1=%x\n",
 			ps.ystride[0], ps.ystride[1]);
-	} else if (mdata->has_decimation && pipe->src_fmt->is_yuv) {
-		ps.num_planes = 2;
-		ps.ystride[0] = width;
-		ps.ystride[1] = ps.ystride[0];
 	} else {
 		rc = mdss_mdp_get_plane_sizes(pipe->src_fmt->format,
 			width, pipe->src.h, &ps, 0);
 		if (rc)
 			return rc;
 
-		if (pipe->mixer && pipe->mixer->rotator_mode)
+		if (pipe->mixer && pipe->mixer->rotator_mode) {
 			rot_mode = 1;
-		else if (ps.num_planes == 1)
+		} else if (ps.num_planes == 1) {
 			ps.ystride[0] = MAX_BPP *
 				max(pipe->mixer->width, width);
+		} else if (mdata->has_decimation) {
+			/*
+			 * when decimation block is used, all chroma planes
+			 * are fetched on a single SMP plane for chroma pixels
+			 */
+			if (ps.num_planes == 3) {
+				ps.num_planes = 2;
+				ps.ystride[1] += ps.ystride[2];
+			}
+
+			/*
+			 * To avoid quailty loss, MDP does one less decimation
+			 * on chroma components if they are subsampled.
+			 * Account for this to have enough SMPs for latency
+			 */
+			switch (pipe->src_fmt->chroma_sample) {
+			case MDSS_MDP_CHROMA_H2V1:
+			case MDSS_MDP_CHROMA_420:
+				ps.ystride[1] <<= 1;
+				break;
+			}
+		}
 	}
 
 	nlines = pipe->bwc_mode ? 1 : 2;
diff --git a/drivers/video/msm/mdss/mdss_mdp_pp.c b/drivers/video/msm/mdss/mdss_mdp_pp.c
index 6cedd98..09b789b 100644
--- a/drivers/video/msm/mdss/mdss_mdp_pp.c
+++ b/drivers/video/msm/mdss/mdss_mdp_pp.c
@@ -19,6 +19,8 @@
 #include <linux/uaccess.h>
 #include <linux/spinlock.h>
 #include <linux/delay.h>
+#include <mach/msm_bus.h>
+#include <mach/msm_bus_board.h>
 
 struct mdp_csc_cfg mdp_csc_convert[MDSS_MDP_MAX_CSC] = {
 	[MDSS_MDP_CSC_RGB2RGB] = {
@@ -226,6 +228,27 @@
 #define SHARP_SMOOTH_THR_DEFAULT	8
 #define SHARP_NOISE_THR_DEFAULT	2
 
+#define MDP_PP_BUS_VECTOR_ENTRY(ab_val, ib_val)		\
+	{						\
+		.src = MSM_BUS_MASTER_SPDM,		\
+		.dst = MSM_BUS_SLAVE_IMEM_CFG,		\
+		.ab = (ab_val),				\
+		.ib = (ib_val),				\
+	}
+
+#define SZ_37_5M (37500000 * 8)
+
+static struct msm_bus_vectors mdp_pp_bus_vectors[] = {
+	MDP_PP_BUS_VECTOR_ENTRY(0, 0),
+	MDP_PP_BUS_VECTOR_ENTRY(0, SZ_37_5M),
+};
+static struct msm_bus_paths mdp_pp_bus_usecases[ARRAY_SIZE(mdp_pp_bus_vectors)];
+static struct msm_bus_scale_pdata mdp_pp_bus_scale_table = {
+	.usecase = mdp_pp_bus_usecases,
+	.num_usecases = ARRAY_SIZE(mdp_pp_bus_usecases),
+	.name = "mdss_pp",
+};
+
 struct mdss_pp_res_type {
 	/* logical info */
 	u32 pp_disp_flags[MDSS_BLOCK_DISP_NUM];
@@ -266,7 +289,8 @@
 static void pp_update_igc_lut(struct mdp_igc_lut_data *cfg,
 				u32 offset, u32 blk_idx);
 static void pp_update_gc_one_lut(u32 offset,
-				struct mdp_ar_gc_lut_data *lut_data);
+				struct mdp_ar_gc_lut_data *lut_data,
+				uint8_t num_stages);
 static void pp_update_argc_lut(u32 offset,
 				struct mdp_pgc_lut_data *config);
 static void pp_update_hist_lut(char __iomem *base,
@@ -1008,8 +1032,7 @@
 		flags = 0;
 
 	mixer_cnt = mdss_mdp_get_ctl_mixers(disp_num, mixer_id);
-	if (dspp_num < mdata->nad_cfgs && (mixer_cnt != 2) &&
-			ctl->mfd->panel_info->type != MIPI_CMD_PANEL) {
+	if (dspp_num < mdata->nad_cfgs && (mixer_cnt != 2)) {
 		ret = mdss_mdp_ad_setup(ctl->mfd);
 		if (ret < 0)
 			pr_warn("ad_setup(dspp%d) returns %d", dspp_num, ret);
@@ -1188,7 +1211,7 @@
 		if (PP_AD_STATE_INIT & ad->state)
 			pp_ad_init_write(ad);
 		if (PP_AD_STATE_DATA & ad->state) {
-			bl = ctl->mfd->bl_level;
+			bl = ad->bl_mfd->bl_level;
 			ad->last_bl = bl;
 			if (ad->state & PP_AD_STATE_BL_LIN) {
 				bl = ad->bl_lin[bl >> ad->bl_bright_shift];
@@ -1268,6 +1291,7 @@
 	int i, ret = 0;
 	struct mdss_data_type *mdata = mdss_mdp_get_mdata();
 	struct mdss_mdp_pipe *vig;
+	struct msm_bus_scale_pdata *pp_bus_pdata;
 
 	mutex_lock(&mdss_pp_mutex);
 	if (!mdss_pp_res) {
@@ -1289,12 +1313,34 @@
 			mutex_init(&vig[i].pp_res.hist.hist_mutex);
 			spin_lock_init(&vig[i].pp_res.hist.hist_lock);
 		}
+		if (!mdata->pp_bus_hdl) {
+			pp_bus_pdata = &mdp_pp_bus_scale_table;
+			for (i = 0; i < pp_bus_pdata->num_usecases; i++) {
+				mdp_pp_bus_usecases[i].num_paths = 1;
+				mdp_pp_bus_usecases[i].vectors =
+					&mdp_pp_bus_vectors[i];
+			}
+
+			mdata->pp_bus_hdl =
+				msm_bus_scale_register_client(pp_bus_pdata);
+			if (!mdata->pp_bus_hdl) {
+				pr_err("not able to register pp_bus_scale\n");
+				ret = -ENOMEM;
+			}
+			pr_debug("register pp_bus_hdl=%x\n", mdata->pp_bus_hdl);
+		}
+
 	}
 	mutex_unlock(&mdss_pp_mutex);
 	return ret;
 }
 void mdss_mdp_pp_term(struct device *dev)
 {
+	struct mdss_data_type *mdata = mdss_mdp_get_mdata();
+	if (mdata->pp_bus_hdl) {
+		msm_bus_scale_unregister_client(mdata->pp_bus_hdl);
+		mdata->pp_bus_hdl = 0;
+	}
 	if (!mdss_pp_res) {
 		mutex_lock(&mdss_pp_mutex);
 		devm_kfree(dev, mdss_pp_res);
@@ -1707,35 +1753,48 @@
 	return ret;
 }
 static void pp_update_gc_one_lut(u32 offset,
-		struct mdp_ar_gc_lut_data *lut_data)
+		struct mdp_ar_gc_lut_data *lut_data,
+		uint8_t num_stages)
 {
-	int i, start_idx;
+	int i, start_idx, idx;
 
 	start_idx = (MDSS_MDP_REG_READ(offset) >> 16) & 0xF;
-	for (i = start_idx; i < GC_LUT_SEGMENTS; i++)
-		MDSS_MDP_REG_WRITE(offset, lut_data[i].x_start);
-	for (i = 0; i < start_idx; i++)
-		MDSS_MDP_REG_WRITE(offset, lut_data[i].x_start);
+	for (i = start_idx; i < GC_LUT_SEGMENTS; i++) {
+		idx = min((uint8_t)i, (uint8_t)(num_stages-1));
+		MDSS_MDP_REG_WRITE(offset, lut_data[idx].x_start);
+	}
+	for (i = 0; i < start_idx; i++) {
+		idx = min((uint8_t)i, (uint8_t)(num_stages-1));
+		MDSS_MDP_REG_WRITE(offset, lut_data[idx].x_start);
+	}
 	offset += 4;
 	start_idx = (MDSS_MDP_REG_READ(offset) >> 16) & 0xF;
-	for (i = start_idx; i < GC_LUT_SEGMENTS; i++)
-		MDSS_MDP_REG_WRITE(offset, lut_data[i].slope);
-	for (i = 0; i < start_idx; i++)
-		MDSS_MDP_REG_WRITE(offset, lut_data[i].slope);
+	for (i = start_idx; i < GC_LUT_SEGMENTS; i++) {
+		idx = min((uint8_t)i, (uint8_t)(num_stages-1));
+		MDSS_MDP_REG_WRITE(offset, lut_data[idx].slope);
+	}
+	for (i = 0; i < start_idx; i++) {
+		idx = min((uint8_t)i, (uint8_t)(num_stages-1));
+		MDSS_MDP_REG_WRITE(offset, lut_data[idx].slope);
+	}
 	offset += 4;
 	start_idx = (MDSS_MDP_REG_READ(offset) >> 16) & 0xF;
-	for (i = start_idx; i < GC_LUT_SEGMENTS; i++)
-		MDSS_MDP_REG_WRITE(offset, lut_data[i].offset);
-	for (i = 0; i < start_idx; i++)
-		MDSS_MDP_REG_WRITE(offset, lut_data[i].offset);
+	for (i = start_idx; i < GC_LUT_SEGMENTS; i++) {
+		idx = min((uint8_t)i, (uint8_t)(num_stages-1));
+		MDSS_MDP_REG_WRITE(offset, lut_data[idx].offset);
+	}
+	for (i = 0; i < start_idx; i++) {
+		idx = min((uint8_t)i, (uint8_t)(num_stages-1));
+		MDSS_MDP_REG_WRITE(offset, lut_data[idx].offset);
+	}
 }
 static void pp_update_argc_lut(u32 offset, struct mdp_pgc_lut_data *config)
 {
-	pp_update_gc_one_lut(offset, config->r_data);
+	pp_update_gc_one_lut(offset, config->r_data, config->num_r_stages);
 	offset += 0x10;
-	pp_update_gc_one_lut(offset, config->g_data);
+	pp_update_gc_one_lut(offset, config->g_data, config->num_g_stages);
 	offset += 0x10;
-	pp_update_gc_one_lut(offset, config->b_data);
+	pp_update_gc_one_lut(offset, config->b_data, config->num_b_stages);
 }
 static void pp_read_gc_one_lut(u32 offset,
 		struct mdp_ar_gc_lut_data *gc_data)
@@ -1813,7 +1872,7 @@
 	u32 argc_offset = 0, disp_num, dspp_num = 0;
 	struct mdp_pgc_lut_data local_cfg;
 	struct mdp_pgc_lut_data *pgc_ptr;
-	u32 tbl_size;
+	u32 tbl_size, r_size, g_size, b_size;
 
 	if (!ctl)
 		return -EINVAL;
@@ -1884,18 +1943,35 @@
 		*copyback = 1;
 		mdss_mdp_clk_ctrl(MDP_BLOCK_POWER_OFF, false);
 	} else {
+		r_size = config->num_r_stages *
+			sizeof(struct mdp_ar_gc_lut_data);
+		g_size = config->num_g_stages *
+			sizeof(struct mdp_ar_gc_lut_data);
+		b_size = config->num_b_stages *
+			sizeof(struct mdp_ar_gc_lut_data);
+		if (r_size > tbl_size ||
+			g_size > tbl_size ||
+			b_size > tbl_size ||
+			r_size == 0 ||
+			g_size == 0 ||
+			b_size == 0) {
+			ret = -EINVAL;
+			pr_warn("%s, number of rgb stages invalid",
+				__func__);
+			goto argc_config_exit;
+		}
 		if (copy_from_user(&mdss_pp_res->gc_lut_r[disp_num][0],
-			config->r_data, tbl_size)) {
+			config->r_data, r_size)) {
 			ret = -EFAULT;
 			goto argc_config_exit;
 		}
 		if (copy_from_user(&mdss_pp_res->gc_lut_g[disp_num][0],
-			config->g_data, tbl_size)) {
+			config->g_data, g_size)) {
 			ret = -EFAULT;
 			goto argc_config_exit;
 		}
 		if (copy_from_user(&mdss_pp_res->gc_lut_b[disp_num][0],
-			config->b_data, tbl_size)) {
+			config->b_data, b_size)) {
 			ret = -EFAULT;
 			goto argc_config_exit;
 		}
@@ -2003,6 +2079,10 @@
 	u32 offset, disp_num, dspp_num = 0;
 	uint16_t *tbl_off;
 	struct mdp_gamut_cfg_data local_cfg;
+	uint16_t *r_tbl[MDP_GAMUT_TABLE_NUM];
+	uint16_t *g_tbl[MDP_GAMUT_TABLE_NUM];
+	uint16_t *b_tbl[MDP_GAMUT_TABLE_NUM];
+
 
 	if (!ctl)
 		return -EINVAL;
@@ -2030,22 +2110,67 @@
 		offset = MDSS_MDP_REG_DSPP_OFFSET(dspp_num) +
 			  MDSS_MDP_REG_DSPP_GAMUT_BASE;
 		for (i = 0; i < MDP_GAMUT_TABLE_NUM; i++) {
+			r_tbl[i] = kzalloc(
+				sizeof(uint16_t) * config->tbl_size[i],
+				GFP_KERNEL);
+			if (!r_tbl[i]) {
+				pr_err("%s: alloc failed\n", __func__);
+				goto gamut_config_exit;
+			}
 			for (j = 0; j < config->tbl_size[i]; j++)
-				config->r_tbl[i][j] =
+				r_tbl[i][j] =
 					(u16)MDSS_MDP_REG_READ(offset);
 			offset += 4;
+			ret = copy_to_user(config->r_tbl[i], r_tbl[i],
+				     sizeof(uint16_t) * config->tbl_size[i]);
+			kfree(r_tbl[i]);
+			if (ret) {
+				pr_err("%s: copy tbl to usr failed\n",
+					__func__);
+				goto gamut_config_exit;
+			}
 		}
 		for (i = 0; i < MDP_GAMUT_TABLE_NUM; i++) {
+			g_tbl[i] = kzalloc(
+				sizeof(uint16_t) * config->tbl_size[i],
+				GFP_KERNEL);
+			if (!g_tbl[i]) {
+				pr_err("%s: alloc failed\n", __func__);
+				goto gamut_config_exit;
+			}
 			for (j = 0; j < config->tbl_size[i]; j++)
-				config->g_tbl[i][j] =
+				g_tbl[i][j] =
 					(u16)MDSS_MDP_REG_READ(offset);
 			offset += 4;
+			ret = copy_to_user(config->g_tbl[i], g_tbl[i],
+				     sizeof(uint16_t) * config->tbl_size[i]);
+			kfree(g_tbl[i]);
+			if (ret) {
+				pr_err("%s: copy tbl to usr failed\n",
+					__func__);
+				goto gamut_config_exit;
+			}
 		}
 		for (i = 0; i < MDP_GAMUT_TABLE_NUM; i++) {
+			b_tbl[i] = kzalloc(
+				sizeof(uint16_t) * config->tbl_size[i],
+				GFP_KERNEL);
+			if (!b_tbl[i]) {
+				pr_err("%s: alloc failed\n", __func__);
+				goto gamut_config_exit;
+			}
 			for (j = 0; j < config->tbl_size[i]; j++)
-				config->b_tbl[i][j] =
+				b_tbl[i][j] =
 					(u16)MDSS_MDP_REG_READ(offset);
 			offset += 4;
+			ret = copy_to_user(config->b_tbl[i], b_tbl[i],
+				     sizeof(uint16_t) * config->tbl_size[i]);
+			kfree(b_tbl[i]);
+			if (ret) {
+				pr_err("%s: copy tbl to usr failed\n",
+					__func__);
+				goto gamut_config_exit;
+			}
 		}
 		*copyback = 1;
 		mdss_mdp_clk_ctrl(MDP_BLOCK_POWER_OFF, false);
@@ -2488,13 +2613,13 @@
 			if (ret)
 				goto hist_collect_exit;
 		}
+		if (hist->bin_cnt != HIST_V_SIZE) {
+			pr_err("User not expecting size %d output",
+							HIST_V_SIZE);
+			ret = -EINVAL;
+			goto hist_collect_exit;
+		}
 		if (hist_cnt > 1) {
-			if (hist->bin_cnt != HIST_V_SIZE) {
-				pr_err("User not expecting size %d output",
-								HIST_V_SIZE);
-				ret = -EINVAL;
-				goto hist_collect_exit;
-			}
 			hist_concat = kmalloc(HIST_V_SIZE * sizeof(u32),
 								GFP_KERNEL);
 			if (!hist_concat) {
@@ -2558,13 +2683,14 @@
 			if (ret)
 				goto hist_collect_exit;
 		}
+		if (pipe_cnt != 0 &&
+			(hist->bin_cnt != (HIST_V_SIZE * pipe_cnt))) {
+			pr_err("User not expecting size %d output",
+						pipe_cnt * HIST_V_SIZE);
+			ret = -EINVAL;
+			goto hist_collect_exit;
+		}
 		if (pipe_cnt > 1) {
-			if (hist->bin_cnt != (HIST_V_SIZE * pipe_cnt)) {
-				pr_err("User not expecting size %d output",
-							pipe_cnt * HIST_V_SIZE);
-				ret = -EINVAL;
-				goto hist_collect_exit;
-			}
 			hist_concat = kmalloc(HIST_V_SIZE * pipe_cnt *
 						sizeof(u32), GFP_KERNEL);
 			if (!hist_concat) {
@@ -2667,6 +2793,22 @@
 	};
 }
 
+static struct msm_fb_data_type *mdss_get_mfd_from_index(int index)
+{
+	struct msm_fb_data_type *out = NULL;
+	struct mdss_mdp_ctl *ctl;
+	struct mdss_data_type *mdata = mdss_mdp_get_mdata();
+	int i;
+
+	for (i = 0; i < mdata->nctl; i++) {
+		ctl = mdata->ctl_off + i;
+		if ((ctl->power_on) && (ctl->mfd)
+				&& (ctl->mfd->index == index))
+			out = ctl->mfd;
+	}
+	return out;
+}
+
 #define MDSS_AD_MAX_MIXERS 1
 static int mdss_ad_init_checks(struct msm_fb_data_type *mfd)
 {
@@ -2675,8 +2817,12 @@
 	u32 ret = -EINVAL;
 	int i = 0;
 	struct mdss_data_type *mdata = mfd_to_mdata(mfd);
+	struct msm_fb_data_type *ad_mfd = mfd;
 
-	if (!mfd || !mdata)
+	if (ad_mfd->ext_ad_ctrl >= 0)
+		ad_mfd = mdss_get_mfd_from_index(ad_mfd->ext_ad_ctrl);
+
+	if (!ad_mfd || !mdata)
 		return ret;
 
 	if (mdata->nad_cfgs == 0) {
@@ -2684,18 +2830,13 @@
 		return -ENODEV;
 	}
 
-	if (mfd->panel_info->type == MIPI_CMD_PANEL) {
-		pr_debug("Command panel not supported");
-		return -EINVAL;
-	}
-
-	mixer_num = mdss_mdp_get_ctl_mixers(mfd->index, mixer_id);
+	mixer_num = mdss_mdp_get_ctl_mixers(ad_mfd->index, mixer_id);
 	if (!mixer_num) {
 		pr_debug("no mixers connected, %d", mixer_num);
 		return -EHOSTDOWN;
 	}
 	if (mixer_num > MDSS_AD_MAX_MIXERS) {
-		pr_warn("too many mixers, not supported, %d", mixer_num);
+		pr_debug("too many mixers, not supported, %d", mixer_num);
 		return ret;
 	}
 
@@ -2762,12 +2903,20 @@
 {
 	struct mdss_ad_info *ad;
 	struct mdss_mdp_ctl *ctl;
+	struct msm_fb_data_type *bl_mfd;
 	int lin_ret = -1, inv_ret = -1, ret = 0;
 	u32 ratio_temp, shift = 0;
 
 	ret = mdss_mdp_get_ad(mfd, &ad);
 	if (ret)
 		return ret;
+	if (mfd->panel_info->type == WRITEBACK_PANEL) {
+		bl_mfd = mdss_get_mfd_from_index(0);
+		if (!bl_mfd)
+			return ret;
+	} else {
+		bl_mfd = mfd;
+	}
 
 	mutex_lock(&ad->lock);
 	if (init_cfg->ops & MDP_PP_AD_INIT) {
@@ -2804,7 +2953,7 @@
 		 * TODO: specify panel independent range of input from cfg,
 		 * scale input backlight_scale to panel bl_max's range
 		 */
-		ad->cfg.backlight_scale = mfd->panel_info->bl_max;
+		ad->cfg.backlight_scale = bl_mfd->panel_info->bl_max;
 		ad->sts |= PP_AD_STS_DIRTY_CFG;
 	}
 
@@ -2814,9 +2963,11 @@
 		cancel_work_sync(&ad->calc_work);
 		mutex_lock(&ad->lock);
 		ad->mfd = NULL;
+		ad->bl_mfd = NULL;
 	} else if (!ret && (init_cfg->ops & MDP_PP_OPS_ENABLE)) {
 		ad->sts |= PP_STS_ENABLE;
 		ad->mfd = mfd;
+		ad->bl_mfd = bl_mfd;
 	}
 	mutex_unlock(&ad->lock);
 	ctl = mfd_to_ctl(mfd);
@@ -2853,7 +3004,7 @@
 			goto error;
 		}
 		ad->ad_data_mode = MDSS_AD_INPUT_AMBIENT;
-
+		pr_debug("ambient = %d", input->in.amb_light);
 		ad->ad_data = input->in.amb_light;
 		ad->calc_itr = ad->cfg.stab_itr;
 		ad->sts |= PP_AD_STS_DIRTY_VSYNC;
@@ -2867,6 +3018,7 @@
 			goto error;
 		}
 		ad->ad_data_mode = MDSS_AD_INPUT_STRENGTH;
+		pr_debug("strength = %d", input->in.strength);
 		ad->ad_data = input->in.strength;
 		ad->calc_itr = ad->cfg.stab_itr;
 		ad->sts |= PP_AD_STS_DIRTY_VSYNC;
@@ -3041,12 +3193,22 @@
 	int ret = 0;
 	struct mdss_ad_info *ad;
 	struct mdss_mdp_ctl *ctl = mfd_to_ctl(mfd);
+	struct msm_fb_data_type *bl_mfd;
 	char __iomem *base;
+	u32 temp;
 	u32 bypass = MDSS_PP_AD_BYPASS_DEF, bl;
 
 	ret = mdss_mdp_get_ad(mfd, &ad);
 	if (ret)
 		return ret;
+	if (mfd->panel_info->type == WRITEBACK_PANEL) {
+		bl_mfd = mdss_get_mfd_from_index(0);
+		if (!bl_mfd)
+			return ret;
+	} else {
+		bl_mfd = mfd;
+	}
+
 
 	base = ad->base;
 
@@ -3066,21 +3228,21 @@
 		 */
 		ad->sts &= ~PP_AD_STS_DIRTY_DATA;
 		ad->state |= PP_AD_STATE_DATA;
-		bl = 0;
-		if (MDSS_AD_RUNNING_AUTO_STR(ad) || ad->last_bl == 0) {
-			mutex_lock(&mfd->bl_lock);
-			bl = mfd->bl_level;
-			if (bl != ad->last_bl) {
-				ad->last_bl = bl;
-				ad->calc_itr = ad->cfg.stab_itr;
-				ad->sts |= PP_AD_STS_DIRTY_VSYNC;
-			}
+		mutex_lock(&bl_mfd->bl_lock);
+		bl = bl_mfd->bl_level;
+		pr_debug("dirty data, last_bl = %d ", ad->last_bl);
+		if ((ad->cfg.mode == MDSS_AD_MODE_AUTO_STR) &&
+							(ad->last_bl != bl)) {
+			ad->last_bl = bl;
+			ad->calc_itr = ad->cfg.stab_itr;
+			ad->sts |= PP_AD_STS_DIRTY_VSYNC;
 			if (ad->state & PP_AD_STATE_BL_LIN) {
 				bl = ad->bl_lin[bl >> ad->bl_bright_shift];
 				bl = bl << ad->bl_bright_shift;
 			}
-			mutex_unlock(&mfd->bl_lock);
+			mutex_unlock(&bl_mfd->bl_lock);
 		}
+		mutex_unlock(&mfd->bl_lock);
 		pp_ad_input_write(ad, bl);
 	}
 
@@ -3102,14 +3264,31 @@
 		pp_ad_init_write(ad);
 	}
 
+	/* update ad screen size if it has changed since last configuration */
+	if (mfd->panel_info->type == WRITEBACK_PANEL &&
+		(ad->init.frame_w != ctl->width ||
+			ad->init.frame_h != ctl->height)) {
+		pr_debug("changing from %dx%d to %dx%d", ad->init.frame_w,
+							ad->init.frame_h,
+							ctl->width,
+							ctl->height);
+		ad->init.frame_w = ctl->width;
+		ad->init.frame_h = ctl->height;
+		temp = ad->init.frame_w << 16;
+		temp |= ad->init.frame_h & 0xFFFF;
+		writel_relaxed(temp, base + MDSS_MDP_REG_AD_FRAME_SIZE);
+	}
+
 	if ((ad->sts & PP_STS_ENABLE) && PP_AD_STATE_IS_READY(ad->state)) {
 		bypass = 0;
 		ret = 1;
 		ad->state |= PP_AD_STATE_RUN;
-		mutex_lock(&mfd->bl_lock);
-		mfd->mdp.update_ad_input = pp_update_ad_input;
-		mfd->ext_bl_ctrl = ad->cfg.bl_ctrl_mode;
-		mutex_unlock(&mfd->bl_lock);
+		mutex_lock(&bl_mfd->bl_lock);
+		if (bl_mfd != mfd)
+			bl_mfd->ext_ad_ctrl = mfd->index;
+		bl_mfd->mdp.update_ad_input = pp_update_ad_input;
+		bl_mfd->ext_bl_ctrl = ad->cfg.bl_ctrl_mode;
+		mutex_unlock(&bl_mfd->bl_lock);
 
 	} else {
 		if (ad->state & PP_AD_STATE_RUN) {
@@ -3124,6 +3303,7 @@
 			ad->bl_bright_shift = 0;
 			ad->ad_data = 0;
 			ad->ad_data_mode = 0;
+			ad->last_bl = 0;
 			ad->calc_itr = 0;
 			memset(&ad->bl_lin, 0, sizeof(uint32_t) *
 								AD_BL_LIN_LEN);
@@ -3131,10 +3311,11 @@
 								AD_BL_LIN_LEN);
 			memset(&ad->init, 0, sizeof(struct mdss_ad_init));
 			memset(&ad->cfg, 0, sizeof(struct mdss_ad_cfg));
-			mutex_lock(&mfd->bl_lock);
-			mfd->mdp.update_ad_input = NULL;
-			mfd->ext_bl_ctrl = 0;
-			mutex_unlock(&mfd->bl_lock);
+			mutex_lock(&bl_mfd->bl_lock);
+			bl_mfd->mdp.update_ad_input = NULL;
+			bl_mfd->ext_bl_ctrl = 0;
+			bl_mfd->ext_ad_ctrl = -1;
+			mutex_unlock(&bl_mfd->bl_lock);
 		}
 		ad->state &= ~PP_AD_STATE_RUN;
 	}
@@ -3169,18 +3350,24 @@
 {
 	struct mdss_ad_info *ad;
 	struct mdss_mdp_ctl *ctl;
-	struct msm_fb_data_type *mfd;
+	struct msm_fb_data_type *mfd, *bl_mfd;
 	u32 bl, calc_done = 0;
 	ad = container_of(work, struct mdss_ad_info, calc_work);
 
 	mutex_lock(&ad->lock);
-	if (!ad->mfd || !(ad->sts & PP_STS_ENABLE)) {
+	if (!ad->mfd  || !ad->bl_mfd || !(ad->sts & PP_STS_ENABLE)) {
 		mutex_unlock(&ad->lock);
 		return;
 	}
 	mfd = ad->mfd;
+	bl_mfd = ad->bl_mfd;
 	ctl = mfd_to_ctl(ad->mfd);
 
+	if ((ad->cfg.mode == MDSS_AD_MODE_AUTO_STR) && (ad->last_bl == 0)) {
+		mutex_unlock(&ad->lock);
+		return;
+	}
+
 	if (PP_AD_STATE_RUN & ad->state) {
 		/* Kick off calculation */
 		ad->calc_itr--;
@@ -3208,9 +3395,10 @@
 				}
 				pr_debug("calc bl = %d", bl);
 				ad->last_str |= bl << 16;
-				mutex_lock(&ad->mfd->bl_lock);
-				mdss_fb_set_backlight(ad->mfd, bl);
-				mutex_unlock(&ad->mfd->bl_lock);
+				mutex_lock(&ad->bl_mfd->bl_lock);
+				if (ad->bl_mfd->bl_level)
+					mdss_fb_set_backlight(ad->bl_mfd, bl);
+				mutex_unlock(&ad->bl_mfd->bl_lock);
 			}
 			pr_debug("calc_str = %d, calc_itr %d",
 							ad->last_str & 0xFF,
@@ -3231,7 +3419,7 @@
 	mutex_unlock(&mfd->lock);
 
 	/* Trigger update notify to wake up those waiting for display updates */
-	mdss_fb_update_notify_update(mfd);
+	mdss_fb_update_notify_update(bl_mfd);
 }
 
 #define PP_AD_LUT_LEN 33
@@ -3269,8 +3457,10 @@
 		mdata->ad_cfgs[i].num = i;
 		mdata->ad_cfgs[i].calc_itr = 0;
 		mdata->ad_cfgs[i].last_str = 0xFFFFFFFF;
+		mdata->ad_cfgs[i].last_bl = 0;
 		mutex_init(&mdata->ad_cfgs[i].lock);
 		mdata->ad_cfgs[i].handle.vsync_handler = pp_ad_vsync_handler;
+		mdata->ad_cfgs[i].handle.cmd_post_flush = true;
 		INIT_WORK(&mdata->ad_cfgs[i].calc_work, pp_ad_calc_worker);
 	}
 	return rc;
@@ -3282,7 +3472,7 @@
 	unsigned int ptr;
 	ptr = (unsigned int) addr;
 	/* if request is outside the MDP reg-map or is not aligned 4 */
-	if (ptr == 0x0 || ptr > 0x5138 || ptr % 0x4)
+	if (ptr > 0x5138 || ptr % 0x4)
 		goto end;
 	if (ptr >= 0x100 && ptr <= 0x5138) {
 		/* if ptr is in dspp range */
@@ -3327,7 +3517,7 @@
 				ret = 1;
 		else if (ptr >= 0x3220 && ptr <= 0x3228)
 				ret = 1;
-		else if (ptr >= 0x3200 || ptr == 0x100)
+		else if (ptr == 0x3200 || ptr == 0x100)
 				ret = 1;
 		else if (ptr == 0x104 || ptr == 0x614 || ptr == 0x714 ||
 			ptr == 0x814 || ptr == 0x914 || ptr == 0xa14)
@@ -3337,7 +3527,8 @@
 				ret = 1;
 		else if (ptr == 0x2234 || ptr == 0x1e34 || ptr == 0x2634)
 				ret = 1;
-	}
+	} else if (ptr == 0x0)
+		ret = 1;
 end:
 	return ret;
 }
diff --git a/drivers/video/msm/mdss/mdss_mdp_rotator.c b/drivers/video/msm/mdss/mdss_mdp_rotator.c
index fcd90e1..8381c5b 100644
--- a/drivers/video/msm/mdss/mdss_mdp_rotator.c
+++ b/drivers/video/msm/mdss/mdss_mdp_rotator.c
@@ -74,14 +74,14 @@
 
 	mixer = mdss_mdp_wb_mixer_alloc(1);
 	if (!mixer) {
-		pr_err("wb mixer alloc failed\n");
+		pr_debug("wb mixer alloc failed\n");
 		return NULL;
 	}
 
 	pipe = mdss_mdp_pipe_alloc_dma(mixer);
 	if (!pipe) {
 		mdss_mdp_wb_mixer_destroy(mixer);
-		pr_err("dma pipe allocation failed\n");
+		pr_debug("dma pipe allocation failed\n");
 	}
 
 	return pipe;
@@ -134,6 +134,7 @@
 
 static int mdss_mdp_rotator_pipe_dequeue(struct mdss_mdp_rotator_session *rot)
 {
+	int rc;
 	if (rot->pipe) {
 		pr_debug("reusing existing session=%d\n", rot->pipe->num);
 		mdss_mdp_rotator_busy_wait(rot);
@@ -153,12 +154,19 @@
 					       struct mdss_mdp_rotator_session,
 					       head);
 
-			pr_debug("wait for rotator pipe=%d\n", tmp->pipe->num);
-			mdss_mdp_rotator_busy_wait(tmp);
+			rc = mdss_mdp_rotator_busy_wait(tmp);
+			list_del(&tmp->head);
+			if (rc) {
+				pr_err("no pipe attached to session=%d\n",
+					tmp->session_id);
+				return rc;
+			} else {
+				pr_debug("waited for rotator pipe=%d\n",
+					  tmp->pipe->num);
+			}
 			rot->pipe = tmp->pipe;
 			tmp->pipe = NULL;
 
-			list_del(&tmp->head);
 			list_add_tail(&rot->head, &rotator_queue);
 		} else {
 			pr_err("no available rotator pipes\n");
diff --git a/drivers/video/msm/mdss/mdss_mdp_rotator.h b/drivers/video/msm/mdss/mdss_mdp_rotator.h
index 43c9e6a..74eeeeb 100644
--- a/drivers/video/msm/mdss/mdss_mdp_rotator.h
+++ b/drivers/video/msm/mdss/mdss_mdp_rotator.h
@@ -23,6 +23,7 @@
 	u32 session_id;
 	u32 ref_cnt;
 	u32 params_changed;
+	int pid;
 
 	u32 format;
 	u32 flags;
@@ -43,6 +44,7 @@
 	struct mdss_mdp_data dst_buf;
 
 	struct list_head head;
+	struct list_head list;
 	struct mdss_mdp_rotator_session *next;
 };
 
diff --git a/drivers/video/msm/mdss/mdss_mdp_wb.c b/drivers/video/msm/mdss/mdss_mdp_wb.c
index 0c74137..a9f3e35 100644
--- a/drivers/video/msm/mdss/mdss_mdp_wb.c
+++ b/drivers/video/msm/mdss/mdss_mdp_wb.c
@@ -533,11 +533,11 @@
 		goto kickoff_fail;
 	}
 
-	ret = wait_for_completion_interruptible_timeout(&comp, KOFF_TIMEOUT);
-	if (ret <= 0) {
+	ret = wait_for_completion_timeout(&comp, KOFF_TIMEOUT);
+	if (ret == 0)
 		WARN(1, "wfd kick off time out=%d ctl=%d", ret, ctl->num);
+	else
 		ret = 0;
-	}
 
 	if (wb && node) {
 		mutex_lock(&wb->lock);
@@ -675,7 +675,8 @@
 		break;
 	case MSMFB_WRITEBACK_QUEUE_BUFFER:
 		if (!copy_from_user(&data, arg, sizeof(data))) {
-			ret = mdss_mdp_wb_queue(mfd, arg, false);
+			ret = mdss_mdp_wb_queue(mfd, &data, false);
+			ret = copy_to_user(arg, &data, sizeof(data));
 		} else {
 			pr_err("wb queue buf failed on copy_from_user\n");
 			ret = -EFAULT;
@@ -683,7 +684,8 @@
 		break;
 	case MSMFB_WRITEBACK_DEQUEUE_BUFFER:
 		if (!copy_from_user(&data, arg, sizeof(data))) {
-			ret = mdss_mdp_wb_dequeue(mfd, arg);
+			ret = mdss_mdp_wb_dequeue(mfd, &data);
+			ret = copy_to_user(arg, &data, sizeof(data));
 		} else {
 			pr_err("wb dequeue buf failed on copy_from_user\n");
 			ret = -EFAULT;
diff --git a/drivers/video/msm/mdss/mdss_panel.h b/drivers/video/msm/mdss/mdss_panel.h
index e8a6312..d05ca66 100644
--- a/drivers/video/msm/mdss/mdss_panel.h
+++ b/drivers/video/msm/mdss/mdss_panel.h
@@ -57,6 +57,33 @@
 	MAX_PHYS_TARGET_NUM,
 };
 
+enum {
+	MDSS_PANEL_INTF_INVALID = -1,
+	MDSS_PANEL_INTF_DSI,
+	MDSS_PANEL_INTF_EDP,
+	MDSS_PANEL_INTF_HDMI,
+};
+
+enum {
+	MODE_GPIO_NOT_VALID = 0,
+	MODE_GPIO_HIGH,
+	MODE_GPIO_LOW,
+};
+
+#define MDSS_MAX_PANEL_LEN      256
+#define MDSS_INTF_MAX_NAME_LEN 5
+struct mdss_panel_intf {
+	char name[MDSS_INTF_MAX_NAME_LEN];
+	int  type;
+};
+
+struct mdss_panel_cfg {
+	char arg_cfg[MDSS_MAX_PANEL_LEN + 1];
+	int  pan_intf;
+	bool lk_cfg;
+	bool init_done;
+};
+
 /**
  * enum mdss_intf_events - Different events generated by MDP core
  *
@@ -133,9 +160,9 @@
 	uint32_t timing[12];
 	uint32_t ctrl[4];
 	uint32_t strength[2];
-	char bistCtrl[6];
+	char bistctrl[6];
 	uint32_t pll[21];
-	char laneCfg[45];
+	char lanecfg[45];
 };
 
 struct mipi_panel_info {
@@ -158,7 +185,7 @@
 	char t_clk_post; /* 0xc0, DSI_CLKOUT_TIMING_CTRL */
 	char t_clk_pre;  /* 0xc0, DSI_CLKOUT_TIMING_CTRL */
 	char vc;	/* virtual channel */
-	struct mdss_dsi_phy_ctrl *dsi_phy_db;
+	struct mdss_dsi_phy_ctrl dsi_phy_db;
 	/* video mode */
 	char pulse_mode_hsa_he;
 	char hfp_power_stop;
@@ -221,6 +248,8 @@
 struct mdss_panel_info {
 	u32 xres;
 	u32 yres;
+	u32 physical_width;
+	u32 physical_height;
 	u32 bpp;
 	u32 type;
 	u32 wait_cycle;
@@ -239,6 +268,7 @@
 	int pwm_pmic_gpio;
 	int pwm_lpg_chan;
 	int pwm_period;
+	u32 mode_gpio_state;
 
 	u32 cont_splash_enabled;
 	struct ion_handle *splash_ihdl;
@@ -326,4 +356,37 @@
 
 int mdss_register_panel(struct platform_device *pdev,
 	struct mdss_panel_data *pdata);
+
+/**
+ * mdss_panel_intf_type: - checks if a given intf type is primary
+ * @intf_val: panel interface type of the individual controller
+ *
+ * Individual controller queries with MDP to check if it is
+ * configured as the primary interface.
+ *
+ * returns a pointer to the configured structure mdss_panel_cfg
+ * to the controller that's configured as the primary panel interface.
+ * returns NULL on error or if @intf_val is not the configured
+ * controller.
+ */
+struct mdss_panel_cfg *mdss_panel_intf_type(int intf_val);
+
+/**
+ * mdss_panel_get_boot_cfg() - checks if bootloader config present
+ *
+ * Function returns true if bootloader has configured the parameters
+ * for primary controller and panel config data.
+ *
+ * returns true if bootloader configured, else false
+ */
+int mdss_panel_get_boot_cfg(void);
+
+/**
+ * mdss_is_ready() - checks if mdss is probed and ready
+ *
+ * Checks if mdss resources have been initialized
+ *
+ * returns true if mdss is ready, else returns false.
+ */
+bool mdss_is_ready(void);
 #endif /* MDSS_PANEL_H */
diff --git a/drivers/video/msm/mdss/mhl_sii8334.c b/drivers/video/msm/mdss/mhl_sii8334.c
index c66d50d..a759e86 100644
--- a/drivers/video/msm/mdss/mhl_sii8334.c
+++ b/drivers/video/msm/mdss/mhl_sii8334.c
@@ -357,14 +357,20 @@
 static int mhl_sii_wait_for_rgnd(struct mhl_tx_ctrl *mhl_ctrl)
 {
 	int timeout;
-	/* let isr handle RGND interrupt */
+
 	pr_debug("%s:%u\n", __func__, __LINE__);
 	INIT_COMPLETION(mhl_ctrl->rgnd_done);
+	/*
+	 * after toggling reset line and enabling disc
+	 * tx can take a while to generate intr
+	 */
 	timeout = wait_for_completion_interruptible_timeout
-		(&mhl_ctrl->rgnd_done, HZ);
+		(&mhl_ctrl->rgnd_done, HZ * 3);
 	if (!timeout) {
-		/* most likely nothing plugged in USB */
-		/* USB HOST connected or already in USB mode */
+		/*
+		 * most likely nothing plugged in USB
+		 * USB HOST connected or already in USB mode
+		 */
 		pr_warn("%s:%u timedout\n", __func__, __LINE__);
 		return -ENODEV;
 	}
@@ -380,9 +386,25 @@
 	struct i2c_client *client = mhl_ctrl->i2c_handle;
 	unsigned long flags;
 
-	enable_irq(client->irq);
+	if (!mhl_ctrl->irq_req_done) {
+		rc = request_threaded_irq(mhl_ctrl->i2c_handle->irq, NULL,
+					  &mhl_tx_isr,
+					  IRQF_TRIGGER_LOW | IRQF_ONESHOT,
+					  client->dev.driver->name, mhl_ctrl);
+		if (rc) {
+			pr_err("request_threaded_irq failed, status: %d\n",
+			       rc);
+			return -EINVAL;
+		} else {
+			pr_debug("request_threaded_irq succeeded\n");
+			mhl_ctrl->irq_req_done = true;
+		}
+	} else {
+		enable_irq(client->irq);
+	}
+
 	/* wait for i2c interrupt line to be activated */
-	msleep(300);
+	msleep(100);
 
 	if (id) {
 		/* When MHL cable is disconnected we get a sii8334
@@ -413,8 +435,10 @@
 		/* chipset PR recommends waiting for at least 100 ms
 		 * the chipset needs longer to come out of D3 state.
 		 */
-		msleep(300);
+		msleep(100);
 		mhl_init_reg_settings(mhl_ctrl, true);
+		/* allow tx to enable dev disc after D3 state */
+		msleep(100);
 		rc = mhl_sii_wait_for_rgnd(mhl_ctrl);
 	} else {
 		if (mhl_ctrl->cur_state == POWER_STATE_D3) {
@@ -493,6 +517,10 @@
 	uint8_t i;
 	struct i2c_client *client = mhl_ctrl->i2c_handle;
 
+	/* Read the chip rev ID */
+	mhl_ctrl->chip_rev_id = MHL_SII_PAGE0_RD(0x04);
+	pr_debug("MHL: chip rev ID read=[%x]\n", mhl_ctrl->chip_rev_id);
+
 	/*
 	 * REG_SRST
 	 */
@@ -1428,40 +1456,6 @@
 	return IRQ_HANDLED;
 }
 
-static int mhl_tx_chip_init(struct mhl_tx_ctrl *mhl_ctrl)
-{
-	uint8_t chip_rev_id = 0x00;
-	struct i2c_client *client = mhl_ctrl->i2c_handle;
-	unsigned long flags;
-
-
-	spin_lock_irqsave(&mhl_ctrl->lock, flags);
-	mhl_ctrl->dwnstream_hpd = 0;
-	mhl_ctrl->tx_powered_off = false;
-	spin_unlock_irqrestore(&mhl_ctrl->lock, flags);
-
-	/* Reset the TX chip */
-	mhl_sii_reset_pin(mhl_ctrl, 0);
-	msleep(20);
-	mhl_sii_reset_pin(mhl_ctrl, 1);
-	/* TX PR-guide requires a 100 ms wait here */
-	msleep(100);
-
-	/* Read the chip rev ID */
-	chip_rev_id = MHL_SII_PAGE0_RD(0x04);
-	pr_debug("MHL: chip rev ID read=[%x]\n", chip_rev_id);
-	mhl_ctrl->chip_rev_id = chip_rev_id;
-
-	/*
-	 * Need to disable MHL discovery if
-	 * MHL-USB handshake is implemented
-	 */
-	mhl_init_reg_settings(mhl_ctrl, true);
-	switch_mode(mhl_ctrl, POWER_STATE_D3, true);
-	pr_debug("%s:%u: power_down\n", __func__, __LINE__);
-	mhl_tx_down(mhl_ctrl);
-	return 0;
-}
 
 static int mhl_sii_reg_config(struct i2c_client *client, bool enable)
 {
@@ -1791,30 +1785,12 @@
 		}
 	}
 
-	rc = mhl_tx_chip_init(mhl_ctrl);
-	if (rc) {
-		pr_err("%s: tx chip init failed [%d]\n",
-			__func__, rc);
-		goto failed_probe;
-	}
+	mhl_ctrl->dwnstream_hpd = 0;
+	mhl_ctrl->tx_powered_off = false;
+
 
 	init_completion(&mhl_ctrl->rgnd_done);
 
-	pr_debug("%s: IRQ from GPIO INTR = %d\n",
-		__func__, mhl_ctrl->i2c_handle->irq);
-	pr_debug("%s: Driver name = [%s]\n", __func__,
-		client->dev.driver->name);
-	rc = request_threaded_irq(mhl_ctrl->i2c_handle->irq, NULL,
-				   &mhl_tx_isr,
-				  IRQF_TRIGGER_LOW | IRQF_ONESHOT,
-				 client->dev.driver->name, mhl_ctrl);
-	if (rc) {
-		pr_err("request_threaded_irq failed, status: %d\n",
-		       rc);
-		goto failed_probe;
-	} else {
-		pr_debug("request_threaded_irq succeeded\n");
-	}
 
 	mhl_ctrl->mhl_psy.name = "ext-vbus";
 	mhl_ctrl->mhl_psy.type = POWER_SUPPLY_TYPE_USB_DCP;
@@ -1940,15 +1916,21 @@
 #if defined(CONFIG_PM) || defined(CONFIG_PM_SLEEP)
 static int mhl_i2c_suspend_sub(struct i2c_client *client)
 {
-	enable_irq_wake(client->irq);
-	disable_irq(client->irq);
+	struct mhl_tx_ctrl *mhl_ctrl = i2c_get_clientdata(client);
+
+	if (mhl_ctrl->irq_req_done) {
+		enable_irq_wake(client->irq);
+		disable_irq(client->irq);
+	}
 	return 0;
 }
 
 static int mhl_i2c_resume_sub(struct i2c_client *client)
 {
-	disable_irq_wake(client->irq);
-	enable_irq(client->irq);
+	struct mhl_tx_ctrl *mhl_ctrl = i2c_get_clientdata(client);
+
+	if (mhl_ctrl->irq_req_done)
+		disable_irq_wake(client->irq);
 	return 0;
 }
 #endif /* defined(CONFIG_PM) || defined(CONFIG_PM_SLEEP) */
diff --git a/drivers/video/msm/mdss/msm_mdss_io_8974.c b/drivers/video/msm/mdss/msm_mdss_io_8974.c
index 7b89eff..d24daab 100644
--- a/drivers/video/msm/mdss/msm_mdss_io_8974.c
+++ b/drivers/video/msm/mdss/msm_mdss_io_8974.c
@@ -504,7 +504,7 @@
 		return;
 	}
 
-	pd = ((ctrl_pdata->panel_data).panel_info.mipi).dsi_phy_db;
+	pd = &(((ctrl_pdata->panel_data).panel_info.mipi).dsi_phy_db);
 
 	/* Strength ctrl 0 */
 	MIPI_OUTP((ctrl_pdata->ctrl_base) + 0x0484, pd->strength[0]);
@@ -564,7 +564,7 @@
 		for (i = 0; i < 9; i++) {
 			offset = i + (ln * 9);
 			MIPI_OUTP((ctrl_pdata->ctrl_base) + off,
-							pd->laneCfg[offset]);
+							pd->lanecfg[offset]);
 			wmb();
 			off += 4;
 		}
@@ -583,7 +583,7 @@
 
 	off = 0x04b4;	/* phy BIST ctrl 0 - 5 */
 	for (i = 0; i < 6; i++) {
-		MIPI_OUTP((ctrl_pdata->ctrl_base) + off, pd->bistCtrl[i]);
+		MIPI_OUTP((ctrl_pdata->ctrl_base) + off, pd->bistctrl[i]);
 		wmb();
 		off += 4;
 	}
diff --git a/include/linux/Kbuild b/include/linux/Kbuild
index f6ca334..f66a034 100644
--- a/include/linux/Kbuild
+++ b/include/linux/Kbuild
@@ -260,6 +260,7 @@
 header-y += msdos_fs.h
 header-y += msg.h
 header-y += msm_adc.h
+header-y += msm_dsps.h
 header-y += msm_ion.h
 header-y += epm_adc.h
 header-y += mtio.h
diff --git a/include/linux/batterydata-lib.h b/include/linux/batterydata-lib.h
index fe2d86f..ff38eb6 100644
--- a/include/linux/batterydata-lib.h
+++ b/include/linux/batterydata-lib.h
@@ -26,6 +26,8 @@
 
 #define MAX_SINGLE_LUT_COLS	20
 
+#define MAX_BATT_ID_NUM		4
+
 struct single_row_lut {
 	int x[MAX_SINGLE_LUT_COLS];
 	int y[MAX_SINGLE_LUT_COLS];
@@ -69,6 +71,11 @@
 	int ocv[PC_TEMP_ROWS][PC_TEMP_COLS];
 };
 
+struct batt_ids {
+	int kohm[MAX_BATT_ID_NUM];
+	int num;
+};
+
 enum battery_type {
 	BATT_UNKNOWN = 0,
 	BATT_PALLADIUM,
@@ -99,7 +106,7 @@
  * @cutoff_uv:		cutoff voltage of the battery
  * @iterm_ua:		termination current of the battery when charging
  *			to 100%
- * @batt_id_kohm:	battery id resistor value
+ * @batt_id_kohm:	the best matched battery id resistor value
  */
 
 struct bms_battery_data {
diff --git a/include/linux/cm36283.h b/include/linux/cm36283.h
index cccd5ee..2872d04 100644
--- a/include/linux/cm36283.h
+++ b/include/linux/cm36283.h
@@ -17,6 +17,8 @@
 #ifndef __LINUX_CM36283_H
 #define __LINUX_CM36283_H
 
+#include <linux/bitops.h>
+
 #define CM36283_I2C_NAME "cm36283"
 
 /* Define Slave Address*/
@@ -102,9 +104,31 @@
 #define INT_FLAG_PS_IF_CLOSE         (1<<9)
 #define INT_FLAG_PS_IF_AWAY          (1<<8)  
 
+#define LS_PWR_ON		BIT(0)
+#define PS_PWR_ON		BIT(1)
+
+#define CAPELLA_CM3602_IOCTL_MAGIC 'c'
+#define CAPELLA_CM3602_IOCTL_GET_ENABLED \
+	_IOR(CAPELLA_CM3602_IOCTL_MAGIC, 1, int *)
+#define CAPELLA_CM3602_IOCTL_ENABLE \
+	_IOW(CAPELLA_CM3602_IOCTL_MAGIC, 2, int *)
+
+#define LIGHTSENSOR_IOCTL_MAGIC 'l'
+#define LIGHTSENSOR_IOCTL_GET_ENABLED _IOR(LIGHTSENSOR_IOCTL_MAGIC, 1, int *)
+#define LIGHTSENSOR_IOCTL_ENABLE _IOW(LIGHTSENSOR_IOCTL_MAGIC, 2, int *)
+
 extern unsigned int ps_kparam1;
 extern unsigned int ps_kparam2;
 
+#define CM36283_LEVELS_SIZE		10
+
+enum {
+	CM36283_ALS_IT0 = 0,
+	CM36283_ALS_IT1,
+	CM36283_ALS_IT2,
+	CM36283_ALS_IT3,
+};
+
 struct cm36283_platform_data {
 	int intr;
 	uint16_t levels[10];
@@ -116,6 +140,7 @@
 	uint16_t ls_cmd;
 	uint16_t ps_conf1_val;
 	uint16_t ps_conf3_val;	
+	bool polling;
 };
 
 #endif
diff --git a/include/linux/coresight-cti.h b/include/linux/coresight-cti.h
index 7f2da3f..c3dce9f 100644
--- a/include/linux/coresight-cti.h
+++ b/include/linux/coresight-cti.h
@@ -34,6 +34,7 @@
 			struct coresight_cti *cti, int trig, int ch);
 extern void coresight_cti_unmap_trigout(
 			struct coresight_cti *cti, int trig, int ch);
+extern void coresight_cti_reset(struct coresight_cti *cti);
 #else
 static inline struct coresight_cti *coresight_cti_get(const char *name)
 {
@@ -54,6 +55,7 @@
 			struct coresight_cti *cti, int trig, int ch) {}
 static inline void coresight_cti_unmap_trigout(
 			struct coresight_cti *cti, int trig, int ch) {}
+static inline void coresight_cti_reset(struct coresight_cti *cti) {}
 #endif
 
 #endif
diff --git a/include/linux/coresight.h b/include/linux/coresight.h
index 5b69884..fbd5fb0 100644
--- a/include/linux/coresight.h
+++ b/include/linux/coresight.h
@@ -41,6 +41,7 @@
 	CORESIGHT_CLK_RATE_OFF,
 	CORESIGHT_CLK_RATE_TRACE = 1000,
 	CORESIGHT_CLK_RATE_HSTRACE = 2000,
+	CORESIGHT_CLK_RATE_FIXED = 3000,
 };
 
 enum coresight_dev_type {
diff --git a/include/linux/device.h b/include/linux/device.h
index 35862c3..c297f25 100644
--- a/include/linux/device.h
+++ b/include/linux/device.h
@@ -555,6 +555,7 @@
 extern void *devm_kzalloc(struct device *dev, size_t size, gfp_t gfp);
 extern void devm_kfree(struct device *dev, void *p);
 
+void __iomem *devm_ioremap_resource(struct device *dev, struct resource *res);
 void __iomem *devm_request_and_ioremap(struct device *dev,
 			struct resource *res);
 
diff --git a/include/linux/input/ft5x06_ts.h b/include/linux/input/ft5x06_ts.h
index af8c332..149133e 100644
--- a/include/linux/input/ft5x06_ts.h
+++ b/include/linux/input/ft5x06_ts.h
@@ -23,7 +23,20 @@
 #define FT5X36_ID		0x14
 #define FT6X06_ID		0x06
 
+struct fw_upgrade_info {
+	bool auto_cal;
+	u16 delay_aa;
+	u16 delay_55;
+	u8 upgrade_id_1;
+	u8 upgrade_id_2;
+	u16 delay_readid;
+	u16 delay_erase_flash;
+};
+
 struct ft5x06_ts_platform_data {
+	struct fw_upgrade_info info;
+	const char *name;
+	const char *fw_name;
 	u32 irqflags;
 	u32 irq_gpio;
 	u32 irq_gpio_flags;
@@ -38,6 +51,11 @@
 	u32 panel_miny;
 	u32 panel_maxx;
 	u32 panel_maxy;
+	u32 group_id;
+	u32 hard_rst_dly;
+	u32 soft_rst_dly;
+	u32 num_max_touches;
+	bool fw_vkey_support;
 	bool no_force_update;
 	bool i2c_pull_up;
 	int (*power_init) (bool);
diff --git a/include/linux/input/synaptics_dsx.h b/include/linux/input/synaptics_dsx.h
index 73016d6..6716ce3 100644
--- a/include/linux/input/synaptics_dsx.h
+++ b/include/linux/input/synaptics_dsx.h
@@ -35,11 +35,23 @@
  * struct synaptics_rmi4_platform_data - rmi4 platform data
  * @x_flip: x flip flag
  * @y_flip: y flip flag
+ * @i2c_pull_up: pull up i2c bus with regulator
+ * @power_down_enable: enable complete regulator shutdown in suspend
  * @irq_gpio: attention interrupt gpio
  * @irq_flags: flags used by the irq
+ * @reset_flags: flags used by reset line
  * @reset_gpio: reset gpio
  * @panel_x: panel maximum values on the x
  * @panel_y: panel maximum values on the y
+ * @disp_maxx: display panel maximum values on the x
+ * @disp_maxy: display panel maximum values on the y
+ * @disp_minx: display panel minimum values on the x
+ * @disp_miny: display panel minimum values on the y
+ * @panel_maxx: touch panel maximum values on the x
+ * @panel_maxy: touch panel maximum values on the y
+ * @panel_minx: touch panel minimum values on the x
+ * @panel_miny: touch panel minimum values on the y
+ * @reset_delay: reset delay
  * @gpio_config: pointer to gpio configuration function
  * @capacitance_button_map: pointer to 0d button map
  */
@@ -47,12 +59,22 @@
 	bool x_flip;
 	bool y_flip;
 	bool i2c_pull_up;
+	bool power_down_enable;
+	bool disable_gpios;
+	bool do_lockdown;
 	unsigned irq_gpio;
 	u32 irq_flags;
 	u32 reset_flags;
 	unsigned reset_gpio;
-	unsigned panel_x;
-	unsigned panel_y;
+	unsigned panel_minx;
+	unsigned panel_miny;
+	unsigned panel_maxx;
+	unsigned panel_maxy;
+	unsigned disp_minx;
+	unsigned disp_miny;
+	unsigned disp_maxx;
+	unsigned disp_maxy;
+	unsigned reset_delay;
 	const char *fw_image_name;
 	int (*gpio_config)(unsigned gpio, bool configure);
 	struct synaptics_rmi4_capacitance_button_map *capacitance_button_map;
diff --git a/include/linux/mfd/wcd9xxx/core-resource.h b/include/linux/mfd/wcd9xxx/core-resource.h
new file mode 100644
index 0000000..442496e
--- /dev/null
+++ b/include/linux/mfd/wcd9xxx/core-resource.h
@@ -0,0 +1,137 @@
+/* Copyright (c) 2013, The Linux Foundation. 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 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#ifndef __MFD_CORE_RESOURCE_H__
+#define __MFD_CORE_RESOURCE_H__
+
+#include <linux/types.h>
+#include <linux/interrupt.h>
+#include <linux/pm_qos.h>
+
+#define WCD9XXX_MAX_IRQ_REGS 4
+#define WCD9XXX_MAX_NUM_IRQS (WCD9XXX_MAX_IRQ_REGS * 8)
+
+struct intr_data {
+	int intr_num;
+	bool clear_first;
+};
+
+enum wcd9xxx_pm_state {
+	WCD9XXX_PM_SLEEPABLE,
+	WCD9XXX_PM_AWAKE,
+	WCD9XXX_PM_ASLEEP,
+};
+
+enum wcd9xxx_intf_status {
+	WCD9XXX_INTERFACE_TYPE_PROBING,
+	WCD9XXX_INTERFACE_TYPE_SLIMBUS,
+	WCD9XXX_INTERFACE_TYPE_I2C,
+};
+
+struct wcd9xxx_core_resource {
+	struct mutex irq_lock;
+	struct mutex nested_irq_lock;
+
+	enum wcd9xxx_pm_state pm_state;
+	struct mutex pm_lock;
+	/* pm_wq notifies change of pm_state */
+	wait_queue_head_t pm_wq;
+	struct pm_qos_request pm_qos_req;
+	int wlock_holders;
+
+
+	/* holds the table of interrupts per codec */
+	const struct intr_data *intr_table;
+	int intr_table_size;
+	unsigned int irq_base;
+	unsigned int irq;
+	u8 irq_masks_cur[WCD9XXX_MAX_IRQ_REGS];
+	u8 irq_masks_cache[WCD9XXX_MAX_IRQ_REGS];
+	bool irq_level_high[WCD9XXX_MAX_NUM_IRQS];
+	int num_irqs;
+	int num_irq_regs;
+
+	/* Callback functions to read/write codec registers */
+	int (*codec_reg_read) (struct wcd9xxx_core_resource *,
+				unsigned short);
+	int (*codec_reg_write) (struct wcd9xxx_core_resource *,
+				unsigned short, u8);
+	int (*codec_bulk_read) (struct wcd9xxx_core_resource *,
+				unsigned short, int, u8 *);
+
+	/* Pointer to parent container data structure */
+	void *parent;
+
+	struct device *dev;
+};
+
+extern int wcd9xxx_core_res_init(
+	struct wcd9xxx_core_resource*,
+	int, int,
+	int (*codec_read)(struct wcd9xxx_core_resource *, unsigned short),
+	int (*codec_write)(struct wcd9xxx_core_resource *, unsigned short, u8),
+	int (*codec_bulk_read) (struct wcd9xxx_core_resource *, unsigned short,
+							int, u8 *));
+
+extern void wcd9xxx_core_res_deinit(
+	struct wcd9xxx_core_resource *);
+
+extern int wcd9xxx_core_res_suspend(
+	struct wcd9xxx_core_resource *,
+	pm_message_t);
+
+extern int wcd9xxx_core_res_resume(
+	struct wcd9xxx_core_resource *);
+
+extern int wcd9xxx_core_irq_init(
+	struct wcd9xxx_core_resource*);
+
+extern int wcd9xxx_initialize_irq(
+	struct wcd9xxx_core_resource*,
+	unsigned int,
+	unsigned int);
+
+enum wcd9xxx_intf_status wcd9xxx_get_intf_type(void);
+void wcd9xxx_set_intf_type(enum wcd9xxx_intf_status);
+
+bool wcd9xxx_lock_sleep(struct wcd9xxx_core_resource *);
+void wcd9xxx_unlock_sleep(struct wcd9xxx_core_resource *);
+void wcd9xxx_nested_irq_lock(struct wcd9xxx_core_resource *);
+void wcd9xxx_nested_irq_unlock(struct wcd9xxx_core_resource *);
+enum wcd9xxx_pm_state wcd9xxx_pm_cmpxchg(
+			struct wcd9xxx_core_resource *,
+			enum wcd9xxx_pm_state,
+			enum wcd9xxx_pm_state);
+
+int wcd9xxx_request_irq(struct wcd9xxx_core_resource *, int,
+			irq_handler_t, const char *, void *);
+
+void wcd9xxx_free_irq(struct wcd9xxx_core_resource *, int, void*);
+void wcd9xxx_enable_irq(struct wcd9xxx_core_resource *, int);
+void wcd9xxx_disable_irq(struct wcd9xxx_core_resource *, int);
+void wcd9xxx_disable_irq_sync(struct wcd9xxx_core_resource *, int);
+int wcd9xxx_reg_read(struct wcd9xxx_core_resource *,
+					 unsigned short);
+int wcd9xxx_reg_write(struct wcd9xxx_core_resource *,
+					  unsigned short, u8);
+int wcd9xxx_bulk_read(struct wcd9xxx_core_resource *,
+					unsigned short, int, u8 *);
+int wcd9xxx_bulk_write(struct wcd9xxx_core_resource*,
+					 unsigned short, int, u8*);
+int wcd9xxx_irq_init(struct wcd9xxx_core_resource *);
+void wcd9xxx_irq_exit(struct wcd9xxx_core_resource *);
+int wcd9xxx_core_res_resume(
+	struct wcd9xxx_core_resource *);
+int wcd9xxx_core_res_suspend(
+	struct wcd9xxx_core_resource *,
+	pm_message_t);
+#endif
diff --git a/include/linux/mfd/wcd9xxx/core.h b/include/linux/mfd/wcd9xxx/core.h
index e688bd9..c2ad2b4 100644
--- a/include/linux/mfd/wcd9xxx/core.h
+++ b/include/linux/mfd/wcd9xxx/core.h
@@ -14,12 +14,10 @@
 #define __MFD_TABLA_CORE_H__
 
 #include <linux/types.h>
-#include <linux/interrupt.h>
-#include <linux/pm_qos.h>
 #include <linux/platform_device.h>
 #include <linux/of_irq.h>
+#include <linux/mfd/wcd9xxx/core-resource.h>
 
-#define WCD9XXX_NUM_IRQ_REGS 4
 
 #define WCD9XXX_SLIM_NUM_PORT_REG 3
 #define TABLA_VERSION_1_0	0
@@ -90,6 +88,7 @@
 	WCD9XXX_IRQ_VBAT_MONITOR_ATTACK,
 	WCD9XXX_IRQ_VBAT_MONITOR_RELEASE,
 	WCD9XXX_NUM_IRQS,
+	WCD9XXX_IRQ_RESERVED_2 = WCD9XXX_NUM_IRQS,
 };
 
 enum {
@@ -99,17 +98,6 @@
 	TAPAN_NUM_IRQS = WCD9XXX_NUM_IRQS,
 };
 
-
-#define MAX(X, Y) (((int)X) >= ((int)Y) ? (X) : (Y))
-#define WCD9XXX_MAX_NUM_IRQS (MAX(MAX(TABLA_NUM_IRQS, SITAR_NUM_IRQS), \
-				  TAIKO_NUM_IRQS))
-
-enum wcd9xxx_pm_state {
-	WCD9XXX_PM_SLEEPABLE,
-	WCD9XXX_PM_AWAKE,
-	WCD9XXX_PM_ASLEEP,
-};
-
 /*
  * data structure for Slimbus and I2S channel.
  * Some of fields are only used in smilbus mode
@@ -145,12 +133,6 @@
 	wait_queue_head_t dai_wait;
 };
 
-enum wcd9xxx_intf_status {
-	WCD9XXX_INTERFACE_TYPE_PROBING,
-	WCD9XXX_INTERFACE_TYPE_SLIMBUS,
-	WCD9XXX_INTERFACE_TYPE_I2C,
-};
-
 #define WCD9XXX_CH(xport, xshift) \
 	{.port = xport, .shift = xshift}
 
@@ -178,8 +160,6 @@
 	struct slim_device *slim_slave;
 	struct mutex io_lock;
 	struct mutex xfer_lock;
-	struct mutex irq_lock;
-	struct mutex nested_irq_lock;
 	u8 version;
 
 	int reset_gpio;
@@ -188,6 +168,7 @@
 			int bytes, void *dest, bool interface_reg);
 	int (*write_dev)(struct wcd9xxx *wcd9xxx, unsigned short reg,
 			int bytes, void *src, bool interface_reg);
+	int (*dev_down)(struct wcd9xxx *wcd9xxx);
 	int (*post_reset)(struct wcd9xxx *wcd9xxx);
 
 	void *ssr_priv;
@@ -196,21 +177,11 @@
 	u32 num_of_supplies;
 	struct regulator_bulk_data *supplies;
 
-	enum wcd9xxx_pm_state pm_state;
-	struct mutex pm_lock;
-	/* pm_wq notifies change of pm_state */
-	wait_queue_head_t pm_wq;
-	struct pm_qos_request pm_qos_req;
-	int wlock_holders;
+	struct wcd9xxx_core_resource core_res;
 
 	u16 id_minor;
 	u16 id_major;
 
-	unsigned int irq_base;
-	unsigned int irq;
-	u8 irq_masks_cur[WCD9XXX_NUM_IRQ_REGS];
-	u8 irq_masks_cache[WCD9XXX_NUM_IRQ_REGS];
-	bool irq_level_high[WCD9XXX_MAX_NUM_IRQS];
 	/* Slimbus or I2S port */
 	u32 num_rx_port;
 	u32 num_tx_port;
@@ -221,36 +192,11 @@
 	const struct wcd9xxx_codec_type *codec_type;
 };
 
-int wcd9xxx_reg_read(struct wcd9xxx *wcd9xxx, unsigned short reg);
-int wcd9xxx_reg_write(struct wcd9xxx *wcd9xxx, unsigned short reg,
-		u8 val);
 int wcd9xxx_interface_reg_read(struct wcd9xxx *wcd9xxx, unsigned short reg);
 int wcd9xxx_interface_reg_write(struct wcd9xxx *wcd9xxx, unsigned short reg,
 		u8 val);
-int wcd9xxx_bulk_read(struct wcd9xxx *wcd9xxx, unsigned short reg,
-			int count, u8 *buf);
-int wcd9xxx_bulk_write(struct wcd9xxx *wcd9xxx, unsigned short reg,
-			int count, u8 *buf);
-int wcd9xxx_irq_init(struct wcd9xxx *wcd9xxx);
-void wcd9xxx_irq_exit(struct wcd9xxx *wcd9xxx);
 int wcd9xxx_get_logical_addresses(u8 *pgd_la, u8 *inf_la);
-enum wcd9xxx_intf_status wcd9xxx_get_intf_type(void);
 
-bool wcd9xxx_lock_sleep(struct wcd9xxx *wcd9xxx);
-void wcd9xxx_unlock_sleep(struct wcd9xxx *wcd9xxx);
-void wcd9xxx_nested_irq_lock(struct wcd9xxx *wcd9xxx);
-void wcd9xxx_nested_irq_unlock(struct wcd9xxx *wcd9xxx);
-enum wcd9xxx_pm_state wcd9xxx_pm_cmpxchg(struct wcd9xxx *wcd9xxx,
-				enum wcd9xxx_pm_state o,
-				enum wcd9xxx_pm_state n);
-
-int wcd9xxx_request_irq(struct wcd9xxx *wcd9xxx, int irq,
-			irq_handler_t handler, const char *name, void *data);
-
-void wcd9xxx_free_irq(struct wcd9xxx *wcd9xxx, int irq, void *data);
-void wcd9xxx_enable_irq(struct wcd9xxx *wcd9xxx, int irq);
-void wcd9xxx_disable_irq(struct wcd9xxx *wcd9xxx, int irq);
-void wcd9xxx_disable_irq_sync(struct wcd9xxx *wcd9xxx, int irq);
 #if defined(CONFIG_WCD9310_CODEC) || \
 	defined(CONFIG_WCD9304_CODEC) || \
 	defined(CONFIG_WCD9320_CODEC) || \
@@ -264,4 +210,16 @@
 	return 0;
 }
 #endif	/* CONFIG_OF */
+static inline void wcd9xxx_reg_update(struct wcd9xxx *core,
+				      unsigned short reg,
+				      u8 mask, u8 val)
+{
+	u8 reg_val;
+
+	if (core) {
+		reg_val = wcd9xxx_reg_read(&core->core_res, reg);
+		reg_val = (reg_val & ~mask) | (val & mask);
+		wcd9xxx_reg_write(&core->core_res, reg, reg_val);
+	}
+}
 #endif
diff --git a/include/linux/mhl_8334.h b/include/linux/mhl_8334.h
index d1ee11c..71dec42 100644
--- a/include/linux/mhl_8334.h
+++ b/include/linux/mhl_8334.h
@@ -165,6 +165,7 @@
 	bool tx_powered_off;
 	uint8_t dwnstream_hpd;
 	bool mhl_det_discon;
+	bool irq_req_done;
 };
 
 int mhl_i2c_reg_read(struct i2c_client *client,
diff --git a/include/linux/mmc/card.h b/include/linux/mmc/card.h
index 2cb297e..9d15908 100644
--- a/include/linux/mmc/card.h
+++ b/include/linux/mmc/card.h
@@ -67,6 +67,7 @@
 #define MMC_HIGH_52_MAX_DTR	52000000
 #define MMC_HIGH_DDR_MAX_DTR	52000000
 #define MMC_HS200_MAX_DTR	200000000
+#define MMC_HS400_MAX_DTR	200000000
 	unsigned int		sectors;
 	unsigned int		card_type;
 	unsigned int		hc_erase_size;		/* In sectors */
@@ -329,6 +330,7 @@
 #define MMC_CARD_SDXC		(1<<6)		/* card is SDXC */
 #define MMC_CARD_REMOVED	(1<<7)		/* card has been removed */
 #define MMC_STATE_HIGHSPEED_200	(1<<8)		/* card is in HS200 mode */
+#define MMC_STATE_HIGHSPEED_400	(1<<9)		/* card is in HS400 mode */
 #define MMC_STATE_DOING_BKOPS	(1<<10)		/* card is doing BKOPS */
 #define MMC_STATE_NEED_BKOPS	(1<<11)		/* card needs to do BKOPS */
 	unsigned int		quirks; 	/* card quirks */
@@ -347,6 +349,8 @@
 #define MMC_QUIRK_SEC_ERASE_TRIM_BROKEN (1<<10)	/* Skip secure for erase/trim */
 						/* byte mode */
 #define MMC_QUIRK_INAND_DATA_TIMEOUT  (1<<8)    /* For incorrect data timeout */
+/* To avoid eMMC device getting broken permanently due to HPI feature */
+#define MMC_QUIRK_BROKEN_HPI (1 << 11)
 
 	unsigned int		erase_size;	/* erase size in sectors */
  	unsigned int		erase_shift;	/* if erase unit is power 2 */
@@ -426,6 +430,8 @@
 
 	/* SDIO-specfic fields. You can use SDIO_ANY_ID here of course */
 	u16 cis_vendor, cis_device;
+	/* for MMC cards */
+	unsigned int ext_csd_rev;
 
 	void (*vendor_fixup)(struct mmc_card *card, int data);
 	int data;
@@ -435,11 +441,19 @@
 #define CID_OEMID_ANY ((unsigned short) -1)
 #define CID_NAME_ANY (NULL)
 
+#define EXT_CSD_REV_ANY (-1u)
+
+#define CID_MANFID_SANDISK	0x2
+#define CID_MANFID_TOSHIBA	0x11
+#define CID_MANFID_MICRON	0x13
+#define CID_MANFID_SAMSUNG	0x15
+#define CID_MANFID_HYNIX	0x90
+
 #define END_FIXUP { 0 }
 
 #define _FIXUP_EXT(_name, _manfid, _oemid, _rev_start, _rev_end,	\
 		   _cis_vendor, _cis_device,				\
-		   _fixup, _data)					\
+		   _fixup, _data, _ext_csd_rev)				\
 	{						   \
 		.name = (_name),			   \
 		.manfid = (_manfid),			   \
@@ -450,23 +464,30 @@
 		.cis_device = (_cis_device),		   \
 		.vendor_fixup = (_fixup),		   \
 		.data = (_data),			   \
+		.ext_csd_rev = (_ext_csd_rev),		   \
 	 }
 
 #define MMC_FIXUP_REV(_name, _manfid, _oemid, _rev_start, _rev_end,	\
-		      _fixup, _data)					\
+		      _fixup, _data, _ext_csd_rev)			\
 	_FIXUP_EXT(_name, _manfid,					\
 		   _oemid, _rev_start, _rev_end,			\
 		   SDIO_ANY_ID, SDIO_ANY_ID,				\
-		   _fixup, _data)					\
+		   _fixup, _data, _ext_csd_rev)				\
 
-#define MMC_FIXUP(_name, _manfid, _oemid, _fixup, _data) \
-	MMC_FIXUP_REV(_name, _manfid, _oemid, 0, -1ull, _fixup, _data)
+#define MMC_FIXUP(_name, _manfid, _oemid, _fixup, _data)		\
+	MMC_FIXUP_REV(_name, _manfid, _oemid, 0, -1ull, _fixup, _data,	\
+		      EXT_CSD_REV_ANY)
+
+#define MMC_FIXUP_EXT_CSD_REV(_name, _manfid, _oemid, _fixup, _data,	\
+			      _ext_csd_rev)				\
+	MMC_FIXUP_REV(_name, _manfid, _oemid, 0, -1ull, _fixup, _data,	\
+		      _ext_csd_rev)
 
 #define SDIO_FIXUP(_vendor, _device, _fixup, _data)			\
 	_FIXUP_EXT(CID_NAME_ANY, CID_MANFID_ANY,			\
 		    CID_OEMID_ANY, 0, -1ull,				\
 		   _vendor, _device,					\
-		   _fixup, _data)					\
+		   _fixup, _data, EXT_CSD_REV_ANY)			\
 
 #define cid_rev(hwrev, fwrev, year, month)	\
 	(((u64) hwrev) << 40 |                  \
@@ -502,6 +523,7 @@
 #define mmc_card_readonly(c)	((c)->state & MMC_STATE_READONLY)
 #define mmc_card_highspeed(c)	((c)->state & MMC_STATE_HIGHSPEED)
 #define mmc_card_hs200(c)	((c)->state & MMC_STATE_HIGHSPEED_200)
+#define mmc_card_hs400(c)	((c)->state & MMC_STATE_HIGHSPEED_400)
 #define mmc_card_blockaddr(c)	((c)->state & MMC_STATE_BLOCKADDR)
 #define mmc_card_ddr_mode(c)	((c)->state & MMC_STATE_HIGHSPEED_DDR)
 #define mmc_card_uhs(c)		((c)->state & MMC_STATE_ULTRAHIGHSPEED)
@@ -514,9 +536,14 @@
 #define mmc_card_set_present(c)	((c)->state |= MMC_STATE_PRESENT)
 #define mmc_card_set_readonly(c) ((c)->state |= MMC_STATE_READONLY)
 #define mmc_card_set_highspeed(c) ((c)->state |= MMC_STATE_HIGHSPEED)
+#define mmc_card_clr_highspeed(c) ((c)->state &= ~MMC_STATE_HIGHSPEED)
 #define mmc_card_set_hs200(c)	((c)->state |= MMC_STATE_HIGHSPEED_200)
+#define mmc_card_clr_hs200(c)	((c)->state &= ~MMC_STATE_HIGHSPEED_200)
+#define mmc_card_set_hs400(c)	((c)->state |= MMC_STATE_HIGHSPEED_400)
+#define mmc_card_clr_hs400(c)	((c)->state &= ~MMC_STATE_HIGHSPEED_400)
 #define mmc_card_set_blockaddr(c) ((c)->state |= MMC_STATE_BLOCKADDR)
 #define mmc_card_set_ddr_mode(c) ((c)->state |= MMC_STATE_HIGHSPEED_DDR)
+#define mmc_card_clr_ddr_mode(c) ((c)->state &= ~MMC_STATE_HIGHSPEED_DDR)
 #define mmc_card_set_uhs(c) ((c)->state |= MMC_STATE_ULTRAHIGHSPEED)
 #define mmc_sd_card_set_uhs(c) ((c)->state |= MMC_STATE_ULTRAHIGHSPEED)
 #define mmc_card_set_ext_capacity(c) ((c)->state |= MMC_CARD_SDXC)
diff --git a/include/linux/mmc/host.h b/include/linux/mmc/host.h
index dbafdfc..e1dbd21 100644
--- a/include/linux/mmc/host.h
+++ b/include/linux/mmc/host.h
@@ -61,6 +61,7 @@
 #define MMC_TIMING_UHS_SDR104	4
 #define MMC_TIMING_UHS_DDR50	5
 #define MMC_TIMING_MMC_HS200	6
+#define MMC_TIMING_MMC_HS400	7
 
 #define MMC_SDR_MODE		0
 #define MMC_1_2V_DDR_MODE	1
@@ -245,6 +246,7 @@
 						/* DDR mode at 1.8V */
 #define MMC_CAP_1_2V_DDR	(1 << 12)	/* can support */
 						/* DDR mode at 1.2V */
+#define MMC_CAP_HSDDR		(MMC_CAP_1_8V_DDR | MMC_CAP_1_2V_DDR)
 #define MMC_CAP_POWER_OFF_CARD	(1 << 13)	/* Can power off after boot */
 #define MMC_CAP_BUS_WIDTH_TEST	(1 << 14)	/* CMD14/CMD19 bus width ok */
 #define MMC_CAP_UHS_SDR12	(1 << 15)	/* Host supports UHS SDR12 mode */
@@ -295,6 +297,11 @@
 #define MMC_CAP2_CORE_RUNTIME_PM (1 << 19)
 /* Allows Asynchronous SDIO irq while card is in 4-bit mode */
 #define MMC_CAP2_ASYNC_SDIO_IRQ_4BIT_MODE (1 << 20)
+
+#define MMC_CAP2_HS400_1_8V	(1 << 21)        /* can support */
+#define MMC_CAP2_HS400_1_2V	(1 << 22)        /* can support */
+#define MMC_CAP2_HS400		(MMC_CAP2_HS400_1_8V | \
+				 MMC_CAP2_HS400_1_2V)
 	mmc_pm_flag_t		pm_caps;	/* supported pm features */
 
 	int			clk_requests;	/* internal reference counter */
diff --git a/include/linux/mmc/mmc.h b/include/linux/mmc/mmc.h
index de145d6..764beec 100644
--- a/include/linux/mmc/mmc.h
+++ b/include/linux/mmc/mmc.h
@@ -52,6 +52,7 @@
 #define MMC_READ_MULTIPLE_BLOCK  18   /* adtc [31:0] data addr   R1  */
 #define MMC_SEND_TUNING_BLOCK    19   /* adtc                    R1  */
 #define MMC_SEND_TUNING_BLOCK_HS200	21	/* adtc R1  */
+#define MMC_SEND_TUNING_BLOCK_HS400	MMC_SEND_TUNING_BLOCK_HS200
 
   /* class 3 */
 #define MMC_WRITE_DAT_UNTIL_STOP 20   /* adtc [31:0] data addr   R1  */
@@ -328,6 +329,8 @@
 #define EXT_CSD_POWER_OFF_LONG_TIME	247	/* RO */
 #define EXT_CSD_GENERIC_CMD6_TIME	248	/* RO */
 #define EXT_CSD_CACHE_SIZE		249	/* RO, 4 bytes */
+#define EXT_CSD_PWR_CL_DDR_200_195	253	/* RO */
+#define EXT_CSD_PWR_CL_DDR_200_360	254	/* RO */
 #define EXT_CSD_TAG_UNIT_SIZE		498	/* RO */
 #define EXT_CSD_DATA_TAG_SUPPORT	499	/* RO */
 #define EXT_CSD_MAX_PACKED_WRITES	500	/* RO */
@@ -359,7 +362,7 @@
 
 #define EXT_CSD_CARD_TYPE_26	(1<<0)	/* Card can run at 26MHz */
 #define EXT_CSD_CARD_TYPE_52	(1<<1)	/* Card can run at 52MHz */
-#define EXT_CSD_CARD_TYPE_MASK	0x3F	/* Mask out reserved bits */
+#define EXT_CSD_CARD_TYPE_MASK	0xFF	/* Mask out reserved bits */
 #define EXT_CSD_CARD_TYPE_DDR_1_8V  (1<<2)   /* Card can run at 52MHz */
 					     /* DDR mode @1.8V or 3V I/O */
 #define EXT_CSD_CARD_TYPE_DDR_1_2V  (1<<3)   /* Card can run at 52MHz */
@@ -369,6 +372,14 @@
 #define EXT_CSD_CARD_TYPE_SDR_1_8V	(1<<4)	/* Card can run at 200MHz */
 #define EXT_CSD_CARD_TYPE_SDR_1_2V	(1<<5)	/* Card can run at 200MHz */
 						/* SDR mode @1.2V I/O */
+#define EXT_CSD_CARD_TYPE_HS200		(EXT_CSD_CARD_TYPE_SDR_1_8V  \
+					| EXT_CSD_CARD_TYPE_SDR_1_2V)
+#define EXT_CSD_CARD_TYPE_HS400_1_8V	(1<<6)	/* Card can run at 200MHz */
+							/* DDR mode @1.8V I/O */
+#define EXT_CSD_CARD_TYPE_HS400_1_2V	(1<<7)	/* Card can run at 200MHz */
+							/* DDR mode @1.2V I/O */
+#define EXT_CSD_CARD_TYPE_HS400		(EXT_CSD_CARD_TYPE_HS400_1_8V  \
+					| EXT_CSD_CARD_TYPE_HS400_1_2V)
 
 #define EXT_CSD_BUS_WIDTH_1	0	/* Card is in 1 bit mode */
 #define EXT_CSD_BUS_WIDTH_4	1	/* Card is in 4 bit mode */
diff --git a/include/linux/mmc/sdhci.h b/include/linux/mmc/sdhci.h
index 424b1d9..186fff1 100644
--- a/include/linux/mmc/sdhci.h
+++ b/include/linux/mmc/sdhci.h
@@ -190,6 +190,7 @@
 #define SDHCI_PV_ENABLED	(1<<8)	/* Preset value enabled */
 #define SDHCI_SDIO_IRQ_ENABLED	(1<<9)	/* SDIO irq enabled */
 #define SDHCI_HS200_NEEDS_TUNING (1<<10)	/* HS200 needs tuning */
+#define SDHCI_HS400_NEEDS_TUNING (1<<11)	/* HS400 needs tuning */
 
 	unsigned int version;	/* SDHCI spec. version */
 
diff --git a/include/linux/msm_audio_acdb.h b/include/linux/msm_audio_acdb.h
index e8ca1cd..853899e 100644
--- a/include/linux/msm_audio_acdb.h
+++ b/include/linux/msm_audio_acdb.h
@@ -63,6 +63,10 @@
 			(AUDIO_MAX_COMMON_IOCTL_NUM+28), unsigned)
 #define AUDIO_DEREGISTER_VOCPROC_VOL_TABLE	_IOW(AUDIO_IOCTL_MAGIC, \
 			(AUDIO_MAX_COMMON_IOCTL_NUM+29), unsigned)
+#define AUDIO_SET_HW_DELAY_RX	_IOW(AUDIO_IOCTL_MAGIC, \
+			(AUDIO_MAX_COMMON_IOCTL_NUM+30), struct hw_delay)
+#define AUDIO_SET_HW_DELAY_TX	_IOW(AUDIO_IOCTL_MAGIC, \
+			(AUDIO_MAX_COMMON_IOCTL_NUM+31), struct hw_delay)
 #define	AUDIO_MAX_ACDB_IOCTL	(AUDIO_MAX_COMMON_IOCTL_NUM+40)
 
 /* ACDB structures */
@@ -96,6 +100,11 @@
 	int status;
 };
 
+struct hw_delay {
+	uint32_t num_entries;
+	void *delay_info;
+};
+
 /* For Real-Time Audio Calibration */
 #define AUDIO_GET_RTAC_ADM_INFO		_IOR(AUDIO_IOCTL_MAGIC, \
 			(AUDIO_MAX_ACDB_IOCTL+1), unsigned)
diff --git a/include/linux/msm_dsps.h b/include/linux/msm_dsps.h
index 1f997ba..e3da576 100644
--- a/include/linux/msm_dsps.h
+++ b/include/linux/msm_dsps.h
@@ -1,17 +1,3 @@
-/*
- * Copyright (c) 2011, The Linux Foundation. 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 and
- * only version 2 as published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- */
-
 #ifndef _DSPS_H_
 #define _DSPS_H_
 
diff --git a/include/linux/msm_kgsl.h b/include/linux/msm_kgsl.h
index f74fcbe..87047d2 100644
--- a/include/linux/msm_kgsl.h
+++ b/include/linux/msm_kgsl.h
@@ -20,10 +20,7 @@
 #define KGSL_CONTEXT_TRASH_STATE	0x00000020
 #define KGSL_CONTEXT_PER_CONTEXT_TS	0x00000040
 #define KGSL_CONTEXT_USER_GENERATED_TS	0x00000080
-#define KGSL_CONTEXT_END_OF_FRAME	0x00000100
-
 #define KGSL_CONTEXT_NO_FAULT_TOLERANCE 0x00000200
-#define KGSL_CONTEXT_SYNC               0x00000400
 /* bits [12:15] are reserved for future use */
 #define KGSL_CONTEXT_TYPE_MASK          0x01F00000
 #define KGSL_CONTEXT_TYPE_SHIFT         20
@@ -286,7 +283,7 @@
 #define IOCTL_KGSL_DEVICE_WAITTIMESTAMP_CTXTID \
 	_IOW(KGSL_IOC_TYPE, 0x7, struct kgsl_device_waittimestamp_ctxtid)
 
-/* DEPRECATED: issue indirect commands to the GPU.
+/* issue indirect commands to the GPU.
  * drawctxt_id must have been created with IOCTL_KGSL_DRAWCTXT_CREATE
  * ibaddr and sizedwords must specify a subset of a buffer created
  * with IOCTL_KGSL_SHAREDMEM_FROM_PMEM
@@ -294,9 +291,6 @@
  * timestamp is a returned counter value which can be passed to
  * other ioctls to determine when the commands have been executed by
  * the GPU.
- *
- * This fucntion is deprecated - consider using IOCTL_KGSL_SUBMIT_COMMANDS
- * instead
  */
 struct kgsl_ringbuffer_issueibcmds {
 	unsigned int drawctxt_id;
@@ -811,77 +805,6 @@
 #define IOCTL_KGSL_GPUMEM_SYNC_CACHE_BULK \
 	_IOWR(KGSL_IOC_TYPE, 0x3C, struct kgsl_gpumem_sync_cache_bulk)
 
-/*
- * struct kgsl_cmd_syncpoint_timestamp
- * @context_id: ID of a KGSL context
- * @timestamp: GPU timestamp
- *
- * This structure defines a syncpoint comprising a context/timestamp pair. A
- * list of these may be passed by IOCTL_KGSL_SUBMIT_COMMANDS to define
- * dependencies that must be met before the command can be submitted to the
- * hardware
- */
-struct kgsl_cmd_syncpoint_timestamp {
-	unsigned int context_id;
-	unsigned int timestamp;
-};
-
-#define KGSL_CMD_SYNCPOINT_TYPE_TIMESTAMP 0
-
-struct kgsl_cmd_syncpoint_fence {
-	int fd;
-};
-
-#define KGSL_CMD_SYNCPOINT_TYPE_FENCE 1
-
-/**
- * struct kgsl_cmd_syncpoint - Define a sync point for a command batch
- * @type: type of sync point defined here
- * @priv: Pointer to the type specific buffer
- * @size: Size of the type specific buffer
- *
- * This structure contains pointers defining a specific command sync point.
- * The pointer and size should point to a type appropriate structure.
- */
-struct kgsl_cmd_syncpoint {
-	int type;
-	void __user *priv;
-	unsigned int size;
-};
-
-/**
- * struct kgsl_submit_commands - Argument to IOCTL_KGSL_SUBMIT_COMMANDS
- * @context_id: KGSL context ID that owns the commands
- * @flags:
- * @cmdlist: User pointer to a list of kgsl_ibdesc structures
- * @numcmds: Number of commands listed in cmdlist
- * @synclist: User pointer to a list of kgsl_cmd_syncpoint structures
- * @numsyncs: Number of sync points listed in synclist
- * @timestamp: On entry the a user defined timestamp, on exist the timestamp
- * assigned to the command batch
- *
- * This structure specifies a command to send to the GPU hardware.  This is
- * similar to kgsl_issueibcmds expect that it doesn't support the legacy way to
- * submit IB lists and it adds sync points to block the IB until the
- * dependencies are satisified.  This entry point is the new and preferred way
- * to submit commands to the GPU.
- */
-
-struct kgsl_submit_commands {
-	unsigned int context_id;
-	unsigned int flags;
-	struct kgsl_ibdesc __user *cmdlist;
-	unsigned int numcmds;
-	struct kgsl_cmd_syncpoint __user *synclist;
-	unsigned int numsyncs;
-	unsigned int timestamp;
-/* private: reserved for future use */
-	unsigned int __pad[4];
-};
-
-#define IOCTL_KGSL_SUBMIT_COMMANDS \
-	_IOWR(KGSL_IOC_TYPE, 0x3D, struct kgsl_submit_commands)
-
 #ifdef __KERNEL__
 #ifdef CONFIG_MSM_KGSL_DRM
 int kgsl_gem_obj_addr(int drm_fd, int handle, unsigned long *start,
diff --git a/include/linux/msm_mdp.h b/include/linux/msm_mdp.h
index 2455212..baa9d6c 100644
--- a/include/linux/msm_mdp.h
+++ b/include/linux/msm_mdp.h
@@ -126,6 +126,15 @@
 	MDP_BGR_888,      /* BGR 888 */
 	MDP_Y_CBCR_H2V2_VENUS,
 	MDP_BGRX_8888,   /* BGRX 8888 */
+	MDP_RGBA_8888_TILE,	/* RGBA 8888 in tile format */
+	MDP_ARGB_8888_TILE,	/* ARGB 8888 in tile format */
+	MDP_ABGR_8888_TILE,	/* ABGR 8888 in tile format */
+	MDP_BGRA_8888_TILE,	/* BGRA 8888 in tile format */
+	MDP_RGBX_8888_TILE,	/* RGBX 8888 in tile format */
+	MDP_XRGB_8888_TILE,	/* XRGB 8888 in tile format */
+	MDP_XBGR_8888_TILE,	/* XBGR 8888 in tile format */
+	MDP_BGRX_8888_TILE,	/* BGRX 8888 in tile format */
+	MDP_YCBYCR_H2V1,  /* YCbYCr interleave */
 	MDP_IMGTYPE_LIMIT,
 	MDP_RGB_BORDERFILL,	/* border fill pipe */
 	MDP_FB_FORMAT = MDP_IMGTYPE2_START,    /* framebuffer format */
@@ -405,6 +414,33 @@
 	struct mdp_hist_lut_data hist_lut_cfg;
 };
 
+/**
+ * enum mdss_mdp_blend_op - Different blend operations set by userspace
+ *
+ * @BLEND_OP_NOT_DEFINED:    No blend operation defined for the layer.
+ * @BLEND_OP_OPAQUE:         Apply a constant blend operation. The layer
+ *                           would appear opaque in case fg plane alpha is
+ *                           0xff.
+ * @BLEND_OP_PREMULTIPLIED:  Apply source over blend rule. Layer already has
+ *                           alpha pre-multiplication done. If fg plane alpha
+ *                           is less than 0xff, apply modulation as well. This
+ *                           operation is intended on layers having alpha
+ *                           channel.
+ * @BLEND_OP_COVERAGE:       Apply source over blend rule. Layer is not alpha
+ *                           pre-multiplied. Apply pre-multiplication. If fg
+ *                           plane alpha is less than 0xff, apply modulation as
+ *                           well.
+ * @BLEND_OP_MAX:            Used to track maximum blend operation possible by
+ *                           mdp.
+ */
+enum mdss_mdp_blend_op {
+	BLEND_OP_NOT_DEFINED = 0,
+	BLEND_OP_OPAQUE,
+	BLEND_OP_PREMULTIPLIED,
+	BLEND_OP_COVERAGE,
+	BLEND_OP_MAX,
+};
+
 struct mdp_overlay {
 	struct msmfb_img src;
 	struct mdp_rect src_rect;
@@ -412,6 +448,7 @@
 	uint32_t z_order;	/* stage number */
 	uint32_t is_fg;		/* control alpha & transp */
 	uint32_t alpha;
+	uint32_t blend_op;
 	uint32_t transp_mask;
 	uint32_t flags;
 	uint32_t id;
diff --git a/include/linux/msm_thermal.h b/include/linux/msm_thermal.h
index 2c1fa11..2ca9900 100644
--- a/include/linux/msm_thermal.h
+++ b/include/linux/msm_thermal.h
@@ -23,6 +23,8 @@
 	uint32_t freq_control_mask;
 	int32_t core_limit_temp_degC;
 	int32_t core_temp_hysteresis_degC;
+	int32_t hotplug_temp_degC;
+	int32_t hotplug_temp_hysteresis_degC;
 	uint32_t core_control_mask;
 	int32_t vdd_rstr_temp_degC;
 	int32_t vdd_rstr_temp_hyst_degC;
diff --git a/include/linux/power_supply.h b/include/linux/power_supply.h
index 5d6cdac..5106c71 100644
--- a/include/linux/power_supply.h
+++ b/include/linux/power_supply.h
@@ -51,10 +51,12 @@
 	POWER_SUPPLY_HEALTH_UNKNOWN = 0,
 	POWER_SUPPLY_HEALTH_GOOD,
 	POWER_SUPPLY_HEALTH_OVERHEAT,
+	POWER_SUPPLY_HEALTH_WARM,
 	POWER_SUPPLY_HEALTH_DEAD,
 	POWER_SUPPLY_HEALTH_OVERVOLTAGE,
 	POWER_SUPPLY_HEALTH_UNSPEC_FAILURE,
 	POWER_SUPPLY_HEALTH_COLD,
+	POWER_SUPPLY_HEALTH_COOL,
 };
 
 enum {
@@ -122,6 +124,8 @@
 	POWER_SUPPLY_PROP_CAPACITY, /* in percents! */
 	POWER_SUPPLY_PROP_CAPACITY_LEVEL,
 	POWER_SUPPLY_PROP_TEMP,
+	POWER_SUPPLY_PROP_COOL_TEMP,
+	POWER_SUPPLY_PROP_WARM_TEMP,
 	POWER_SUPPLY_PROP_TEMP_AMBIENT,
 	POWER_SUPPLY_PROP_TIME_TO_EMPTY_NOW,
 	POWER_SUPPLY_PROP_TIME_TO_EMPTY_AVG,
diff --git a/include/linux/qpnp-revid.h b/include/linux/qpnp-revid.h
new file mode 100644
index 0000000..3cf9f1c
--- /dev/null
+++ b/include/linux/qpnp-revid.h
@@ -0,0 +1,111 @@
+/* Copyright (c) 2013, The Linux Foundation. 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 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#ifndef __QPNP_REVID
+#define __QPNP_REVID
+
+#define PM8226_V2P1_REV1	0x00
+#define PM8226_V2P1_REV2	0x00
+#define PM8226_V2P1_REV3	0x01
+#define PM8226_V2P1_REV4	0x02
+#define PM8226_V2P1_TYPE	0x51
+#define PM8226_V2P1_SUBTYPE	0x04
+
+#define PM8226_V2P0_REV1	0x00
+#define PM8226_V2P0_REV2	0x00
+#define PM8226_V2P0_REV3	0x00
+#define PM8226_V2P0_REV4	0x02
+#define PM8226_V2P0_TYPE	0x51
+#define PM8226_V2P0_SUBTYPE	0x04
+
+#define PM8226_V1P0_REV1	0x00
+#define PM8226_V1P0_REV2	0x00
+#define PM8226_V1P0_REV3	0x00
+#define PM8226_V1P0_REV4	0x00
+#define PM8226_V1P0_TYPE	0x51
+#define PM8226_V1P0_SUBTYPE	0x04
+
+#define PM8941_V1P0_REV1	0x00
+#define PM8941_V1P0_REV2	0x00
+#define PM8941_V1P0_REV3	0x00
+#define PM8941_V1P0_REV4	0x01
+#define PM8941_V1P0_TYPE	0x51
+#define PM8941_V1P0_SUBTYPE	0x01
+
+#define PM8941_V2P0_REV1	0x00
+#define PM8941_V2P0_REV2	0x00
+#define PM8941_V2P0_REV3	0x00
+#define PM8941_V2P0_REV4	0x01
+#define PM8941_V2P0_TYPE	0x51
+#define PM8941_V2P0_SUBTYPE	0x01
+
+#define PM8941_V3P0_REV1	0x00
+#define PM8941_V3P0_REV2	0x00
+#define PM8941_V3P0_REV3	0x00
+#define PM8941_V3P0_REV4	0x03
+#define PM8941_V3P0_TYPE	0x51
+#define PM8941_V3P0_SUBTYPE	0x01
+
+#define PM8941_V3P1_REV1	0x00
+#define PM8941_V3P1_REV2	0x00
+#define PM8941_V3P1_REV3	0x01
+#define PM8941_V3P1_REV4	0x03
+#define PM8941_V3P1_TYPE	0x51
+#define PM8941_V3P1_SUBTYPE	0x01
+
+#define PM8110_V1P0_REV1	0x00
+#define PM8110_V1P0_REV2	0x00
+#define PM8110_V1P0_REV3	0x00
+#define PM8110_V1P0_REV4	0x01
+#define PM8110_V1P0_TYPE	0x51
+#define PM8110_V1P0_SUBTYPE	0x05
+
+#define PM8110_V1P1_REV1	0x00
+#define PM8110_V1P1_REV2	0x01
+#define PM8110_V1P1_REV3	0x00
+#define PM8110_V1P1_REV4	0x01
+#define PM8110_V1P1_TYPE	0x51
+#define PM8110_V1P1_SUBTYPE	0x05
+
+#define PM8110_V1P3_REV1	0x00
+#define PM8110_V1P3_REV2	0x03
+#define PM8110_V1P3_REV3	0x00
+#define PM8110_V1P3_REV4	0x01
+#define PM8110_V1P3_TYPE	0x51
+#define PM8110_V1P3_SUBTYPE	0x05
+
+#define PM8110_V2P0_REV1	0x00
+#define PM8110_V2P0_REV2	0x00
+#define PM8110_V2P0_REV3	0x00
+#define PM8110_V2P0_REV4	0x02
+#define PM8110_V2P0_TYPE	0x51
+#define PM8110_V2P0_SUBTYPE	0x05
+
+struct pmic_revid_data {
+	u8	rev1;
+	u8	rev2;
+	u8	rev3;
+	u8	rev4;
+	u8	pmic_type;
+	u8	pmic_subtype;
+};
+
+#ifdef CONFIG_QPNP_REVID
+struct pmic_revid_data *get_revid_data(struct device_node *dev_node);
+#else
+static inline
+struct pmic_revid_data *get_revid_data(struct device_node *dev_node)
+{
+	return NULL;
+}
+#endif
+#endif
diff --git a/include/linux/qpnp/qpnp-adc.h b/include/linux/qpnp/qpnp-adc.h
index a9e13d5..6e711c2 100644
--- a/include/linux/qpnp/qpnp-adc.h
+++ b/include/linux/qpnp/qpnp-adc.h
@@ -143,6 +143,12 @@
 /* Structure device for qpnp vadc */
 struct qpnp_vadc_chip;
 
+/* Structure device for qpnp iadc */
+struct qpnp_iadc_chip;
+
+/* Structure device for qpnp adc tm */
+struct qpnp_adc_tm_chip;
+
 /**
  * enum qpnp_adc_decimation_type - Sampling rate supported.
  * %DECIMATION_TYPE1: 512
@@ -212,6 +218,8 @@
  *				 Uses a mapping table with 150K pullup.
  * %SCALE_QRD_BATT_THERM: Conversion to temperature(decidegC) based on
  *			btm parameters.
+ * %SCALE_QRD_SKUAA_BATT_THERM: Conversion to temperature(decidegC) based on
+ *          btm parametersi for SKUAA.
  * %SCALE_NONE: Do not use this scaling type.
  */
 enum qpnp_adc_scale_fn_type {
@@ -222,6 +230,7 @@
 	SCALE_XOTHERM,
 	SCALE_THERM_150K_PULLUP,
 	SCALE_QRD_BATT_THERM,
+	SCALE_QRD_SKUAA_BATT_THERM,
 	SCALE_NONE,
 };
 
@@ -606,6 +615,21 @@
 	QPNP_ADC_TM_CH_SELECT_NONE
 };
 
+/**
+ * Channel index for the corresponding index to qpnp_adc_tm_channel_selec
+ */
+enum qpnp_adc_tm_channel_num {
+	QPNP_ADC_TM_CHAN0 = 0,
+	QPNP_ADC_TM_CHAN1,
+	QPNP_ADC_TM_CHAN2,
+	QPNP_ADC_TM_CHAN3,
+	QPNP_ADC_TM_CHAN4,
+	QPNP_ADC_TM_CHAN5,
+	QPNP_ADC_TM_CHAN6,
+	QPNP_ADC_TM_CHAN7,
+	QPNP_ADC_TM_CHAN_NONE
+};
+
 enum qpnp_comp_scheme_type {
 	COMP_ID_GF = 0,
 	COMP_ID_SMIC,
@@ -613,27 +637,6 @@
 	COMP_ID_NUM,
 };
 
-enum qpnp_iadc_rev {
-	QPNP_IADC_VER_3_0 = 0x1,
-	QPNP_IADC_VER_3_1 = 0x3,
-};
-
-#define QPNP_VBAT_SNS_COEFF_1_TYPEA				3000
-#define QPNP_VBAT_SNS_COEFF_2_TYPEA				45810000
-#define QPNP_VBAT_SNS_COEFF_3					100000
-#define QPNP_VBAT_SNS_COEFF_1_TYPEB				3500
-#define QPNP_VBAT_SNS_COEFF_2_TYPEB				80000000
-
-#define QPNP_COEFF_1					969000
-#define QPNP_COEFF_2					34
-#define QPNP_COEFF_3_TYPEA				1700000
-#define QPNP_COEFF_3_TYPEB				1000000
-#define QPNP_COEFF_4					100
-#define QPNP_COEFF_5					15000
-#define QPNP_COEFF_6					100000
-#define QPNP_COEFF_7					21700
-#define QPNP_COEFF_8					100000000
-
 /**
  * struct qpnp_adc_tm_config - Represent ADC Thermal Monitor configuration.
  * @channel: ADC channel for which thermal monitoring is requested.
@@ -1115,6 +1118,23 @@
 			const struct qpnp_vadc_chan_properties *chan_prop,
 			struct qpnp_vadc_result *chan_rslt);
 /**
+ * qpnp_adc_scale_qrd_skuaa_batt_therm() - Scales the pre-calibrated digital output
+ *		of an ADC to the ADC reference and compensates for the
+ *		gain and offset. Returns the temperature in decidegC.
+ * @dev:	Structure device for qpnp vadc
+ * @adc_code:	pre-calibrated digital ouput of the ADC.
+ * @adc_prop:	adc properties of the pm8xxx adc such as bit resolution,
+ *		reference voltage.
+ * @chan_prop:	individual channel properties to compensate the i/p scaling,
+ *		slope and offset.
+ * @chan_rslt:	physical result to be stored.
+ */
+int32_t qpnp_adc_scale_qrd_skuaa_batt_therm(struct qpnp_vadc_chip *dev,
+			int32_t adc_code,
+			const struct qpnp_adc_properties *adc_prop,
+			const struct qpnp_vadc_chan_properties *chan_prop,
+			struct qpnp_vadc_result *chan_rslt);
+/**
  * qpnp_adc_scale_batt_id() - Scales the pre-calibrated digital output
  *		of an ADC to the ADC reference and compensates for the
  *		gain and offset.
@@ -1360,7 +1380,13 @@
 			struct qpnp_vadc_chip *vadc, int32_t adc_code,
 			const struct qpnp_adc_properties *adc_prop,
 			const struct qpnp_vadc_chan_properties *chan_prop,
-			struct qpnp_vadc_result *chan_rslt);
+			struct qpnp_vadc_result *chan_rslt)
+{ return -ENXIO; }
+static inline int32_t qpnp_adc_scale_qrd_skuaa_batt_therm(
+			struct qpnp_vadc_chip *vadc, int32_t adc_code,
+			const struct qpnp_adc_properties *adc_prop,
+			const struct qpnp_vadc_chan_properties *chan_prop,
+			struct qpnp_vadc_result *chan_rslt)
 { return -ENXIO; }
 static inline int32_t qpnp_adc_scale_batt_id(struct qpnp_vadc_chip *vadc,
 			int32_t adc_code,
@@ -1436,44 +1462,59 @@
 			|| defined(CONFIG_SENSORS_QPNP_ADC_CURRENT_MODULE)
 /**
  * qpnp_iadc_read() - Performs ADC read on the current channel.
+ * @dev:	Structure device for qpnp iadc
  * @channel:	Input channel to perform the ADC read.
  * @result:	Current across rsense in mA.
+ * @return:	0 on success.
  */
-int32_t qpnp_iadc_read(enum qpnp_iadc_channels channel,
+int32_t qpnp_iadc_read(struct qpnp_iadc_chip *dev,
+				enum qpnp_iadc_channels channel,
 				struct qpnp_iadc_result *result);
 /**
  * qpnp_iadc_get_rsense() - Reads the RDS resistance value from the
 			trim registers.
+ * @dev:	Structure device for qpnp iadc
  * @rsense:	RDS resistance in nOhms.
+ * @return:	0 on success.
  */
-int32_t qpnp_iadc_get_rsense(int32_t *rsense);
+int32_t qpnp_iadc_get_rsense(struct qpnp_iadc_chip *dev, int32_t *rsense);
 /**
  * qpnp_iadc_get_gain_and_offset() - Performs gain calibration
  *				over 17.8571mV and offset over selected
  *				channel. Channel can be internal rsense,
  *				external rsense and alternate lead pair.
+ * @dev:	Structure device for qpnp iadc
  * @result:	result structure where the gain and offset is stored of
  *		type qpnp_iadc_calib.
+ * @return:	0 on success.
  */
-int32_t qpnp_iadc_get_gain_and_offset(struct qpnp_iadc_calib *result);
+int32_t qpnp_iadc_get_gain_and_offset(struct qpnp_iadc_chip *dev,
+					struct qpnp_iadc_calib *result);
 /**
- * qpnp_iadc_is_ready() - Clients can use this API to check if the
- *			  device is ready to use.
- * @result:	0 on success and -EPROBE_DEFER when probe for the device
- *		has not occured.
+ * qpnp_get_iadc() - Clients need to register with the iadc with the
+ *		corresponding device instance it wants to read the channels.
+ *		Read the bindings document on how to pass the phandle for
+ *		the corresponding vadc driver to register with.
+ * @dev:	Clients device structure
+ * @name:	Corresponding client's DT parser name. Read the DT bindings
+ *		document on how to register with the iadc
+ * @struct qpnp_iadc_chip * - On success returns the iadc device structure
+ *		pointer used everytime client makes an ADC request.
  */
-int32_t qpnp_iadc_is_ready(void);
+struct qpnp_iadc_chip *qpnp_get_iadc(struct device *dev, const char *name);
 /**
  * qpnp_iadc_vadc_sync_read() - Performs synchronous VADC and IADC read.
  *		The api is to be used only by the BMS to perform
  *		simultaneous VADC and IADC measurement for battery voltage
  *		and current.
+ * @dev:	Structure device for qpnp iadc
  * @i_channel:	Input battery current channel to perform the IADC read.
  * @i_result:	Current across the rsense in mA.
  * @v_channel:	Input battery voltage channel to perform VADC read.
  * @v_result:	Voltage on the vbatt channel with units in mV.
+ * @return:	0 on success.
  */
-int32_t qpnp_iadc_vadc_sync_read(
+int32_t qpnp_iadc_vadc_sync_read(struct qpnp_iadc_chip *dev,
 	enum qpnp_iadc_channels i_channel, struct qpnp_iadc_result *i_result,
 	enum qpnp_vadc_channels v_channel, struct qpnp_vadc_result *v_result);
 /**
@@ -1481,31 +1522,60 @@
  *		IADC. The offset and gain values are programmed in the trim
  *		registers. The offset and the gain can be retrieved using
  *		qpnp_iadc_get_gain_and_offset
+ * @dev:	Structure device for qpnp iadc
  * @batfet_closed: batfet is opened or closed. The IADC chooses proper
  *			channel (internal/external) based on batfet status
  *			for calibration.
  * RETURNS:	0 on success.
  */
-int32_t qpnp_iadc_calibrate_for_trim(bool batfet_closed);
-int32_t qpnp_iadc_comp_result(int64_t *result);
+int32_t qpnp_iadc_calibrate_for_trim(struct qpnp_iadc_chip *dev,
+						bool batfet_closed);
+/**
+ * qpnp_iadc_comp_result() - Compensates the result of the current based on
+ *		the gain and offset co-effients and rsense parameters.
+ * @dev:	Structure device for qpnp iadc
+ * @result:	Current value to perform the compensation.
+ * @return:	0 on success.
+ */
+int32_t qpnp_iadc_comp_result(struct qpnp_iadc_chip *dev, int64_t *result);
+/**
+ * qpnp_iadc_skip_calibration() - Clients can use this API to ask the driver
+ *				to skip iadc calibrations
+ * @dev:	Structure device for qpnp iadc
+ * @result:	0 on success and -EPROBE_DEFER when probe for the device
+ *		has not occured.
+ */
+int qpnp_iadc_skip_calibration(struct qpnp_iadc_chip *dev);
+/**
+ * qpnp_iadc_resume_calibration() - Clients can use this API to ask the driver
+ *				to resume iadc calibrations
+ * @dev:	Structure device for qpnp iadc
+ * @result:	0 on success and -EPROBE_DEFER when probe for the device
+ *		has not occured.
+ */
+int qpnp_iadc_resume_calibration(struct qpnp_iadc_chip *dev);
 #else
-static inline int32_t qpnp_iadc_read(enum qpnp_iadc_channels channel,
-						struct qpnp_iadc_result *result)
+static inline int32_t qpnp_iadc_read(struct qpnp_iadc_chip *iadc,
+	enum qpnp_iadc_channels channel, struct qpnp_iadc_result *result)
 { return -ENXIO; }
-static inline int32_t qpnp_iadc_get_rsense(int32_t *rsense)
+static inline int32_t qpnp_iadc_get_rsense(struct qpnp_iadc_chip *iadc,
+							int32_t *rsense)
 { return -ENXIO; }
-static inline int32_t qpnp_iadc_get_gain_and_offset(struct qpnp_iadc_calib
-									*result)
+static inline int32_t qpnp_iadc_get_gain_and_offset(struct qpnp_iadc_chip *iadc,
+				struct qpnp_iadc_calib *result)
 { return -ENXIO; }
-static inline int32_t qpnp_iadc_is_ready(void)
-{ return -ENXIO; }
-static inline int32_t qpnp_iadc_vadc_sync_read(
+static inline struct qpnp_iadc_chip *qpnp_get_iadc(struct device *dev,
+							const char *name)
+{ return ERR_PTR(-ENXIO); }
+static inline int32_t qpnp_iadc_vadc_sync_read(struct qpnp_iadc_chip *iadc,
 	enum qpnp_iadc_channels i_channel, struct qpnp_iadc_result *i_result,
 	enum qpnp_vadc_channels v_channel, struct qpnp_vadc_result *v_result)
 { return -ENXIO; }
-static inline int32_t qpnp_iadc_calibrate_for_trim(bool batfet_closed)
+static inline int32_t qpnp_iadc_calibrate_for_trim(struct qpnp_iadc_chip *iadc,
+							bool batfet_closed)
 { return -ENXIO; }
-static inline int32_t qpnp_iadc_comp_result(int64_t *result, int32_t sign)
+static inline int32_t qpnp_iadc_comp_result(struct qpnp_iadc_chip *iadc,
+						int64_t *result, int32_t sign)
 { return -ENXIO; }
 #endif
 
@@ -1522,14 +1592,15 @@
  *		Clients pass the low/high voltage along with the threshold
  *		notification callback.
  */
-int32_t qpnp_adc_tm_usbid_configure(struct qpnp_adc_tm_btm_param *param);
+int32_t qpnp_adc_tm_usbid_configure(struct qpnp_adc_tm_chip *chip,
+					struct qpnp_adc_tm_btm_param *param);
 /**
  * qpnp_adc_tm_usbid_end() - Disables the monitoring of channel 0 thats
  *		assigned for monitoring USB_ID. Disables the low/high
  *		threshold activation for channel 0 as well.
  * @param:	none.
  */
-int32_t qpnp_adc_tm_usbid_end(void);
+int32_t qpnp_adc_tm_usbid_end(struct qpnp_adc_tm_chip *chip);
 /**
  * qpnp_adc_tm_channel_measure() - Configures kernel clients a channel to
  *		monitor the corresponding ADC channel for threshold detection.
@@ -1540,7 +1611,8 @@
  *		Clients pass the low/high temperature along with the threshold
  *		notification callback.
  */
-int32_t qpnp_adc_tm_channel_measure(struct qpnp_adc_tm_btm_param *param);
+int32_t qpnp_adc_tm_channel_measure(struct qpnp_adc_tm_chip *chip,
+					struct qpnp_adc_tm_btm_param *param);
 /**
  * qpnp_adc_tm_disable_chan_meas() - Disables the monitoring of channel thats
  *		assigned for monitoring kernel clients. Disables the low/high
@@ -1549,45 +1621,36 @@
  *		This is used to identify the channel for which the corresponding
  *		channels high/low threshold notification will be disabled.
  */
-int32_t qpnp_adc_tm_disable_chan_meas(struct qpnp_adc_tm_btm_param *param);
+int32_t qpnp_adc_tm_disable_chan_meas(struct qpnp_adc_tm_chip *chip,
+					struct qpnp_adc_tm_btm_param *param);
 /**
- * qpnp_adc_tm_is_ready() - Clients can use this API to check if the
- *			  device is ready to use.
- * @result:	0 on success and -EPROBE_DEFER when probe for the device
- *		has not occured.
+ * qpnp_get_adc_tm() - Clients need to register with the adc_tm using the
+ *		corresponding device instance it wants to read the channels
+ *		from. Read the bindings document on how to pass the phandle
+ *		for the corresponding adc_tm driver to register with.
+ * @name:	Corresponding client's DT parser name. Read the DT bindings
+ *		document on how to register with the vadc
+ * @struct qpnp_adc_tm_chip * - On success returns the vadc device structure
+ *		pointer that needs to be used during an ADC TM request.
  */
-int32_t	qpnp_adc_tm_is_ready(void);
-/**
- * qpnp_iadc_skip_calibration() - Clients can use this API to ask the driver
- *				to skip iadc calibrations
- * @result:	0 on success and -EPROBE_DEFER when probe for the device
- *		has not occured.
- */
-int qpnp_iadc_skip_calibration(void);
-/**
- * qpnp_iadc_resume_calibration() - Clients can use this API to ask the driver
- *				to resume iadc calibrations
- * @result:	0 on success and -EPROBE_DEFER when probe for the device
- *		has not occured.
- */
-int qpnp_iadc_resume_calibration(void);
+struct qpnp_adc_tm_chip *qpnp_get_adc_tm(struct device *dev, const char *name);
 #else
 static inline int32_t qpnp_adc_tm_usbid_configure(
+			struct qpnp_adc_tm_chip *chip,
 			struct qpnp_adc_tm_btm_param *param)
 { return -ENXIO; }
-static inline int32_t qpnp_adc_tm_usbid_end(void)
+static inline int32_t qpnp_adc_tm_usbid_end(struct qpnp_adc_tm_chip *chip)
 { return -ENXIO; }
 static inline int32_t qpnp_adc_tm_channel_measure(
-		struct qpnp_adc_tm_btm_param *param)
+					struct qpnp_adc_tm_chip *chip,
+					struct qpnp_adc_tm_btm_param *param)
 { return -ENXIO; }
-static inline int32_t qpnp_adc_tm_disable_chan_meas(void)
+static inline int32_t qpnp_adc_tm_disable_chan_meas(
+					struct qpnp_adc_tm_chip *chip)
 { return -ENXIO; }
-static inline int32_t qpnp_adc_tm_is_ready(void)
-{ return -ENXIO; }
-static inline int qpnp_iadc_skip_calibration(void)
-{ return -ENXIO; }
-static inline int qpnp_iadc_resume_calibration(void);
-{ return -ENXIO; }
+static inline struct qpnp_adc_tm_chip *qpnp_get_adc_tm(struct device *dev,
+							const char *name)
+{ return ERR_PTR(-ENXIO); }
 #endif
 
 #endif
diff --git a/include/linux/security.h b/include/linux/security.h
index 673afbb..b62f396 100644
--- a/include/linux/security.h
+++ b/include/linux/security.h
@@ -1381,6 +1381,11 @@
 struct security_operations {
 	char name[SECURITY_NAME_MAX + 1];
 
+	int (*binder_set_context_mgr) (struct task_struct *mgr);
+	int (*binder_transaction) (struct task_struct *from, struct task_struct *to);
+	int (*binder_transfer_binder) (struct task_struct *from, struct task_struct *to);
+	int (*binder_transfer_file) (struct task_struct *from, struct task_struct *to, struct file *file);
+
 	int (*ptrace_access_check) (struct task_struct *child, unsigned int mode);
 	int (*ptrace_traceme) (struct task_struct *parent);
 	int (*capget) (struct task_struct *target,
@@ -1664,6 +1669,10 @@
 
 
 /* Security operations */
+int security_binder_set_context_mgr(struct task_struct *mgr);
+int security_binder_transaction(struct task_struct *from, struct task_struct *to);
+int security_binder_transfer_binder(struct task_struct *from, struct task_struct *to);
+int security_binder_transfer_file(struct task_struct *from, struct task_struct *to, struct file *file);
 int security_ptrace_access_check(struct task_struct *child, unsigned int mode);
 int security_ptrace_traceme(struct task_struct *parent);
 int security_capget(struct task_struct *target,
@@ -1842,6 +1851,26 @@
 	return 0;
 }
 
+static inline int security_binder_set_context_mgr(struct task_struct *mgr)
+{
+	return 0;
+}
+
+static inline int security_binder_transaction(struct task_struct *from, struct task_struct *to)
+{
+	return 0;
+}
+
+static inline int security_binder_transfer_binder(struct task_struct *from, struct task_struct *to)
+{
+	return 0;
+}
+
+static inline int security_binder_transfer_file(struct task_struct *from, struct task_struct *to, struct file *file)
+{
+	return 0;
+}
+
 static inline int security_ptrace_access_check(struct task_struct *child,
 					     unsigned int mode)
 {
diff --git a/include/linux/slimbus/slimbus.h b/include/linux/slimbus/slimbus.h
index 132135e..cba4394 100644
--- a/include/linux/slimbus/slimbus.h
+++ b/include/linux/slimbus/slimbus.h
@@ -581,6 +581,11 @@
  * @shutdown: Standard shutdown callback used during powerdown/halt.
  * @suspend: Standard suspend callback used during system suspend
  * @resume: Standard resume callback used during system resume
+ * @device_up: This callback is called when the device reports present and
+ *		gets a logical address assigned to it
+ * @device_down: This callback is called when device reports absent, or the
+ *		bus goes down. Device will report present when bus is up and
+ *		device_up callback will be called again when that happens
  * @driver: Slimbus device drivers should initialize name and owner field of
  *	this structure
  * @id_table: List of slimbus devices supported by this driver
@@ -593,6 +598,8 @@
 					pm_message_t pmesg);
 	int				(*resume)(struct slim_device *sldev);
 	int				(*device_up)(struct slim_device *sldev);
+	int				(*device_down)
+						(struct slim_device *sldev);
 
 	struct device_driver		driver;
 	const struct slim_device_id	*id_table;
@@ -1022,6 +1029,13 @@
 				u8 e_len, u8 *laddr, bool valid);
 
 /*
+ * slim_report_absent: Controller calls this function when a device
+ *	reports absent, OR when the device cannot be communicated with
+ * @sbdev: Device that cannot be reached, or that sent report absent
+ */
+void slim_report_absent(struct slim_device *sbdev);
+
+/*
  * slim_msg_response: Deliver Message response received from a device to the
  *	framework.
  * @ctrl: Controller handle
diff --git a/include/linux/smsc3503.h b/include/linux/smsc_hub.h
similarity index 90%
rename from include/linux/smsc3503.h
rename to include/linux/smsc_hub.h
index 1e28a58..9c0afc0 100644
--- a/include/linux/smsc3503.h
+++ b/include/linux/smsc_hub.h
@@ -14,6 +14,12 @@
 #ifndef __LINUX_SMSC3503_H__
 #define __LINUX_SMSC3503_H__
 
+#define SMSC3503_ID	3503
+#define SMSC4604_ID	4604
+#define SMSC3503_I2C_ADDR	0x08
+#define SMSC4604_I2C_ADDR	0x2d
+#define SMSC_GSBI_I2C_BUS_ID	0
+
 /*Serial interface Registers*/
 #define SMSC3503_VENDORID	0x00 /*u16 read*/
 #define SMSC3503_PRODUCTID	0x02 /*u16 read*/
@@ -42,6 +48,7 @@
 #define OCSPINSEL	(1<<5)
 
 struct smsc_hub_platform_data {
+	u32 model_id;
 	int hub_reset;
 	int refclk_gpio;
 	int int_gpio;
diff --git a/include/linux/stk3x1x.h b/include/linux/stk3x1x.h
index c34116a..6dd446c 100644
--- a/include/linux/stk3x1x.h
+++ b/include/linux/stk3x1x.h
@@ -1,29 +1,30 @@
-/*

- *

- * $Id: stk3x1x.h

- *

- * Copyright (C) 2012 Lex Hsieh     <lex_hsieh@sitronix.com.tw>

- *

- * This file is subject to the terms and conditions of the GNU General Public

- * License.  See the file COPYING in the main directory of this archive for

- * more details.

- *

- */

-#ifndef __STK3X1X_H__

-#define __STK3X1X_H__

-

-/* platform data */

-struct stk3x1x_platform_data

-{

-	uint8_t state_reg;

-	uint8_t psctrl_reg;

-	uint8_t alsctrl_reg;

-	uint8_t ledctrl_reg;

-	uint8_t	wait_reg;

-	uint16_t ps_thd_h;

-	uint16_t ps_thd_l;

-	int int_pin;

-	uint32_t transmittance;

-};

-

-#endif // __STK3X1X_H__

+/*
+ *
+ * Id: stk3x1x.h
+ *
+ * Copyright (C) 2012 Lex Hsieh     <lex_hsieh@sitronix.com.tw>
+ *
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License.  See the file COPYING in the main directory of this archive for
+ * more details.
+ *
+ */
+#ifndef __STK3X1X_H__
+#define __STK3X1X_H__
+
+/* platform data */
+struct stk3x1x_platform_data {
+	uint8_t state_reg;
+	uint8_t psctrl_reg;
+	uint8_t alsctrl_reg;
+	uint8_t ledctrl_reg;
+	uint8_t wait_reg;
+	uint16_t ps_thd_h;
+	uint16_t ps_thd_l;
+	int int_pin;
+	uint32_t transmittance;
+	uint32_t int_flags;
+	bool use_fir;
+};
+
+#endif /* __STK3X1X_H__ */
diff --git a/include/linux/thermal.h b/include/linux/thermal.h
index f740640..1bb3b06 100644
--- a/include/linux/thermal.h
+++ b/include/linux/thermal.h
@@ -97,6 +97,27 @@
 				((long)t-2732+5)/10 : ((long)t-2732-5)/10)
 #define CELSIUS_TO_KELVIN(t)	((t)*10+2732)
 
+struct sensor_threshold {
+	int temp;
+	enum thermal_trip_type trip;
+	int (*notify)(enum thermal_trip_type type, int temp, void *data);
+	void *data;
+	struct list_head list;
+};
+
+struct sensor_info {
+	uint32_t sensor_id;
+	struct thermal_zone_device *tz;
+	int threshold_min;
+	int threshold_max;
+	int max_idx;
+	int min_idx;
+	struct list_head sensor_list;
+	struct list_head threshold_list;
+	struct mutex lock;
+	struct work_struct work;
+};
+
 struct thermal_zone_device {
 	int id;
 	char type[THERMAL_NAME_LENGTH];
@@ -116,6 +137,8 @@
 	struct mutex lock;	/* protect cooling devices list */
 	struct list_head node;
 	struct delayed_work poll_queue;
+	struct sensor_threshold tz_threshold[2];
+	struct sensor_info sensor;
 };
 /* Adding event notification support elements */
 #define THERMAL_GENL_FAMILY_NAME                "thermal_event"
@@ -163,6 +186,12 @@
 		const struct thermal_cooling_device_ops *);
 void thermal_cooling_device_unregister(struct thermal_cooling_device *);
 
+int sensor_get_id(char *name);
+int sensor_set_trip(uint32_t sensor_id, struct sensor_threshold *threshold);
+int sensor_cancel_trip(uint32_t sensor_id, struct sensor_threshold *threshold);
+int thermal_sensor_trip(struct thermal_zone_device *tz,
+		enum thermal_trip_type trip, unsigned long temp);
+
 #ifdef CONFIG_NET
 extern int thermal_generate_netlink_event(u32 orig, enum events event);
 #else
diff --git a/include/linux/tty.h b/include/linux/tty.h
index 6fcafa8..6a0259d 100644
--- a/include/linux/tty.h
+++ b/include/linux/tty.h
@@ -282,10 +282,8 @@
 	struct winsize winsize;		/* termios mutex */
 	unsigned char stopped:1, hw_stopped:1, flow_stopped:1, packet:1;
 	unsigned char low_latency:1, warned:1;
-	unsigned char update_room_in_ldisc:1;
 	unsigned char ctrl_status;	/* ctrl_lock */
 	unsigned int receive_room;	/* Bytes free for queue */
-	unsigned int rr_bug;
 
 	struct tty_struct *link;
 	struct fasync_struct *fasync;
diff --git a/include/linux/usb/android.h b/include/linux/usb/android.h
index 0b11fdaf..e17e978 100644
--- a/include/linux/usb/android.h
+++ b/include/linux/usb/android.h
@@ -24,6 +24,7 @@
 	u32 swfi_latency;
 	u8 usb_core_id;
 	bool cdrom;
+	bool internal_ums;
 };
 
 #ifndef CONFIG_TARGET_CORE
diff --git a/include/linux/usb/msm_hsusb.h b/include/linux/usb/msm_hsusb.h
index 8d104c6..f462b64 100644
--- a/include/linux/usb/msm_hsusb.h
+++ b/include/linux/usb/msm_hsusb.h
@@ -312,8 +312,8 @@
  * @async_irq: IRQ number used by some controllers during low power state
  * @clk: clock struct of alt_core_clk.
  * @pclk: clock struct of iface_clk.
- * @phy_reset_clk: clock struct of phy_clk.
  * @core_clk: clock struct of core_bus_clk.
+ * @sleep_clk: clock struct of sleep_clk for USB PHY.
  * @core_clk_rate: core clk max frequency
  * @regs: ioremapped register base address.
  * @inputs: OTG state machine inputs(Id, SessValid etc).
@@ -348,8 +348,8 @@
 	struct clk *xo_clk;
 	struct clk *clk;
 	struct clk *pclk;
-	struct clk *phy_reset_clk;
 	struct clk *core_clk;
+	struct clk *sleep_clk;
 	long core_clk_rate;
 	struct resource *io_res;
 	void __iomem *regs;
@@ -461,11 +461,20 @@
 	bool l1_supported;
 };
 
+/**
+ * struct msm_hsic_host_platform_data - platform device data
+ *              for msm_hsic_host driver.
+ * @phy_sof_workaround: Enable ALL PHY SOF bug related workarounds for
+		SUSPEND, RESET and RESUME.
+ * @phy_susp_sof_workaround: Enable PHY SOF workaround only for SUSPEND.
+ *
+ */
 struct msm_hsic_host_platform_data {
 	unsigned strobe;
 	unsigned data;
 	bool ignore_cal_pad_config;
 	bool phy_sof_workaround;
+	bool phy_susp_sof_workaround;
 	u32 reset_delay;
 	int strobe_pad_offset;
 	int data_pad_offset;
@@ -554,6 +563,7 @@
 #ifdef CONFIG_USB_DWC3_MSM
 int msm_ep_config(struct usb_ep *ep);
 int msm_ep_unconfig(struct usb_ep *ep);
+void dwc3_tx_fifo_resize_request(struct usb_ep *ep, bool qdss_enable);
 int msm_data_fifo_config(struct usb_ep *ep, u32 addr, u32 size,
 	u8 dst_pipe_idx);
 
@@ -577,6 +587,12 @@
 	return -ENODEV;
 }
 
+static inline void dwc3_tx_fifo_resize_request(
+					struct usb_ep *ep, bool qdss_enable)
+{
+	return;
+}
+
 static inline void msm_dwc3_restart_usb_session(struct usb_gadget *gadget)
 {
 	return;
diff --git a/include/linux/usb/msm_hsusb_hw.h b/include/linux/usb/msm_hsusb_hw.h
index 064d210..58ab4eb 100644
--- a/include/linux/usb/msm_hsusb_hw.h
+++ b/include/linux/usb/msm_hsusb_hw.h
@@ -84,6 +84,9 @@
 #define PHY_IDHV_INTEN          (1 << 8) /* PHY ID HV interrupt */
 #define PHY_OTGSESSVLDHV_INTEN  (1 << 9) /* PHY Session Valid HV int. */
 #define PHY_CLAMP_DPDMSE_EN	(1 << 21) /* PHY mpm DP DM clamp enable */
+#define PHY_POR_BIT_MASK	BIT(0)
+#define PHY_POR_ASSERT		(1 << 0) /* USB2 28nm PHY POR ASSERT */
+#define PHY_POR_DEASSERT	(0 << 0) /* USB2 28nm PHY POR DEASSERT */
 
 #define STS_PCI                 (1 << 2) /* R/WC - Port Change Detect */
 #define STS_URI                 (1 << 6) /* R/WC - RESET recv'd */
diff --git a/include/linux/videodev2.h b/include/linux/videodev2.h
index 101325e..e1c096b 100644
--- a/include/linux/videodev2.h
+++ b/include/linux/videodev2.h
@@ -403,6 +403,7 @@
 #define V4L2_PIX_FMT_DIVX      v4l2_fourcc('D', 'I', 'V', 'X') /* DIVX        */
 #define V4L2_PIX_FMT_VP8 v4l2_fourcc('V', 'P', '8', '0') /* ON2 VP8 stream */
 #define V4L2_PIX_FMT_HEVC v4l2_fourcc('H', 'E', 'V', 'C') /* for HEVC stream */
+#define V4L2_PIX_FMT_HEVC_HYBRID v4l2_fourcc('H', 'V', 'C', 'H')
 
 /*  Vendor-specific formats   */
 #define V4L2_PIX_FMT_CPIA1    v4l2_fourcc('C', 'P', 'I', 'A') /* cpia1 YUV */
@@ -705,6 +706,7 @@
 #define V4L2_QCOM_BUF_DATA_CORRUPT 0x80000
 #define V4L2_QCOM_BUF_DROP_FRAME 0x100000
 #define V4L2_QCOM_BUF_INPUT_UNSUPPORTED 0x200000
+#define V4L2_QCOM_BUF_FLAG_EOS          0x2000
 
 /*
  *	O V E R L A Y   P R E V I E W
@@ -1551,6 +1553,7 @@
 	V4L2_MPEG_VIDEO_H264_LEVEL_4_2	= 13,
 	V4L2_MPEG_VIDEO_H264_LEVEL_5_0	= 14,
 	V4L2_MPEG_VIDEO_H264_LEVEL_5_1	= 15,
+	V4L2_MPEG_VIDEO_H264_LEVEL_5_2	= 16,
 };
 #define V4L2_CID_MPEG_VIDEO_H264_LOOP_FILTER_ALPHA	(V4L2_CID_MPEG_BASE+360)
 #define V4L2_CID_MPEG_VIDEO_H264_LOOP_FILTER_BETA	(V4L2_CID_MPEG_BASE+361)
@@ -1874,6 +1877,16 @@
 	V4L2_MPEG_VIDC_FRAME_ASSEMBLY_ENABLE	= 1,
 };
 
+#define V4L2_CID_MPEG_VIDC_VIDEO_VP8_PROFILE_LEVEL \
+		(V4L2_CID_MPEG_MSM_VIDC_BASE+32)
+enum v4l2_mpeg_vidc_video_vp8_profile_level {
+	V4L2_MPEG_VIDC_VIDEO_VP8_UNUSED,
+	V4L2_MPEG_VIDC_VIDEO_VP8_VERSION_0,
+	V4L2_MPEG_VIDC_VIDEO_VP8_VERSION_1,
+	V4L2_MPEG_VIDC_VIDEO_VP8_VERSION_2,
+	V4L2_MPEG_VIDC_VIDEO_VP8_VERSION_3,
+};
+
 /*  Camera class control IDs */
 #define V4L2_CID_CAMERA_CLASS_BASE 	(V4L2_CTRL_CLASS_CAMERA | 0x900)
 #define V4L2_CID_CAMERA_CLASS 		(V4L2_CTRL_CLASS_CAMERA | 1)
diff --git a/include/media/msm_cam_sensor.h b/include/media/msm_cam_sensor.h
index 2805401..540fd2c 100644
--- a/include/media/msm_cam_sensor.h
+++ b/include/media/msm_cam_sensor.h
@@ -52,6 +52,7 @@
 	MSM_CAMERA_I2C_BYTE_ADDR = 1,
 	MSM_CAMERA_I2C_WORD_ADDR,
 	MSM_CAMERA_I2C_3B_ADDR,
+	MSM_CAMERA_I2C_ADDR_TYPE_MAX,
 };
 
 enum msm_camera_i2c_data_type {
@@ -62,6 +63,7 @@
 	MSM_CAMERA_I2C_SET_WORD_MASK,
 	MSM_CAMERA_I2C_UNSET_WORD_MASK,
 	MSM_CAMERA_I2C_SET_BYTE_WRITE_MASK_DATA,
+	MSM_CAMERA_I2C_DATA_TYPE_MAX,
 };
 
 enum msm_sensor_power_seq_type_t {
@@ -122,6 +124,62 @@
 	SUB_MODULE_MAX,
 };
 
+enum {
+	MSM_CAMERA_EFFECT_MODE_OFF,
+	MSM_CAMERA_EFFECT_MODE_MONO,
+	MSM_CAMERA_EFFECT_MODE_NEGATIVE,
+	MSM_CAMERA_EFFECT_MODE_SOLARIZE,
+	MSM_CAMERA_EFFECT_MODE_SEPIA,
+	MSM_CAMERA_EFFECT_MODE_POSTERIZE,
+	MSM_CAMERA_EFFECT_MODE_WHITEBOARD,
+	MSM_CAMERA_EFFECT_MODE_BLACKBOARD,
+	MSM_CAMERA_EFFECT_MODE_AQUA,
+	MSM_CAMERA_EFFECT_MODE_EMBOSS,
+	MSM_CAMERA_EFFECT_MODE_SKETCH,
+	MSM_CAMERA_EFFECT_MODE_NEON,
+	MSM_CAMERA_EFFECT_MODE_MAX
+};
+
+enum {
+	MSM_CAMERA_WB_MODE_AUTO,
+	MSM_CAMERA_WB_MODE_CUSTOM,
+	MSM_CAMERA_WB_MODE_INCANDESCENT,
+	MSM_CAMERA_WB_MODE_FLUORESCENT,
+	MSM_CAMERA_WB_MODE_WARM_FLUORESCENT,
+	MSM_CAMERA_WB_MODE_DAYLIGHT,
+	MSM_CAMERA_WB_MODE_CLOUDY_DAYLIGHT,
+	MSM_CAMERA_WB_MODE_TWILIGHT,
+	MSM_CAMERA_WB_MODE_SHADE,
+	MSM_CAMERA_WB_MODE_OFF,
+	MSM_CAMERA_WB_MODE_MAX
+};
+
+enum {
+	MSM_CAMERA_SCENE_MODE_OFF,
+	MSM_CAMERA_SCENE_MODE_AUTO,
+	MSM_CAMERA_SCENE_MODE_LANDSCAPE,
+	MSM_CAMERA_SCENE_MODE_SNOW,
+	MSM_CAMERA_SCENE_MODE_BEACH,
+	MSM_CAMERA_SCENE_MODE_SUNSET,
+	MSM_CAMERA_SCENE_MODE_NIGHT,
+	MSM_CAMERA_SCENE_MODE_PORTRAIT,
+	MSM_CAMERA_SCENE_MODE_BACKLIGHT,
+	MSM_CAMERA_SCENE_MODE_SPORTS,
+	MSM_CAMERA_SCENE_MODE_ANTISHAKE,
+	MSM_CAMERA_SCENE_MODE_FLOWERS,
+	MSM_CAMERA_SCENE_MODE_CANDLELIGHT,
+	MSM_CAMERA_SCENE_MODE_FIREWORKS,
+	MSM_CAMERA_SCENE_MODE_PARTY,
+	MSM_CAMERA_SCENE_MODE_NIGHT_PORTRAIT,
+	MSM_CAMERA_SCENE_MODE_THEATRE,
+	MSM_CAMERA_SCENE_MODE_ACTION,
+	MSM_CAMERA_SCENE_MODE_AR,
+	MSM_CAMERA_SCENE_MODE_FACE_PRIORITY,
+	MSM_CAMERA_SCENE_MODE_BARCODE,
+	MSM_CAMERA_SCENE_MODE_HDR,
+	MSM_CAMERA_SCENE_MODE_MAX
+};
+
 enum csid_cfg_type_t {
 	CSID_INIT,
 	CSID_CFG,
@@ -361,6 +419,12 @@
 	CFG_SET_SATURATION,
 	CFG_SET_CONTRAST,
 	CFG_SET_SHARPNESS,
+	CFG_SET_ISO,
+	CFG_SET_EXPOSURE_COMPENSATION,
+	CFG_SET_ANTIBANDING,
+	CFG_SET_BESTSHOT_MODE,
+	CFG_SET_EFFECT,
+	CFG_SET_WHITE_BALANCE,
 	CFG_SET_AUTOFOCUS,
 	CFG_CANCEL_AUTOFOCUS,
 };
diff --git a/include/media/msmb_isp.h b/include/media/msmb_isp.h
index ec8ec9a..23b19b5 100644
--- a/include/media/msmb_isp.h
+++ b/include/media/msmb_isp.h
@@ -225,6 +225,7 @@
 	VFE_READ_DMI_16BIT,
 	VFE_READ_DMI_32BIT,
 	VFE_READ_DMI_64BIT,
+	GET_SOC_HW_VER,
 };
 
 struct msm_vfe_cfg_cmd2 {
@@ -348,17 +349,10 @@
 	struct timeval timestamp;
 	/* Monotonic timestamp since bootup */
 	struct timeval mono_timestamp;
-	/* if pix is a src frame_id is from camif */
+	enum msm_vfe_input_src input_intf;
 	uint32_t frame_id;
 	union {
-		/* START_ACK, STOP_ACK */
-		struct msm_isp_stream_ack stream_ack;
-		/* REG_UPDATE_TRIGGER, bus over flow */
-		enum msm_vfe_input_src input_src;
-		/* stats notify */
 		struct msm_isp_stats_event stats;
-		/* IRQ_VIOLATION, STATS_OVER_FLOW, WM_OVER_FLOW */
-		uint32_t irq_status_mask;
 		struct msm_isp_buf_event buf_done;
 	} u; /* union can have max 52 bytes */
 };
diff --git a/include/media/msmb_ispif.h b/include/media/msmb_ispif.h
index 61dfd52..6417237 100644
--- a/include/media/msmb_ispif.h
+++ b/include/media/msmb_ispif.h
@@ -23,6 +23,7 @@
 	INTF_MAX
 };
 #define MAX_PARAM_ENTRIES (INTF_MAX * 2)
+#define MAX_CID_CH	8
 
 #define PIX0_MASK (1 << PIX0)
 #define PIX1_MASK (1 << PIX1)
diff --git a/include/media/radio-iris.h b/include/media/radio-iris.h
index 419e055..d28a8c0 100644
--- a/include/media/radio-iris.h
+++ b/include/media/radio-iris.h
@@ -627,7 +627,9 @@
 	FM_TRANS,
 	FM_RESET,
 	FM_CALIB,
-	FM_TURNING_OFF
+	FM_TURNING_OFF,
+	FM_RECV_TURNING_ON,
+	FM_TRANS_TURNING_ON,
 };
 
 enum emphasis_type {
diff --git a/include/net/cfg80211.h b/include/net/cfg80211.h
index fb2b57a..4ecadd8 100644
--- a/include/net/cfg80211.h
+++ b/include/net/cfg80211.h
@@ -3486,6 +3486,14 @@
 		       struct cfg80211_ft_event_params *ft_event);
 
 
+
+/**
+ * cfg80211_ap_stopped - notify userspace that AP mode stopped
+ * @netdev: network device
+ * @gfp: context flags
+ */
+void cfg80211_ap_stopped(struct net_device *netdev, gfp_t gfp);
+
 /* Logging, debugging and troubleshooting/diagnostic helpers. */
 
 /* wiphy_printk helpers, similar to dev_printk */
diff --git a/include/net/sock.h b/include/net/sock.h
index 5a0a58a..83e98f6 100644
--- a/include/net/sock.h
+++ b/include/net/sock.h
@@ -162,6 +162,7 @@
 	volatile unsigned char	skc_state;
 	unsigned char		skc_reuse;
 	int			skc_bound_dev_if;
+	int			padding[2];
 	union {
 		struct hlist_node	skc_bind_node;
 		struct hlist_nulls_node skc_portaddr_node;
diff --git a/include/sound/apr_audio-v2.h b/include/sound/apr_audio-v2.h
index 88fcf61..bbda72e 100644
--- a/include/sound/apr_audio-v2.h
+++ b/include/sound/apr_audio-v2.h
@@ -82,14 +82,15 @@
 */
 #define ADM_CMD_DEVICE_OPEN_V5                          0x00010326
 
-#define ADM_BIT_SHIFT_DEVICE_PERF_MODE_FLAG                           13
+/* Definition for a low latency stream session. */
+#define ADM_LOW_LATENCY_DEVICE_SESSION			0x2000
+
+/* Definition for a ultra low latency stream session. */
+#define ADM_ULTRA_LOW_LATENCY_DEVICE_SESSION		0x4000
 
 /* Definition for a legacy device session. */
 #define ADM_LEGACY_DEVICE_SESSION                                      0
 
-/* Definition for a low latency stream session. */
-#define ADM_LOW_LATENCY_DEVICE_SESSION                                 1
-
 /* Indicates that endpoint_id_2 is to be ignored.*/
 #define ADM_CMD_COPP_OPEN_END_POINT_ID_2_IGNORE				0xFFFF
 
@@ -1967,6 +1968,14 @@
 	 */
 } __packed;
 
+#define AFE_PARAM_ID_DEVICE_HW_DELAY     0x00010243
+#define AFE_API_VERSION_DEVICE_HW_DELAY  0x1
+
+struct afe_param_id_device_hw_delay_cfg {
+	uint32_t    device_hw_delay_minor_version;
+	uint32_t    delay_in_us;
+} __packed;
+
 union afe_port_config {
 	struct afe_param_id_pcm_cfg               pcm;
 	struct afe_param_id_i2s_cfg               i2s;
@@ -1975,6 +1984,7 @@
 	struct afe_param_id_rt_proxy_port_cfg     rtproxy;
 	struct afe_param_id_internal_bt_fm_cfg    int_bt_fm;
 	struct afe_param_id_pseudo_port_cfg       pseudo_port;
+	struct afe_param_id_device_hw_delay_cfg   hw_delay;
 } __packed;
 
 struct afe_audioif_config_command_no_payload {
@@ -2480,6 +2490,8 @@
 
 #define ASM_STREAM_POSTPROC_TOPO_ID_DEFAULT 0x00010BE4
 
+#define ASM_STREAM_POSTPROC_TOPO_ID_NONE 0x00010C68
+
 #define ASM_MEDIA_FMT_EVRCB_FS 0x00010BEF
 
 #define ASM_MEDIA_FMT_EVRCWB_FS 0x00010BF0
@@ -3816,11 +3828,12 @@
 #define ASM_STREAM_CMD_OPEN_WRITE_V2       0x00010D8F
 #define ASM_STREAM_CMD_OPEN_WRITE_V3       0x00010DB3
 
-#define ASM_SHIFT_STREAM_PERF_MODE_FLAG_IN_OPEN_WRITE                     28
+#define ASM_LOW_LATENCY_STREAM_SESSION				0x10000000
+
+#define ASM_ULTRA_LOW_LATENCY_STREAM_SESSION			0x20000000
 
 #define ASM_LEGACY_STREAM_SESSION                                      0
 
-#define ASM_LOW_LATENCY_STREAM_SESSION                                  1
 
 struct asm_stream_cmd_open_write_v3 {
 	struct apr_hdr			hdr;
@@ -4296,7 +4309,6 @@
 struct asm_aac_dual_mono_mapping_param {
 	struct apr_hdr							hdr;
 	struct asm_stream_cmd_set_encdec_param	encdec;
-	struct asm_enc_cfg_blk_param_v2			encblk;
 	u16    left_channel_sce;
 	u16    right_channel_sce;
 
diff --git a/include/sound/core.h b/include/sound/core.h
index bc05668..5b9969e 100644
--- a/include/sound/core.h
+++ b/include/sound/core.h
@@ -134,6 +134,9 @@
 	wait_queue_head_t shutdown_sleep;
 	struct device *dev;		/* device assigned to this card */
 	struct device *card_dev;	/* cardX object for sysfs */
+	int offline;			/* if this sound card is offline */
+	unsigned long offline_change;
+	wait_queue_head_t offline_poll_wait;
 
 #ifdef CONFIG_PM
 	unsigned int power_state;	/* power state */
@@ -295,6 +298,8 @@
 int snd_component_add(struct snd_card *card, const char *component);
 int snd_card_file_add(struct snd_card *card, struct file *file);
 int snd_card_file_remove(struct snd_card *card, struct file *file);
+void snd_card_change_online_state(struct snd_card *card, int online);
+bool snd_card_is_online_state(struct snd_card *card);
 
 #define snd_card_set_dev(card, devptr) ((card)->dev = (devptr))
 
diff --git a/include/sound/q6adm-v2.h b/include/sound/q6adm-v2.h
index e07f634..6f121b3 100644
--- a/include/sound/q6adm-v2.h
+++ b/include/sound/q6adm-v2.h
@@ -16,6 +16,7 @@
 #define ADM_PATH_PLAYBACK 0x1
 #define ADM_PATH_LIVE_REC 0x2
 #define ADM_PATH_NONLIVE_REC 0x3
+#include <mach/qdsp6v2/rtac.h>
 #include <sound/q6afe-v2.h>
 #include <sound/q6audio-v2.h>
 
@@ -41,11 +42,16 @@
 int adm_multi_ch_copp_open(int port, int path, int rate, int mode,
 			int topology, bool perf_mode, uint16_t bits_per_sample);
 
+int adm_unmap_cal_blocks(void);
+
+int adm_map_rtac_block(struct rtac_cal_block_data *cal_block);
+
+int adm_unmap_rtac_block(uint32_t *mem_map_handle);
+
 int adm_memory_map_regions(int port_id, uint32_t *buf_add, uint32_t mempool_id,
 				uint32_t *bufsz, uint32_t bufcnt);
 
-int adm_memory_unmap_regions(int port_id, uint32_t *buf_add, uint32_t *bufsz,
-						uint32_t bufcnt);
+int adm_memory_unmap_regions(int port_id);
 
 int adm_close(int port, bool perf_mode);
 
diff --git a/include/sound/q6afe-v2.h b/include/sound/q6afe-v2.h
index 12934aa..3fc85b2 100644
--- a/include/sound/q6afe-v2.h
+++ b/include/sound/q6afe-v2.h
@@ -92,7 +92,8 @@
 	MAD_HW_NONE = 0x00,
 	MAD_HW_AUDIO = 0x01,
 	MAD_HW_BEACON = 0x02,
-	MAD_HW_ULTRASOUND = 0x04
+	MAD_HW_ULTRASOUND = 0x04,
+	MAD_SW_AUDIO = 0x05,
 };
 
 struct afe_audio_buffer {
@@ -148,6 +149,7 @@
 int afe_start_pseudo_port(u16 port_id);
 int afe_stop_pseudo_port(u16 port_id);
 uint32_t afe_req_mmap_handle(struct afe_audio_client *ac);
+int afe_unmap_cal_blocks(void);
 int afe_memory_map(u32 dma_addr_p, u32 dma_buf_sz, struct afe_audio_client *ac);
 int afe_cmd_memory_map(u32 dma_addr_p, u32 dma_buf_sz);
 int afe_cmd_memory_map_nowait(int port_id, u32 dma_addr_p, u32 dma_buf_sz);
diff --git a/include/sound/q6asm-v2.h b/include/sound/q6asm-v2.h
index 4ad1ca9..0dd1f1c 100644
--- a/include/sound/q6asm-v2.h
+++ b/include/sound/q6asm-v2.h
@@ -13,6 +13,7 @@
 #define __Q6_ASM_V2_H__
 
 #include <mach/qdsp6v2/apr.h>
+#include <mach/qdsp6v2/rtac.h>
 #include <sound/apr_audio-v2.h>
 #include <linux/list.h>
 #include <linux/msm_ion.h>
@@ -76,7 +77,8 @@
 #define SOFT_PAUSE_ENABLE	1
 #define SOFT_PAUSE_DISABLE	0
 
-#define SESSION_MAX	0x08
+#define SESSION_MAX		0x08
+#define ASM_CONTROL_SESSION	0x0F
 
 /* payload structure bytes */
 #define READDONE_IDX_STATUS 0
@@ -92,7 +94,7 @@
 #define READDONE_IDX_SEQ_ID 10
 
 #define SOFT_PAUSE_PERIOD       30   /* ramp up/down for 30ms    */
-#define SOFT_PAUSE_STEP         2000 /* Step value 2ms or 2000us */
+#define SOFT_PAUSE_STEP         0 /* Step value 0ms or 0us */
 enum {
 	SOFT_PAUSE_CURVE_LINEAR = 0,
 	SOFT_PAUSE_CURVE_EXP,
@@ -100,7 +102,7 @@
 };
 
 #define SOFT_VOLUME_PERIOD       30   /* ramp up/down for 30ms    */
-#define SOFT_VOLUME_STEP         2000 /* Step value 2ms or 2000us */
+#define SOFT_VOLUME_STEP         0 /* Step value 0ms or 0us */
 enum {
 	SOFT_VOLUME_CURVE_LINEAR = 0,
 	SOFT_VOLUME_CURVE_EXP,
@@ -224,6 +226,12 @@
 int q6asm_memory_unmap(struct audio_client *ac, uint32_t buf_add,
 							int dir);
 
+int q6asm_unmap_cal_blocks(void);
+
+int q6asm_map_rtac_block(struct rtac_cal_block_data *cal_block);
+
+int q6asm_unmap_rtac_block(uint32_t *mem_map_handle);
+
 int q6asm_run(struct audio_client *ac, uint32_t flags,
 		uint32_t msw_ts, uint32_t lsw_ts);
 
diff --git a/include/sound/q6lsm.h b/include/sound/q6lsm.h
index d7a01a0..34eba81 100644
--- a/include/sound/q6lsm.h
+++ b/include/sound/q6lsm.h
@@ -19,7 +19,7 @@
 #include <sound/lsm_params.h>
 #include <mach/qdsp6v2/apr.h>
 
-typedef void (*app_cb)(uint32_t opcode, uint32_t token,
+typedef void (*lsm_app_cb)(uint32_t opcode, uint32_t token,
 		       uint32_t *payload, void *priv);
 
 struct lsm_sound_model {
@@ -34,7 +34,7 @@
 
 struct lsm_client {
 	int		session;
-	app_cb		cb;
+	lsm_app_cb	cb;
 	atomic_t	cmd_state;
 	void		*priv;
 	struct apr_svc  *apr;
@@ -118,7 +118,7 @@
 	uint32_t	mem_map_handle;
 } __packed;
 
-struct lsm_client *q6lsm_client_alloc(app_cb cb, void *priv);
+struct lsm_client *q6lsm_client_alloc(lsm_app_cb cb, void *priv);
 void q6lsm_client_free(struct lsm_client *client);
 int q6lsm_open(struct lsm_client *client);
 int q6lsm_start(struct lsm_client *client, bool wait);
@@ -126,6 +126,7 @@
 int q6lsm_snd_model_buf_alloc(struct lsm_client *client, uint32_t len);
 int q6lsm_snd_model_buf_free(struct lsm_client *client);
 int q6lsm_close(struct lsm_client *client);
+int q6lsm_unmap_cal_blocks(void);
 int q6lsm_register_sound_model(struct lsm_client *client,
 			       enum lsm_detection_mode mode, u16 minkeyword,
 			       u16 minuser, bool detectfailure);
diff --git a/include/sound/soc.h b/include/sound/soc.h
index 7886e84..b1e536d 100644
--- a/include/sound/soc.h
+++ b/include/sound/soc.h
@@ -426,6 +426,9 @@
 	struct snd_ac97_bus_ops *ops, int num);
 void snd_soc_free_ac97_codec(struct snd_soc_codec *codec);
 
+void snd_soc_card_change_online_state(struct snd_soc_card *soc_card,
+				      int online);
+
 /*
  *Controls
  */
@@ -967,7 +970,6 @@
 	enum snd_soc_pcm_subclass pcm_subclass;
 	struct snd_pcm_ops ops;
 
-	unsigned int complete:1;
 	unsigned int dev_registered:1;
 
 	/* Dynamic PCM BE runtime data */
diff --git a/init/main.c b/init/main.c
index 737ab05..b2fc496 100644
--- a/init/main.c
+++ b/init/main.c
@@ -477,11 +477,6 @@
 	smp_setup_processor_id();
 	debug_objects_early_init();
 
-	/*
-	 * Set up the the initial canary ASAP:
-	 */
-	boot_init_stack_canary();
-
 	cgroup_init_early();
 
 	local_irq_disable();
@@ -496,6 +491,10 @@
 	page_address_init();
 	printk(KERN_NOTICE "%s", linux_banner);
 	setup_arch(&command_line);
+	/*
+	 * Set up the the initial canary ASAP:
+	 */
+	boot_init_stack_canary();
 	mm_init_owner(&init_mm, &init_task);
 	mm_init_cpumask(&init_mm);
 	setup_command_line(command_line);
diff --git a/kernel/power/qos.c b/kernel/power/qos.c
index 6a031e6..bb2dad8 100644
--- a/kernel/power/qos.c
+++ b/kernel/power/qos.c
@@ -237,11 +237,18 @@
  */
 static void pm_qos_work_fn(struct work_struct *work)
 {
+	s32 new_value = PM_QOS_DEFAULT_VALUE;
 	struct pm_qos_request *req = container_of(to_delayed_work(work),
 						  struct pm_qos_request,
 						  work);
 
-	pm_qos_update_request(req, PM_QOS_DEFAULT_VALUE);
+	if (!req || !pm_qos_request_active(req))
+		return;
+
+	if (new_value != req->node.prio)
+		pm_qos_update_target(
+			pm_qos_array[req->pm_qos_class]->constraints,
+			&req->node, PM_QOS_UPDATE_REQ, new_value);
 }
 
 /**
diff --git a/kernel/sched/core.c b/kernel/sched/core.c
index d9c4b64..627dab1 100644
--- a/kernel/sched/core.c
+++ b/kernel/sched/core.c
@@ -1670,8 +1670,10 @@
 {
 	struct rq *rq = task_rq(p);
 
-	BUG_ON(rq != this_rq());
-	BUG_ON(p == current);
+	if (WARN_ON(rq != this_rq()) ||
+	    WARN_ON(p == current))
+		return;
+
 	lockdep_assert_held(&rq->lock);
 
 	if (!raw_spin_trylock(&p->pi_lock)) {
@@ -5202,9 +5204,6 @@
 	 */
 	rq->stop = NULL;
 
-	/* Ensure any throttled groups are reachable by pick_next_task */
-	unthrottle_offline_cfs_rqs(rq);
-
 	for ( ; ; ) {
 		/*
 		 * There's this thread running, bail when that's the only
diff --git a/kernel/sched/fair.c b/kernel/sched/fair.c
index 5d6ab86..2e98983 100644
--- a/kernel/sched/fair.c
+++ b/kernel/sched/fair.c
@@ -2060,7 +2060,7 @@
 	hrtimer_cancel(&cfs_b->slack_timer);
 }
 
-void unthrottle_offline_cfs_rqs(struct rq *rq)
+static void unthrottle_offline_cfs_rqs(struct rq *rq)
 {
 	struct cfs_rq *cfs_rq;
 
@@ -2114,7 +2114,7 @@
 	return NULL;
 }
 static inline void destroy_cfs_bandwidth(struct cfs_bandwidth *cfs_b) {}
-void unthrottle_offline_cfs_rqs(struct rq *rq) {}
+static inline void unthrottle_offline_cfs_rqs(struct rq *rq) {}
 
 #endif /* CONFIG_CFS_BANDWIDTH */
 
@@ -5186,6 +5186,9 @@
 static void rq_offline_fair(struct rq *rq)
 {
 	update_sysctl();
+
+	/* Ensure any throttled groups are reachable by pick_next_task */
+	unthrottle_offline_cfs_rqs(rq);
 }
 
 #endif /* CONFIG_SMP */
diff --git a/kernel/sched/rt.c b/kernel/sched/rt.c
index 8f32475..be427c5 100644
--- a/kernel/sched/rt.c
+++ b/kernel/sched/rt.c
@@ -685,6 +685,7 @@
 		 * runtime - in which case borrowing doesn't make sense.
 		 */
 		rt_rq->rt_runtime = RUNTIME_INF;
+		rt_rq->rt_throttled = 0;
 		raw_spin_unlock(&rt_rq->rt_runtime_lock);
 		raw_spin_unlock(&rt_b->rt_runtime_lock);
 	}
diff --git a/kernel/sched/sched.h b/kernel/sched/sched.h
index 5370bcb..55f6d9c 100644
--- a/kernel/sched/sched.h
+++ b/kernel/sched/sched.h
@@ -1155,7 +1155,6 @@
 
 extern void init_cfs_rq(struct cfs_rq *cfs_rq);
 extern void init_rt_rq(struct rt_rq *rt_rq, struct rq *rq);
-extern void unthrottle_offline_cfs_rqs(struct rq *rq);
 
 extern void account_cfs_bandwidth_used(int enabled, int was_enabled);
 
diff --git a/kernel/smp.c b/kernel/smp.c
index 2f8b10e..3cbd828 100644
--- a/kernel/smp.c
+++ b/kernel/smp.c
@@ -310,20 +310,20 @@
 	 */
 	this_cpu = get_cpu();
 
-	/*
-	 * Can deadlock when called with interrupts disabled.
-	 * We allow cpu's that are not yet online though, as no one else can
-	 * send smp call function interrupt to this cpu and as such deadlocks
-	 * can't happen.
-	 */
-	WARN_ON_ONCE(cpu_online(this_cpu) && irqs_disabled()
-		     && !oops_in_progress);
-
 	if (cpu == this_cpu) {
 		local_irq_save(flags);
 		func(info);
 		local_irq_restore(flags);
 	} else {
+		/*
+		 * Can deadlock when called with interrupts disabled.
+		 * We allow cpu's that are not yet online though, as no one else
+		 * can send smp call function interrupt to this cpu and as such
+		 * deadlocks can't happen.
+		 */
+		WARN_ON_ONCE(cpu_online(this_cpu) && irqs_disabled()
+			     && !oops_in_progress);
+
 		if ((unsigned)cpu < nr_cpu_ids && cpu_online(cpu)) {
 			struct call_single_data *data = &d;
 
@@ -408,20 +408,21 @@
 	unsigned long flags;
 
 	this_cpu = get_cpu();
-	/*
-	 * Can deadlock when called with interrupts disabled.
-	 * We allow cpu's that are not yet online though, as no one else can
-	 * send smp call function interrupt to this cpu and as such deadlocks
-	 * can't happen.
-	 */
-	WARN_ON_ONCE(cpu_online(smp_processor_id()) && wait && irqs_disabled()
-		     && !oops_in_progress);
 
 	if (cpu == this_cpu) {
 		local_irq_save(flags);
 		data->func(data->info);
 		local_irq_restore(flags);
 	} else {
+		/*
+		 * Can deadlock when called with interrupts disabled.
+		 * We allow cpu's that are not yet online though, as no one else
+		 * can send smp call function interrupt to this cpu and as such
+		 * deadlocks can't happen.
+		 */
+		WARN_ON_ONCE(cpu_online(smp_processor_id()) && wait
+			     && irqs_disabled() && !oops_in_progress);
+
 		csd_lock(data);
 		generic_exec_single(cpu, data, wait);
 	}
diff --git a/kernel/watchdog.c b/kernel/watchdog.c
index df30ee0..818920f 100644
--- a/kernel/watchdog.c
+++ b/kernel/watchdog.c
@@ -127,7 +127,7 @@
 /* Commands for resetting the watchdog */
 static void __touch_watchdog(void)
 {
-	int this_cpu = smp_processor_id();
+	int this_cpu = raw_smp_processor_id();
 
 	__this_cpu_write(watchdog_touch_ts, get_timestamp(this_cpu));
 }
diff --git a/lib/devres.c b/lib/devres.c
index 80b9c76..9c76b3a 100644
--- a/lib/devres.c
+++ b/lib/devres.c
@@ -86,6 +86,60 @@
 EXPORT_SYMBOL(devm_iounmap);
 
 /**
+ * devm_ioremap_resource() - check, request region, and ioremap resource
+ * @dev: generic device to handle the resource for
+ * @res: resource to be handled
+ *
+ * Checks that a resource is a valid memory region, requests the memory region
+ * and ioremaps it either as cacheable or as non-cacheable memory depending on
+ * the resource's flags. All operations are managed and will be undone on
+ * driver detach.
+ *
+ * Returns a pointer to the remapped memory or an ERR_PTR() encoded error code
+ * on failure. Usage example:
+ *
+ *	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ *	base = devm_ioremap_resource(&pdev->dev, res);
+ *	if (IS_ERR(base))
+ *		return PTR_ERR(base);
+ */
+void __iomem *devm_ioremap_resource(struct device *dev, struct resource *res)
+{
+	resource_size_t size;
+	const char *name;
+	void __iomem *dest_ptr;
+
+	BUG_ON(!dev);
+
+	if (!res || resource_type(res) != IORESOURCE_MEM) {
+		dev_err(dev, "invalid resource\n");
+		return ERR_PTR(-EINVAL);
+	}
+
+	size = resource_size(res);
+	name = res->name ?: dev_name(dev);
+
+	if (!devm_request_mem_region(dev, res->start, size, name)) {
+		dev_err(dev, "can't request region for resource %pR\n", res);
+		return ERR_PTR(-EBUSY);
+	}
+
+	if (res->flags & IORESOURCE_CACHEABLE)
+		dest_ptr = devm_ioremap(dev, res->start, size);
+	else
+		dest_ptr = devm_ioremap_nocache(dev, res->start, size);
+
+	if (!dest_ptr) {
+		dev_err(dev, "ioremap failed for resource %pR\n", res);
+		devm_release_mem_region(dev, res->start, size);
+		dest_ptr = ERR_PTR(-ENOMEM);
+	}
+
+	return dest_ptr;
+}
+EXPORT_SYMBOL(devm_ioremap_resource);
+
+/**
  * devm_request_and_ioremap() - Check, request region, and ioremap resource
  * @dev: Generic device to handle the resource for
  * @res: resource to be handled
@@ -100,37 +154,14 @@
  *	if (!base)
  *		return -EADDRNOTAVAIL;
  */
-void __iomem *devm_request_and_ioremap(struct device *dev,
-			struct resource *res)
+void __iomem *devm_request_and_ioremap(struct device *device,
+				       struct resource *res)
 {
-	resource_size_t size;
-	const char *name;
 	void __iomem *dest_ptr;
 
-	BUG_ON(!dev);
-
-	if (!res || resource_type(res) != IORESOURCE_MEM) {
-		dev_err(dev, "invalid resource\n");
+	dest_ptr = devm_ioremap_resource(device, res);
+	if (IS_ERR(dest_ptr))
 		return NULL;
-	}
-
-	size = resource_size(res);
-	name = res->name ?: dev_name(dev);
-
-	if (!devm_request_mem_region(dev, res->start, size, name)) {
-		dev_err(dev, "can't request region for resource %pR\n", res);
-		return NULL;
-	}
-
-	if (res->flags & IORESOURCE_CACHEABLE)
-		dest_ptr = devm_ioremap(dev, res->start, size);
-	else
-		dest_ptr = devm_ioremap_nocache(dev, res->start, size);
-
-	if (!dest_ptr) {
-		dev_err(dev, "ioremap failed for resource %pR\n", res);
-		devm_release_mem_region(dev, res->start, size);
-	}
 
 	return dest_ptr;
 }
diff --git a/lib/spinlock_debug.c b/lib/spinlock_debug.c
index ac516f4..6d22836 100644
--- a/lib/spinlock_debug.c
+++ b/lib/spinlock_debug.c
@@ -108,7 +108,7 @@
 static void __spin_lock_debug(raw_spinlock_t *lock)
 {
 	u64 i;
-	u64 loops = (loops_per_jiffy * HZ) >> 4;
+	u64 loops = (loops_per_jiffy * HZ) >> 1;
 
 	for (i = 0; i < loops; i++) {
 		if (arch_spin_trylock(&lock->raw_lock))
diff --git a/mm/bootmem.c b/mm/bootmem.c
index 0131170..3db5820 100644
--- a/mm/bootmem.c
+++ b/mm/bootmem.c
@@ -154,7 +154,7 @@
  * down, but we are still initializing the system.  Pages are given directly
  * to the page allocator, no bootmem metadata is updated because it is gone.
  */
-void __init free_bootmem_late(unsigned long addr, unsigned long size)
+void free_bootmem_late(unsigned long addr, unsigned long size)
 {
 	unsigned long cursor, end;
 
diff --git a/mm/page_alloc.c b/mm/page_alloc.c
index 9cc2f45..46ccd2f 100644
--- a/mm/page_alloc.c
+++ b/mm/page_alloc.c
@@ -745,7 +745,7 @@
 	local_irq_restore(flags);
 }
 
-void __meminit __free_pages_bootmem(struct page *page, unsigned int order)
+void __free_pages_bootmem(struct page *page, unsigned int order)
 {
 	unsigned int nr_pages = 1 << order;
 	unsigned int loop;
diff --git a/net/core/rtnetlink.c b/net/core/rtnetlink.c
index 90430b7..1604bf2 100644
--- a/net/core/rtnetlink.c
+++ b/net/core/rtnetlink.c
@@ -494,8 +494,10 @@
 	}
 	if (ops->fill_info) {
 		data = nla_nest_start(skb, IFLA_INFO_DATA);
-		if (data == NULL)
+		if (data == NULL) {
+			err = -EMSGSIZE;
 			goto err_cancel_link;
+		}
 		err = ops->fill_info(skb, dev);
 		if (err < 0)
 			goto err_cancel_data;
@@ -1059,7 +1061,7 @@
 	rcu_read_lock();
 	cb->seq = net->dev_base_seq;
 
-	if (nlmsg_parse(cb->nlh, sizeof(struct rtgenmsg), tb, IFLA_MAX,
+	if (nlmsg_parse(cb->nlh, sizeof(struct ifinfomsg), tb, IFLA_MAX,
 			ifla_policy) >= 0) {
 
 		if (tb[IFLA_EXT_MASK])
@@ -1902,7 +1904,7 @@
 	u32 ext_filter_mask = 0;
 	u16 min_ifinfo_dump_size = 0;
 
-	if (nlmsg_parse(nlh, sizeof(struct rtgenmsg), tb, IFLA_MAX,
+	if (nlmsg_parse(nlh, sizeof(struct ifinfomsg), tb, IFLA_MAX,
 			ifla_policy) >= 0) {
 		if (tb[IFLA_EXT_MASK])
 			ext_filter_mask = nla_get_u32(tb[IFLA_EXT_MASK]);
diff --git a/net/core/sock.c b/net/core/sock.c
index b2e14c0..0f8402e 100644
--- a/net/core/sock.c
+++ b/net/core/sock.c
@@ -1600,6 +1600,11 @@
 	gfp_t gfp_mask;
 	long timeo;
 	int err;
+	int npages = (data_len + (PAGE_SIZE - 1)) >> PAGE_SHIFT;
+
+	err = -EMSGSIZE;
+	if (npages > MAX_SKB_FRAGS)
+		goto failure;
 
 	gfp_mask = sk->sk_allocation;
 	if (gfp_mask & __GFP_WAIT)
@@ -1618,14 +1623,12 @@
 		if (atomic_read(&sk->sk_wmem_alloc) < sk->sk_sndbuf) {
 			skb = alloc_skb(header_len, gfp_mask);
 			if (skb) {
-				int npages;
 				int i;
 
 				/* No pages, we're done... */
 				if (!data_len)
 					break;
 
-				npages = (data_len + (PAGE_SIZE - 1)) >> PAGE_SHIFT;
 				skb->truesize += data_len;
 				skb_shinfo(skb)->nr_frags = npages;
 				for (i = 0; i < npages; i++) {
diff --git a/net/core/sock_diag.c b/net/core/sock_diag.c
index b9868e1..aa74be4 100644
--- a/net/core/sock_diag.c
+++ b/net/core/sock_diag.c
@@ -126,6 +126,9 @@
 	if (nlmsg_len(nlh) < sizeof(*req))
 		return -EINVAL;
 
+	if (req->sdiag_family >= AF_MAX)
+		return -EINVAL;
+
 	hndl = sock_diag_lock_handler(req->sdiag_family);
 	if (hndl == NULL)
 		err = -ENOENT;
diff --git a/net/netfilter/xt_qtaguid.c b/net/netfilter/xt_qtaguid.c
index 21d66c2..9704f85 100644
--- a/net/netfilter/xt_qtaguid.c
+++ b/net/netfilter/xt_qtaguid.c
@@ -19,6 +19,7 @@
 #include <linux/module.h>
 #include <linux/netfilter/x_tables.h>
 #include <linux/netfilter/xt_qtaguid.h>
+#include <linux/ratelimit.h>
 #include <linux/skbuff.h>
 #include <linux/workqueue.h>
 #include <net/addrconf.h>
@@ -53,25 +54,22 @@
 module_param_named(stats_perms, proc_stats_perms, uint, S_IRUGO | S_IWUSR);
 
 static struct proc_dir_entry *xt_qtaguid_ctrl_file;
-#ifdef CONFIG_ANDROID_PARANOID_NETWORK
+
+/* Everybody can write. But proc_ctrl_write_limited is true by default which
+ * limits what can be controlled. See the can_*() functions.
+ */
 static unsigned int proc_ctrl_perms = S_IRUGO | S_IWUGO;
-#else
-static unsigned int proc_ctrl_perms = S_IRUGO | S_IWUSR;
-#endif
 module_param_named(ctrl_perms, proc_ctrl_perms, uint, S_IRUGO | S_IWUSR);
 
-#ifdef CONFIG_ANDROID_PARANOID_NETWORK
-#include <linux/android_aid.h>
-static gid_t proc_stats_readall_gid = AID_NET_BW_STATS;
-static gid_t proc_ctrl_write_gid = AID_NET_BW_ACCT;
-#else
-/* 0 means, don't limit anybody */
-static gid_t proc_stats_readall_gid;
-static gid_t proc_ctrl_write_gid;
-#endif
-module_param_named(stats_readall_gid, proc_stats_readall_gid, uint,
+/* Limited by default, so the gid of the ctrl and stats proc entries
+ * will limit what can be done. See the can_*() functions.
+ */
+static bool proc_stats_readall_limited = true;
+static bool proc_ctrl_write_limited = true;
+
+module_param_named(stats_readall_limited, proc_stats_readall_limited, bool,
 		   S_IRUGO | S_IWUSR);
-module_param_named(ctrl_write_gid, proc_ctrl_write_gid, uint,
+module_param_named(ctrl_write_limited, proc_ctrl_write_limited, bool,
 		   S_IRUGO | S_IWUSR);
 
 /*
@@ -242,8 +240,9 @@
 static bool can_manipulate_uids(void)
 {
 	/* root pwnd */
-	return unlikely(!current_fsuid()) || unlikely(!proc_ctrl_write_gid)
-		|| in_egroup_p(proc_ctrl_write_gid);
+	return in_egroup_p(xt_qtaguid_ctrl_file->gid)
+		|| unlikely(!current_fsuid()) || unlikely(!proc_ctrl_write_limited)
+		|| unlikely(current_fsuid() == xt_qtaguid_ctrl_file->uid);
 }
 
 static bool can_impersonate_uid(uid_t uid)
@@ -254,9 +253,10 @@
 static bool can_read_other_uid_stats(uid_t uid)
 {
 	/* root pwnd */
-	return unlikely(!current_fsuid()) || uid == current_fsuid()
-		|| unlikely(!proc_stats_readall_gid)
-		|| in_egroup_p(proc_stats_readall_gid);
+	return in_egroup_p(xt_qtaguid_stats_file->gid)
+		|| unlikely(!current_fsuid()) || uid == current_fsuid()
+		|| unlikely(!proc_stats_readall_limited)
+		|| unlikely(current_fsuid() == xt_qtaguid_ctrl_file->uid);
 }
 
 static inline void dc_add_byte_packets(struct data_counters *counters, int set,
@@ -269,24 +269,6 @@
 	counters->bpc[set][direction][ifs_proto].packets += packets;
 }
 
-static inline uint64_t dc_sum_bytes(struct data_counters *counters,
-				    int set,
-				    enum ifs_tx_rx direction)
-{
-	return counters->bpc[set][direction][IFS_TCP].bytes
-		+ counters->bpc[set][direction][IFS_UDP].bytes
-		+ counters->bpc[set][direction][IFS_PROTO_OTHER].bytes;
-}
-
-static inline uint64_t dc_sum_packets(struct data_counters *counters,
-				      int set,
-				      enum ifs_tx_rx direction)
-{
-	return counters->bpc[set][direction][IFS_TCP].packets
-		+ counters->bpc[set][direction][IFS_UDP].packets
-		+ counters->bpc[set][direction][IFS_PROTO_OTHER].packets;
-}
-
 static struct tag_node *tag_node_tree_search(struct rb_root *root, tag_t tag)
 {
 	struct rb_node *node = root->rb_node;
@@ -788,6 +770,53 @@
 	return iface_entry;
 }
 
+/* This is for fmt2 only */
+static int pp_iface_stat_line(bool header, char *outp,
+			      int char_count, struct iface_stat *iface_entry)
+{
+	int len;
+	if (header) {
+		len = snprintf(outp, char_count,
+			       "ifname "
+			       "total_skb_rx_bytes total_skb_rx_packets "
+			       "total_skb_tx_bytes total_skb_tx_packets "
+			       "rx_tcp_bytes rx_tcp_packets "
+			       "rx_udp_bytes rx_udp_packets "
+			       "rx_other_bytes rx_other_packets "
+			       "tx_tcp_bytes tx_tcp_packets "
+			       "tx_udp_bytes tx_udp_packets "
+			       "tx_other_bytes tx_other_packets\n"
+			);
+	} else {
+		struct data_counters *cnts;
+		int cnt_set = 0;   /* We only use one set for the device */
+		cnts = &iface_entry->totals_via_skb;
+		len = snprintf(
+			outp, char_count,
+			"%s "
+			"%llu %llu %llu %llu %llu %llu %llu %llu "
+			"%llu %llu %llu %llu %llu %llu %llu %llu\n",
+			iface_entry->ifname,
+			dc_sum_bytes(cnts, cnt_set, IFS_RX),
+			dc_sum_packets(cnts, cnt_set, IFS_RX),
+			dc_sum_bytes(cnts, cnt_set, IFS_TX),
+			dc_sum_packets(cnts, cnt_set, IFS_TX),
+			cnts->bpc[cnt_set][IFS_RX][IFS_TCP].bytes,
+			cnts->bpc[cnt_set][IFS_RX][IFS_TCP].packets,
+			cnts->bpc[cnt_set][IFS_RX][IFS_UDP].bytes,
+			cnts->bpc[cnt_set][IFS_RX][IFS_UDP].packets,
+			cnts->bpc[cnt_set][IFS_RX][IFS_PROTO_OTHER].bytes,
+			cnts->bpc[cnt_set][IFS_RX][IFS_PROTO_OTHER].packets,
+			cnts->bpc[cnt_set][IFS_TX][IFS_TCP].bytes,
+			cnts->bpc[cnt_set][IFS_TX][IFS_TCP].packets,
+			cnts->bpc[cnt_set][IFS_TX][IFS_UDP].bytes,
+			cnts->bpc[cnt_set][IFS_TX][IFS_UDP].packets,
+			cnts->bpc[cnt_set][IFS_TX][IFS_PROTO_OTHER].bytes,
+			cnts->bpc[cnt_set][IFS_TX][IFS_PROTO_OTHER].packets);
+	}
+	return len;
+}
+
 static int iface_stat_fmt_proc_read(char *page, char **num_items_returned,
 				    off_t items_to_skip, int char_count,
 				    int *eof, void *data)
@@ -817,11 +846,7 @@
 		return 0;
 
 	if (fmt == 2 && item_index++ >= items_to_skip) {
-		len = snprintf(outp, char_count,
-			       "ifname "
-			       "total_skb_rx_bytes total_skb_rx_packets "
-			       "total_skb_tx_bytes total_skb_tx_packets\n"
-			);
+		len = pp_iface_stat_line(true, outp, char_count, NULL);
 		if (len >= char_count) {
 			*outp = '\0';
 			return outp - page;
@@ -866,16 +891,8 @@
 				stats->tx_bytes, stats->tx_packets
 				);
 		} else {
-			len = snprintf(
-				outp, char_count,
-				"%s "
-				"%llu %llu %llu %llu\n",
-				iface_entry->ifname,
-				iface_entry->totals_via_skb[IFS_RX].bytes,
-				iface_entry->totals_via_skb[IFS_RX].packets,
-				iface_entry->totals_via_skb[IFS_TX].bytes,
-				iface_entry->totals_via_skb[IFS_TX].packets
-				);
+			len = pp_iface_stat_line(false, outp, char_count,
+						 iface_entry);
 		}
 		if (len >= char_count) {
 			spin_unlock_bh(&iface_stat_list_lock);
@@ -1092,18 +1109,13 @@
 	spin_lock_bh(&iface_stat_list_lock);
 	entry = get_iface_entry(ifname);
 	if (entry != NULL) {
-		bool activate = !ipv4_is_loopback(ipaddr);
 		IF_DEBUG("qtaguid: iface_stat: create(%s): entry=%p\n",
 			 ifname, entry);
 		iface_check_stats_reset_and_adjust(net_dev, entry);
-		_iface_stat_set_active(entry, net_dev, activate);
+		_iface_stat_set_active(entry, net_dev, true);
 		IF_DEBUG("qtaguid: %s(%s): "
 			 "tracking now %d on ip=%pI4\n", __func__,
-			 entry->ifname, activate, &ipaddr);
-		goto done_unlock_put;
-	} else if (ipv4_is_loopback(ipaddr)) {
-		IF_DEBUG("qtaguid: iface_stat: create(%s): "
-			 "ignore loopback dev. ip=%pI4\n", ifname, &ipaddr);
+			 entry->ifname, true, &ipaddr);
 		goto done_unlock_put;
 	}
 
@@ -1154,19 +1166,13 @@
 	spin_lock_bh(&iface_stat_list_lock);
 	entry = get_iface_entry(ifname);
 	if (entry != NULL) {
-		bool activate = !(addr_type & IPV6_ADDR_LOOPBACK);
 		IF_DEBUG("qtaguid: %s(%s): entry=%p\n", __func__,
 			 ifname, entry);
 		iface_check_stats_reset_and_adjust(net_dev, entry);
-		_iface_stat_set_active(entry, net_dev, activate);
+		_iface_stat_set_active(entry, net_dev, true);
 		IF_DEBUG("qtaguid: %s(%s): "
 			 "tracking now %d on ip=%pI6c\n", __func__,
-			 entry->ifname, activate, &ifa->addr);
-		goto done_unlock_put;
-	} else if (addr_type & IPV6_ADDR_LOOPBACK) {
-		IF_DEBUG("qtaguid: %s(%s): "
-			 "ignore loopback dev. ip=%pI6c\n", __func__,
-			 ifname, &ifa->addr);
+			 entry->ifname, true, &ifa->addr);
 		goto done_unlock_put;
 	}
 
@@ -1305,6 +1311,7 @@
 	const struct net_device *el_dev;
 	enum ifs_tx_rx direction = par->in ? IFS_RX : IFS_TX;
 	int bytes = skb->len;
+	int proto;
 
 	if (!skb->dev) {
 		MT_DEBUG("qtaguid[%d]: no skb->dev\n", par->hooknum);
@@ -1322,15 +1329,15 @@
 	}
 
 	if (unlikely(!el_dev)) {
-		pr_err("qtaguid[%d]: %s(): no par->in/out?!!\n",
-		       par->hooknum, __func__);
+		pr_err_ratelimited("qtaguid[%d]: %s(): no par->in/out?!!\n",
+				   par->hooknum, __func__);
 		BUG();
 	} else if (unlikely(!el_dev->name)) {
-		pr_err("qtaguid[%d]: %s(): no dev->name?!!\n",
-		       par->hooknum, __func__);
+		pr_err_ratelimited("qtaguid[%d]: %s(): no dev->name?!!\n",
+				   par->hooknum, __func__);
 		BUG();
 	} else {
-		int proto = ipx_proto(skb, par);
+		proto = ipx_proto(skb, par);
 		MT_DEBUG("qtaguid[%d]: dev name=%s type=%d fam=%d proto=%d\n",
 			 par->hooknum, el_dev->name, el_dev->type,
 			 par->family, proto);
@@ -1348,8 +1355,8 @@
 	IF_DEBUG("qtaguid: %s(%s): entry=%p\n", __func__,
 		 el_dev->name, entry);
 
-	entry->totals_via_skb[direction].bytes += bytes;
-	entry->totals_via_skb[direction].packets++;
+	data_counters_update(&entry->totals_via_skb, 0, direction, proto,
+			     bytes);
 	spin_unlock_bh(&iface_stat_list_lock);
 }
 
@@ -1412,8 +1419,8 @@
 	iface_entry = get_iface_entry(ifname);
 	if (!iface_entry) {
 		spin_unlock_bh(&iface_stat_list_lock);
-		pr_err("qtaguid: iface_stat: stat_update() %s not found\n",
-		       ifname);
+		pr_err_ratelimited("qtaguid: iface_stat: stat_update() "
+				   "%s not found\n", ifname);
 		return;
 	}
 	spin_unlock_bh(&iface_stat_list_lock);
@@ -1464,6 +1471,8 @@
 		 *  - No {0, uid_tag} stats and no {acc_tag, uid_tag} stats.
 		 */
 		new_tag_stat = create_if_tag_stat(iface_entry, uid_tag);
+		if (!new_tag_stat)
+			goto unlock;
 		uid_tag_counters = &new_tag_stat->counters;
 	} else {
 		uid_tag_counters = &tag_stat_entry->counters;
@@ -1472,6 +1481,8 @@
 	if (acct_tag) {
 		/* Create the child {acct_tag, uid_tag} and hook up parent. */
 		new_tag_stat = create_if_tag_stat(iface_entry, tag);
+		if (!new_tag_stat)
+			goto unlock;
 		new_tag_stat->parent_counters = uid_tag_counters;
 	} else {
 		/*
@@ -1485,6 +1496,7 @@
 		BUG_ON(!new_tag_stat);
 	}
 	tag_stat_update(new_tag_stat, direction, proto, bytes);
+unlock:
 	spin_unlock_bh(&iface_entry->tag_stat_list_lock);
 }
 
@@ -2302,11 +2314,12 @@
 	}
 	CT_DEBUG("qtaguid: ctrl_tag(%s): "
 		 "pid=%u tgid=%u uid=%u euid=%u fsuid=%u "
-		 "in_group=%d in_egroup=%d\n",
+		 "ctrl.gid=%u in_group()=%d in_egroup()=%d\n",
 		 input, current->pid, current->tgid, current_uid(),
 		 current_euid(), current_fsuid(),
-		 in_group_p(proc_ctrl_write_gid),
-		 in_egroup_p(proc_ctrl_write_gid));
+		 xt_qtaguid_ctrl_file->gid,
+		 in_group_p(xt_qtaguid_ctrl_file->gid),
+		 in_egroup_p(xt_qtaguid_ctrl_file->gid));
 	if (argc < 4) {
 		uid = current_fsuid();
 	} else if (!can_impersonate_uid(uid)) {
@@ -2593,14 +2606,16 @@
 	} else {
 		tag_t tag = ppi->ts_entry->tn.tag;
 		uid_t stat_uid = get_uid_from_tag(tag);
-
-		if (!can_read_other_uid_stats(stat_uid)) {
+		/* Detailed tags are not available to everybody */
+		if (get_atag_from_tag(tag)
+		    && !can_read_other_uid_stats(stat_uid)) {
 			CT_DEBUG("qtaguid: stats line: "
 				 "%s 0x%llx %u: insufficient priv "
-				 "from pid=%u tgid=%u uid=%u\n",
+				 "from pid=%u tgid=%u uid=%u stats.gid=%u\n",
 				 ppi->iface_entry->ifname,
 				 get_atag_from_tag(tag), stat_uid,
-				 current->pid, current->tgid, current_fsuid());
+				 current->pid, current->tgid, current_fsuid(),
+				 xt_qtaguid_stats_file->gid);
 			return 0;
 		}
 		if (ppi->item_index++ < ppi->items_to_skip)
@@ -2756,7 +2771,7 @@
 	utd_entry = get_uid_data(current_fsuid(), &utd_entry_found);
 	if (IS_ERR_OR_NULL(utd_entry)) {
 		res = PTR_ERR(utd_entry);
-		goto err;
+		goto err_unlock;
 	}
 
 	/* Look for existing PID based proc_data */
@@ -2798,8 +2813,8 @@
 		rb_erase(&utd_entry->node, &uid_tag_data_tree);
 		kfree(utd_entry);
 	}
+err_unlock:
 	spin_unlock_bh(&uid_tag_data_tree_lock);
-err:
 	return res;
 }
 
diff --git a/net/netfilter/xt_qtaguid_internal.h b/net/netfilter/xt_qtaguid_internal.h
index d79f838..6dc14a9 100644
--- a/net/netfilter/xt_qtaguid_internal.h
+++ b/net/netfilter/xt_qtaguid_internal.h
@@ -179,6 +179,25 @@
 	struct byte_packet_counters bpc[IFS_MAX_COUNTER_SETS][IFS_MAX_DIRECTIONS][IFS_MAX_PROTOS];
 };
 
+static inline uint64_t dc_sum_bytes(struct data_counters *counters,
+				    int set,
+				    enum ifs_tx_rx direction)
+{
+	return counters->bpc[set][direction][IFS_TCP].bytes
+		+ counters->bpc[set][direction][IFS_UDP].bytes
+		+ counters->bpc[set][direction][IFS_PROTO_OTHER].bytes;
+}
+
+static inline uint64_t dc_sum_packets(struct data_counters *counters,
+				      int set,
+				      enum ifs_tx_rx direction)
+{
+	return counters->bpc[set][direction][IFS_TCP].packets
+		+ counters->bpc[set][direction][IFS_UDP].packets
+		+ counters->bpc[set][direction][IFS_PROTO_OTHER].packets;
+}
+
+
 /* Generic X based nodes used as a base for rb_tree ops */
 struct tag_node {
 	struct rb_node node;
@@ -203,7 +222,7 @@
 	struct net_device *net_dev;
 
 	struct byte_packet_counters totals_via_dev[IFS_MAX_DIRECTIONS];
-	struct byte_packet_counters totals_via_skb[IFS_MAX_DIRECTIONS];
+	struct data_counters totals_via_skb;
 	/*
 	 * We keep the last_known, because some devices reset their counters
 	 * just before NETDEV_UP, while some will reset just before
diff --git a/net/netfilter/xt_qtaguid_print.c b/net/netfilter/xt_qtaguid_print.c
index 8cbd8e4..f6a00a3 100644
--- a/net/netfilter/xt_qtaguid_print.c
+++ b/net/netfilter/xt_qtaguid_print.c
@@ -177,9 +177,10 @@
 char *pp_iface_stat(struct iface_stat *is)
 {
 	char *res;
-	if (!is)
+	if (!is) {
 		res = kasprintf(GFP_ATOMIC, "iface_stat@null{}");
-	else
+	} else {
+		struct data_counters *cnts = &is->totals_via_skb;
 		res = kasprintf(GFP_ATOMIC, "iface_stat@%p{"
 				"list=list_head{...}, "
 				"ifname=%s, "
@@ -206,10 +207,10 @@
 				is->totals_via_dev[IFS_RX].packets,
 				is->totals_via_dev[IFS_TX].bytes,
 				is->totals_via_dev[IFS_TX].packets,
-				is->totals_via_skb[IFS_RX].bytes,
-				is->totals_via_skb[IFS_RX].packets,
-				is->totals_via_skb[IFS_TX].bytes,
-				is->totals_via_skb[IFS_TX].packets,
+				dc_sum_bytes(cnts, 0, IFS_RX),
+				dc_sum_packets(cnts, 0, IFS_RX),
+				dc_sum_bytes(cnts, 0, IFS_TX),
+				dc_sum_packets(cnts, 0, IFS_TX),
 				is->last_known_valid,
 				is->last_known[IFS_RX].bytes,
 				is->last_known[IFS_RX].packets,
@@ -218,6 +219,7 @@
 				is->active,
 				is->net_dev,
 				is->proc_ptr);
+	}
 	_bug_on_err_or_null(res);
 	return res;
 }
diff --git a/net/wireless/db.txt b/net/wireless/db.txt
index a2fc3a0..c5861b8 100644
--- a/net/wireless/db.txt
+++ b/net/wireless/db.txt
@@ -1,17 +1,799 @@
-#
-# This file is a placeholder to prevent accidental build breakage if someone
-# enables CONFIG_CFG80211_INTERNAL_REGDB.  Almost no one actually needs to
-# enable that build option.
-#
-# You should be using CRDA instead.  It is even better if you use the CRDA
-# package provided by your distribution, since they will probably keep it
-# up-to-date on your behalf.
-#
-# If you _really_ intend to use CONFIG_CFG80211_INTERNAL_REGDB then you will
-# need to replace this file with one containing appropriately formatted
-# regulatory rules that cover the regulatory domains you will be using.  Your
-# best option is to extract the db.txt file from the wireless-regdb git
-# repository:
-#
-#   git://git.kernel.org/pub/scm/linux/kernel/git/linville/wireless-regdb.git
-#
+# This is the world regulatory domain
+country 00:
+	(2402 - 2472 @ 40), (3, 20)
+	# Channel 12 - 13.
+	(2457 - 2482 @ 40), (3, 20), PASSIVE-SCAN, NO-IBSS
+	# Channel 14. Only JP enables this and for 802.11b only
+	(2474 - 2494 @ 20), (3, 20), PASSIVE-SCAN, NO-IBSS, NO-OFDM
+	# Channel 36 - 48
+	(5170 - 5250 @ 40), (3, 20), PASSIVE-SCAN, NO-IBSS
+	# NB: 5260 MHz - 5700 MHz requies DFS
+	# Channel 149 - 165
+	(5735 - 5835 @ 40), (3, 20), PASSIVE-SCAN, NO-IBSS
+
+
+country AD:
+	# 60 gHz band channels 1-4, ref: Etsi En 302 567
+	(57240 - 65880 @ 2160), (N/A, 40), NO-OUTDOOR
+
+country AE:
+	(2402 - 2482 @ 40), (N/A, 20)
+	(5170 - 5250 @ 40), (N/A, 20)
+	(5250 - 5330 @ 40), (N/A, 20), DFS
+	(5490 - 5710 @ 40), (N/A, 27), DFS
+
+country AL:
+	(2402 - 2482 @ 20), (N/A, 20)
+
+country AM:
+	(2402 - 2482 @ 40), (N/A, 20)
+	(5170 - 5250 @ 20), (N/A, 18)
+	(5250 - 5330 @ 20), (N/A, 18), DFS
+
+country AN:
+	(2402 - 2482 @ 40), (N/A, 20)
+	(5170 - 5250 @ 40), (N/A, 20)
+	(5250 - 5330 @ 40), (N/A, 20), DFS
+	(5490 - 5710 @ 40), (N/A, 27), DFS
+
+country AR:
+	(2402 - 2482 @ 40), (N/A, 20)
+	(5170 - 5250 @ 40), (3, 17)
+	(5250 - 5330 @ 40), (3, 20), DFS
+	(5490 - 5710 @ 40), (3, 20), DFS
+	(5735 - 5835 @ 40), (3, 30)
+
+country AT: DFS-ETSI
+	(2402 - 2482 @ 40), (N/A, 20)
+	(5170 - 5250 @ 40), (N/A, 20)
+	(5250 - 5330 @ 40), (N/A, 20), DFS
+	(5490 - 5710 @ 40), (N/A, 27), DFS
+	# 60 gHz band channels 1-4, ref: Etsi En 302 567
+	(57240 - 65880 @ 2160), (N/A, 40), NO-OUTDOOR
+
+country AU:
+	(2402 - 2482 @ 40), (N/A, 20)
+	(5170 - 5250 @ 40), (3, 23)
+	(5250 - 5330 @ 40), (3, 23), DFS
+	(5735 - 5835 @ 40), (3, 30)
+
+country AW:
+	(2402 - 2482 @ 40), (N/A, 20)
+	(5170 - 5250 @ 40), (N/A, 20)
+	(5250 - 5330 @ 40), (N/A, 20), DFS
+	(5490 - 5710 @ 40), (N/A, 27), DFS
+
+country AZ:
+	(2402 - 2482 @ 40), (N/A, 20)
+	(5170 - 5250 @ 40), (N/A, 18)
+	(5250 - 5330 @ 40), (N/A, 18), DFS
+
+country BA: DFS-ETSI
+	(2402 - 2482 @ 40), (N/A, 20)
+	(5170 - 5250 @ 40), (N/A, 20)
+	(5250 - 5330 @ 40), (N/A, 20), DFS
+	(5490 - 5710 @ 40), (N/A, 27), DFS
+	# 60 gHz band channels 1-4, ref: Etsi En 302 567
+	(57240 - 65880 @ 2160), (N/A, 40), NO-OUTDOOR
+
+country BB:
+	(2402 - 2482 @ 40), (N/A, 20)
+	(5170 - 5250 @ 40), (3, 23)
+	(5250 - 5330 @ 40), (3, 23), DFS
+	(5735 - 5835 @ 40), (3, 30)
+
+country BD:
+	(2402 - 2482 @ 40), (N/A, 20)
+
+country BE: DFS-ETSI
+	(2402 - 2482 @ 40), (N/A, 20)
+	(5170 - 5250 @ 40), (N/A, 20)
+	(5250 - 5330 @ 40), (N/A, 20), DFS
+	(5490 - 5710 @ 40), (N/A, 27), DFS
+	# 60 gHz band channels 1-4, ref: Etsi En 302 567
+	(57240 - 65880 @ 2160), (N/A, 40), NO-OUTDOOR
+
+country BG: DFS-ETSI
+	(2402 - 2482 @ 40), (N/A, 20)
+	(5170 - 5250 @ 40), (N/A, 23)
+	(5250 - 5290 @ 40), (N/A, 23), DFS
+	(5490 - 5710 @ 40), (N/A, 30), DFS
+	# 60 gHz band channels 1-4, ref: Etsi En 302 567
+	(57240 - 65880 @ 2160), (N/A, 40), NO-OUTDOOR
+
+country BH:
+	(2402 - 2482 @ 40), (N/A, 20)
+	(5170 - 5250 @ 20), (N/A, 20)
+	(5250 - 5330 @ 20), (N/A, 20), DFS
+	(5735 - 5835 @ 20), (N/A, 20)
+
+country BL:
+	(2402 - 2482 @ 40), (N/A, 20)
+	(5170 - 5250 @ 40), (N/A, 18)
+	(5250 - 5330 @ 40), (N/A, 18), DFS
+
+country BN:
+	(2402 - 2482 @ 40), (N/A, 20)
+	(5170 - 5250 @ 40), (N/A, 20)
+	(5250 - 5330 @ 40), (N/A, 20), DFS
+	(5735 - 5835 @ 40), (N/A, 30)
+
+country BO:
+	(2402 - 2482 @ 40), (N/A, 30)
+	(5735 - 5835 @ 40), (N/A, 30)
+
+country BR:
+	(2402 - 2482 @ 40), (N/A, 20)
+	(5170 - 5250 @ 40), (3, 17)
+	(5250 - 5330 @ 40), (3, 20), DFS
+	(5490 - 5710 @ 40), (3, 20), DFS
+	(5735 - 5835 @ 40), (3, 30)
+
+country BY:
+	(2402 - 2482 @ 40), (N/A, 20)
+	(5170 - 5250 @ 40), (N/A, 20)
+	(5250 - 5330 @ 40), (N/A, 20), DFS
+	(5490 - 5710 @ 40), (N/A, 27), DFS
+
+country BZ:
+	(2402 - 2482 @ 40), (N/A, 30)
+	(5735 - 5835 @ 40), (N/A, 30)
+
+country CA:
+	(2402 - 2472 @ 40), (3, 27)
+	(5170 - 5250 @ 40), (3, 17)
+	(5250 - 5330 @ 40), (3, 20), DFS
+	(5490 - 5710 @ 40), (3, 20), DFS
+	(5735 - 5835 @ 40), (3, 30)
+
+country CH: DFS-ETSI
+	(2402 - 2482 @ 40), (N/A, 20)
+	(5170 - 5250 @ 40), (N/A, 20)
+	(5250 - 5330 @ 40), (N/A, 20), DFS
+	(5490 - 5710 @ 40), (N/A, 27), DFS
+	# 60 gHz band channels 1-4, ref: Etsi En 302 567
+	(57240 - 65880 @ 2160), (N/A, 40), NO-OUTDOOR
+
+country CL:
+	(2402 - 2482 @ 40), (N/A, 20)
+	(5170 - 5250 @ 40), (N/A, 20)
+	(5250 - 5330 @ 40), (N/A, 20), DFS
+	(5735 - 5835 @ 40), (N/A, 20)
+
+country CN:
+	(2402 - 2482 @ 40), (N/A, 20)
+	(5735 - 5835 @ 40), (N/A, 30)
+	# 60 gHz band channels 1,4: 28dBm, channels 2,3: 44dBm
+	# ref: http://www.miit.gov.cn/n11293472/n11505629/n11506593/n11960250/n11960606/n11960700/n12330791.files/n12330790.pdf
+	(57240 - 59400 @ 2160), (N/A, 28)
+	(59400 - 63720 @ 2160), (N/A, 44)
+	(63720 - 65880 @ 2160), (N/A, 28)
+
+country CO:
+	(2402 - 2472 @ 40), (3, 27)
+	(5170 - 5250 @ 40), (3, 17)
+	(5250 - 5330 @ 40), (3, 23), DFS
+	(5735 - 5835 @ 40), (3, 30)
+
+country CR:
+	(2402 - 2482 @ 40), (N/A, 20)
+	(5170 - 5250 @ 20), (3, 17)
+	(5250 - 5330 @ 20), (3, 23), DFS
+	(5735 - 5835 @ 20), (3, 30)
+
+country CS:
+	(2402 - 2482 @ 40), (N/A, 20)
+	(5170 - 5250 @ 40), (N/A, 20)
+	(5250 - 5330 @ 40), (N/A, 20), DFS
+	(5490 - 5710 @ 40), (N/A, 27), DFS
+
+country CY: DFS-ETSI
+	(2402 - 2482 @ 40), (N/A, 20)
+	(5170 - 5250 @ 40), (N/A, 20)
+	(5250 - 5330 @ 40), (N/A, 20), DFS
+	(5490 - 5710 @ 40), (N/A, 27), DFS
+	# 60 gHz band channels 1-4, ref: Etsi En 302 567
+	(57240 - 65880 @ 2160), (N/A, 40), NO-OUTDOOR
+
+# Data from http://www.ctu.eu/164/download/VOR/VOR-12-08-2005-34.pdf
+# and http://www.ctu.eu/164/download/VOR/VOR-12-05-2007-6-AN.pdf
+# Power at 5250 - 5350 MHz and 5470 - 5725 MHz can be doubled if TPC is
+# implemented.
+country CZ: DFS-ETSI
+	(2400 - 2483.5 @ 40), (N/A, 100 mW)
+	(5150 - 5250 @ 40), (N/A, 200 mW), NO-OUTDOOR
+	(5250 - 5350 @ 40), (N/A, 100 mW), NO-OUTDOOR, DFS
+	(5470 - 5725 @ 40), (N/A, 500 mW), DFS
+	# 60 gHz band channels 1-4, ref: Etsi En 302 567
+	(57240 - 65880 @ 2160), (N/A, 40), NO-OUTDOOR
+
+# Data from "Frequenznutzungsplan" (as published in April 2008), downloaded from
+# http://www.bundesnetzagentur.de/cae/servlet/contentblob/38448/publicationFile/2659/Frequenznutzungsplan2008_Id17448pdf.pdf
+# For the 5GHz range also see
+# http://www.bundesnetzagentur.de/cae/servlet/contentblob/38216/publicationFile/6579/WLAN5GHzVfg7_2010_28042010pdf.pdf
+# The values have been reduced by a factor of 2 (3db) for non TPC devices
+# (in other words: devices with TPC can use twice the tx power of this table).
+# Note that the docs do not require TPC for 5150--5250; the reduction to
+# 100mW thus is not strictly required -- however the conservative 100mW
+# limit is used here as the non-interference with radar and satellite
+# apps relies on the attenuation by the building walls only in the
+# absence of DFS; the neighbour countries have 100mW limit here as well.
+
+country DE: DFS-ETSI
+	# entries 279004 and 280006
+	(2400 - 2483.5 @ 40), (N/A, 100 mW)
+	# entry 303005
+	(5150 - 5250 @ 40), (N/A, 100 mW), NO-OUTDOOR
+	# entries 304002 and 305002
+	(5250 - 5350 @ 40), (N/A, 100 mW), NO-OUTDOOR, DFS
+	# entries 308002, 309001 and 310003
+	(5470 - 5725 @ 40), (N/A, 500 mW), DFS
+	# 60 gHz band channels 1-4, ref: Etsi En 302 567
+	(57240 - 65880 @ 2160), (N/A, 40), NO-OUTDOOR
+
+country DK: DFS-ETSI
+	(2402 - 2482 @ 40), (N/A, 20)
+	(5170 - 5250 @ 40), (N/A, 20)
+	(5250 - 5330 @ 40), (N/A, 20), DFS
+	(5490 - 5710 @ 40), (N/A, 27), DFS
+	# 60 gHz band channels 1-4, ref: Etsi En 302 567
+	(57240 - 65880 @ 2160), (N/A, 40), NO-OUTDOOR
+
+country DO:
+	(2402 - 2472 @ 40), (3, 27)
+	(5170 - 5250 @ 40), (3, 17)
+	(5250 - 5330 @ 40), (3, 23), DFS
+	(5735 - 5835 @ 40), (3, 30)
+
+country DZ:
+	(2402 - 2482 @ 40), (N/A, 20)
+
+country EC:
+	(2402 - 2482 @ 40), (N/A, 20)
+	(5170 - 5250 @ 20), (3, 17)
+	(5250 - 5330 @ 20), (3, 23), DFS
+	(5735 - 5835 @ 20), (3, 30)
+
+country EE: DFS-ETSI
+	(2402 - 2482 @ 40), (N/A, 20)
+	(5170 - 5250 @ 40), (N/A, 20)
+	(5250 - 5330 @ 40), (N/A, 20), DFS
+	(5490 - 5710 @ 40), (N/A, 27), DFS
+	# 60 gHz band channels 1-4, ref: Etsi En 302 567
+	(57240 - 65880 @ 2160), (N/A, 40), NO-OUTDOOR
+
+country EG:
+	(2402 - 2482 @ 40), (N/A, 20)
+	(5170 - 5250 @ 20), (N/A, 20)
+	(5250 - 5330 @ 20), (N/A, 20), DFS
+
+country ES: DFS-ETSI
+	(2400 - 2483.5 @ 40), (N/A, 100 mW)
+	(5150 - 5250 @ 40), (N/A, 100 mW), NO-OUTDOOR
+	(5250 - 5350 @ 40), (N/A, 100 mW), NO-OUTDOOR, DFS
+	(5470 - 5725 @ 40), (N/A, 500 mW), DFS
+	# 60 gHz band channels 1-4, ref: Etsi En 302 567
+	(57240 - 65880 @ 2160), (N/A, 40), NO-OUTDOOR
+
+country FI: DFS-ETSI
+	(2402 - 2482 @ 40), (N/A, 20)
+	(5170 - 5250 @ 40), (N/A, 20)
+	(5250 - 5330 @ 40), (N/A, 20), DFS
+	(5490 - 5710 @ 40), (N/A, 27), DFS
+	# 60 gHz band channels 1-4, ref: Etsi En 302 567
+	(57240 - 65880 @ 2160), (N/A, 40), NO-OUTDOOR
+
+country FR: DFS-ETSI
+	(2402 - 2482 @ 40), (N/A, 20)
+	(5170 - 5250 @ 40), (N/A, 20)
+	(5250 - 5330 @ 40), (N/A, 20), DFS
+	(5490 - 5710 @ 40), (N/A, 27), DFS
+	# 60 gHz band channels 1-4, ref: Etsi En 302 567
+	(57240 - 65880 @ 2160), (N/A, 40), NO-OUTDOOR
+
+country GE:
+	(2402 - 2482 @ 40), (N/A, 20)
+	(5170 - 5250 @ 40), (N/A, 18)
+	(5250 - 5330 @ 40), (N/A, 18), DFS
+	# 60 gHz band channels 1-4, ref: Etsi En 302 567
+	(57240 - 65880 @ 2160), (N/A, 40), NO-OUTDOOR
+
+country GB: DFS-ETSI
+	(2402 - 2482 @ 40), (N/A, 20)
+	(5170 - 5250 @ 40), (N/A, 20)
+	(5250 - 5330 @ 40), (N/A, 20), DFS
+	(5490 - 5710 @ 40), (N/A, 27), DFS
+	# 60 gHz band channels 1-4, ref: Etsi En 302 567
+	(57240 - 65880 @ 2160), (N/A, 40), NO-OUTDOOR
+
+country GD:
+	(2402 - 2472 @ 40), (3, 27)
+	(5170 - 5250 @ 40), (3, 17)
+	(5250 - 5330 @ 40), (3, 20), DFS
+	(5490 - 5710 @ 40), (3, 20), DFS
+	(5735 - 5835 @ 40), (3, 30)
+
+country GR: DFS-ETSI
+	(2402 - 2482 @ 40), (N/A, 20)
+	(5170 - 5250 @ 40), (N/A, 20)
+	(5250 - 5330 @ 40), (N/A, 20), DFS
+	(5490 - 5710 @ 40), (N/A, 27), DFS
+	# 60 gHz band channels 1-4, ref: Etsi En 302 567
+	(57240 - 65880 @ 2160), (N/A, 40), NO-OUTDOOR
+
+country GL: DFS-ETSI
+	(2402 - 2482 @ 40), (N/A, 20)
+	(5170 - 5250 @ 20), (N/A, 20)
+	(5250 - 5330 @ 20), (N/A, 20), DFS
+	(5490 - 5710 @ 20), (N/A, 27), DFS
+
+country GT:
+	(2402 - 2472 @ 40), (3, 27)
+	(5170 - 5250 @ 40), (3, 17)
+	(5250 - 5330 @ 40), (3, 23), DFS
+	(5735 - 5835 @ 40), (3, 30)
+
+country GU:
+	(2402 - 2472 @ 40), (3, 27)
+	(5170 - 5250 @ 20), (3, 17)
+	(5250 - 5330 @ 20), (3, 23), DFS
+	(5735 - 5835 @ 20), (3, 30)
+
+country HN:
+	(2402 - 2482 @ 40), (N/A, 20)
+	(5170 - 5250 @ 40), (3, 17)
+	(5250 - 5330 @ 40), (3, 20), DFS
+	(5490 - 5710 @ 40), (3, 20), DFS
+	(5735 - 5835 @ 40), (3, 30)
+
+country HK:
+	(2402 - 2482 @ 40), (N/A, 20)
+	(5170 - 5250 @ 40), (3, 17)
+	(5250 - 5330 @ 40), (3, 20), DFS
+	(5490 - 5710 @ 40), (3, 20), DFS
+	(5735 - 5835 @ 40), (3, 30)
+
+country HR: DFS-ETSI
+	(2402 - 2482 @ 40), (N/A, 20)
+	(5170 - 5250 @ 40), (N/A, 20)
+	(5250 - 5330 @ 40), (N/A, 20), DFS
+	(5490 - 5710 @ 40), (N/A, 27), DFS
+	# 60 gHz band channels 1-4, ref: Etsi En 302 567
+	(57240 - 65880 @ 2160), (N/A, 40), NO-OUTDOOR
+
+country HT:
+	(2402 - 2482 @ 40), (N/A, 20)
+	(5170 - 5250 @ 40), (N/A, 20)
+	(5250 - 5330 @ 40), (N/A, 20), DFS
+	(5490 - 5710 @ 40), (N/A, 27), DFS
+
+country HU: DFS-ETSI
+	(2402 - 2482 @ 40), (N/A, 20)
+	(5170 - 5250 @ 40), (N/A, 20)
+	(5250 - 5330 @ 40), (N/A, 20), DFS
+	(5490 - 5710 @ 40), (N/A, 27), DFS
+	# 60 gHz band channels 1-4, ref: Etsi En 302 567
+	(57240 - 65880 @ 2160), (N/A, 40), NO-OUTDOOR
+
+country ID:
+	(2402 - 2482 @ 40), (N/A, 20)
+
+country IE: DFS-ETSI
+	(2402 - 2482 @ 40), (N/A, 20)
+	(5170 - 5250 @ 40), (N/A, 20)
+	(5250 - 5330 @ 40), (N/A, 20), DFS
+	(5490 - 5710 @ 40), (N/A, 27), DFS
+	# 60 gHz band channels 1-4, ref: Etsi En 302 567
+	(57240 - 65880 @ 2160), (N/A, 40), NO-OUTDOOR
+
+country IL:
+	(2402 - 2482 @ 40), (N/A, 20)
+	(5150 - 5250 @ 40), (N/A, 200 mW), NO-OUTDOOR
+	(5250 - 5350 @ 40), (N/A, 200 mW), NO-OUTDOOR, DFS
+
+country IN:
+	(2402 - 2482 @ 40), (N/A, 20)
+	(5170 - 5250 @ 40), (N/A, 20)
+	(5250 - 5330 @ 40), (N/A, 20), DFS
+	(5735 - 5835 @ 40), (N/A, 20)
+
+country IS: DFS-ETSI
+	(2402 - 2482 @ 40), (N/A, 20)
+	(5170 - 5250 @ 40), (N/A, 20)
+	(5250 - 5330 @ 40), (N/A, 20), DFS
+	(5490 - 5710 @ 40), (N/A, 27), DFS
+	# 60 gHz band channels 1-4, ref: Etsi En 302 567
+	(57240 - 65880 @ 2160), (N/A, 40), NO-OUTDOOR
+
+country IR:
+	(2402 - 2482 @ 40), (N/A, 20)
+	(5735 - 5835 @ 40), (N/A, 30)
+
+country IT: DFS-ETSI
+	(2402 - 2482 @ 40), (N/A, 20)
+	(5170 - 5250 @ 40), (N/A, 20)
+	(5250 - 5330 @ 40), (N/A, 20), DFS
+	(5490 - 5710 @ 40), (N/A, 27), DFS
+	# 60 gHz band channels 1-4, ref: Etsi En 302 567
+	(57240 - 65880 @ 2160), (N/A, 40), NO-OUTDOOR
+
+country JM:
+	(2402 - 2482 @ 40), (N/A, 20)
+	(5170 - 5250 @ 40), (3, 17)
+	(5250 - 5330 @ 40), (3, 20), DFS
+	(5490 - 5710 @ 40), (3, 20), DFS
+	(5735 - 5835 @ 40), (3, 30)
+
+country JP:
+	(2402 - 2482 @ 40), (N/A, 20)
+	(2474 - 2494 @ 20), (N/A, 20), NO-OFDM
+	(4910 - 4990 @ 40), (N/A, 23)
+	(5030 - 5090 @ 40), (N/A, 23)
+	(5170 - 5250 @ 40), (N/A, 20)
+	(5250 - 5330 @ 40), (N/A, 20), DFS
+	(5490 - 5710 @ 40), (N/A, 23), DFS
+
+country JO:
+	(2402 - 2482 @ 40), (N/A, 20)
+	(5170 - 5250 @ 40), (N/A, 18)
+
+country KE:
+	(2402 - 2482 @ 40), (N/A, 20)
+	(5735 - 5835 @ 40), (N/A, 30)
+
+country KH:
+	(2402 - 2482 @ 40), (N/A, 20)
+	(5170 - 5250 @ 40), (N/A, 20)
+	(5250 - 5330 @ 40), (N/A, 20), DFS
+	(5490 - 5710 @ 40), (N/A, 27), DFS
+
+country KP:
+	(2402 - 2482 @ 40), (N/A, 20)
+	(5170 - 5330 @ 40), (3, 20)
+	(5160 - 5250 @ 40), (3, 20), DFS
+	(5490 - 5630 @ 40), (3, 30), DFS
+	(5735 - 5815 @ 40), (3, 30)
+
+country KR:
+	(2402 - 2482 @ 20), (N/A, 20)
+	(5170 - 5250 @ 20), (3, 20)
+	(5250 - 5330 @ 20), (3, 20), DFS
+	(5490 - 5630 @ 20), (3, 30), DFS
+	(5735 - 5815 @ 20), (3, 30)
+
+country KW:
+	(2402 - 2482 @ 40), (N/A, 20)
+	(5170 - 5250 @ 40), (N/A, 20)
+	(5250 - 5330 @ 40), (N/A, 20), DFS
+
+country KZ:
+	(2402 - 2482 @ 40), (N/A, 20)
+
+country LB:
+	(2402 - 2482 @ 40), (N/A, 20)
+	(5735 - 5835 @ 40), (N/A, 30)
+
+country LI: DFS-ETSI
+	(2402 - 2482 @ 40), (N/A, 20)
+	(5170 - 5250 @ 40), (N/A, 20)
+	(5250 - 5330 @ 40), (N/A, 20), DFS
+	(5490 - 5710 @ 40), (N/A, 27), DFS
+
+country LK:
+	(2402 - 2482 @ 40), (N/A, 20)
+	(5170 - 5250 @ 20), (3, 17)
+	(5250 - 5330 @ 20), (3, 20), DFS
+	(5490 - 5710 @ 20), (3, 20), DFS
+	(5735 - 5835 @ 20), (3, 30)
+
+country LT: DFS-ETSI
+	(2402 - 2482 @ 40), (N/A, 20)
+	(5170 - 5250 @ 40), (N/A, 20)
+	(5250 - 5330 @ 40), (N/A, 20), DFS
+	(5490 - 5710 @ 40), (N/A, 27), DFS
+	# 60 gHz band channels 1-4, ref: Etsi En 302 567
+	(57240 - 65880 @ 2160), (N/A, 40), NO-OUTDOOR
+
+country LU: DFS-ETSI
+	(2402 - 2482 @ 40), (N/A, 20)
+	(5170 - 5250 @ 40), (N/A, 20)
+	(5250 - 5330 @ 40), (N/A, 20), DFS
+	(5490 - 5710 @ 40), (N/A, 27), DFS
+	# 60 gHz band channels 1-4, ref: Etsi En 302 567
+	(57240 - 65880 @ 2160), (N/A, 40), NO-OUTDOOR
+
+country LV: DFS-ETSI
+	(2402 - 2482 @ 40), (N/A, 20)
+	(5170 - 5250 @ 40), (N/A, 20)
+	(5250 - 5330 @ 40), (N/A, 20), DFS
+	(5490 - 5710 @ 40), (N/A, 27), DFS
+	# 60 gHz band channels 1-4, ref: Etsi En 302 567
+	(57240 - 65880 @ 2160), (N/A, 40), NO-OUTDOOR
+
+country MC: DFS-ETSI
+	(2402 - 2482 @ 40), (N/A, 20)
+	(5170 - 5250 @ 40), (N/A, 18)
+	(5250 - 5330 @ 40), (N/A, 18), DFS
+
+country MA:
+	(2402 - 2482 @ 40), (N/A, 20)
+
+country MO:
+	(2402 - 2482 @ 40), (N/A, 20)
+	(5170 - 5250 @ 40), (3, 23)
+	(5250 - 5330 @ 40), (3, 23), DFS
+	(5735 - 5835 @ 40), (3, 30)
+
+country MK: DFS-ETSI
+	(2402 - 2482 @ 40), (N/A, 20)
+	(5170 - 5250 @ 40), (N/A, 20)
+	(5250 - 5330 @ 40), (N/A, 20), DFS
+	(5490 - 5710 @ 40), (N/A, 27), DFS
+	# 60 gHz band channels 1-4, ref: Etsi En 302 567
+	(57240 - 65880 @ 2160), (N/A, 40), NO-OUTDOOR
+
+country MT: DFS-ETSI
+	(2402 - 2482 @ 40), (N/A, 20)
+	(5170 - 5250 @ 40), (N/A, 20)
+	(5250 - 5330 @ 40), (N/A, 20), DFS
+	(5490 - 5710 @ 40), (N/A, 27), DFS
+	# 60 gHz band channels 1-4, ref: Etsi En 302 567
+	(57240 - 65880 @ 2160), (N/A, 40), NO-OUTDOOR
+
+country MY:
+	(2402 - 2482 @ 40), (N/A, 20)
+	(5250 - 5330 @ 40), (N/A, 30), DFS
+	(5735 - 5835 @ 40), (N/A, 30)
+
+country MX:
+	(2402 - 2472 @ 40), (3, 27)
+	(5170 - 5250 @ 40), (3, 17)
+	(5250 - 5330 @ 40), (3, 23), DFS
+	(5735 - 5835 @ 40), (3, 30)
+
+country NL: DFS-ETSI
+	(2402 - 2482 @ 40), (N/A, 20)
+	(5170 - 5250 @ 40), (N/A, 20), NO-OUTDOOR
+	(5250 - 5330 @ 40), (N/A, 20), NO-OUTDOOR, DFS
+	(5490 - 5710 @ 40), (N/A, 27), DFS
+	# 60 gHz band channels 1-4, ref: Etsi En 302 567
+	(57240 - 65880 @ 2160), (N/A, 40), NO-OUTDOOR
+
+country NO: DFS-ETSI
+	(2402 - 2482 @ 40), (N/A, 20)
+	(5170 - 5250 @ 40), (N/A, 20)
+	(5250 - 5330 @ 40), (N/A, 20), DFS
+	(5490 - 5710 @ 40), (N/A, 27), DFS
+	# 60 gHz band channels 1-4, ref: Etsi En 302 567
+	(57240 - 65880 @ 2160), (N/A, 40), NO-OUTDOOR
+
+country NP:
+	(2402 - 2482 @ 40), (N/A, 20)
+	(5735 - 5835 @ 40), (N/A, 30)
+
+country NZ:
+	(2402 - 2482 @ 40), (N/A, 30)
+	(5170 - 5250 @ 20), (3, 23)
+	(5250 - 5330 @ 20), (3, 23), DFS
+	(5735 - 5835 @ 20), (3, 30)
+
+country OM:
+	(2402 - 2482 @ 40), (N/A, 20)
+	(5170 - 5250 @ 40), (3, 17)
+	(5250 - 5330 @ 40), (3, 20), DFS
+	(5490 - 5710 @ 40), (3, 20), DFS
+	(5735 - 5835 @ 40), (3, 30)
+
+country PA:
+	(2402 - 2472 @ 40), (3, 27)
+	(5170 - 5250 @ 40), (3, 17)
+	(5250 - 5330 @ 40), (3, 23), DFS
+	(5735 - 5835 @ 40), (3, 30)
+
+country PE:
+	(2402 - 2482 @ 40), (N/A, 20)
+	(5735 - 5835 @ 40), (N/A, 30)
+
+country PG:
+	(2402 - 2482 @ 40), (N/A, 20)
+	(5170 - 5250 @ 40), (3, 17)
+	(5250 - 5330 @ 40), (3, 23), DFS
+	(5735 - 5835 @ 40), (3, 30)
+
+country PH:
+	(2402 - 2482 @ 40), (N/A, 20)
+	(5735 - 5835 @ 40), (N/A, 30)
+
+country PK:
+	(2402 - 2482 @ 40), (N/A, 20)
+	(5735 - 5835 @ 40), (N/A, 30)
+
+country PL: DFS-ETSI
+	(2402 - 2482 @ 40), (N/A, 20)
+	(5170 - 5250 @ 40), (N/A, 20)
+	(5250 - 5330 @ 40), (N/A, 20), DFS
+	(5490 - 5710 @ 40), (N/A, 27), DFS
+	# 60 gHz band channels 1-4, ref: Etsi En 302 567
+	(57240 - 65880 @ 2160), (N/A, 40), NO-OUTDOOR
+
+country PT: DFS-ETSI
+	(2402 - 2482 @ 40), (N/A, 20)
+	(5170 - 5250 @ 40), (N/A, 20)
+	(5250 - 5330 @ 40), (N/A, 20), DFS
+	(5490 - 5710 @ 40), (N/A, 27), DFS
+	# 60 gHz band channels 1-4, ref: Etsi En 302 567
+	(57240 - 65880 @ 2160), (N/A, 40), NO-OUTDOOR
+
+country PR:
+	(2402 - 2472 @ 40), (3, 27)
+	(5170 - 5250 @ 40), (3, 17)
+	(5250 - 5330 @ 40), (3, 23), DFS
+	(5735 - 5835 @ 40), (3, 30)
+
+country QA:
+	(2402 - 2482 @ 40), (N/A, 20)
+	(5735 - 5835 @ 40), (N/A, 30)
+
+country RO: DFS-ETSI
+	(2402 - 2482 @ 40), (N/A, 20)
+	(5170 - 5250 @ 40), (N/A, 20)
+	(5250 - 5330 @ 40), (N/A, 20), DFS
+	(5490 - 5710 @ 40), (N/A, 27), DFS
+	# 60 gHz band channels 1-4, ref: Etsi En 302 567
+	(57240 - 65880 @ 2160), (N/A, 40), NO-OUTDOOR
+
+
+# Source:
+# http://www.ratel.rs/upload/documents/Plan_namene/Plan_namene-sl_glasnik.pdf
+country RS:
+	(2400 - 2483.5 @ 40), (N/A, 100 mW)
+	(5150 - 5350 @ 40), (N/A, 200 mW), NO-OUTDOOR
+	(5470 - 5725 @ 20), (3, 1000 mW), DFS
+	# 60 gHz band channels 1-4, ref: Etsi En 302 567
+	(57240 - 65880 @ 2160), (N/A, 40), NO-OUTDOOR
+
+country RU:
+	(2402 - 2482 @ 40), (N/A, 20)
+	(5735 - 5835 @ 20), (N/A, 30)
+
+country RW:
+	(2402 - 2482 @ 40), (N/A, 20)
+	(5735 - 5835 @ 40), (N/A, 30)
+
+country SA:
+	(2402 - 2482 @ 40), (N/A, 20)
+	(5170 - 5250 @ 20), (3, 23)
+	(5250 - 5330 @ 20), (3, 23), DFS
+	(5735 - 5835 @ 20), (3, 30)
+
+country SE: DFS-ETSI
+	(2402 - 2482 @ 40), (N/A, 20)
+	(5170 - 5250 @ 40), (N/A, 20)
+	(5250 - 5330 @ 40), (N/A, 20), DFS
+	(5490 - 5710 @ 40), (N/A, 27), DFS
+	# 60 gHz band channels 1-4, ref: Etsi En 302 567
+	(57240 - 65880 @ 2160), (N/A, 40), NO-OUTDOOR
+
+country SG:
+	(2402 - 2482 @ 40), (N/A, 20)
+	(5170 - 5250 @ 40), (N/A, 20)
+	(5250 - 5330 @ 40), (N/A, 20), DFS
+	(5735 - 5835 @ 40), (N/A, 20)
+
+country SI: DFS-ETSI
+	(2402 - 2482 @ 40), (N/A, 20)
+	(5170 - 5250 @ 40), (N/A, 20)
+	(5250 - 5330 @ 40), (N/A, 20), DFS
+	(5490 - 5710 @ 40), (N/A, 27), DFS
+	# 60 gHz band channels 1-4, ref: Etsi En 302 567
+	(57240 - 65880 @ 2160), (N/A, 40), NO-OUTDOOR
+
+country SK: DFS-ETSI
+	(2402 - 2482 @ 40), (N/A, 20)
+	(5170 - 5250 @ 40), (N/A, 20)
+	(5250 - 5330 @ 40), (N/A, 20), DFS
+	(5490 - 5710 @ 40), (N/A, 27), DFS
+	# 60 gHz band channels 1-4, ref: Etsi En 302 567
+	(57240 - 65880 @ 2160), (N/A, 40), NO-OUTDOOR
+
+country SV:
+	(2402 - 2482 @ 40), (N/A, 20)
+	(5170 - 5250 @ 20), (3, 17)
+	(5250 - 5330 @ 20), (3, 23), DFS
+	(5735 - 5835 @ 20), (3, 30)
+
+country SY:
+	(2402 - 2482 @ 40), (N/A, 20)
+
+country TW:
+	(2402 - 2472 @ 40), (3, 27)
+	(5270 - 5330 @ 40), (3, 17), DFS
+	(5735 - 5815 @ 40), (3, 30)
+
+country TH:
+	(2402 - 2482 @ 40), (N/A, 20)
+	(5170 - 5250 @ 40), (3, 17)
+	(5250 - 5330 @ 40), (3, 20), DFS
+	(5490 - 5710 @ 40), (3, 20), DFS
+	(5735 - 5835 @ 40), (3, 30)
+
+country TT:
+	(2402 - 2482 @ 40), (N/A, 20)
+	(5170 - 5250 @ 40), (3, 17)
+	(5250 - 5330 @ 40), (3, 20), DFS
+	(5490 - 5710 @ 40), (3, 20), DFS
+	(5735 - 5835 @ 40), (3, 30)
+
+country TN:
+	(2402 - 2482 @ 40), (N/A, 20)
+	(5170 - 5250 @ 20), (N/A, 20)
+	(5250 - 5330 @ 20), (N/A, 20), DFS
+
+country TR: DFS-ETSI
+	(2402 - 2482 @ 40), (N/A, 20)
+	(5170 - 5250 @ 20), (N/A, 20)
+	(5250 - 5330 @ 20), (N/A, 20), DFS
+	# 60 gHz band channels 1-4, ref: Etsi En 302 567
+	(57240 - 65880 @ 2160), (N/A, 40), NO-OUTDOOR
+ 
+# Source:
+# #914 / 06 Sep 2007: http://www.ucrf.gov.ua/uk/doc/nkrz/1196068874
+# #1174 / 23 Oct 2008: http://www.nkrz.gov.ua/uk/activities/ruling/1225269361
+# (appendix 8)
+# Listed 5GHz range is a lowest common denominator for all related
+# rules in the referenced laws. Such a range is used because of
+# disputable definitions there.
+country UA:
+	(2400 - 2483.5 @ 40), (N/A, 20), NO-OUTDOOR
+	(5150 - 5350 @ 40), (N/A, 20), NO-OUTDOOR
+	# 60 gHz band channels 1-4, ref: Etsi En 302 567
+	(57240 - 65880 @ 2160), (N/A, 40), NO-OUTDOOR
+
+country US: DFS-FCC
+	(2402 - 2472 @ 40), (3, 27)
+	(5170 - 5250 @ 40), (3, 17)
+	(5250 - 5330 @ 40), (3, 20), DFS
+	(5490 - 5600 @ 40), (3, 20), DFS
+	(5650 - 5710 @ 40), (3, 20), DFS
+	(5735 - 5835 @ 40), (3, 30)
+	# 60g band
+	# reference: http://cfr.regstoday.com/47cfr15.aspx#47_CFR_15p255
+	# channels 1,2,3, EIRP=40dBm(43dBm peak)
+	(57240 - 63720 @ 2160), (N/A, 40)
+
+country UY:
+	(2402 - 2482 @ 40), (N/A, 20)
+	(5170 - 5250 @ 40), (3, 17)
+	(5250 - 5330 @ 40), (3, 20), DFS
+	(5490 - 5710 @ 40), (3, 20), DFS
+	(5735 - 5835 @ 40), (3, 30)
+
+country UZ:
+	(2402 - 2472 @ 40), (3, 27)
+	(5170 - 5250 @ 40), (3, 17)
+	(5250 - 5330 @ 40), (3, 20), DFS
+	(5490 - 5710 @ 40), (3, 20), DFS
+	(5735 - 5835 @ 40), (3, 30)
+
+country VE:
+	(2402 - 2482 @ 40), (N/A, 20)
+	(5735 - 5815 @ 40), (N/A, 23)
+
+country VN:
+	(2402 - 2482 @ 40), (N/A, 20)
+	(5170 - 5250 @ 40), (N/A, 20)
+	(5250 - 5330 @ 40), (N/A, 20), DFS
+
+country YE:
+	(2402 - 2482 @ 40), (N/A, 20)
+
+country ZA:
+	(2402 - 2482 @ 40), (N/A, 20)
+	(5170 - 5250 @ 40), (3, 17)
+	(5250 - 5330 @ 40), (3, 20), DFS
+	(5490 - 5710 @ 40), (3, 20), DFS
+	(5735 - 5835 @ 40), (3, 30)
+
+country ZW:
+	(2402 - 2482 @ 40), (N/A, 20)
+
diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c
index 1dee449..7db02f3 100644
--- a/net/wireless/nl80211.c
+++ b/net/wireless/nl80211.c
@@ -2408,8 +2408,8 @@
 		return -ENOENT;
 
 	err = rdev->ops->stop_ap(&rdev->wiphy, dev);
-	if (!err)
-		wdev->beacon_interval = 0;
+	wdev->beacon_interval = 0;
+
 	return err;
 }
 
@@ -8473,6 +8473,18 @@
 }
 EXPORT_SYMBOL(cfg80211_ft_event);
 
+
+void cfg80211_ap_stopped(struct net_device *netdev, gfp_t gfp)
+{
+	struct wireless_dev *wdev = netdev->ieee80211_ptr;
+	struct cfg80211_registered_device *rdev = wiphy_to_dev(wdev->wiphy);
+
+	nl80211_send_mlme_event(rdev, netdev, NULL, 0,
+				NL80211_CMD_STOP_AP, gfp);
+}
+EXPORT_SYMBOL(cfg80211_ap_stopped);
+
+
 /* initialisation/exit functions */
 
 int nl80211_init(void)
diff --git a/scripts/Makefile.lib b/scripts/Makefile.lib
index 0be6f11..b1dd350 100644
--- a/scripts/Makefile.lib
+++ b/scripts/Makefile.lib
@@ -266,6 +266,12 @@
 quiet_cmd_dtc = DTC     $@
 cmd_dtc = $(objtree)/scripts/dtc/dtc -O dtb -o $@ -b 0 $(DTC_FLAGS) -d $(depfile) $<
 
+# cat
+# ---------------------------------------------------------------------------
+# Concatentate multiple files together
+quiet_cmd_cat = CAT     $@
+cmd_cat = (cat $(filter-out FORCE,$^) > $@) || (rm -f $@; false)
+
 # Bzip2
 # ---------------------------------------------------------------------------
 
diff --git a/security/capability.c b/security/capability.c
index 5bb21b1..fc991bc 100644
--- a/security/capability.c
+++ b/security/capability.c
@@ -12,6 +12,26 @@
 
 #include <linux/security.h>
 
+static int cap_binder_set_context_mgr(struct task_struct *mgr)
+{
+	return 0;
+}
+
+static int cap_binder_transaction(struct task_struct *from, struct task_struct *to)
+{
+	return 0;
+}
+
+static int cap_binder_transfer_binder(struct task_struct *from, struct task_struct *to)
+{
+	return 0;
+}
+
+static int cap_binder_transfer_file(struct task_struct *from, struct task_struct *to, struct file *file)
+{
+	return 0;
+}
+
 static int cap_syslog(int type)
 {
 	return 0;
@@ -877,6 +897,10 @@
 
 void __init security_fixup_ops(struct security_operations *ops)
 {
+	set_to_cap_if_null(ops, binder_set_context_mgr);
+	set_to_cap_if_null(ops, binder_transaction);
+	set_to_cap_if_null(ops, binder_transfer_binder);
+	set_to_cap_if_null(ops, binder_transfer_file);
 	set_to_cap_if_null(ops, ptrace_access_check);
 	set_to_cap_if_null(ops, ptrace_traceme);
 	set_to_cap_if_null(ops, capget);
diff --git a/security/security.c b/security/security.c
index bf619ff..cecd55e 100644
--- a/security/security.c
+++ b/security/security.c
@@ -130,6 +130,26 @@
 
 /* Security operations */
 
+int security_binder_set_context_mgr(struct task_struct *mgr)
+{
+	return security_ops->binder_set_context_mgr(mgr);
+}
+
+int security_binder_transaction(struct task_struct *from, struct task_struct *to)
+{
+	return security_ops->binder_transaction(from, to);
+}
+
+int security_binder_transfer_binder(struct task_struct *from, struct task_struct *to)
+{
+	return security_ops->binder_transfer_binder(from, to);
+}
+
+int security_binder_transfer_file(struct task_struct *from, struct task_struct *to, struct file *file)
+{
+	return security_ops->binder_transfer_file(from, to, file);
+}
+
 int security_ptrace_access_check(struct task_struct *child, unsigned int mode)
 {
 	return security_ops->ptrace_access_check(child, mode);
diff --git a/security/selinux/hooks.c b/security/selinux/hooks.c
index d85b793..b28b7eb 100644
--- a/security/selinux/hooks.c
+++ b/security/selinux/hooks.c
@@ -1818,6 +1818,67 @@
 
 /* Hook functions begin here. */
 
+static int selinux_binder_set_context_mgr(struct task_struct *mgr)
+{
+	u32 mysid = current_sid();
+	u32 mgrsid = task_sid(mgr);
+
+	return avc_has_perm(mysid, mgrsid, SECCLASS_BINDER, BINDER__SET_CONTEXT_MGR, NULL);
+}
+
+static int selinux_binder_transaction(struct task_struct *from, struct task_struct *to)
+{
+	u32 mysid = current_sid();
+	u32 fromsid = task_sid(from);
+	u32 tosid = task_sid(to);
+	int rc;
+
+	if (mysid != fromsid) {
+		rc = avc_has_perm(mysid, fromsid, SECCLASS_BINDER, BINDER__IMPERSONATE, NULL);
+		if (rc)
+			return rc;
+	}
+
+	return avc_has_perm(fromsid, tosid, SECCLASS_BINDER, BINDER__CALL, NULL);
+}
+
+static int selinux_binder_transfer_binder(struct task_struct *from, struct task_struct *to)
+{
+	u32 fromsid = task_sid(from);
+	u32 tosid = task_sid(to);
+	return avc_has_perm(fromsid, tosid, SECCLASS_BINDER, BINDER__TRANSFER, NULL);
+}
+
+static int selinux_binder_transfer_file(struct task_struct *from, struct task_struct *to, struct file *file)
+{
+	u32 sid = task_sid(to);
+	struct file_security_struct *fsec = file->f_security;
+	struct inode *inode = file->f_path.dentry->d_inode;
+	struct inode_security_struct *isec = inode->i_security;
+	struct common_audit_data ad;
+	struct selinux_audit_data sad = {0,};
+	int rc;
+
+	COMMON_AUDIT_DATA_INIT(&ad, PATH);
+	ad.u.path = file->f_path;
+	ad.selinux_audit_data = &sad;
+
+	if (sid != fsec->sid) {
+		rc = avc_has_perm(sid, fsec->sid,
+				  SECCLASS_FD,
+				  FD__USE,
+				  &ad);
+		if (rc)
+			return rc;
+	}
+
+	if (unlikely(IS_PRIVATE(inode)))
+		return 0;
+
+	return avc_has_perm(sid, isec->sid, isec->sclass, file_to_av(file),
+			    &ad);
+}
+
 static int selinux_ptrace_access_check(struct task_struct *child,
 				     unsigned int mode)
 {
@@ -5523,6 +5584,11 @@
 static struct security_operations selinux_ops = {
 	.name =				"selinux",
 
+	.binder_set_context_mgr =	selinux_binder_set_context_mgr,
+	.binder_transaction =		selinux_binder_transaction,
+	.binder_transfer_binder =	selinux_binder_transfer_binder,
+	.binder_transfer_file =		selinux_binder_transfer_file,
+
 	.ptrace_access_check =		selinux_ptrace_access_check,
 	.ptrace_traceme =		selinux_ptrace_traceme,
 	.capget =			selinux_capget,
diff --git a/security/selinux/include/classmap.h b/security/selinux/include/classmap.h
index b8c5372..4a4a9ae 100644
--- a/security/selinux/include/classmap.h
+++ b/security/selinux/include/classmap.h
@@ -149,5 +149,6 @@
 	{ "kernel_service", { "use_as_override", "create_files_as", NULL } },
 	{ "tun_socket",
 	  { COMMON_SOCK_PERMS, NULL } },
+	{ "binder", { "impersonate", "call", "set_context_mgr", "transfer", NULL } },
 	{ NULL }
   };
diff --git a/sound/core/init.c b/sound/core/init.c
index f300bd3..6559a40 100644
--- a/sound/core/init.c
+++ b/sound/core/init.c
@@ -55,6 +55,8 @@
 module_param_array(slots, charp, NULL, 0444);
 MODULE_PARM_DESC(slots, "Module names assigned to the slots.");
 
+#define SND_CARD_STATE_MAX_LEN 16
+
 /* return non-zero if the given index is reserved for the given
  * module via slots option
  */
@@ -104,10 +106,40 @@
 	snd_iprintf(buffer, "%s\n", entry->card->id);
 }
 
+static int snd_card_state_read(struct snd_info_entry *entry,
+			       void *file_private_data, struct file *file,
+			       char __user *buf, size_t count, loff_t pos)
+{
+	int len;
+	char buffer[SND_CARD_STATE_MAX_LEN];
+
+	/* make sure offline is updated prior to wake up */
+	rmb();
+	len = snprintf(buffer, sizeof(buffer), "%s\n",
+		       entry->card->offline ? "OFFLINE" : "ONLINE");
+	return simple_read_from_buffer(buf, count, &pos, buffer, len);
+}
+
+static unsigned int snd_card_state_poll(struct snd_info_entry *entry,
+					void *private_data, struct file *file,
+					poll_table *wait)
+{
+	poll_wait(file, &entry->card->offline_poll_wait, wait);
+	if (xchg(&entry->card->offline_change, 0))
+		return POLLIN | POLLPRI | POLLRDNORM;
+	else
+		return 0;
+}
+
+static struct snd_info_entry_ops snd_card_state_proc_ops = {
+	.read = snd_card_state_read,
+	.poll = snd_card_state_poll,
+};
+
 static inline int init_info_for_card(struct snd_card *card)
 {
 	int err;
-	struct snd_info_entry *entry;
+	struct snd_info_entry *entry, *entry_state;
 
 	if ((err = snd_info_card_register(card)) < 0) {
 		snd_printd("unable to create card info\n");
@@ -123,6 +155,24 @@
 		entry = NULL;
 	}
 	card->proc_id = entry;
+
+	entry_state = snd_info_create_card_entry(card, "state",
+						 card->proc_root);
+	if (entry_state == NULL) {
+		snd_printd("unable to create card entry state\n");
+		card->proc_id = NULL;
+		return err;
+	}
+	entry_state->size = SND_CARD_STATE_MAX_LEN;
+	entry_state->content = SNDRV_INFO_CONTENT_DATA;
+	entry_state->c.ops = &snd_card_state_proc_ops;
+	err = snd_info_register(entry_state);
+	if (err < 0) {
+		snd_printd("unable to register card entry state\n");
+		card->proc_id = NULL;
+		return err;
+	}
+
 	return 0;
 }
 #else /* !CONFIG_PROC_FS */
@@ -216,6 +266,7 @@
 	mutex_init(&card->power_lock);
 	init_waitqueue_head(&card->power_sleep);
 #endif
+	init_waitqueue_head(&card->offline_poll_wait);
 	/* 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);
@@ -909,6 +960,35 @@
 
 EXPORT_SYMBOL(snd_card_file_remove);
 
+/**
+ * snd_card_change_online_state - mark card's online/offline state
+ * @card: Card to mark
+ * @online: whether online of offline
+ *
+ * Mutes the DAI DAC.
+ */
+void snd_card_change_online_state(struct snd_card *card, int online)
+{
+	snd_printd("snd card %s state change %d -> %d\n",
+		   card->shortname, !card->offline, online);
+	card->offline = !online;
+	/* make sure offline is updated prior to wake up */
+	wmb();
+	xchg(&card->offline_change, 1);
+	wake_up_interruptible(&card->offline_poll_wait);
+}
+EXPORT_SYMBOL(snd_card_change_online_state);
+
+/**
+ * snd_card_is_online_state - return true if card is online state
+ * @card: Card to query
+ */
+bool snd_card_is_online_state(struct snd_card *card)
+{
+	return !card->offline;
+}
+EXPORT_SYMBOL(snd_card_is_online_state);
+
 #ifdef CONFIG_PM
 /**
  *  snd_power_wait - wait until the power-state is changed.
diff --git a/sound/soc/codecs/Makefile b/sound/soc/codecs/Makefile
index c0469e3..56cd5e6 100644
--- a/sound/soc/codecs/Makefile
+++ b/sound/soc/codecs/Makefile
@@ -165,7 +165,7 @@
 obj-$(CONFIG_SND_SOC_CS8427)	+= snd-soc-cs8427.o
 obj-$(CONFIG_SND_SOC_WCD9320)	+= snd-soc-wcd9320.o
 obj-$(CONFIG_SND_SOC_WCD9306)	+= snd-soc-wcd9306.o wcd9xxx-resmgr.o wcd9xxx-mbhc.o
-obj-$(CONFIG_SND_SOC_MSM8X10_WCD)	+= snd-soc-msm8x10-wcd.o wcd9xxx-resmgr.o
+obj-$(CONFIG_SND_SOC_MSM8X10_WCD)	+= snd-soc-msm8x10-wcd.o wcd9xxx-resmgr.o wcd9xxx-mbhc.o
 obj-$(CONFIG_SND_SOC_WL1273)	+= snd-soc-wl1273.o
 obj-$(CONFIG_SND_SOC_WM1250_EV1) += snd-soc-wm1250-ev1.o
 obj-$(CONFIG_SND_SOC_WM2000)	+= snd-soc-wm2000.o
diff --git a/sound/soc/codecs/msm8x10-wcd.c b/sound/soc/codecs/msm8x10-wcd.c
index 46b0a91..4e3df21 100644
--- a/sound/soc/codecs/msm8x10-wcd.c
+++ b/sound/soc/codecs/msm8x10-wcd.c
@@ -27,7 +27,6 @@
 #include <linux/i2c.h>
 #include <linux/of_gpio.h>
 #include <linux/regulator/consumer.h>
-#include <linux/mfd/wcd9xxx/core.h>
 #include <linux/mfd/wcd9xxx/pdata.h>
 #include <sound/pcm.h>
 #include <sound/pcm_params.h>
@@ -52,6 +51,7 @@
 
 #define MSM8X10_WCD_I2S_MASTER_MODE_MASK	0x08
 #define MSM8X10_DINO_CODEC_BASE_ADDR		0xFE043000
+#define MSM8X10_DINO_CODEC_REG_SIZE		0x200
 #define MSM8x10_TLMM_CDC_PULL_CTL			0xFD512050
 #define HELICON_CORE_0_I2C_ADDR				0x0d
 #define HELICON_CORE_1_I2C_ADDR				0x77
@@ -61,6 +61,7 @@
 #define MAX_MSM8X10_WCD_DEVICE	4
 #define CODEC_DT_MAX_PROP_SIZE	40
 #define MAX_ON_DEMAND_SUPPLY_NAME_LENGTH 64
+#define HELICON_MCLK_CLK_9P6MHZ				9600000
 
 enum {
 	MSM8X10_WCD_I2C_TOP_LEVEL = 0,
@@ -125,6 +126,16 @@
 	ON_DEMAND_SUPPLIES_MAX,
 };
 
+/*
+ * The delay list is per codec HW specification.
+ * Please add delay in the list in the future instead
+ * of magic number
+ */
+enum {
+	CODEC_DELAY_1_MS = 1000,
+	CODEC_DELAY_1_1_MS  = 1100,
+};
+
 struct hpf_work {
 	struct msm8x10_wcd_priv *msm8x10_wcd;
 	u32 decimator;
@@ -149,15 +160,14 @@
 	u32 adc_count;
 	u32 rx_bias_count;
 	s32 dmic_1_2_clk_cnt;
-	enum msm8x10_wcd_bandgap_type bandgap_type;
-	bool mclk_enabled;
-	bool clock_active;
-	bool config_mode_active;
-	bool mbhc_polling_active;
 	struct on_demand_supply on_demand_list[ON_DEMAND_SUPPLIES_MAX];
-	struct mutex codec_resource_lock;
 	/* resmgr module */
 	struct wcd9xxx_resmgr resmgr;
+	/* mbhc module */
+	struct wcd9xxx_mbhc mbhc;
+
+	struct delayed_work hs_detect_work;
+	struct wcd9xxx_mbhc_config *mbhc_cfg;
 };
 
 static unsigned short rx_digital_gain_reg[] = {
@@ -211,20 +221,23 @@
 	return rtn;
 }
 
-static int msm8x10_wcd_abh_write_device(u16 reg, u8 *value, u32 bytes)
+static int msm8x10_wcd_abh_write_device(struct msm8x10_wcd *msm8x10_wcd,
+					u16 reg, u8 *value, u32 bytes)
 {
 	u32 temp = ((u32)(*value)) & 0x000000FF;
 	u32 offset = (((u32)(reg)) ^ 0x00000400) & 0x00000FFF;
-	iowrite32(temp, ioremap(MSM8X10_DINO_CODEC_BASE_ADDR + offset, 4));
+
+	iowrite32(temp, (msm8x10_wcd->pdino_base+offset));
 	return 0;
 }
 
-static int msm8x10_wcd_abh_read_device(u16 reg, u32 bytes, u8 *value)
+static int msm8x10_wcd_abh_read_device(struct msm8x10_wcd *msm8x10_wcd,
+					u16 reg, u32 bytes, u8 *value)
 {
 	u32 temp;
 	u32 offset = (((u32)(reg)) ^ 0x00000400) & 0x00000FFF;
-	temp = ioread32(ioremap(MSM8X10_DINO_CODEC_BASE_ADDR +
-				      offset, 4));
+
+	temp = ioread32((msm8x10_wcd->pdino_base+offset));
 	*value = (u8)temp;
 	return 0;
 }
@@ -330,40 +343,112 @@
 	return msm8x10_wcd_i2c_write_device(reg, src, bytes);
 }
 
-static int msm8x10_wcd_reg_read(struct msm8x10_wcd *msm8x10_wcd,
-				u16 reg, unsigned int *val)
+static unsigned short msm8x10_wcd_mask_reg(unsigned short reg)
+{
+	if (reg >= 0x3C0 && reg <= 0x3DF)
+		reg = reg & 0x00FF;
+	return reg;
+}
+
+static int __msm8x10_wcd_reg_read(struct msm8x10_wcd *msm8x10_wcd,
+				unsigned short reg)
 {
 	int ret = -EINVAL;
 	u8 temp;
 
+	reg = msm8x10_wcd_mask_reg(reg);
+
 	/* check if use I2C interface for Helicon or AHB for Dino */
 	mutex_lock(&msm8x10_wcd->io_lock);
 	if (MSM8X10_WCD_IS_HELICON_REG(reg))
 		ret = msm8x10_wcd_i2c_read(reg, 1, &temp);
 	else if (MSM8X10_WCD_IS_DINO_REG(reg))
-		ret = msm8x10_wcd_abh_read_device(reg, 1, &temp);
+		ret = msm8x10_wcd_abh_read_device(msm8x10_wcd, reg, 1, &temp);
 	mutex_unlock(&msm8x10_wcd->io_lock);
-	*val = temp;
+
+	if (ret < 0) {
+		dev_err(msm8x10_wcd->dev,
+				"%s: codec read failed for reg 0x%x\n",
+				__func__, reg);
+		return ret;
+	} else {
+		dev_dbg(msm8x10_wcd->dev, "Read 0x%02x from 0x%x\n",
+				temp, reg);
+	}
+
+	return temp;
+}
+
+int msm8x10_wcd_reg_read(struct wcd9xxx_core_resource *core_res,
+				unsigned short reg)
+{
+	struct msm8x10_wcd *msm8x10_wcd = core_res->parent;
+	return __msm8x10_wcd_reg_read(msm8x10_wcd, reg);
+}
+EXPORT_SYMBOL(msm8x10_wcd_reg_read);
+
+static int __msm8x10_wcd_bulk_read(struct msm8x10_wcd *msm8x10_wcd,
+		unsigned short reg, int count, u8 *buf)
+{
+	int ret = -EINVAL;
+	mutex_lock(&msm8x10_wcd->io_lock);
+	if (MSM8X10_WCD_IS_HELICON_REG(reg))
+		ret = msm8x10_wcd_i2c_read(reg, count, buf);
+	else if (MSM8X10_WCD_IS_DINO_REG(reg))
+		ret = msm8x10_wcd_abh_read_device(msm8x10_wcd, reg,
+						count, buf);
+	mutex_unlock(&msm8x10_wcd->io_lock);
+
+	if (ret < 0)
+		dev_err(msm8x10_wcd->dev,
+				"%s: codec bulk read failed\n", __func__);
 	return ret;
 }
 
+int msm8x10_wcd_bulk_read(struct wcd9xxx_core_resource *core_res,
+			unsigned short reg, int count, u8 *buf)
+{
+	struct msm8x10_wcd *msm8x10_wcd =
+				(struct msm8x10_wcd *) core_res->parent;
+	return __msm8x10_wcd_bulk_read(msm8x10_wcd, reg, count, buf);
+}
+EXPORT_SYMBOL(msm8x10_wcd_bulk_read);
 
-static int msm8x10_wcd_reg_write(struct msm8x10_wcd *msm8x10_wcd, u16  reg,
-				 u8 val)
+static int __msm8x10_wcd_reg_write(struct msm8x10_wcd *msm8x10_wcd,
+			unsigned short reg, u8 val)
 {
 	int ret = -EINVAL;
 
+	reg = msm8x10_wcd_mask_reg(reg);
+
 	/* check if use I2C interface for Helicon or AHB for Dino */
 	mutex_lock(&msm8x10_wcd->io_lock);
 	if (MSM8X10_WCD_IS_HELICON_REG(reg))
 		ret = msm8x10_wcd_i2c_write(reg, 1, &val);
 	else if (MSM8X10_WCD_IS_DINO_REG(reg))
-		ret = msm8x10_wcd_abh_write_device(reg, &val, 1);
+		ret = msm8x10_wcd_abh_write_device(msm8x10_wcd, reg, &val, 1);
 	mutex_unlock(&msm8x10_wcd->io_lock);
 
+	if (ret < 0)
+		dev_err(msm8x10_wcd->dev,
+				"%s: codec write to reg 0x%x failed\n",
+				__func__, reg);
+	else
+		dev_dbg(msm8x10_wcd->dev,
+				"%s: Codec reg 0x%x written with value 0x%x\n",
+				__func__, reg, val);
+
 	return ret;
 }
 
+int msm8x10_wcd_reg_write(struct wcd9xxx_core_resource *core_res,
+	unsigned short reg, u8 val)
+{
+	struct msm8x10_wcd *msm8x10_wcd = core_res->parent;
+	return __msm8x10_wcd_reg_write(msm8x10_wcd, reg, val);
+}
+EXPORT_SYMBOL(msm8x10_wcd_reg_write);
+
 static bool msm8x10_wcd_is_digital_gain_register(unsigned int reg)
 {
 	bool rtn = false;
@@ -437,7 +522,7 @@
 				reg, ret);
 	}
 
-	return msm8x10_wcd_reg_write(codec->control_data, reg, (u8)value);
+	return __msm8x10_wcd_reg_write(codec->control_data, reg, (u8)value);
 }
 
 static unsigned int msm8x10_wcd_read(struct snd_soc_codec *codec,
@@ -463,7 +548,7 @@
 				reg, ret);
 	}
 
-	ret = msm8x10_wcd_reg_read(codec->control_data, reg, &val);
+	val = __msm8x10_wcd_reg_read(codec->control_data, reg);
 	return val;
 }
 
@@ -1051,9 +1136,6 @@
 			  MSM8X10_WCD_A_CDC_IIR1_GAIN_B4_CTL,
 			  -84,	40, digital_gain),
 
-	SOC_SINGLE("MICBIAS1 CAPLESS Switch",
-		   MSM8X10_WCD_A_MICB_1_CTL, 4, 1, 1),
-
 	SOC_ENUM("TX1 HPF cut off", cf_dec1_enum),
 	SOC_ENUM("TX2 HPF cut off", cf_dec2_enum),
 
@@ -1144,19 +1226,24 @@
 	"ZERO", "ADC1", "ADC2", "DMIC1", "DMIC2"
 };
 
-static const char * const anc_mux_text[] = {
-	"ZERO", "ADC1", "ADC2", "ADC3", "ADC4", "ADC5", "ADC6", "ADC_MB",
-		"RSVD_1", "DMIC1", "DMIC2", "DMIC3", "DMIC4", "DMIC5", "DMIC6"
-};
-
-static const char * const anc1_fb_mux_text[] = {
-	"ZERO", "EAR_HPH_L", "EAR_LINE_1",
+static const char * const adc2_mux_text[] = {
+	"ZERO", "INP2", "INP3"
 };
 
 static const char * const iir1_inp1_text[] = {
 	"ZERO", "DEC1", "DEC2", "RX1", "RX2", "RX3"
 };
 
+/*
+  * There is only one bit to select RX2 (0) or RX3 (1) so add 'ZERO' won't
+  * cause any issue to select the right input, but it eliminates that lineout
+  * is powered-up when HPH is enabled if the 'ZERO" is used in the disable
+  * sequence for lineout.
+  */
+static const char * const rx_rdac4_text[] = {
+	"ZERO", "RX3", "RX2"
+};
+
 static const struct soc_enum rx_mix1_inp1_chain_enum =
 	SOC_ENUM_SINGLE(MSM8X10_WCD_A_CDC_CONN_RX1_B1_CTL, 0, 6, rx_mix1_text);
 
@@ -1194,6 +1281,13 @@
 	SOC_ENUM_SINGLE(MSM8X10_WCD_A_CDC_CONN_EQ1_B1_CTL, 0, 6,
 	iir1_inp1_text);
 
+static const struct soc_enum rx_rdac4_enum  =
+	SOC_ENUM_SINGLE(MSM8X10_WCD_A_CDC_CONN_LO_DAC_CTL, 0, 3,
+	rx_rdac4_text);
+
+static const struct soc_enum adc2_enum =
+	SOC_ENUM_SINGLE_EXT(ARRAY_SIZE(adc2_mux_text), adc2_mux_text);
+
 static const struct snd_kcontrol_new rx_mix1_inp1_mux =
 	SOC_DAPM_ENUM("RX1 MIX1 INP1 Mux", rx_mix1_inp1_chain_enum);
 
@@ -1221,6 +1315,12 @@
 static const struct snd_kcontrol_new rx2_mix2_inp1_mux =
 	SOC_DAPM_ENUM("RX2 MIX2 INP1 Mux", rx2_mix2_inp1_chain_enum);
 
+static const struct snd_kcontrol_new rx_dac4_mux =
+	SOC_DAPM_ENUM("RDAC4 MUX Mux", rx_rdac4_enum);
+
+static const struct snd_kcontrol_new tx_adc2_mux =
+	SOC_DAPM_ENUM("ADC2 MUX Mux", adc2_enum);
+
 static int msm8x10_wcd_put_dec_enum(struct snd_kcontrol *kcontrol,
 			      struct snd_ctl_elem_value *ucontrol)
 {
@@ -1312,6 +1412,10 @@
 	SOC_DAPM_SINGLE("Switch", MSM8X10_WCD_A_RX_HPH_L_DAC_CTL, 6, 1, 0)
 };
 
+static const struct snd_kcontrol_new spkr_switch[] = {
+	SOC_DAPM_SINGLE("Switch", MSM8X10_WCD_A_SPKR_DRV_DAC_CTL, 2, 1, 0)
+};
+
 static void msm8x10_wcd_codec_enable_adc_block(struct snd_soc_codec *codec,
 					 int enable)
 {
@@ -1324,13 +1428,8 @@
 		snd_soc_update_bits(codec,
 				    MSM8X10_WCD_A_CDC_ANA_CLK_CTL,
 				    0x20, 0x20);
-	} else {
+	} else
 		wcd8x10->adc_count--;
-		if (!wcd8x10->adc_count)
-			snd_soc_update_bits(codec,
-					    MSM8X10_WCD_A_CDC_ANA_CLK_CTL,
-					    0x20, 0x0);
-	}
 }
 
 static int msm8x10_wcd_codec_enable_adc(struct snd_soc_dapm_widget *w,
@@ -1345,7 +1444,8 @@
 
 	if (w->reg == MSM8X10_WCD_A_TX_1_EN)
 		init_bit_shift = 7;
-	else if (w->reg == MSM8X10_WCD_A_TX_2_EN)
+	else if ((w->reg == MSM8X10_WCD_A_TX_2_EN) ||
+		 (w->reg == MSM8X10_WCD_A_TX_3_EN))
 		init_bit_shift = 6;
 	else {
 		dev_err(codec->dev, "%s: Error, invalid adc register\n",
@@ -1358,9 +1458,11 @@
 		msm8x10_wcd_codec_enable_adc_block(codec, 1);
 		snd_soc_update_bits(codec, adc_reg, 1 << init_bit_shift,
 				1 << init_bit_shift);
+		usleep_range(CODEC_DELAY_1_MS, CODEC_DELAY_1_1_MS);
 		break;
 	case SND_SOC_DAPM_POST_PMU:
 		snd_soc_update_bits(codec, adc_reg, 1 << init_bit_shift, 0x00);
+		usleep_range(CODEC_DELAY_1_MS, CODEC_DELAY_1_1_MS);
 		break;
 	case SND_SOC_DAPM_POST_PMD:
 		msm8x10_wcd_codec_enable_adc_block(codec, 0);
@@ -1467,15 +1569,20 @@
 	struct snd_kcontrol *kcontrol, int event)
 {
 	struct snd_soc_codec *codec = w->codec;
+	struct msm8x10_wcd_priv *msm8x10_wcd = snd_soc_codec_get_drvdata(codec);
 	u16 micb_int_reg;
 	char *internal1_text = "Internal1";
 	char *internal2_text = "Internal2";
 	char *internal3_text = "Internal3";
+	enum wcd9xxx_notify_event e_post_off, e_pre_on, e_post_on;
 
 	dev_dbg(codec->dev, "%s %d\n", __func__, event);
 	switch (w->reg) {
 	case MSM8X10_WCD_A_MICB_1_CTL:
 		micb_int_reg = MSM8X10_WCD_A_MICB_1_INT_RBIAS;
+		e_pre_on = WCD9XXX_EVENT_PRE_MICBIAS_1_ON;
+		e_post_on = WCD9XXX_EVENT_POST_MICBIAS_1_ON;
+		e_post_off = WCD9XXX_EVENT_POST_MICBIAS_1_OFF;
 		break;
 	default:
 		dev_err(codec->dev,
@@ -1486,18 +1593,28 @@
 
 	switch (event) {
 	case SND_SOC_DAPM_PRE_PMU:
+		/* Let MBHC module know micbias is about to turn ON */
+		wcd9xxx_resmgr_notifier_call(&msm8x10_wcd->resmgr, e_pre_on);
+
 		if (strnstr(w->name, internal1_text, 30))
 			snd_soc_update_bits(codec, micb_int_reg, 0x80, 0x80);
 		else if (strnstr(w->name, internal2_text, 30))
 			snd_soc_update_bits(codec, micb_int_reg, 0x10, 0x10);
 		else if (strnstr(w->name, internal3_text, 30))
 			snd_soc_update_bits(codec, micb_int_reg, 0x2, 0x2);
-		snd_soc_update_bits(codec, w->reg, 0x1, 0x0);
+
+		/* Always pull up TxFe for TX2 to Micbias */
+		snd_soc_update_bits(codec, micb_int_reg, 0x04, 0x04);
 		break;
 	case SND_SOC_DAPM_POST_PMU:
 		usleep_range(20000, 20100);
+		/* Let MBHC module know so micbias is on */
+		wcd9xxx_resmgr_notifier_call(&msm8x10_wcd->resmgr, e_post_on);
 		break;
 	case SND_SOC_DAPM_POST_PMD:
+		/* Let MBHC module know so micbias switch to be off */
+		wcd9xxx_resmgr_notifier_call(&msm8x10_wcd->resmgr, e_post_off);
+
 		if (strnstr(w->name, internal1_text, 30))
 			snd_soc_update_bits(codec, micb_int_reg, 0x80, 0x00);
 		else if (strnstr(w->name, internal2_text, 30))
@@ -1505,7 +1622,8 @@
 		else if (strnstr(w->name, internal3_text, 30))
 			snd_soc_update_bits(codec, micb_int_reg, 0x2, 0x0);
 
-		snd_soc_update_bits(codec, w->reg, 0x1, 0x1);
+		/* Disable pull up TxFe for TX2 to Micbias */
+		snd_soc_update_bits(codec, micb_int_reg, 0x04, 0x00);
 		break;
 	}
 	return 0;
@@ -1757,12 +1875,6 @@
 		/* Let MBHC module know PA turned off */
 		wcd9xxx_resmgr_notifier_call(&msm8x10_wcd->resmgr, e_post_off);
 
-		/*
-		 * schedule work is required because at the time HPH PA DAPM
-		 * event callback is called by DAPM framework, CODEC dapm mutex
-		 * would have been locked while snd_soc_jack_report also
-		 * attempts to acquire same lock.
-		 */
 		dev_dbg(codec->dev,
 			"%s: sleep 10 ms after %s PA disable.\n", __func__,
 			w->name);
@@ -1791,13 +1903,6 @@
 	return 0;
 }
 
-static int msm8x10_wcd_spk_dac_event(struct snd_soc_dapm_widget *w,
-	struct snd_kcontrol *kcontrol, int event)
-{
-	dev_dbg(w->codec->dev, "%s %s %d\n", __func__, w->name, event);
-	return 0;
-}
-
 static const struct snd_soc_dapm_route audio_map[] = {
 	{"RX_I2S_CLK", NULL, "CDC_CONN"},
 	{"I2S RX1", NULL, "RX_I2S_CLK"},
@@ -1815,6 +1920,13 @@
 	{"EAR PA", NULL, "DAC1"},
 	{"DAC1", NULL, "CP"},
 
+	/* Clocks for playback path */
+	{"DAC1", NULL, "EAR CLK"},
+	{"HPHL DAC", NULL, "HPHL CLK"},
+	{"HPHR DAC", NULL, "HPHR CLK"},
+	{"SPK DAC", NULL, "SPK CLK"},
+	{"LINEOUT DAC", NULL, "LINEOUT CLK"},
+
 	/* Headset (RX MIX1 and RX MIX2) */
 	{"HEADPHONE", NULL, "HPHL"},
 	{"HEADPHONE", NULL, "HPHR"},
@@ -1837,11 +1949,15 @@
 
 	{"LINEOUT PA", NULL, "CP"},
 	{"LINEOUT PA", NULL, "LINEOUT DAC"},
+	{"LINEOUT DAC", NULL, "RDAC4 MUX"},
+
+	{"RDAC4 MUX", "RX2", "RX2 CHAIN"},
+	{"RDAC4 MUX", "RX3", "RX3 CHAIN"},
 
 	{"CP", NULL, "CP_REGULATOR"},
 	{"CP", NULL, "RX_BIAS"},
 	{"SPK PA", NULL, "SPK DAC"},
-	{"SPK DAC", NULL, "RX3 CHAIN"},
+	{"SPK DAC", "Switch", "RX3 CHAIN"},
 
 	{"RX1 CHAIN", NULL, "RX1 CLK"},
 	{"RX2 CHAIN", NULL, "RX2 CLK"},
@@ -1908,9 +2024,14 @@
 	{"DEC2 MUX", "ADC2", "ADC2"},
 	{"DEC2 MUX", NULL, "CDC_CONN"},
 
+	{"ADC2", NULL, "ADC2 MUX"},
+	{"ADC2 MUX", "INP2", "ADC2_INP2"},
+	{"ADC2 MUX", "INP3", "ADC2_INP3"},
+
 	/* ADC Connections */
 	{"ADC1", NULL, "AMIC1"},
-	{"ADC2", NULL, "AMIC2"},
+	{"ADC2_INP2", NULL, "AMIC2"},
+	{"ADC2_INP3", NULL, "AMIC3"},
 
 	{"IIR1", NULL, "IIR1 INP1 MUX"},
 	{"IIR1 INP1 MUX", "DEC1", "DEC1 MUX"},
@@ -1940,88 +2061,6 @@
 		substream->name, substream->stream);
 }
 
-static int msm8x10_wcd_codec_enable_clock_block(struct snd_soc_codec *codec,
-						int enable)
-{
-	if (enable) {
-		snd_soc_update_bits(codec, MSM8X10_WCD_A_CDC_CLK_MCLK_CTL,
-				    0x01, 0x01);
-		snd_soc_update_bits(codec, MSM8X10_WCD_A_CDC_CLK_PDM_CTL,
-				    0x03, 0x03);
-		snd_soc_update_bits(codec, MSM8X10_WCD_A_CDC_TOP_CLK_CTL,
-				    0x0f, 0x0d);
-	} else {
-		snd_soc_update_bits(codec, MSM8X10_WCD_A_CDC_TOP_CLK_CTL,
-				    0x0f, 0x00);
-		snd_soc_update_bits(codec, MSM8X10_WCD_A_CDC_CLK_PDM_CTL,
-				    0x03, 0x00);
-	}
-	return 0;
-}
-
-static void msm8x10_wcd_codec_enable_audio_mode_bandgap(struct snd_soc_codec
-							*codec)
-{
-	snd_soc_update_bits(codec, MSM8X10_WCD_A_BIAS_CENTRAL_BG_CTL, 0x80,
-		0x80);
-	snd_soc_update_bits(codec, MSM8X10_WCD_A_BIAS_CENTRAL_BG_CTL, 0x04,
-		0x04);
-	snd_soc_update_bits(codec, MSM8X10_WCD_A_BIAS_CENTRAL_BG_CTL, 0x01,
-		0x01);
-	usleep_range(1000, 1000);
-	snd_soc_update_bits(codec, MSM8X10_WCD_A_BIAS_CENTRAL_BG_CTL, 0x80,
-		0x00);
-}
-
-static void msm8x10_wcd_codec_enable_bandgap(struct snd_soc_codec *codec,
-	enum msm8x10_wcd_bandgap_type choice)
-{
-	struct msm8x10_wcd_priv *msm8x10_wcd = snd_soc_codec_get_drvdata(codec);
-
-	/* TODO lock resources accessed by audio streams and threaded
-	 * interrupt handlers
-	 */
-
-	dev_dbg(codec->dev, "%s, choice is %d, current is %d\n",
-		__func__, choice,
-		msm8x10_wcd->bandgap_type);
-
-	if (msm8x10_wcd->bandgap_type == choice)
-		return;
-
-	if ((msm8x10_wcd->bandgap_type == MSM8X10_WCD_BANDGAP_OFF) &&
-		(choice == MSM8X10_WCD_BANDGAP_AUDIO_MODE)) {
-		msm8x10_wcd_codec_enable_audio_mode_bandgap(codec);
-	} else if (choice == MSM8X10_WCD_BANDGAP_MBHC_MODE) {
-		/* bandgap mode becomes fast,
-		 * mclk should be off or clk buff source souldn't be VBG
-		 * Let's turn off mclk always */
-		snd_soc_update_bits(codec, MSM8X10_WCD_A_BIAS_CENTRAL_BG_CTL,
-				    0x2, 0x2);
-		snd_soc_update_bits(codec, MSM8X10_WCD_A_BIAS_CENTRAL_BG_CTL,
-				    0x80, 0x80);
-		snd_soc_update_bits(codec, MSM8X10_WCD_A_BIAS_CENTRAL_BG_CTL,
-				    0x4, 0x4);
-		snd_soc_update_bits(codec, MSM8X10_WCD_A_BIAS_CENTRAL_BG_CTL,
-				    0x01, 0x01);
-		usleep_range(1000, 1000);
-		snd_soc_update_bits(codec, MSM8X10_WCD_A_BIAS_CENTRAL_BG_CTL,
-				    0x80, 0x00);
-	} else if ((msm8x10_wcd->bandgap_type ==
-		    MSM8X10_WCD_BANDGAP_MBHC_MODE) &&
-		    (choice == MSM8X10_WCD_BANDGAP_AUDIO_MODE)) {
-		snd_soc_write(codec, MSM8X10_WCD_A_BIAS_CENTRAL_BG_CTL, 0x50);
-		usleep_range(100, 100);
-		msm8x10_wcd_codec_enable_audio_mode_bandgap(codec);
-	} else if (choice == MSM8X10_WCD_BANDGAP_OFF) {
-		snd_soc_write(codec, MSM8X10_WCD_A_BIAS_CENTRAL_BG_CTL, 0x50);
-	} else {
-		dev_err(codec->dev,
-			"%s: Error, Invalid bandgap settings\n", __func__);
-	}
-	msm8x10_wcd->bandgap_type = choice;
-}
-
 int msm8x10_wcd_mclk_enable(struct snd_soc_codec *codec,
 			    int mclk_enable, bool dapm)
 {
@@ -2029,28 +2068,21 @@
 
 	dev_dbg(codec->dev, "%s: mclk_enable = %u, dapm = %d\n",
 		__func__, mclk_enable, dapm);
-	if (dapm)
-		MSM8X10_WCD_ACQUIRE_LOCK(msm8x10_wcd->codec_resource_lock);
+
+	WCD9XXX_BG_CLK_LOCK(&msm8x10_wcd->resmgr);
+
 	if (mclk_enable) {
-		msm8x10_wcd->mclk_enabled = true;
-		msm8x10_wcd_codec_enable_bandgap(codec,
-					   MSM8X10_WCD_BANDGAP_AUDIO_MODE);
-		msm8x10_wcd_codec_enable_clock_block(codec, 1);
+		wcd9xxx_resmgr_get_bandgap(&msm8x10_wcd->resmgr,
+				WCD9XXX_BANDGAP_AUDIO_MODE);
+		wcd9xxx_resmgr_get_clk_block(&msm8x10_wcd->resmgr,
+				WCD9XXX_CLK_MCLK);
 	} else {
-		if (!msm8x10_wcd->mclk_enabled) {
-			if (dapm)
-				MSM8X10_WCD_RELEASE_LOCK(
-				  msm8x10_wcd->codec_resource_lock);
-			dev_err(codec->dev, "Error, MCLK already diabled\n");
-			return -EINVAL;
-		}
-		msm8x10_wcd->mclk_enabled = false;
-		msm8x10_wcd_codec_enable_clock_block(codec, 0);
-		msm8x10_wcd_codec_enable_bandgap(codec,
-						   MSM8X10_WCD_BANDGAP_OFF);
+		wcd9xxx_resmgr_put_clk_block(&msm8x10_wcd->resmgr,
+					WCD9XXX_CLK_MCLK);
+		wcd9xxx_resmgr_put_bandgap(&msm8x10_wcd->resmgr,
+					WCD9XXX_BANDGAP_AUDIO_MODE);
 	}
-	if (dapm)
-		MSM8X10_WCD_RELEASE_LOCK(msm8x10_wcd->codec_resource_lock);
+	WCD9XXX_BG_CLK_UNLOCK(&msm8x10_wcd->resmgr);
 	return 0;
 }
 
@@ -2270,6 +2302,9 @@
 		msm8x10_wcd_hphr_dac_event,
 		SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
 
+	SND_SOC_DAPM_MIXER("SPK DAC", SND_SOC_NOPM, 0, 0,
+		spkr_switch, ARRAY_SIZE(spkr_switch)),
+
 	/* Speaker */
 	SND_SOC_DAPM_OUTPUT("LINEOUT"),
 	SND_SOC_DAPM_OUTPUT("SPK_OUT"),
@@ -2289,10 +2324,6 @@
 		msm8x10_wcd_lineout_dac_event,
 		SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
 
-	SND_SOC_DAPM_DAC_E("SPK DAC", NULL, SND_SOC_NOPM, 0, 0,
-			   msm8x10_wcd_spk_dac_event,
-			   SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
-
 	SND_SOC_DAPM_MIXER("RX1 MIX1", SND_SOC_NOPM, 0, 0, NULL, 0),
 	SND_SOC_DAPM_MIXER("RX2 MIX1", SND_SOC_NOPM, 0, 0, NULL, 0),
 
@@ -2322,6 +2353,17 @@
 	SND_SOC_DAPM_MIXER("RX3 CHAIN", MSM8X10_WCD_A_CDC_RX3_B6_CTL,
 		5, 0, NULL, 0),
 
+	SND_SOC_DAPM_SUPPLY("HPHR CLK", MSM8X10_WCD_A_CDC_ANA_CLK_CTL,
+		0, 0, NULL, 0),
+	SND_SOC_DAPM_SUPPLY("HPHL CLK", MSM8X10_WCD_A_CDC_ANA_CLK_CTL,
+		1, 0, NULL, 0),
+	SND_SOC_DAPM_SUPPLY("EAR CLK", MSM8X10_WCD_A_CDC_ANA_CLK_CTL,
+		2, 0, NULL, 0),
+	SND_SOC_DAPM_SUPPLY("LINEOUT CLK", MSM8X10_WCD_A_CDC_ANA_CLK_CTL,
+		3, 0, NULL, 0),
+	SND_SOC_DAPM_SUPPLY("SPK CLK", MSM8X10_WCD_A_CDC_ANA_CLK_CTL,
+		4, 0, NULL, 0),
+
 	SND_SOC_DAPM_MUX("RX1 MIX1 INP1", SND_SOC_NOPM, 0, 0,
 		&rx_mix1_inp1_mux),
 	SND_SOC_DAPM_MUX("RX1 MIX1 INP2", SND_SOC_NOPM, 0, 0,
@@ -2340,6 +2382,8 @@
 		&rx1_mix2_inp1_mux),
 	SND_SOC_DAPM_MUX("RX2 MIX2 INP1", SND_SOC_NOPM, 0, 0,
 		&rx2_mix2_inp1_mux),
+	SND_SOC_DAPM_MUX("RDAC4 MUX", SND_SOC_NOPM, 0, 0,
+		&rx_dac4_mux),
 
 	SND_SOC_DAPM_SUPPLY("MICBIAS_REGULATOR", SND_SOC_NOPM,
 		ON_DEMAND_MICBIAS, 0,
@@ -2383,9 +2427,17 @@
 	SND_SOC_DAPM_ADC_E("ADC1", NULL, MSM8X10_WCD_A_TX_1_EN, 7, 0,
 		msm8x10_wcd_codec_enable_adc, SND_SOC_DAPM_PRE_PMU |
 		SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
-	SND_SOC_DAPM_ADC_E("ADC2", NULL, MSM8X10_WCD_A_TX_2_EN, 7, 0,
+	SND_SOC_DAPM_ADC_E("ADC2_INP2", NULL, MSM8X10_WCD_A_TX_2_EN, 7, 0,
 		msm8x10_wcd_codec_enable_adc, SND_SOC_DAPM_PRE_PMU |
 		SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
+	SND_SOC_DAPM_ADC_E("ADC2_INP3", NULL, MSM8X10_WCD_A_TX_3_EN, 7, 0,
+		msm8x10_wcd_codec_enable_adc, SND_SOC_DAPM_PRE_PMU |
+		SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
+
+	SND_SOC_DAPM_MIXER("ADC2", SND_SOC_NOPM, 0, 0, NULL, 0),
+
+	SND_SOC_DAPM_MUX("ADC2 MUX", SND_SOC_NOPM, 0, 0,
+		&tx_adc2_mux),
 
 	SND_SOC_DAPM_MICBIAS("MIC BIAS External", MSM8X10_WCD_A_MICB_1_CTL,
 			     7, 0),
@@ -2463,7 +2515,7 @@
 	MSM8X10_WCD_REG_VAL(MSM8X10_WCD_A_BIAS_CURR_CTL_2, 0x04),
 	MSM8X10_WCD_REG_VAL(MSM8X10_WCD_A_MICB_CFILT_1_VAL, 0x60),
 	/* Enable pulldown to reduce leakage */
-	MSM8X10_WCD_REG_VAL(MSM8X10_WCD_A_MICB_1_CTL, 0x83),
+	MSM8X10_WCD_REG_VAL(MSM8X10_WCD_A_MICB_1_CTL, 0x82),
 	MSM8X10_WCD_REG_VAL(MSM8X10_WCD_A_TX_COM_BIAS, 0xE0),
 	MSM8X10_WCD_REG_VAL(MSM8X10_WCD_A_TX_1_EN, 0x32),
 	MSM8X10_WCD_REG_VAL(MSM8X10_WCD_A_TX_2_EN, 0x32),
@@ -2477,6 +2529,10 @@
 
 	/* Always set TXD_CLK_EN bit to reduce the leakage */
 	MSM8X10_WCD_REG_VAL(MSM8X10_WCD_A_CDC_DIG_CLK_CTL, 0x10),
+
+	/* Always disable clock gating for MCLK to mbhc clock gate */
+	MSM8X10_WCD_REG_VAL(MSM8X10_WCD_A_CDC_ANA_CLK_CTL, 0x20),
+	MSM8X10_WCD_REG_VAL(MSM8X10_WCD_A_CDC_DIG_CLK_CTL, 0x10),
 };
 
 static void msm8x10_wcd_update_reg_defaults(struct snd_soc_codec *codec)
@@ -2512,6 +2568,8 @@
 	/* config DMIC clk to CLK_MODE_1 (3.2Mhz@9.6Mhz mclk) */
 	{MSM8X10_WCD_A_CDC_CLK_DMIC_B1_CTL, 0xEE, 0x22},
 
+	/* Disable REF_EN for MSM8X10_WCD_A_SPKR_DRV_DAC_CTL */
+	{MSM8X10_WCD_A_SPKR_DRV_DAC_CTL, 0x04, 0x00},
 };
 
 static void msm8x10_wcd_codec_init_reg(struct snd_soc_codec *codec)
@@ -2525,9 +2583,164 @@
 				    msm8x10_wcd_codec_reg_init_val[i].val);
 }
 
-int msm8x10_wcd_hs_detect(struct snd_soc_codec *codec,
-		    struct msm8x10_wcd_mbhc_config *mbhc_cfg)
+static void msm8x10_wcd_enable_mux_bias_block(
+		struct snd_soc_codec *codec)
 {
+	snd_soc_update_bits(codec, WCD9XXX_A_MBHC_SCALING_MUX_1,
+				0x80, 0x00);
+}
+
+static void msm8x10_wcd_put_cfilt_fast_mode(
+	struct snd_soc_codec *codec,
+	struct wcd9xxx_mbhc *mbhc)
+{
+	snd_soc_update_bits(codec, mbhc->mbhc_bias_regs.cfilt_ctl,
+			0x30, 0x30);
+}
+
+static void msm8x10_wcd_codec_specific_cal_setup(
+	struct snd_soc_codec *codec,
+	struct wcd9xxx_mbhc *mbhc)
+{
+	snd_soc_update_bits(codec, WCD9XXX_A_CDC_MBHC_B1_CTL,
+			0x04, 0x04);
+	snd_soc_update_bits(codec, WCD9XXX_A_TX_7_MBHC_EN,
+			0xE0, 0xE0);
+}
+
+static int msm8x10_wcd_get_jack_detect_irq(
+		struct snd_soc_codec *codec)
+{
+	return MSM8X10_WCD_IRQ_MBHC_HS_DET;
+}
+
+static struct wcd9xxx_cfilt_mode msm8x10_wcd_switch_cfilt_mode(
+	struct wcd9xxx_mbhc *mbhc, bool fast)
+{
+	struct snd_soc_codec *codec = mbhc->codec;
+	struct wcd9xxx_cfilt_mode cfilt_mode;
+
+	if (fast)
+		cfilt_mode.reg_mode_val = WCD9XXX_CFILT_EXT_PRCHG_EN;
+	else
+		cfilt_mode.reg_mode_val = WCD9XXX_CFILT_EXT_PRCHG_DSBL;
+
+	cfilt_mode.cur_mode_val =
+		snd_soc_read(codec, mbhc->mbhc_bias_regs.cfilt_ctl) & 0x30;
+	cfilt_mode.reg_mask = 0x30;
+	return cfilt_mode;
+}
+
+static void msm8x10_wcd_select_cfilt(struct snd_soc_codec *codec,
+	struct wcd9xxx_mbhc *mbhc)
+{
+	snd_soc_update_bits(codec,
+			mbhc->mbhc_bias_regs.ctl_reg, 0x60, 0x00);
+}
+
+static void msm8x10_wcd_free_irq(struct wcd9xxx_mbhc *mbhc)
+{
+	struct msm8x10_wcd *msm8x10_wcd = mbhc->codec->control_data;
+	struct wcd9xxx_core_resource *core_res =
+			&msm8x10_wcd->wcd9xxx_res;
+	wcd9xxx_free_irq(core_res, MSM8X10_WCD_IRQ_MBHC_HS_DET, mbhc);
+}
+
+enum wcd9xxx_cdc_type msm8x10_wcd_get_cdc_type(void)
+{
+	return WCD9XXX_CDC_TYPE_HELICON;
+}
+
+static void msm8x10_wcd_mbhc_clk_gate(struct snd_soc_codec *codec,
+		bool on)
+{
+	snd_soc_update_bits(codec, MSM8X10_WCD_A_CDC_TOP_CLK_CTL, 0x10, 0x10);
+}
+
+static void msm8x10_wcd_mbhc_txfe(struct snd_soc_codec *codec, bool on)
+{
+	snd_soc_update_bits(codec, MSM8X10_WCD_A_TX_7_MBHC_EN_ATEST_CTRL,
+			    0x80, on ? 0x80 : 0x00);
+}
+
+static int msm8x10_wcd_enable_ext_mb_source(struct snd_soc_codec *codec,
+	bool turn_on)
+{
+	int ret = 0;
+
+	if (turn_on)
+		ret = snd_soc_dapm_force_enable_pin(&codec->dapm,
+				"MICBIAS_REGULATOR");
+	else
+		ret = snd_soc_dapm_disable_pin(&codec->dapm,
+				"MICBIAS_REGULATOR");
+
+	snd_soc_dapm_sync(&codec->dapm);
+
+	if (ret)
+		dev_err(codec->dev, "%s: Failed to %s external micbias source\n",
+			__func__, turn_on ? "enable" : "disabled");
+	else
+		dev_dbg(codec->dev, "%s: %s external micbias source\n",
+			 __func__, turn_on ? "Enabled" : "Disabled");
+
+	return ret;
+}
+
+static void msm8x10_wcd_micb_internal(struct snd_soc_codec *codec, bool on)
+{
+	snd_soc_update_bits(codec, MSM8X10_WCD_A_MICB_1_INT_RBIAS,
+			    0x1C, on ? 0x14 : 0x00);
+}
+
+static void msm8x10_wcd_enable_mb_vddio(struct snd_soc_codec *codec, bool on)
+{
+	snd_soc_update_bits(codec, MSM8X10_WCD_A_MICB_CFILT_1_CTL,
+			    0x40, on ? 0x40 : 0x00);
+}
+
+static const struct wcd9xxx_mbhc_cb mbhc_cb = {
+	.enable_mux_bias_block = msm8x10_wcd_enable_mux_bias_block,
+	.cfilt_fast_mode = msm8x10_wcd_put_cfilt_fast_mode,
+	.codec_specific_cal = msm8x10_wcd_codec_specific_cal_setup,
+	.jack_detect_irq = msm8x10_wcd_get_jack_detect_irq,
+	.switch_cfilt_mode = msm8x10_wcd_switch_cfilt_mode,
+	.select_cfilt = msm8x10_wcd_select_cfilt,
+	.free_irq = msm8x10_wcd_free_irq,
+	.get_cdc_type = msm8x10_wcd_get_cdc_type,
+	.enable_clock_gate = msm8x10_wcd_mbhc_clk_gate,
+	.enable_mbhc_txfe = msm8x10_wcd_mbhc_txfe,
+	.enable_mb_source = msm8x10_wcd_enable_ext_mb_source,
+	.setup_int_rbias = msm8x10_wcd_micb_internal,
+	.pull_mb_to_vddio = msm8x10_wcd_enable_mb_vddio,
+};
+
+static void delayed_hs_detect_fn(struct work_struct *work)
+{
+	struct delayed_work *delayed_work;
+	struct msm8x10_wcd_priv *wcd_priv;
+
+	delayed_work = to_delayed_work(work);
+	wcd_priv = container_of(delayed_work, struct msm8x10_wcd_priv,
+				hs_detect_work);
+
+	if (!wcd_priv) {
+		pr_err("%s: Invalid private data for codec\n", __func__);
+		return;
+	}
+
+	wcd9xxx_mbhc_start(&wcd_priv->mbhc, wcd_priv->mbhc_cfg);
+}
+
+
+int msm8x10_wcd_hs_detect(struct snd_soc_codec *codec,
+		    struct wcd9xxx_mbhc_config *mbhc_cfg)
+{
+	struct msm8x10_wcd_priv *wcd = snd_soc_codec_get_drvdata(codec);
+
+	wcd->mbhc_cfg = mbhc_cfg;
+	schedule_delayed_work(&wcd->hs_detect_work,
+			msecs_to_jiffies(5000));
 	return 0;
 }
 EXPORT_SYMBOL_GPL(msm8x10_wcd_hs_detect);
@@ -2605,45 +2818,86 @@
 
 static int msm8x10_wcd_codec_probe(struct snd_soc_codec *codec)
 {
-	struct msm8x10_wcd_priv *msm8x10_wcd;
-	int i;
+	struct msm8x10_wcd_priv *msm8x10_wcd_priv;
+	struct msm8x10_wcd *msm8x10_wcd;
+	struct wcd9xxx_core_resource *core_res;
+	int i, ret = 0;
+	struct msm8x10_wcd_pdata *pdata;
+
 	dev_dbg(codec->dev, "%s()\n", __func__);
 
-	msm8x10_wcd = kzalloc(sizeof(struct msm8x10_wcd_priv), GFP_KERNEL);
-	if (!msm8x10_wcd) {
+	msm8x10_wcd_priv = devm_kzalloc(codec->dev,
+			sizeof(struct msm8x10_wcd_priv), GFP_KERNEL);
+
+	if (!msm8x10_wcd_priv) {
 		dev_err(codec->dev, "Failed to allocate private data\n");
 		return -ENOMEM;
 	}
 
 	for (i = 0 ; i < NUM_DECIMATORS; i++) {
-		tx_hpf_work[i].msm8x10_wcd = msm8x10_wcd;
+		tx_hpf_work[i].msm8x10_wcd = msm8x10_wcd_priv;
 		tx_hpf_work[i].decimator = i + 1;
 		INIT_DELAYED_WORK(&tx_hpf_work[i].dwork,
 			tx_hpf_corner_freq_callback);
 	}
 
 	codec->control_data = dev_get_drvdata(codec->dev);
-	snd_soc_codec_set_drvdata(codec, msm8x10_wcd);
-	msm8x10_wcd->codec = codec;
+	snd_soc_codec_set_drvdata(codec, msm8x10_wcd_priv);
+	msm8x10_wcd_priv->codec = codec;
+
+	/* map digital codec registers once */
+	msm8x10_wcd = codec->control_data;
+	msm8x10_wcd->pdino_base = ioremap(MSM8X10_DINO_CODEC_BASE_ADDR,
+					  MSM8X10_DINO_CODEC_REG_SIZE);
+	INIT_DELAYED_WORK(&msm8x10_wcd_priv->hs_detect_work,
+			delayed_hs_detect_fn);
+
+	/* codec resmgr module init */
+	msm8x10_wcd = codec->control_data;
+	core_res = &msm8x10_wcd->wcd9xxx_res;
+	ret = wcd9xxx_resmgr_init(&msm8x10_wcd_priv->resmgr,
+				codec, core_res, NULL, NULL,
+				WCD9XXX_CDC_TYPE_HELICON);
+	if (ret) {
+		dev_err(codec->dev,
+				"%s: wcd9xxx init failed %d\n",
+				__func__, ret);
+		goto exit_probe;
+	}
+
 	msm8x10_wcd_bringup(codec);
 	msm8x10_wcd_codec_init_reg(codec);
 	msm8x10_wcd_update_reg_defaults(codec);
-	msm8x10_wcd->on_demand_list[ON_DEMAND_CP].supply =
+
+	pdata = dev_get_platdata(msm8x10_wcd->dev);
+	if (!pdata) {
+		dev_err(msm8x10_wcd->dev, "%s: platform data not found\n",
+			__func__);
+	}
+
+	/* update micbias capless mode */
+	snd_soc_update_bits(codec, MSM8X10_WCD_A_MICB_1_CTL, 0x10,
+			    pdata->micbias.bias1_cap_mode << 4);
+
+	msm8x10_wcd_priv->on_demand_list[ON_DEMAND_CP].supply =
 				wcd8x10_wcd_codec_find_regulator(
 				codec->control_data,
 				on_demand_supply_name[ON_DEMAND_CP]);
-	atomic_set(&msm8x10_wcd->on_demand_list[ON_DEMAND_CP].ref, 0);
-	msm8x10_wcd->on_demand_list[ON_DEMAND_MICBIAS].supply =
+	atomic_set(&msm8x10_wcd_priv->on_demand_list[ON_DEMAND_CP].ref, 0);
+	msm8x10_wcd_priv->on_demand_list[ON_DEMAND_MICBIAS].supply =
 				wcd8x10_wcd_codec_find_regulator(
 				codec->control_data,
 				on_demand_supply_name[ON_DEMAND_MICBIAS]);
-	atomic_set(&msm8x10_wcd->on_demand_list[ON_DEMAND_MICBIAS].ref, 0);
-	msm8x10_wcd->mclk_enabled = false;
-	msm8x10_wcd->bandgap_type = MSM8X10_WCD_BANDGAP_OFF;
-	msm8x10_wcd->clock_active = false;
-	msm8x10_wcd->config_mode_active = false;
-	msm8x10_wcd->mbhc_polling_active = false;
-	mutex_init(&msm8x10_wcd->codec_resource_lock);
+	atomic_set(&msm8x10_wcd_priv->on_demand_list[ON_DEMAND_MICBIAS].ref, 0);
+
+	ret = wcd9xxx_mbhc_init(&msm8x10_wcd_priv->mbhc,
+				&msm8x10_wcd_priv->resmgr,
+				codec, NULL, &mbhc_cb,
+				HELICON_MCLK_CLK_9P6MHZ, false);
+	if (ret) {
+		pr_err("%s: Failed to initialize mbhc\n", __func__);
+		goto exit_probe;
+	}
 
 	registered_codec = codec;
 	adsp_state_notifier =
@@ -2656,15 +2910,25 @@
 		return -ENOMEM;
 	}
 	return 0;
+
+exit_probe:
+	return ret;
+
 }
 
 static int msm8x10_wcd_codec_remove(struct snd_soc_codec *codec)
 {
-	struct msm8x10_wcd_priv *msm8x10_wcd = snd_soc_codec_get_drvdata(codec);
-	msm8x10_wcd->on_demand_list[ON_DEMAND_CP].supply = NULL;
-	atomic_set(&msm8x10_wcd->on_demand_list[ON_DEMAND_CP].ref, 0);
-	msm8x10_wcd->on_demand_list[ON_DEMAND_MICBIAS].supply = NULL;
-	atomic_set(&msm8x10_wcd->on_demand_list[ON_DEMAND_MICBIAS].ref, 0);
+	struct msm8x10_wcd_priv *pwcd_priv = snd_soc_codec_get_drvdata(codec);
+	struct msm8x10_wcd *msm8x10_wcd = pwcd_priv->codec->control_data;
+	pwcd_priv->on_demand_list[ON_DEMAND_CP].supply = NULL;
+	atomic_set(&pwcd_priv->on_demand_list[ON_DEMAND_CP].ref, 0);
+	pwcd_priv->on_demand_list[ON_DEMAND_MICBIAS].supply = NULL;
+	atomic_set(&pwcd_priv->on_demand_list[ON_DEMAND_MICBIAS].ref, 0);
+
+	/* cleanup resmgr */
+	wcd9xxx_resmgr_deinit(&pwcd_priv->resmgr);
+
+	iounmap(msm8x10_wcd->pdino_base);
 	return 0;
 }
 
@@ -2812,25 +3076,41 @@
 
 static int msm8x10_wcd_pads_config(void)
 {
+	void __iomem *ppull = ioremap(MSM8x10_TLMM_CDC_PULL_CTL, 4);
 	/* Set I2C pads as pull up and rest of pads as no pull */
-	iowrite32(0x03C00000, ioremap(MSM8x10_TLMM_CDC_PULL_CTL, 4));
+	iowrite32(0x03C00000, ppull);
 	usleep_range(100, 200);
+
+	iounmap(ppull);
 	return 0;
 }
 
 
 static int msm8x10_wcd_clk_init(void)
 {
+	void __iomem *pdig1 = ioremap(MSM8X10_DINO_LPASS_DIGCODEC_CFG_RCGR, 4);
+	void __iomem *pdig2 = ioremap(MSM8X10_DINO_LPASS_DIGCODEC_M, 4);
+	void __iomem *pdig3 = ioremap(MSM8X10_DINO_LPASS_DIGCODEC_N, 4);
+	void __iomem *pdig4 = ioremap(MSM8X10_DINO_LPASS_DIGCODEC_D, 4);
+	void __iomem *pdig5 = ioremap(MSM8X10_DINO_LPASS_DIGCODEC_CBCR, 4);
+	void __iomem *pdig6 = ioremap(MSM8X10_DINO_LPASS_DIGCODEC_CMD_RCGR, 4);
 	/* Div-2 */
-	iowrite32(0x3, ioremap(MSM8X10_DINO_LPASS_DIGCODEC_CFG_RCGR, 4));
-	iowrite32(0x0, ioremap(MSM8X10_DINO_LPASS_DIGCODEC_M, 4));
-	iowrite32(0x0, ioremap(MSM8X10_DINO_LPASS_DIGCODEC_N, 4));
-	iowrite32(0x0, ioremap(MSM8X10_DINO_LPASS_DIGCODEC_D, 4));
+	iowrite32(0x3, pdig1);
+	iowrite32(0x0, pdig2);
+	iowrite32(0x0, pdig3);
+	iowrite32(0x0, pdig4);
 	/* Digital codec clock enable */
-	iowrite32(0x1, ioremap(MSM8X10_DINO_LPASS_DIGCODEC_CBCR, 4));
+	iowrite32(0x1, pdig5);
 	/* Set the update bit to make the settings go through */
-	iowrite32(0x1, ioremap(MSM8X10_DINO_LPASS_DIGCODEC_CMD_RCGR, 4));
+	iowrite32(0x1, pdig6);
 	usleep_range(100, 200);
+
+	iounmap(pdig1);
+	iounmap(pdig2);
+	iounmap(pdig3);
+	iounmap(pdig4);
+	iounmap(pdig5);
+	iounmap(pdig6);
 	return 0;
 }
 
@@ -2838,13 +3118,38 @@
 {
 	mutex_init(&msm8x10->io_lock);
 	mutex_init(&msm8x10->xfer_lock);
-	mutex_init(&msm8x10->pm_lock);
-	msm8x10->wlock_holders = 0;
 	msm8x10_wcd_pads_config();
 	msm8x10_wcd_clk_init();
 	return 0;
 }
 
+static struct intr_data interrupt_table[] = {
+	{MSM8X10_WCD_IRQ_MBHC_INSERTION, true},
+	{MSM8X10_WCD_IRQ_MBHC_POTENTIAL, true},
+	{MSM8X10_WCD_IRQ_MBHC_RELEASE, true},
+	{MSM8X10_WCD_IRQ_MBHC_PRESS, true},
+	{MSM8X10_WCD_IRQ_MBHC_SHORT_TERM, true},
+	{MSM8X10_WCD_IRQ_MBHC_REMOVAL, true},
+	{MSM8X10_WCD_IRQ_MBHC_HS_DET, true},
+	{MSM8X10_WCD_IRQ_RESERVED_0, false},
+	{MSM8X10_WCD_IRQ_PA_STARTUP, false},
+	{MSM8X10_WCD_IRQ_BG_PRECHARGE, false},
+	{MSM8X10_WCD_IRQ_RESERVED_1, false},
+	{MSM8X10_WCD_IRQ_EAR_PA_OCPL_FAULT, false},
+	{MSM8X10_WCD_IRQ_EAR_PA_STARTUP, false},
+	{MSM8X10_WCD_IRQ_SPKR_PA_OCPL_FAULT, false},
+	{MSM8X10_WCD_IRQ_SPKR_CLIP_FAULT, false},
+	{MSM8X10_WCD_IRQ_RESERVED_2, false},
+	{MSM8X10_WCD_IRQ_HPH_L_PA_STARTUP, false},
+	{MSM8X10_WCD_IRQ_HPH_R_PA_STARTUP, false},
+	{MSM8X10_WCD_IRQ_HPH_PA_OCPL_FAULT, false},
+	{MSM8X10_WCD_IRQ_HPH_PA_OCPR_FAULT, false},
+	{MSM8X10_WCD_IRQ_RESERVED_3, false},
+	{MSM8X10_WCD_IRQ_RESERVED_4, false},
+	{MSM8X10_WCD_IRQ_RESERVED_5, false},
+	{MSM8X10_WCD_IRQ_RESERVED_6, false},
+};
+
 static int __devinit msm8x10_wcd_i2c_probe(struct i2c_client *client,
 			const struct i2c_device_id *id)
 {
@@ -2854,6 +3159,7 @@
 	static int device_id;
 	struct device *dev;
 	enum apr_subsys_state q6_state;
+	struct wcd9xxx_core_resource *core_res;
 
 	dev_dbg(&client->dev, "%s(%d):slave addr = 0x%x device_id = %d\n",
 		__func__, __LINE__,  client->addr, device_id);
@@ -2913,8 +3219,8 @@
 	}
 
 	msm8x10->dev = &client->dev;
-	msm8x10->read_dev = msm8x10_wcd_reg_read;
-	msm8x10->write_dev = msm8x10_wcd_reg_write;
+	msm8x10->read_dev = __msm8x10_wcd_reg_read;
+	msm8x10->write_dev = __msm8x10_wcd_reg_write;
 	ret = msm8x10_wcd_init_supplies(msm8x10, pdata);
 	if (ret) {
 		dev_err(&client->dev, "%s: Fail to enable Codec supplies\n",
@@ -2938,15 +3244,37 @@
 		goto err_supplies;
 	}
 	dev_set_drvdata(&client->dev, msm8x10);
+	core_res = &msm8x10->wcd9xxx_res;
+	core_res->parent = msm8x10;
+	core_res->dev = msm8x10->dev;
+	core_res->intr_table = interrupt_table;
+	core_res->intr_table_size = ARRAY_SIZE(interrupt_table);
+
+	wcd9xxx_core_res_init(core_res,
+					MSM8X10_WCD_NUM_IRQS,
+					MSM8X10_WCD_NUM_IRQ_REGS,
+					msm8x10_wcd_reg_read,
+					msm8x10_wcd_reg_write,
+					msm8x10_wcd_bulk_read);
+	if (wcd9xxx_core_irq_init(core_res)) {
+		dev_err(msm8x10->dev,
+				"%s: irq initialization failed\n", __func__);
+	} else {
+		dev_info(msm8x10->dev,
+				"%s: irq initialization passed\n", __func__);
+	}
+
 	ret = snd_soc_register_codec(&client->dev, &soc_codec_dev_msm8x10_wcd,
 				     msm8x10_wcd_i2s_dai,
 				     ARRAY_SIZE(msm8x10_wcd_i2s_dai));
-	if (ret)
+	if (ret) {
 		dev_err(&client->dev,
 			"%s:snd_soc_register_codec failed with error %d\n",
 			__func__, ret);
-	else
+	} else {
+		wcd9xxx_set_intf_type(WCD9XXX_INTERFACE_TYPE_I2C);
 		goto rtn;
+	}
 
 err_supplies:
 	msm8x10_wcd_disable_supplies(msm8x10, pdata);
@@ -2958,7 +3286,6 @@
 
 static void msm8x10_wcd_device_exit(struct msm8x10_wcd *msm8x10)
 {
-	mutex_destroy(&msm8x10->pm_lock);
 	mutex_destroy(&msm8x10->io_lock);
 	mutex_destroy(&msm8x10->xfer_lock);
 	kfree(msm8x10);
@@ -3002,6 +3329,7 @@
 	int ret;
 
 	pr_debug("%s:\n", __func__);
+	wcd9xxx_set_intf_type(WCD9XXX_INTERFACE_TYPE_PROBING);
 	ret = i2c_add_driver(&msm8x10_wcd_i2c_driver);
 	if (ret != 0)
 		pr_err("%s: Failed to add msm8x10 wcd I2C driver - error %d\n",
diff --git a/sound/soc/codecs/msm8x10-wcd.h b/sound/soc/codecs/msm8x10-wcd.h
index 8e561cf..5f67cba 100644
--- a/sound/soc/codecs/msm8x10-wcd.h
+++ b/sound/soc/codecs/msm8x10-wcd.h
@@ -168,31 +168,6 @@
 	MSM8X10_WCD_MICBIAS1 = 0,
 };
 
-struct msm8x10_wcd_mbhc_config {
-	struct snd_soc_jack *headset_jack;
-	struct snd_soc_jack *button_jack;
-	bool read_fw_bin;
-	/*
-	 * void* calibration contains:
-	 *  struct msm8x10_wcd_mbhc_general_cfg generic;
-	 *  struct msm8x10_wcd_mbhc_plug_detect_cfg plug_det;
-	 *  struct msm8x10_wcd_mbhc_plug_type_cfg plug_type;
-	 *  struct msm8x10_wcd_mbhc_btn_detect_cfg btn_det;
-	 *  struct msm8x10_wcd_mbhc_imped_detect_cfg imped_det;
-	 * Note: various size depends on btn_det->num_btn
-	 */
-	void *calibration;
-	enum msm8x10_wcd_micbias_num micbias;
-	int (*mclk_cb_fn) (struct snd_soc_codec*, int, bool);
-	unsigned int mclk_rate;
-	unsigned int gpio;
-	unsigned int gpio_irq;
-	int gpio_level_insert;
-	bool detect_extn_cable;
-	/* swap_gnd_mic returns true if extern GND/MIC swap switch toggled */
-	bool (*swap_gnd_mic) (struct snd_soc_codec *);
-};
-
 enum msm8x10_wcd_pm_state {
 	MSM8X10_WCD_PM_SLEEPABLE,
 	MSM8X10_WCD_PM_AWAKE,
@@ -203,39 +178,29 @@
 	struct device *dev;
 	struct mutex io_lock;
 	struct mutex xfer_lock;
-	struct mutex irq_lock;
 	u8 version;
 
 	int reset_gpio;
 	int (*read_dev)(struct msm8x10_wcd *msm8x10,
-			unsigned short reg, unsigned int *val);
+			unsigned short reg);
 	int (*write_dev)(struct msm8x10_wcd *msm8x10,
 			 unsigned short reg, u8 val);
 
 	u32 num_of_supplies;
 	struct regulator_bulk_data *supplies;
 
-	enum msm8x10_wcd_pm_state pm_state;
-	struct mutex pm_lock;
-	/* pm_wq notifies change of pm_state */
-	wait_queue_head_t pm_wq;
-	struct pm_qos_request pm_qos_req;
-	int wlock_holders;
-
 	u8 idbyte[4];
 
-	unsigned int irq_base;
-	unsigned int irq;
-	u8 irq_masks_cur[MSM8X10_WCD_NUM_IRQ_REGS];
-	u8 irq_masks_cache[MSM8X10_WCD_NUM_IRQ_REGS];
-	bool irq_level_high[MSM8X10_WCD_NUM_IRQS];
 	int num_irqs;
 	u32 mclk_rate;
+	char __iomem *pdino_base;
+
+	struct wcd9xxx_core_resource wcd9xxx_res;
 };
 
 extern int msm8x10_wcd_mclk_enable(struct snd_soc_codec *codec, int mclk_enable,
 			     bool dapm);
 extern int msm8x10_wcd_hs_detect(struct snd_soc_codec *codec,
-			   struct msm8x10_wcd_mbhc_config *mbhc_cfg);
+			struct wcd9xxx_mbhc_config *mbhc_cfg);
 
 #endif
diff --git a/sound/soc/codecs/wcd9304.c b/sound/soc/codecs/wcd9304.c
index 58ea22d..a68722c 100644
--- a/sound/soc/codecs/wcd9304.c
+++ b/sound/soc/codecs/wcd9304.c
@@ -3961,8 +3961,10 @@
 {
 	short bias_value;
 	struct sitar_priv *sitar = snd_soc_codec_get_drvdata(codec);
+	struct wcd9xxx *core = codec->control_data;
+	struct wcd9xxx_core_resource *core_res = &core->core_res;
 
-	wcd9xxx_disable_irq(codec->control_data, WCD9XXX_IRQ_MBHC_POTENTIAL);
+	wcd9xxx_disable_irq(core_res, WCD9XXX_IRQ_MBHC_POTENTIAL);
 	if (noreldetection)
 		sitar_turn_onoff_rel_detection(codec, false);
 
@@ -4103,11 +4105,12 @@
 {
 	int r = 0;
 	struct wcd9xxx *core = dev_get_drvdata(sitar->codec->dev->parent);
+	struct wcd9xxx_core_resource *core_res = &core->core_res;
 
 	if (cancel_delayed_work_sync(&sitar->mbhc_btn_dwork)) {
 		/* if scheduled mbhc_btn_dwork is canceled from here,
 		 * we have to unlock from here instead btn_work */
-		wcd9xxx_unlock_sleep(core);
+		wcd9xxx_unlock_sleep(core_res);
 		r = 1;
 	}
 	return r;
@@ -4171,12 +4174,14 @@
 	short bias_value;
 	int dce_mv, sta_mv;
 	struct wcd9xxx *core;
+	struct wcd9xxx_core_resource *core_res;
 
 	pr_debug("%s:\n", __func__);
 
 	delayed_work = to_delayed_work(work);
 	sitar = container_of(delayed_work, struct sitar_priv, mbhc_btn_dwork);
 	core = dev_get_drvdata(sitar->codec->dev->parent);
+	core_res = &core->core_res;
 
 	if (sitar) {
 		if (sitar->mbhc_cfg.button_jack) {
@@ -4198,7 +4203,7 @@
 	}
 
 	pr_debug("%s: leave\n", __func__);
-	wcd9xxx_unlock_sleep(core);
+	wcd9xxx_unlock_sleep(core_res);
 }
 
 
@@ -4212,11 +4217,13 @@
 	u32 dce_wait, sta_wait;
 	u8 *n_cic;
 	void *calibration;
+	struct wcd9xxx *core = codec->control_data;
+	struct wcd9xxx_core_resource *core_res = &core->core_res;
 
 	sitar = snd_soc_codec_get_drvdata(codec);
 	calibration = sitar->mbhc_cfg.calibration;
 
-	wcd9xxx_disable_irq(codec->control_data, WCD9XXX_IRQ_MBHC_POTENTIAL);
+	wcd9xxx_disable_irq(core_res, WCD9XXX_IRQ_MBHC_POTENTIAL);
 	sitar_turn_onoff_rel_detection(codec, false);
 
 	/* First compute the DCE / STA wait times
@@ -4707,22 +4714,28 @@
 /* should be called under interrupt context that hold suspend */
 static void sitar_schedule_hs_detect_plug(struct sitar_priv *sitar)
 {
+	struct wcd9xxx *core = sitar->codec->control_data;
+	struct wcd9xxx_core_resource *core_res = &core->core_res;
+
 	pr_debug("%s: scheduling sitar_hs_correct_gpio_plug\n", __func__);
 	sitar->hs_detect_work_stop = false;
-	wcd9xxx_lock_sleep(sitar->codec->control_data);
+	wcd9xxx_lock_sleep(core_res);
 	schedule_work(&sitar->hs_correct_plug_work);
 }
 
 /* called under codec_resource_lock acquisition */
 static void sitar_cancel_hs_detect_plug(struct sitar_priv *sitar)
 {
+	struct wcd9xxx *core = sitar->codec->control_data;
+	struct wcd9xxx_core_resource *core_res = &core->core_res;
+
 	pr_debug("%s: canceling hs_correct_plug_work\n", __func__);
 	sitar->hs_detect_work_stop = true;
 	wmb();
 	SITAR_RELEASE_LOCK(sitar->codec_resource_lock);
 	if (cancel_work_sync(&sitar->hs_correct_plug_work)) {
 		pr_debug("%s: hs_correct_plug_work is canceled\n", __func__);
-		wcd9xxx_unlock_sleep(sitar->codec->control_data);
+		wcd9xxx_unlock_sleep(core_res);
 	}
 	SITAR_ACQUIRE_LOCK(sitar->codec_resource_lock);
 }
@@ -4737,9 +4750,13 @@
 	short mb_v[MBHC_NUM_DCE_PLUG_DETECT];
 	enum sitar_mbhc_plug_type plug_type[MBHC_NUM_DCE_PLUG_DETECT];
 	unsigned long timeout;
+	struct wcd9xxx *core;
+	struct wcd9xxx_core_resource *core_res;
 
 	sitar = container_of(work, struct sitar_priv, hs_correct_plug_work);
 	codec = sitar->codec;
+	core = sitar->codec->control_data;
+	core_res = &core->core_res;
 
 	pr_debug("%s: enter\n", __func__);
 	sitar->mbhc_cfg.mclk_cb_fn(codec, 1, false);
@@ -4815,7 +4832,7 @@
 	sitar->mbhc_cfg.mclk_cb_fn(codec, 0, false);
 	pr_debug("%s: leave\n", __func__);
 	/* unlock sleep */
-	wcd9xxx_unlock_sleep(sitar->codec->control_data);
+	wcd9xxx_unlock_sleep(core_res);
 }
 
 /* called under codec_resource_lock acquisition */
@@ -4966,8 +4983,10 @@
 {
 	int r = IRQ_HANDLED;
 	struct snd_soc_codec *codec = data;
+	struct wcd9xxx *core = codec->control_data;
+	struct wcd9xxx_core_resource *core_res = &core->core_res;
 
-	if (unlikely(wcd9xxx_lock_sleep(codec->control_data) == false)) {
+	if (unlikely(wcd9xxx_lock_sleep(core_res) == false)) {
 		pr_warn("%s(): Failed to hold suspend\n", __func__);
 		r = IRQ_NONE;
 	} else {
@@ -5181,6 +5200,7 @@
 	short btnmeas[d->n_btn_meas + 1];
 	struct snd_soc_codec *codec = priv->codec;
 	struct wcd9xxx *core = dev_get_drvdata(priv->codec->dev->parent);
+	struct wcd9xxx_core_resource *core_res = &core->core_res;
 	int n_btn_meas = d->n_btn_meas;
 	u8 mbhc_status = snd_soc_read(codec, SITAR_A_CDC_MBHC_B1_STATUS) & 0x3E;
 
@@ -5271,12 +5291,12 @@
 		}
 		mask = sitar_get_button_mask(btn);
 		priv->buttons_pressed |= mask;
-		wcd9xxx_lock_sleep(core);
+		wcd9xxx_lock_sleep(core_res);
 		if (schedule_delayed_work(&priv->mbhc_btn_dwork,
 					  msecs_to_jiffies(400)) == 0) {
 			WARN(1, "Button pressed twice without release"
 			     "event\n");
-			wcd9xxx_unlock_sleep(core);
+			wcd9xxx_unlock_sleep(core_res);
 		}
 	} else {
 		pr_debug("%s: bogus button press, too short press?\n",
@@ -5386,11 +5406,16 @@
 {
 	struct sitar_priv *sitar = data;
 	struct snd_soc_codec *codec;
+	struct wcd9xxx *core;
+	struct wcd9xxx_core_resource *core_res;
 
 	pr_info("%s: received HPHL OCP irq\n", __func__);
 
 	if (sitar) {
 		codec = sitar->codec;
+		core = codec->control_data;
+		core_res = &core->core_res;
+
 		if ((sitar->hphlocp_cnt < SITAR_OCP_ATTEMPT) &&
 		    (!sitar->hphrocp_cnt)) {
 			pr_info("%s: retry\n", __func__);
@@ -5400,7 +5425,7 @@
 			snd_soc_update_bits(codec, SITAR_A_RX_HPH_OCP_CTL, 0x10,
 					    0x10);
 		} else {
-			wcd9xxx_disable_irq(codec->control_data,
+			wcd9xxx_disable_irq(core_res,
 					    WCD9XXX_IRQ_HPH_PA_OCPL_FAULT);
 			sitar->hph_status |= SND_JACK_OC_HPHL;
 			if (sitar->mbhc_cfg.headset_jack)
@@ -5420,11 +5445,16 @@
 {
 	struct sitar_priv *sitar = data;
 	struct snd_soc_codec *codec;
+	struct wcd9xxx *core;
+	struct wcd9xxx_core_resource *core_res;
 
 	pr_info("%s: received HPHR OCP irq\n", __func__);
 
 	if (sitar) {
 		codec = sitar->codec;
+		core = codec->control_data;
+		core_res = &core->core_res;
+
 		if ((sitar->hphrocp_cnt < SITAR_OCP_ATTEMPT) &&
 		    (!sitar->hphlocp_cnt)) {
 			pr_info("%s: retry\n", __func__);
@@ -5434,7 +5464,7 @@
 			snd_soc_update_bits(codec, SITAR_A_RX_HPH_OCP_CTL, 0x10,
 					   0x10);
 		} else {
-			wcd9xxx_disable_irq(codec->control_data,
+			wcd9xxx_disable_irq(core_res,
 					    WCD9XXX_IRQ_HPH_PA_OCPR_FAULT);
 			sitar->hph_status |= SND_JACK_OC_HPHR;
 			if (sitar->mbhc_cfg.headset_jack)
@@ -5454,10 +5484,12 @@
 {
 	struct sitar_priv *priv = data;
 	struct snd_soc_codec *codec = priv->codec;
+	struct wcd9xxx *core = codec->control_data;
+	struct wcd9xxx_core_resource *core_res = &core->core_res;
 
 	pr_debug("%s: enter\n", __func__);
 	SITAR_ACQUIRE_LOCK(priv->codec_resource_lock);
-	wcd9xxx_disable_irq(codec->control_data, WCD9XXX_IRQ_MBHC_INSERTION);
+	wcd9xxx_disable_irq(core_res, WCD9XXX_IRQ_MBHC_INSERTION);
 
 	snd_soc_update_bits(codec, SITAR_A_CDC_MBHC_INT_CTL, 0x03, 0x00);
 
@@ -5847,9 +5879,11 @@
 	int i;
 	u8 sitar_version;
 	void *ptr = NULL;
+	struct wcd9xxx_core_resource *core_res;
 
 	codec->control_data = dev_get_drvdata(codec->dev->parent);
 	core = codec->control_data;
+	core_res = &core->core_res;
 
 	sitar = kzalloc(sizeof(struct sitar_priv), GFP_KERNEL);
 	if (!sitar) {
@@ -5951,7 +5985,7 @@
 	snd_soc_dapm_sync(dapm);
 
 
-	ret = wcd9xxx_request_irq(codec->control_data,
+	ret = wcd9xxx_request_irq(core_res,
 				  WCD9XXX_IRQ_MBHC_INSERTION,
 		sitar_hs_insert_irq, "Headset insert detect", sitar);
 	if (ret) {
@@ -5959,9 +5993,9 @@
 		       WCD9XXX_IRQ_MBHC_INSERTION);
 		goto err_insert_irq;
 	}
-	wcd9xxx_disable_irq(codec->control_data, WCD9XXX_IRQ_MBHC_INSERTION);
+	wcd9xxx_disable_irq(core_res, WCD9XXX_IRQ_MBHC_INSERTION);
 
-	ret = wcd9xxx_request_irq(codec->control_data,
+	ret = wcd9xxx_request_irq(core_res,
 				  WCD9XXX_IRQ_MBHC_REMOVAL,
 		sitar_hs_remove_irq, "Headset remove detect", sitar);
 	if (ret) {
@@ -5970,7 +6004,7 @@
 		goto err_remove_irq;
 	}
 
-	ret = wcd9xxx_request_irq(codec->control_data,
+	ret = wcd9xxx_request_irq(core_res,
 				  WCD9XXX_IRQ_MBHC_POTENTIAL,
 		sitar_dce_handler, "DC Estimation detect", sitar);
 	if (ret) {
@@ -5979,7 +6013,7 @@
 		goto err_potential_irq;
 	}
 
-	ret = wcd9xxx_request_irq(codec->control_data,
+	ret = wcd9xxx_request_irq(core_res,
 				  WCD9XXX_IRQ_MBHC_RELEASE,
 				  sitar_release_handler,
 				  "Button Release detect", sitar);
@@ -5989,7 +6023,7 @@
 		goto err_release_irq;
 	}
 
-	ret = wcd9xxx_request_irq(codec->control_data, WCD9XXX_IRQ_SLIMBUS,
+	ret = wcd9xxx_request_irq(core_res, WCD9XXX_IRQ_SLIMBUS,
 				  sitar_slimbus_irq, "SLIMBUS Slave", sitar);
 	if (ret) {
 		pr_err("%s: Failed to request irq %d\n", __func__,
@@ -6002,7 +6036,7 @@
 			SITAR_SLIM_PGD_PORT_INT_EN0 + i, 0xFF);
 
 
-	ret = wcd9xxx_request_irq(codec->control_data,
+	ret = wcd9xxx_request_irq(core_res,
 				  WCD9XXX_IRQ_HPH_PA_OCPL_FAULT,
 				  sitar_hphl_ocp_irq,
 				  "HPH_L OCP detect", sitar);
@@ -6011,10 +6045,10 @@
 		       WCD9XXX_IRQ_HPH_PA_OCPL_FAULT);
 		goto err_hphl_ocp_irq;
 	}
-	wcd9xxx_disable_irq(codec->control_data,
+	wcd9xxx_disable_irq(core_res,
 			    WCD9XXX_IRQ_HPH_PA_OCPL_FAULT);
 
-	ret = wcd9xxx_request_irq(codec->control_data,
+	ret = wcd9xxx_request_irq(core_res,
 				  WCD9XXX_IRQ_HPH_PA_OCPR_FAULT,
 				  sitar_hphr_ocp_irq, "HPH_R OCP detect",
 				  sitar);
@@ -6023,7 +6057,7 @@
 		       WCD9XXX_IRQ_HPH_PA_OCPR_FAULT);
 		goto err_hphr_ocp_irq;
 	}
-	wcd9xxx_disable_irq(codec->control_data, WCD9XXX_IRQ_HPH_PA_OCPR_FAULT);
+	wcd9xxx_disable_irq(core_res, WCD9XXX_IRQ_HPH_PA_OCPR_FAULT);
 
 	codec->ignore_pmdown_time = 1;
 
@@ -6034,19 +6068,19 @@
 	return ret;
 
 err_hphr_ocp_irq:
-	wcd9xxx_free_irq(codec->control_data, WCD9XXX_IRQ_HPH_PA_OCPL_FAULT,
+	wcd9xxx_free_irq(core_res, WCD9XXX_IRQ_HPH_PA_OCPL_FAULT,
 			 sitar);
 err_hphl_ocp_irq:
-	wcd9xxx_free_irq(codec->control_data, WCD9XXX_IRQ_SLIMBUS, sitar);
+	wcd9xxx_free_irq(core_res, WCD9XXX_IRQ_SLIMBUS, sitar);
 err_slimbus_irq:
-	wcd9xxx_free_irq(codec->control_data, WCD9XXX_IRQ_MBHC_RELEASE, sitar);
+	wcd9xxx_free_irq(core_res, WCD9XXX_IRQ_MBHC_RELEASE, sitar);
 err_release_irq:
-	wcd9xxx_free_irq(codec->control_data, WCD9XXX_IRQ_MBHC_POTENTIAL,
+	wcd9xxx_free_irq(core_res, WCD9XXX_IRQ_MBHC_POTENTIAL,
 			 sitar);
 err_potential_irq:
-	wcd9xxx_free_irq(codec->control_data, WCD9XXX_IRQ_MBHC_REMOVAL, sitar);
+	wcd9xxx_free_irq(core_res, WCD9XXX_IRQ_MBHC_REMOVAL, sitar);
 err_remove_irq:
-	wcd9xxx_free_irq(codec->control_data, WCD9XXX_IRQ_MBHC_INSERTION,
+	wcd9xxx_free_irq(core_res, WCD9XXX_IRQ_MBHC_INSERTION,
 			 sitar);
 err_insert_irq:
 	kfree(ptr);
@@ -6059,12 +6093,15 @@
 static int sitar_codec_remove(struct snd_soc_codec *codec)
 {
 	struct sitar_priv *sitar = snd_soc_codec_get_drvdata(codec);
-	wcd9xxx_free_irq(codec->control_data, WCD9XXX_IRQ_SLIMBUS, sitar);
-	wcd9xxx_free_irq(codec->control_data, WCD9XXX_IRQ_MBHC_RELEASE, sitar);
-	wcd9xxx_free_irq(codec->control_data, WCD9XXX_IRQ_MBHC_POTENTIAL,
+	struct wcd9xxx *core = codec->control_data;
+	struct wcd9xxx_core_resource *core_res = &core->core_res;
+
+	wcd9xxx_free_irq(core_res, WCD9XXX_IRQ_SLIMBUS, sitar);
+	wcd9xxx_free_irq(core_res, WCD9XXX_IRQ_MBHC_RELEASE, sitar);
+	wcd9xxx_free_irq(core_res, WCD9XXX_IRQ_MBHC_POTENTIAL,
 			 sitar);
-	wcd9xxx_free_irq(codec->control_data, WCD9XXX_IRQ_MBHC_REMOVAL, sitar);
-	wcd9xxx_free_irq(codec->control_data, WCD9XXX_IRQ_MBHC_INSERTION,
+	wcd9xxx_free_irq(core_res, WCD9XXX_IRQ_MBHC_REMOVAL, sitar);
+	wcd9xxx_free_irq(core_res, WCD9XXX_IRQ_MBHC_INSERTION,
 			 sitar);
 	SITAR_ACQUIRE_LOCK(sitar->codec_resource_lock);
 	sitar_codec_disable_clock_block(codec);
diff --git a/sound/soc/codecs/wcd9306.c b/sound/soc/codecs/wcd9306.c
index ff190cd..4e07d7f 100644
--- a/sound/soc/codecs/wcd9306.c
+++ b/sound/soc/codecs/wcd9306.c
@@ -24,6 +24,7 @@
 #include <linux/mfd/wcd9xxx/wcd9xxx_registers.h>
 #include <linux/mfd/wcd9xxx/wcd9306_registers.h>
 #include <linux/mfd/wcd9xxx/pdata.h>
+#include <linux/regulator/consumer.h>
 #include <sound/pcm.h>
 #include <sound/pcm_params.h>
 #include <sound/soc.h>
@@ -41,6 +42,22 @@
 #define TAPAN_HPH_PA_SETTLE_COMP_ON 3000
 #define TAPAN_HPH_PA_SETTLE_COMP_OFF 13000
 
+#define TAPAN_VDD_CX_OPTIMAL_UA 10000
+#define TAPAN_VDD_CX_SLEEP_UA 2000
+
+/* RX_HPH_CNP_WG_TIME increases by 0.24ms */
+#define TAPAN_WG_TIME_FACTOR_US  240
+
+#define TAPAN_SB_PGD_PORT_RX_BASE   0x40
+#define TAPAN_SB_PGD_PORT_TX_BASE   0x50
+#define TAPAN_REGISTER_START_OFFSET 0x800
+
+#define CODEC_REG_CFG_MINOR_VER 1
+
+static struct regulator *tapan_codec_find_regulator(
+	struct snd_soc_codec *codec,
+	const char *name);
+
 static atomic_t kp_tapan_priv;
 static int spkr_drv_wrnd_param_set(const char *val,
 				   const struct kernel_param *kp);
@@ -58,6 +75,9 @@
 			SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_48000 |\
 			SNDRV_PCM_RATE_96000 | SNDRV_PCM_RATE_192000)
 
+#define WCD9302_RATES (SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_16000 |\
+			SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_48000)
+
 #define NUM_DECIMATORS 4
 #define NUM_INTERPOLATORS 4
 #define BITS_PER_REG 8
@@ -79,6 +99,67 @@
 
 #define TAPAN_IRQ_MBHC_JACK_SWITCH 21
 
+enum tapan_codec_type {
+	WCD9306,
+	WCD9302,
+};
+
+static enum tapan_codec_type codec_ver;
+
+/*
+ * Multiplication factor to compute impedance on Tapan
+ * This is computed from (Vx / (m*Ical)) = (10mV/(180*30uA))
+ */
+#define TAPAN_ZDET_MUL_FACTOR 1852
+
+static struct afe_param_cdc_reg_cfg audio_reg_cfg[] = {
+	{
+		CODEC_REG_CFG_MINOR_VER,
+		(TAPAN_REGISTER_START_OFFSET + TAPAN_SB_PGD_PORT_TX_BASE),
+		SB_PGD_PORT_TX_WATERMARK_N, 0x1E, 8, 0x1
+	},
+	{
+		CODEC_REG_CFG_MINOR_VER,
+		(TAPAN_REGISTER_START_OFFSET + TAPAN_SB_PGD_PORT_TX_BASE),
+		SB_PGD_PORT_TX_ENABLE_N, 0x1, 8, 0x1
+	},
+	{
+		CODEC_REG_CFG_MINOR_VER,
+		(TAPAN_REGISTER_START_OFFSET + TAPAN_SB_PGD_PORT_RX_BASE),
+		SB_PGD_PORT_RX_WATERMARK_N, 0x1E, 8, 0x1
+	},
+	{
+		CODEC_REG_CFG_MINOR_VER,
+		(TAPAN_REGISTER_START_OFFSET + TAPAN_SB_PGD_PORT_RX_BASE),
+		SB_PGD_PORT_RX_ENABLE_N, 0x1, 8, 0x1
+	},
+	{
+		CODEC_REG_CFG_MINOR_VER,
+		(TAPAN_REGISTER_START_OFFSET + TAPAN_A_CDC_ANC1_IIR_B1_CTL),
+		AANC_FF_GAIN_ADAPTIVE, 0x4, 8, 0
+	},
+	{
+		CODEC_REG_CFG_MINOR_VER,
+		(TAPAN_REGISTER_START_OFFSET + TAPAN_A_CDC_ANC1_IIR_B1_CTL),
+		AANC_FFGAIN_ADAPTIVE_EN, 0x8, 8, 0
+	},
+	{
+		CODEC_REG_CFG_MINOR_VER,
+		(TAPAN_REGISTER_START_OFFSET + TAPAN_A_CDC_ANC1_GAIN_CTL),
+		AANC_GAIN_CONTROL, 0xFF, 8, 0
+	},
+};
+
+static struct afe_param_cdc_reg_cfg_data tapan_audio_reg_cfg = {
+	.num_registers = ARRAY_SIZE(audio_reg_cfg),
+	.reg_data = audio_reg_cfg,
+};
+
+static struct afe_param_id_cdc_aanc_version tapan_cdc_aanc_version = {
+	.cdc_aanc_minor_version = AFE_API_VERSION_CDC_AANC_VERSION,
+	.aanc_hw_version        = AANC_HW_BLOCK_VERSION_2,
+};
+
 enum {
 	AIF1_PB = 0,
 	AIF1_CAP,
@@ -189,6 +270,12 @@
 	0,	/* AIF1_CAP */
 };
 
+enum {
+	CP_REG_BUCK = 0,
+	CP_REG_BHELPER,
+	CP_REG_MAX,
+};
+
 struct tapan_priv {
 	struct snd_soc_codec *codec;
 	u32 adc_count;
@@ -217,6 +304,8 @@
 
 	bool spkr_pa_widget_on;
 
+	struct afe_param_cdc_slimbus_slave_cfg slimbus_slave_cfg;
+
 	/* resmgr module */
 	struct wcd9xxx_resmgr resmgr;
 	/* mbhc module */
@@ -224,6 +313,18 @@
 
 	/* class h specific data */
 	struct wcd9xxx_clsh_cdc_data clsh_d;
+
+	/* pointers to regulators required for chargepump */
+	struct regulator *cp_regulators[CP_REG_MAX];
+
+	/*
+	 * list used to save/restore registers at start and
+	 * end of impedance measurement
+	 */
+	struct list_head reg_save_restore;
+
+	int (*machine_codec_event_cb)(struct snd_soc_codec *codec,
+					enum wcd9xxx_codec_event);
 };
 
 static const u32 comp_shift[] = {
@@ -756,20 +857,34 @@
 	struct tapan_priv *tapan = snd_soc_codec_get_drvdata(codec);
 	struct wcd9xxx_pdata *pdata = tapan->resmgr.pdata;
 	int i;
+	bool found_regulator = false;
 
 	for (i = 0; i < ARRAY_SIZE(pdata->regulator); i++) {
+		if (pdata->regulator[i].name == NULL)
+			continue;
+
 		if (!strncmp(pdata->regulator[i].name,
-					 WCD9XXX_SUPPLY_BUCK_NAME,
-					 sizeof(WCD9XXX_SUPPLY_BUCK_NAME))) {
+			     WCD9XXX_SUPPLY_BUCK_NAME,
+			     sizeof(WCD9XXX_SUPPLY_BUCK_NAME))) {
+			found_regulator = true;
 			if ((pdata->regulator[i].min_uV ==
-					WCD9XXX_CDC_BUCK_MV_1P8) ||
-				(pdata->regulator[i].min_uV ==
-					WCD9XXX_CDC_BUCK_MV_2P15))
+			     WCD9XXX_CDC_BUCK_MV_1P8) ||
+			    (pdata->regulator[i].min_uV ==
+			     WCD9XXX_CDC_BUCK_MV_2P15))
 				buck_volt = pdata->regulator[i].min_uV;
 			break;
 		}
 	}
-	pr_debug("%s: S4 voltage requested is %d\n", __func__, buck_volt);
+
+	if (!found_regulator)
+		dev_err(codec->dev,
+			"%s: Failed to find regulator for %s\n",
+			__func__, WCD9XXX_SUPPLY_BUCK_NAME);
+	else
+		dev_dbg(codec->dev,
+			"%s: S4 voltage requested is %d\n",
+			__func__, buck_volt);
+
 	return buck_volt;
 }
 
@@ -948,7 +1063,7 @@
 static const struct snd_kcontrol_new class_h_dsm_mux =
 	SOC_DAPM_ENUM("CLASS_H_DSM MUX Mux", class_h_dsm_enum);
 
-static const struct snd_kcontrol_new tapan_snd_controls[] = {
+static const struct snd_kcontrol_new tapan_common_snd_controls[] = {
 
 	SOC_ENUM_EXT("EAR PA Gain", tapan_ear_pa_gain_enum[0],
 		tapan_pa_gain_get, tapan_pa_gain_put),
@@ -970,25 +1085,17 @@
 	SOC_SINGLE_TLV("ADC2 Volume", TAPAN_A_TX_2_EN, 2, 19, 0, analog_gain),
 	SOC_SINGLE_TLV("ADC3 Volume", TAPAN_A_TX_3_EN, 2, 19, 0, analog_gain),
 	SOC_SINGLE_TLV("ADC4 Volume", TAPAN_A_TX_4_EN, 2, 19, 0, analog_gain),
-	SOC_SINGLE_TLV("ADC5 Volume", TAPAN_A_TX_5_EN, 2, 19, 0, analog_gain),
-
 	SOC_SINGLE_S8_TLV("RX1 Digital Volume", TAPAN_A_CDC_RX1_VOL_CTL_B2_CTL,
 		-84, 40, digital_gain),
 	SOC_SINGLE_S8_TLV("RX2 Digital Volume", TAPAN_A_CDC_RX2_VOL_CTL_B2_CTL,
 		-84, 40, digital_gain),
 	SOC_SINGLE_S8_TLV("RX3 Digital Volume", TAPAN_A_CDC_RX3_VOL_CTL_B2_CTL,
 		-84, 40, digital_gain),
-	SOC_SINGLE_S8_TLV("RX4 Digital Volume", TAPAN_A_CDC_RX4_VOL_CTL_B2_CTL,
-		-84, 40, digital_gain),
 
 	SOC_SINGLE_S8_TLV("DEC1 Volume", TAPAN_A_CDC_TX1_VOL_CTL_GAIN, -84, 40,
 		digital_gain),
 	SOC_SINGLE_S8_TLV("DEC2 Volume", TAPAN_A_CDC_TX2_VOL_CTL_GAIN, -84, 40,
 		digital_gain),
-	SOC_SINGLE_S8_TLV("DEC3 Volume", TAPAN_A_CDC_TX3_VOL_CTL_GAIN, -84, 40,
-		digital_gain),
-	SOC_SINGLE_S8_TLV("DEC4 Volume", TAPAN_A_CDC_TX4_VOL_CTL_GAIN, -84, 40,
-		digital_gain),
 
 	SOC_SINGLE_S8_TLV("IIR1 INP1 Volume", TAPAN_A_CDC_IIR1_GAIN_B1_CTL, -84,
 		40, digital_gain),
@@ -999,10 +1106,6 @@
 	SOC_SINGLE_S8_TLV("IIR1 INP4 Volume", TAPAN_A_CDC_IIR1_GAIN_B4_CTL, -84,
 		40, digital_gain),
 
-	SOC_SINGLE_EXT("ANC Slot", SND_SOC_NOPM, 0, 100, 0, tapan_get_anc_slot,
-		tapan_put_anc_slot),
-	SOC_ENUM_EXT("ANC Function", tapan_anc_func_enum, tapan_get_anc_func,
-		tapan_put_anc_func),
 	SOC_ENUM("TX1 HPF cut off", cf_dec1_enum),
 	SOC_ENUM("TX2 HPF cut off", cf_dec2_enum),
 	SOC_ENUM("TX3 HPF cut off", cf_dec3_enum),
@@ -1016,12 +1119,10 @@
 	SOC_SINGLE("RX1 HPF Switch", TAPAN_A_CDC_RX1_B5_CTL, 2, 1, 0),
 	SOC_SINGLE("RX2 HPF Switch", TAPAN_A_CDC_RX2_B5_CTL, 2, 1, 0),
 	SOC_SINGLE("RX3 HPF Switch", TAPAN_A_CDC_RX3_B5_CTL, 2, 1, 0),
-	SOC_SINGLE("RX4 HPF Switch", TAPAN_A_CDC_RX4_B5_CTL, 2, 1, 0),
 
 	SOC_ENUM("RX1 HPF cut off", cf_rxmix1_enum),
 	SOC_ENUM("RX2 HPF cut off", cf_rxmix2_enum),
 	SOC_ENUM("RX3 HPF cut off", cf_rxmix3_enum),
-	SOC_ENUM("RX4 HPF cut off", cf_rxmix4_enum),
 
 	SOC_SINGLE_EXT("IIR1 Enable Band1", IIR1, BAND1, 1, 0,
 	tapan_get_iir_enable_audio_mixer, tapan_put_iir_enable_audio_mixer),
@@ -1064,6 +1165,23 @@
 	tapan_get_iir_band_audio_mixer, tapan_put_iir_band_audio_mixer),
 	SOC_SINGLE_MULTI_EXT("IIR2 Band5", IIR2, BAND5, 255, 0, 5,
 	tapan_get_iir_band_audio_mixer, tapan_put_iir_band_audio_mixer),
+};
+
+static const struct snd_kcontrol_new tapan_9306_snd_controls[] = {
+	SOC_SINGLE_TLV("ADC5 Volume", TAPAN_A_TX_5_EN, 2, 19, 0, analog_gain),
+
+	SOC_SINGLE_S8_TLV("RX4 Digital Volume", TAPAN_A_CDC_RX4_VOL_CTL_B2_CTL,
+		-84, 40, digital_gain),
+	SOC_SINGLE_S8_TLV("DEC3 Volume", TAPAN_A_CDC_TX3_VOL_CTL_GAIN, -84, 40,
+		digital_gain),
+	SOC_SINGLE_S8_TLV("DEC4 Volume", TAPAN_A_CDC_TX4_VOL_CTL_GAIN, -84, 40,
+		digital_gain),
+	SOC_SINGLE_EXT("ANC Slot", SND_SOC_NOPM, 0, 100, 0, tapan_get_anc_slot,
+		tapan_put_anc_slot),
+	SOC_ENUM_EXT("ANC Function", tapan_anc_func_enum, tapan_get_anc_func,
+		tapan_put_anc_func),
+	SOC_SINGLE("RX4 HPF Switch", TAPAN_A_CDC_RX4_B5_CTL, 2, 1, 0),
+	SOC_ENUM("RX4 HPF cut off", cf_rxmix4_enum),
 
 	SOC_SINGLE_EXT("COMP0 Switch", SND_SOC_NOPM, COMPANDER_0, 1, 0,
 		       tapan_get_compander, tapan_set_compander),
@@ -1071,7 +1189,6 @@
 		       tapan_get_compander, tapan_set_compander),
 	SOC_SINGLE_EXT("COMP2 Switch", SND_SOC_NOPM, COMPANDER_2, 1, 0,
 		       tapan_get_compander, tapan_set_compander),
-
 };
 
 static const char * const rx_1_2_mix1_text[] = {
@@ -1088,6 +1205,14 @@
 	"ZERO", "SRC1", "SRC2", "IIR1", "IIR2"
 };
 
+static const char * const rx_rdac3_text[] = {
+	"DEM1", "DEM2"
+};
+
+static const char * const rx_rdac4_text[] = {
+	"DEM3", "DEM2"
+};
+
 static const char * const rx_rdac5_text[] = {
 	"DEM4", "DEM3_INV"
 };
@@ -1194,6 +1319,12 @@
 static const struct soc_enum rx4_mix2_inp2_chain_enum =
 	SOC_ENUM_SINGLE(TAPAN_A_CDC_CONN_RX4_B3_CTL, 3, 5, rx_mix2_text);
 
+static const struct soc_enum rx_rdac3_enum =
+	SOC_ENUM_SINGLE(TAPAN_A_CDC_CONN_RX2_B2_CTL, 4, 2, rx_rdac3_text);
+
+static const struct soc_enum rx_rdac4_enum =
+	SOC_ENUM_SINGLE(TAPAN_A_CDC_CONN_MISC, 1, 2, rx_rdac4_text);
+
 static const struct soc_enum rx_rdac5_enum =
 	SOC_ENUM_SINGLE(TAPAN_A_CDC_CONN_MISC, 2, 2, rx_rdac5_text);
 
@@ -1283,6 +1414,12 @@
 static const struct snd_kcontrol_new rx4_mix2_inp2_mux =
 	SOC_DAPM_ENUM("RX4 MIX2 INP2 Mux", rx4_mix2_inp2_chain_enum);
 
+static const struct snd_kcontrol_new rx_dac3_mux =
+	SOC_DAPM_ENUM("RDAC3 MUX Mux", rx_rdac3_enum);
+
+static const struct snd_kcontrol_new rx_dac4_mux =
+	SOC_DAPM_ENUM("RDAC4 MUX Mux", rx_rdac4_enum);
+
 static const struct snd_kcontrol_new rx_dac5_mux =
 	SOC_DAPM_ENUM("RDAC5 MUX Mux", rx_rdac5_enum);
 
@@ -2497,90 +2634,24 @@
 	{"SLIM TX2 MUX", NULL, "I2S_CLK"},
 };
 
-static const struct snd_soc_dapm_route audio_map[] = {
-	/* SLIMBUS Connections */
-	{"AIF1 CAP", NULL, "AIF1_CAP Mixer"},
-	{"AIF2 CAP", NULL, "AIF2_CAP Mixer"},
-	{"AIF3 CAP", NULL, "AIF3_CAP Mixer"},
-
-	/* SLIM_MIXER("AIF1_CAP Mixer"),*/
-	{"AIF1_CAP Mixer", "SLIM TX1", "SLIM TX1 MUX"},
-	{"AIF1_CAP Mixer", "SLIM TX2", "SLIM TX2 MUX"},
-	{"AIF1_CAP Mixer", "SLIM TX3", "SLIM TX3 MUX"},
-	{"AIF1_CAP Mixer", "SLIM TX4", "SLIM TX4 MUX"},
-	{"AIF1_CAP Mixer", "SLIM TX5", "SLIM TX5 MUX"},
-	/* SLIM_MIXER("AIF2_CAP Mixer"),*/
-	{"AIF2_CAP Mixer", "SLIM TX1", "SLIM TX1 MUX"},
-	{"AIF2_CAP Mixer", "SLIM TX2", "SLIM TX2 MUX"},
-	{"AIF2_CAP Mixer", "SLIM TX3", "SLIM TX3 MUX"},
-	{"AIF2_CAP Mixer", "SLIM TX4", "SLIM TX4 MUX"},
-	{"AIF2_CAP Mixer", "SLIM TX5", "SLIM TX5 MUX"},
-	/* SLIM_MIXER("AIF3_CAP Mixer"),*/
-	{"AIF3_CAP Mixer", "SLIM TX1", "SLIM TX1 MUX"},
-	{"AIF3_CAP Mixer", "SLIM TX2", "SLIM TX2 MUX"},
-	{"AIF3_CAP Mixer", "SLIM TX3", "SLIM TX3 MUX"},
-	{"AIF3_CAP Mixer", "SLIM TX4", "SLIM TX4 MUX"},
-	{"AIF3_CAP Mixer", "SLIM TX5", "SLIM TX5 MUX"},
-
-	{"SLIM TX1 MUX", "DEC1", "DEC1 MUX"},
-	{"SLIM TX1 MUX", "DEC2", "DEC2 MUX"},
+static const struct snd_soc_dapm_route wcd9306_map[] = {
+	{"SLIM TX1 MUX", "RMIX4", "RX4 MIX1"},
+	{"SLIM TX2 MUX", "RMIX4", "RX4 MIX1"},
+	{"SLIM TX3 MUX", "RMIX4", "RX4 MIX1"},
+	{"SLIM TX4 MUX", "RMIX4", "RX4 MIX1"},
+	{"SLIM TX5 MUX", "RMIX4", "RX4 MIX1"},
 	{"SLIM TX1 MUX", "DEC3", "DEC3 MUX"},
 	{"SLIM TX1 MUX", "DEC4", "DEC4 MUX"},
-	{"SLIM TX1 MUX", "RMIX1", "RX1 MIX1"},
-	{"SLIM TX1 MUX", "RMIX2", "RX2 MIX1"},
-	{"SLIM TX1 MUX", "RMIX3", "RX3 MIX1"},
-	{"SLIM TX1 MUX", "RMIX4", "RX4 MIX1"},
-
-	{"SLIM TX2 MUX", "DEC1", "DEC1 MUX"},
-	{"SLIM TX2 MUX", "DEC2", "DEC2 MUX"},
 	{"SLIM TX2 MUX", "DEC3", "DEC3 MUX"},
 	{"SLIM TX2 MUX", "DEC4", "DEC4 MUX"},
-	{"SLIM TX2 MUX", "RMIX1", "RX1 MIX1"},
-	{"SLIM TX2 MUX", "RMIX2", "RX2 MIX1"},
-	{"SLIM TX2 MUX", "RMIX3", "RX3 MIX1"},
-	{"SLIM TX2 MUX", "RMIX4", "RX4 MIX1"},
-
 	{"SLIM TX3 MUX", "DEC3", "DEC3 MUX"},
-	{"SLIM TX3 MUX", "RMIX1", "RX1 MIX1"},
-	{"SLIM TX3 MUX", "RMIX2", "RX2 MIX1"},
-	{"SLIM TX3 MUX", "RMIX3", "RX3 MIX1"},
-	{"SLIM TX3 MUX", "RMIX4", "RX4 MIX1"},
-
 	{"SLIM TX4 MUX", "DEC4", "DEC4 MUX"},
-	{"SLIM TX4 MUX", "RMIX1", "RX1 MIX1"},
-	{"SLIM TX4 MUX", "RMIX2", "RX2 MIX1"},
-	{"SLIM TX4 MUX", "RMIX3", "RX3 MIX1"},
-	{"SLIM TX4 MUX", "RMIX4", "RX4 MIX1"},
-
-	{"SLIM TX5 MUX", "DEC1", "DEC1 MUX"},
-	{"SLIM TX5 MUX", "RMIX1", "RX1 MIX1"},
-	{"SLIM TX5 MUX", "RMIX2", "RX2 MIX1"},
-	{"SLIM TX5 MUX", "RMIX3", "RX3 MIX1"},
-	{"SLIM TX5 MUX", "RMIX4", "RX4 MIX1"},
-
-	/* Earpiece (RX MIX1) */
-	{"EAR", NULL, "EAR PA"},
-	{"EAR PA", NULL, "EAR_PA_MIXER"},
-	{"EAR_PA_MIXER", NULL, "DAC1"},
-	{"DAC1", NULL, "RX_BIAS"},
 
 	{"ANC EAR", NULL, "ANC EAR PA"},
 	{"ANC EAR PA", NULL, "EAR_PA_MIXER"},
 	{"ANC1 FB MUX", "EAR_HPH_L", "RX1 MIX2"},
 	{"ANC1 FB MUX", "EAR_LINE_1", "RX2 MIX2"},
 
-	/* Headset (RX MIX1 and RX MIX2) */
-	{"HEADPHONE", NULL, "HPHL"},
-	{"HEADPHONE", NULL, "HPHR"},
-
-	{"HPHL", NULL, "HPHL_PA_MIXER"},
-	{"HPHL_PA_MIXER", NULL, "HPHL DAC"},
-	{"HPHL DAC", NULL, "RX_BIAS"},
-
-	{"HPHR", NULL, "HPHR_PA_MIXER"},
-	{"HPHR_PA_MIXER", NULL, "HPHR DAC"},
-	{"HPHR DAC", NULL, "RX_BIAS"},
-
 	{"ANC HEADPHONE", NULL, "ANC HPHL"},
 	{"ANC HEADPHONE", NULL, "ANC HPHR"},
 
@@ -2608,6 +2679,150 @@
 
 	{"ANC HPHR", NULL, "CDC_CONN"},
 
+	{"RDAC5 MUX", "DEM4", "RX4 MIX2"},
+	{"SPK DAC", "Switch", "RX4 MIX2"},
+
+	{"RX1 MIX2", NULL, "ANC1 MUX"},
+	{"RX2 MIX2", NULL, "ANC2 MUX"},
+
+	{"RX1 MIX1", NULL, "COMP1_CLK"},
+	{"RX2 MIX1", NULL, "COMP1_CLK"},
+	{"RX3 MIX1", NULL, "COMP2_CLK"},
+	{"RX4 MIX1", NULL, "COMP0_CLK"},
+
+	{"RX4 MIX1", NULL, "RX4 MIX1 INP1"},
+	{"RX4 MIX1", NULL, "RX4 MIX1 INP2"},
+	{"RX4 MIX2", NULL, "RX4 MIX1"},
+	{"RX4 MIX2", NULL, "RX4 MIX2 INP1"},
+	{"RX4 MIX2", NULL, "RX4 MIX2 INP2"},
+
+	{"RX4 MIX1 INP1", "RX1", "SLIM RX1"},
+	{"RX4 MIX1 INP1", "RX2", "SLIM RX2"},
+	{"RX4 MIX1 INP1", "RX3", "SLIM RX3"},
+	{"RX4 MIX1 INP1", "RX4", "SLIM RX4"},
+	{"RX4 MIX1 INP1", "RX5", "SLIM RX5"},
+	{"RX4 MIX1 INP1", "IIR1", "IIR1"},
+	{"RX4 MIX1 INP2", "RX1", "SLIM RX1"},
+	{"RX4 MIX1 INP2", "RX2", "SLIM RX2"},
+	{"RX4 MIX1 INP2", "RX3", "SLIM RX3"},
+	{"RX4 MIX1 INP2", "RX5", "SLIM RX5"},
+	{"RX4 MIX1 INP2", "RX4", "SLIM RX4"},
+	{"RX4 MIX1 INP2", "IIR1", "IIR1"},
+	{"RX4 MIX2 INP1", "IIR1", "IIR1"},
+	{"RX4 MIX2 INP2", "IIR1", "IIR1"},
+
+	{"DEC1 MUX", "DMIC3", "DMIC3"},
+	{"DEC1 MUX", "DMIC4", "DMIC4"},
+	{"DEC2 MUX", "DMIC3", "DMIC3"},
+	{"DEC2 MUX", "DMIC4", "DMIC4"},
+
+	{"DEC3 MUX", "ADC1", "ADC1"},
+	{"DEC3 MUX", "ADC2", "ADC2"},
+	{"DEC3 MUX", "ADC3", "ADC3"},
+	{"DEC3 MUX", "ADC4", "ADC4"},
+	{"DEC3 MUX", "ADC5", "ADC5"},
+	{"DEC3 MUX", "DMIC1", "DMIC1"},
+	{"DEC3 MUX", "DMIC2", "DMIC2"},
+	{"DEC3 MUX", "DMIC3", "DMIC3"},
+	{"DEC3 MUX", "DMIC4", "DMIC4"},
+	{"DEC3 MUX", NULL, "CDC_CONN"},
+
+	{"DEC4 MUX", "ADC1", "ADC1"},
+	{"DEC4 MUX", "ADC2", "ADC2"},
+	{"DEC4 MUX", "ADC3", "ADC3"},
+	{"DEC4 MUX", "ADC4", "ADC4"},
+	{"DEC4 MUX", "ADC5", "ADC5"},
+	{"DEC4 MUX", "DMIC1", "DMIC1"},
+	{"DEC4 MUX", "DMIC2", "DMIC2"},
+	{"DEC4 MUX", "DMIC3", "DMIC3"},
+	{"DEC4 MUX", "DMIC4", "DMIC4"},
+	{"DEC4 MUX", NULL, "CDC_CONN"},
+
+	{"ADC5", NULL, "AMIC5"},
+
+	{"AUX_PGA_Left", NULL, "AMIC5"},
+
+	{"IIR1 INP1 MUX", "DEC3", "DEC3 MUX"},
+	{"IIR1 INP1 MUX", "DEC4", "DEC4 MUX"},
+
+	{"MIC BIAS3 Internal1", NULL, "LDO_H"},
+	{"MIC BIAS3 Internal2", NULL, "LDO_H"},
+	{"MIC BIAS3 External", NULL, "LDO_H"},
+};
+
+static const struct snd_soc_dapm_route audio_map[] = {
+	/* SLIMBUS Connections */
+	{"AIF1 CAP", NULL, "AIF1_CAP Mixer"},
+	{"AIF2 CAP", NULL, "AIF2_CAP Mixer"},
+	{"AIF3 CAP", NULL, "AIF3_CAP Mixer"},
+
+	/* SLIM_MIXER("AIF1_CAP Mixer"),*/
+	{"AIF1_CAP Mixer", "SLIM TX1", "SLIM TX1 MUX"},
+	{"AIF1_CAP Mixer", "SLIM TX2", "SLIM TX2 MUX"},
+	{"AIF1_CAP Mixer", "SLIM TX3", "SLIM TX3 MUX"},
+	{"AIF1_CAP Mixer", "SLIM TX4", "SLIM TX4 MUX"},
+	{"AIF1_CAP Mixer", "SLIM TX5", "SLIM TX5 MUX"},
+	/* SLIM_MIXER("AIF2_CAP Mixer"),*/
+	{"AIF2_CAP Mixer", "SLIM TX1", "SLIM TX1 MUX"},
+	{"AIF2_CAP Mixer", "SLIM TX2", "SLIM TX2 MUX"},
+	{"AIF2_CAP Mixer", "SLIM TX3", "SLIM TX3 MUX"},
+	{"AIF2_CAP Mixer", "SLIM TX4", "SLIM TX4 MUX"},
+	{"AIF2_CAP Mixer", "SLIM TX5", "SLIM TX5 MUX"},
+	/* SLIM_MIXER("AIF3_CAP Mixer"),*/
+	{"AIF3_CAP Mixer", "SLIM TX1", "SLIM TX1 MUX"},
+	{"AIF3_CAP Mixer", "SLIM TX2", "SLIM TX2 MUX"},
+	{"AIF3_CAP Mixer", "SLIM TX3", "SLIM TX3 MUX"},
+	{"AIF3_CAP Mixer", "SLIM TX4", "SLIM TX4 MUX"},
+	{"AIF3_CAP Mixer", "SLIM TX5", "SLIM TX5 MUX"},
+
+	{"SLIM TX1 MUX", "DEC1", "DEC1 MUX"},
+	{"SLIM TX1 MUX", "DEC2", "DEC2 MUX"},
+	{"SLIM TX1 MUX", "RMIX1", "RX1 MIX1"},
+	{"SLIM TX1 MUX", "RMIX2", "RX2 MIX1"},
+	{"SLIM TX1 MUX", "RMIX3", "RX3 MIX1"},
+
+	{"SLIM TX2 MUX", "DEC1", "DEC1 MUX"},
+	{"SLIM TX2 MUX", "DEC2", "DEC2 MUX"},
+	{"SLIM TX2 MUX", "RMIX1", "RX1 MIX1"},
+	{"SLIM TX2 MUX", "RMIX2", "RX2 MIX1"},
+	{"SLIM TX2 MUX", "RMIX3", "RX3 MIX1"},
+
+	{"SLIM TX3 MUX", "RMIX1", "RX1 MIX1"},
+	{"SLIM TX3 MUX", "RMIX2", "RX2 MIX1"},
+	{"SLIM TX3 MUX", "RMIX3", "RX3 MIX1"},
+
+	{"SLIM TX4 MUX", "RMIX1", "RX1 MIX1"},
+	{"SLIM TX4 MUX", "RMIX2", "RX2 MIX1"},
+	{"SLIM TX4 MUX", "RMIX3", "RX3 MIX1"},
+
+	{"SLIM TX5 MUX", "DEC1", "DEC1 MUX"},
+	{"SLIM TX5 MUX", "RMIX1", "RX1 MIX1"},
+	{"SLIM TX5 MUX", "RMIX2", "RX2 MIX1"},
+	{"SLIM TX5 MUX", "RMIX3", "RX3 MIX1"},
+
+	/* Earpiece (RX MIX1) */
+	{"EAR", NULL, "EAR PA"},
+	{"EAR PA", NULL, "EAR_PA_MIXER"},
+	{"EAR_PA_MIXER", NULL, "DAC1"},
+	{"DAC1", NULL, "RX_BIAS"},
+	{"DAC1", NULL, "CDC_CP_VDD"},
+
+
+	/* Headset (RX MIX1 and RX MIX2) */
+	{"HEADPHONE", NULL, "HPHL"},
+	{"HEADPHONE", NULL, "HPHR"},
+
+	{"HPHL", NULL, "HPHL_PA_MIXER"},
+	{"HPHL_PA_MIXER", NULL, "HPHL DAC"},
+	{"HPHL DAC", NULL, "RX_BIAS"},
+	{"HPHL DAC", NULL, "CDC_CP_VDD"},
+
+	{"HPHR", NULL, "HPHR_PA_MIXER"},
+	{"HPHR_PA_MIXER", NULL, "HPHR DAC"},
+	{"HPHR DAC", NULL, "RX_BIAS"},
+	{"HPHR DAC", NULL, "CDC_CP_VDD"},
+
+
 	{"DAC1", "Switch", "CLASS_H_DSM MUX"},
 	{"HPHL DAC", "Switch", "CLASS_H_DSM MUX"},
 	{"HPHR DAC", NULL, "RX2 CHAIN"},
@@ -2618,34 +2833,28 @@
 
 	{"LINEOUT1 PA", NULL, "LINEOUT1_PA_MIXER"},
 	{"LINEOUT1_PA_MIXER", NULL, "LINEOUT1 DAC"},
-
 	{"LINEOUT2 PA", NULL, "LINEOUT2_PA_MIXER"},
 	{"LINEOUT2_PA_MIXER", NULL, "LINEOUT2 DAC"},
 
 	{"LINEOUT1 DAC", NULL, "RX3 MIX1"},
 
 	{"RDAC5 MUX", "DEM3_INV", "RX3 MIX1"},
-	{"RDAC5 MUX", "DEM4", "RX4 MIX2"},
-
 	{"LINEOUT2 DAC", NULL, "RDAC5 MUX"},
 
 	{"SPK PA", NULL, "SPK DAC"},
-	{"SPK DAC", "Switch", "RX4 MIX2"},
 	{"SPK DAC", NULL, "VDD_SPKDRV"},
 
 	{"RX1 CHAIN", NULL, "RX1 MIX2"},
 	{"RX2 CHAIN", NULL, "RX2 MIX2"},
 	{"CLASS_H_DSM MUX", "RX_HPHL", "RX1 CHAIN"},
-	{"RX1 MIX2", NULL, "ANC1 MUX"},
-	{"RX2 MIX2", NULL, "ANC2 MUX"},
 
 	{"LINEOUT1 DAC", NULL, "RX_BIAS"},
 	{"LINEOUT2 DAC", NULL, "RX_BIAS"},
+	{"LINEOUT1 DAC", NULL, "CDC_CP_VDD"},
+	{"LINEOUT2 DAC", NULL, "CDC_CP_VDD"},
 
-	{"RX1 MIX1", NULL, "COMP1_CLK"},
-	{"RX2 MIX1", NULL, "COMP1_CLK"},
-	{"RX3 MIX1", NULL, "COMP2_CLK"},
-	{"RX4 MIX1", NULL, "COMP0_CLK"},
+	{"RDAC3 MUX", "DEM2", "RX2 MIX1"},
+	{"RDAC3 MUX", "DEM1", "RX1 CHAIN"},
 
 	{"RX1 MIX1", NULL, "RX1 MIX1 INP1"},
 	{"RX1 MIX1", NULL, "RX1 MIX1 INP2"},
@@ -2654,17 +2863,12 @@
 	{"RX2 MIX1", NULL, "RX2 MIX1 INP2"},
 	{"RX3 MIX1", NULL, "RX3 MIX1 INP1"},
 	{"RX3 MIX1", NULL, "RX3 MIX1 INP2"},
-	{"RX4 MIX1", NULL, "RX4 MIX1 INP1"},
-	{"RX4 MIX1", NULL, "RX4 MIX1 INP2"},
 	{"RX1 MIX2", NULL, "RX1 MIX1"},
 	{"RX1 MIX2", NULL, "RX1 MIX2 INP1"},
 	{"RX1 MIX2", NULL, "RX1 MIX2 INP2"},
 	{"RX2 MIX2", NULL, "RX2 MIX1"},
 	{"RX2 MIX2", NULL, "RX2 MIX2 INP1"},
 	{"RX2 MIX2", NULL, "RX2 MIX2 INP2"},
-	{"RX4 MIX2", NULL, "RX4 MIX1"},
-	{"RX4 MIX2", NULL, "RX4 MIX2 INP1"},
-	{"RX4 MIX2", NULL, "RX4 MIX2 INP2"},
 
 	/* SLIM_MUX("AIF1_PB", "AIF1 PB"),*/
 	{"SLIM RX1 MUX", "AIF1_PB", "AIF1 PB"},
@@ -2732,25 +2936,11 @@
 	{"RX3 MIX1 INP2", "RX4", "SLIM RX4"},
 	{"RX3 MIX1 INP2", "RX5", "SLIM RX5"},
 	{"RX3 MIX1 INP2", "IIR1", "IIR1"},
-	{"RX4 MIX1 INP1", "RX1", "SLIM RX1"},
-	{"RX4 MIX1 INP1", "RX2", "SLIM RX2"},
-	{"RX4 MIX1 INP1", "RX3", "SLIM RX3"},
-	{"RX4 MIX1 INP1", "RX4", "SLIM RX4"},
-	{"RX4 MIX1 INP1", "RX5", "SLIM RX5"},
-	{"RX4 MIX1 INP1", "IIR1", "IIR1"},
-	{"RX4 MIX1 INP2", "RX1", "SLIM RX1"},
-	{"RX4 MIX1 INP2", "RX2", "SLIM RX2"},
-	{"RX4 MIX1 INP2", "RX3", "SLIM RX3"},
-	{"RX4 MIX1 INP2", "RX5", "SLIM RX5"},
-	{"RX4 MIX1 INP2", "RX4", "SLIM RX4"},
-	{"RX4 MIX1 INP2", "IIR1", "IIR1"},
 
 	{"RX1 MIX2 INP1", "IIR1", "IIR1"},
 	{"RX1 MIX2 INP2", "IIR1", "IIR1"},
 	{"RX2 MIX2 INP1", "IIR1", "IIR1"},
 	{"RX2 MIX2 INP2", "IIR1", "IIR1"},
-	{"RX4 MIX2 INP1", "IIR1", "IIR1"},
-	{"RX4 MIX2 INP2", "IIR1", "IIR1"},
 
 	/* Decimator Inputs */
 	{"DEC1 MUX", "ADC1", "ADC1"},
@@ -2759,8 +2949,6 @@
 	{"DEC1 MUX", "ADC4", "ADC4"},
 	{"DEC1 MUX", "DMIC1", "DMIC1"},
 	{"DEC1 MUX", "DMIC2", "DMIC2"},
-	{"DEC1 MUX", "DMIC3", "DMIC3"},
-	{"DEC1 MUX", "DMIC4", "DMIC4"},
 	{"DEC1 MUX", NULL, "CDC_CONN"},
 
 	{"DEC2 MUX", "ADC1", "ADC1"},
@@ -2769,38 +2957,13 @@
 	{"DEC2 MUX", "ADC4", "ADC4"},
 	{"DEC2 MUX", "DMIC1", "DMIC1"},
 	{"DEC2 MUX", "DMIC2", "DMIC2"},
-	{"DEC2 MUX", "DMIC3", "DMIC3"},
-	{"DEC2 MUX", "DMIC4", "DMIC4"},
 	{"DEC2 MUX", NULL, "CDC_CONN"},
 
-	{"DEC3 MUX", "ADC1", "ADC1"},
-	{"DEC3 MUX", "ADC2", "ADC2"},
-	{"DEC3 MUX", "ADC3", "ADC3"},
-	{"DEC3 MUX", "ADC4", "ADC4"},
-	{"DEC3 MUX", "ADC5", "ADC5"},
-	{"DEC3 MUX", "DMIC1", "DMIC1"},
-	{"DEC3 MUX", "DMIC2", "DMIC2"},
-	{"DEC3 MUX", "DMIC3", "DMIC3"},
-	{"DEC3 MUX", "DMIC4", "DMIC4"},
-	{"DEC3 MUX", NULL, "CDC_CONN"},
-
-	{"DEC4 MUX", "ADC1", "ADC1"},
-	{"DEC4 MUX", "ADC2", "ADC2"},
-	{"DEC4 MUX", "ADC3", "ADC3"},
-	{"DEC4 MUX", "ADC4", "ADC4"},
-	{"DEC4 MUX", "ADC5", "ADC5"},
-	{"DEC4 MUX", "DMIC1", "DMIC1"},
-	{"DEC4 MUX", "DMIC2", "DMIC2"},
-	{"DEC4 MUX", "DMIC3", "DMIC3"},
-	{"DEC4 MUX", "DMIC4", "DMIC4"},
-	{"DEC4 MUX", NULL, "CDC_CONN"},
-
 	/* ADC Connections */
 	{"ADC1", NULL, "AMIC1"},
 	{"ADC2", NULL, "AMIC2"},
 	{"ADC3", NULL, "AMIC3"},
 	{"ADC4", NULL, "AMIC4"},
-	{"ADC5", NULL, "AMIC5"},
 
 	/* AUX PGA Connections */
 	{"EAR_PA_MIXER", "AUX_PGA_L Switch", "AUX_PGA_Left"},
@@ -2808,13 +2971,10 @@
 	{"HPHR_PA_MIXER", "AUX_PGA_R Switch", "AUX_PGA_Right"},
 	{"LINEOUT1_PA_MIXER", "AUX_PGA_L Switch", "AUX_PGA_Left"},
 	{"LINEOUT2_PA_MIXER", "AUX_PGA_R Switch", "AUX_PGA_Right"},
-	{"AUX_PGA_Left", NULL, "AMIC5"},
 
 	{"IIR1", NULL, "IIR1 INP1 MUX"},
 	{"IIR1 INP1 MUX", "DEC1", "DEC1 MUX"},
 	{"IIR1 INP1 MUX", "DEC2", "DEC2 MUX"},
-	{"IIR1 INP1 MUX", "DEC3", "DEC3 MUX"},
-	{"IIR1 INP1 MUX", "DEC4", "DEC4 MUX"},
 
 	{"MIC BIAS1 Internal1", NULL, "LDO_H"},
 	{"MIC BIAS1 Internal2", NULL, "LDO_H"},
@@ -2823,9 +2983,17 @@
 	{"MIC BIAS2 Internal2", NULL, "LDO_H"},
 	{"MIC BIAS2 Internal3", NULL, "LDO_H"},
 	{"MIC BIAS2 External", NULL, "LDO_H"},
-	{"MIC BIAS3 Internal1", NULL, "LDO_H"},
-	{"MIC BIAS3 Internal2", NULL, "LDO_H"},
-	{"MIC BIAS3 External", NULL, "LDO_H"},
+};
+
+static const struct snd_soc_dapm_route wcd9302_map[] = {
+	{"SPK DAC", "Switch", "RX3 MIX1"},
+
+	{"RDAC4 MUX", "DEM3", "RX3 MIX1"},
+	{"RDAC4 MUX", "DEM2", "RX2 CHAIN"},
+	{"LINEOUT1 DAC", NULL, "RDAC4 MUX"},
+
+	{"RDAC5 MUX", "DEM4", "RX3 MIX1"},
+	{"RDAC5 MUX", "DEM3_INV", "RDAC4 MUX"},
 };
 
 static int tapan_readable(struct snd_soc_codec *ssc, unsigned int reg)
@@ -2855,6 +3023,9 @@
 
 static int tapan_volatile(struct snd_soc_codec *ssc, unsigned int reg)
 {
+
+	int i = 0;
+
 	/* Registers lower than 0x100 are top level registers which can be
 	 * written by the Tapan core driver.
 	 */
@@ -2888,6 +3059,11 @@
 	if (reg == TAPAN_A_MBHC_INSERT_DET_STATUS)
 		return 1;
 
+	for (i = 0; i < ARRAY_SIZE(audio_reg_cfg); i++)
+		if (audio_reg_cfg[i].reg_logical_addr -
+			TAPAN_REGISTER_START_OFFSET == reg)
+			return 1;
+
 	return 0;
 }
 
@@ -2896,6 +3072,7 @@
 	unsigned int value)
 {
 	int ret;
+	struct wcd9xxx *wcd9xxx = codec->control_data;
 
 	if (reg == SND_SOC_NOPM)
 		return 0;
@@ -2909,13 +3086,14 @@
 				reg, ret);
 	}
 
-	return wcd9xxx_reg_write(codec->control_data, reg, value);
+	return wcd9xxx_reg_write(&wcd9xxx->core_res, reg, value);
 }
 static unsigned int tapan_read(struct snd_soc_codec *codec,
 				unsigned int reg)
 {
 	unsigned int val;
 	int ret;
+	struct wcd9xxx *wcd9xxx = codec->control_data;
 
 	if (reg == SND_SOC_NOPM)
 		return 0;
@@ -2932,7 +3110,7 @@
 				reg, ret);
 	}
 
-	val = wcd9xxx_reg_read(codec->control_data, reg);
+	val = wcd9xxx_reg_read(&wcd9xxx->core_res, reg);
 	return val;
 }
 
@@ -2964,6 +3142,28 @@
 	}
 }
 
+static void tapan_set_vdd_cx_current(struct snd_soc_codec *codec,
+			int current_uA)
+{
+	struct regulator *cx_regulator;
+	int ret;
+
+	cx_regulator  = tapan_codec_find_regulator(codec,
+				"cdc-vdd-cx");
+
+	if (!cx_regulator) {
+		dev_err(codec->dev, "%s: Regulator %s not defined\n",
+			__func__, "cdc-vdd-cx-supply");
+		return;
+	}
+
+	ret = regulator_set_optimum_mode(cx_regulator, current_uA);
+	if (ret < 0)
+		dev_err(codec->dev,
+			"%s: Failed to set vdd_cx current to %d\n",
+			__func__, current_uA);
+}
+
 int tapan_mclk_enable(struct snd_soc_codec *codec, int mclk_enable, bool dapm)
 {
 	struct tapan_priv *tapan = snd_soc_codec_get_drvdata(codec);
@@ -2973,6 +3173,7 @@
 
 	WCD9XXX_BG_CLK_LOCK(&tapan->resmgr);
 	if (mclk_enable) {
+		tapan_set_vdd_cx_current(codec, TAPAN_VDD_CX_OPTIMAL_UA);
 		wcd9xxx_resmgr_get_bandgap(&tapan->resmgr,
 					   WCD9XXX_BANDGAP_AUDIO_MODE);
 		wcd9xxx_resmgr_get_clk_block(&tapan->resmgr, WCD9XXX_CLK_MCLK);
@@ -2981,6 +3182,8 @@
 		wcd9xxx_resmgr_put_clk_block(&tapan->resmgr, WCD9XXX_CLK_MCLK);
 		wcd9xxx_resmgr_put_bandgap(&tapan->resmgr,
 					   WCD9XXX_BANDGAP_AUDIO_MODE);
+		/* Set the vdd cx power rail sleep mode current */
+		tapan_set_vdd_cx_current(codec, TAPAN_VDD_CX_SLEEP_UA);
 	}
 	WCD9XXX_BG_CLK_UNLOCK(&tapan->resmgr);
 
@@ -3415,6 +3618,93 @@
 	.get_channel_map = tapan_get_channel_map,
 };
 
+static struct snd_soc_dai_driver tapan9302_dai[] = {
+	{
+		.name = "tapan9302_rx1",
+		.id = AIF1_PB,
+		.playback = {
+			.stream_name = "AIF1 Playback",
+			.rates = WCD9302_RATES,
+			.formats = TAPAN_FORMATS,
+			.rate_max = 48000,
+			.rate_min = 8000,
+			.channels_min = 1,
+			.channels_max = 2,
+		},
+		.ops = &tapan_dai_ops,
+	},
+	{
+		.name = "tapan9302_tx1",
+		.id = AIF1_CAP,
+		.capture = {
+			.stream_name = "AIF1 Capture",
+			.rates = WCD9302_RATES,
+			.formats = TAPAN_FORMATS,
+			.rate_max = 48000,
+			.rate_min = 8000,
+			.channels_min = 1,
+			.channels_max = 4,
+		},
+		.ops = &tapan_dai_ops,
+	},
+	{
+		.name = "tapan9302_rx2",
+		.id = AIF2_PB,
+		.playback = {
+			.stream_name = "AIF2 Playback",
+			.rates = WCD9302_RATES,
+			.formats = TAPAN_FORMATS,
+			.rate_min = 8000,
+			.rate_max = 48000,
+			.channels_min = 1,
+			.channels_max = 2,
+		},
+		.ops = &tapan_dai_ops,
+	},
+	{
+		.name = "tapan9302_tx2",
+		.id = AIF2_CAP,
+		.capture = {
+			.stream_name = "AIF2 Capture",
+			.rates = WCD9302_RATES,
+			.formats = TAPAN_FORMATS,
+			.rate_max = 48000,
+			.rate_min = 8000,
+			.channels_min = 1,
+			.channels_max = 4,
+		},
+		.ops = &tapan_dai_ops,
+	},
+	{
+		.name = "tapan9302_tx3",
+		.id = AIF3_CAP,
+		.capture = {
+			.stream_name = "AIF3 Capture",
+			.rates = WCD9302_RATES,
+			.formats = TAPAN_FORMATS,
+			.rate_max = 48000,
+			.rate_min = 8000,
+			.channels_min = 1,
+			.channels_max = 2,
+		},
+		.ops = &tapan_dai_ops,
+	},
+	{
+		.name = "tapan9302_rx3",
+		.id = AIF3_PB,
+		.playback = {
+			.stream_name = "AIF3 Playback",
+			.rates = WCD9302_RATES,
+			.formats = TAPAN_FORMATS,
+			.rate_min = 8000,
+			.rate_max = 48000,
+			.channels_min = 1,
+			.channels_max = 2,
+		},
+		.ops = &tapan_dai_ops,
+	},
+};
+
 static struct snd_soc_dai_driver tapan_dai[] = {
 	{
 		.name = "tapan_rx1",
@@ -3766,11 +4056,147 @@
 	return ret;
 }
 
+static int tapan_codec_chargepump_vdd_event(struct snd_soc_dapm_widget *w,
+			struct snd_kcontrol *kcontrol, int event)
+{
+	struct snd_soc_codec *codec = w->codec;
+	struct tapan_priv *priv = snd_soc_codec_get_drvdata(codec);
+	int ret = 0, i;
+
+	pr_info("%s: event = %d\n", __func__, event);
+
+
+	if (!priv->cp_regulators[CP_REG_BUCK]
+			&& !priv->cp_regulators[CP_REG_BHELPER]) {
+		pr_err("%s: No power supply defined for ChargePump\n",
+				__func__);
+		return -EINVAL;
+	}
+
+	switch (event) {
+	case SND_SOC_DAPM_PRE_PMU:
+		for (i = 0; i < CP_REG_MAX ; i++) {
+			if (!priv->cp_regulators[i])
+				continue;
+
+			ret = regulator_enable(priv->cp_regulators[i]);
+			if (ret) {
+				pr_err("%s: CP Regulator enable failed, index = %d\n",
+						__func__, i);
+				continue;
+			} else {
+				pr_debug("%s: Enabled CP regulator, index %d\n",
+					__func__, i);
+			}
+		}
+		break;
+	case SND_SOC_DAPM_POST_PMD:
+		for (i = 0; i < CP_REG_MAX; i++) {
+			if (!priv->cp_regulators[i])
+				continue;
+
+			ret = regulator_disable(priv->cp_regulators[i]);
+			if (ret) {
+				pr_err("%s: CP Regulator disable failed, index = %d\n",
+						__func__, i);
+				return ret;
+			} else {
+				pr_debug("%s: Disabled CP regulator %d\n",
+						__func__, i);
+			}
+		}
+		break;
+	}
+	return 0;
+}
+
+static const struct snd_soc_dapm_widget tapan_9306_dapm_widgets[] = {
+	/* RX4 MIX1 mux inputs */
+	SND_SOC_DAPM_MUX("RX4 MIX1 INP1", SND_SOC_NOPM, 0, 0,
+		&rx4_mix1_inp1_mux),
+	SND_SOC_DAPM_MUX("RX4 MIX1 INP2", SND_SOC_NOPM, 0, 0,
+		&rx4_mix1_inp2_mux),
+	SND_SOC_DAPM_MUX("RX4 MIX1 INP3", SND_SOC_NOPM, 0, 0,
+		&rx4_mix1_inp2_mux),
+
+	/* RX4 MIX2 mux inputs */
+	SND_SOC_DAPM_MUX("RX4 MIX2 INP1", SND_SOC_NOPM, 0, 0,
+		&rx4_mix2_inp1_mux),
+	SND_SOC_DAPM_MUX("RX4 MIX2 INP2", SND_SOC_NOPM, 0, 0,
+		&rx4_mix2_inp2_mux),
+
+	SND_SOC_DAPM_MIXER("RX4 MIX1", SND_SOC_NOPM, 0, 0, NULL, 0),
+
+	SND_SOC_DAPM_MIXER_E("RX4 MIX2", TAPAN_A_CDC_CLK_RX_B1_CTL, 3, 0, NULL,
+		0, tapan_codec_enable_interpolator, SND_SOC_DAPM_PRE_PMU |
+		SND_SOC_DAPM_POST_PMU),
+
+	SND_SOC_DAPM_MUX_E("DEC3 MUX", TAPAN_A_CDC_CLK_TX_CLK_EN_B1_CTL, 2, 0,
+		&dec3_mux, tapan_codec_enable_dec,
+		SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU |
+		SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD),
+
+	SND_SOC_DAPM_MUX_E("DEC4 MUX", TAPAN_A_CDC_CLK_TX_CLK_EN_B1_CTL, 3, 0,
+		&dec4_mux, tapan_codec_enable_dec,
+		SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU |
+		SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD),
+
+	SND_SOC_DAPM_SUPPLY("COMP0_CLK", SND_SOC_NOPM, 0, 0,
+		tapan_config_compander, SND_SOC_DAPM_PRE_PMU |
+		SND_SOC_DAPM_PRE_PMD),
+	SND_SOC_DAPM_SUPPLY("COMP1_CLK", SND_SOC_NOPM, 1, 0,
+		tapan_config_compander, SND_SOC_DAPM_PRE_PMU |
+		SND_SOC_DAPM_PRE_PMD),
+	SND_SOC_DAPM_SUPPLY("COMP2_CLK", SND_SOC_NOPM, 2, 0,
+		tapan_config_compander, SND_SOC_DAPM_PRE_PMU |
+		SND_SOC_DAPM_PRE_PMD),
+
+	SND_SOC_DAPM_INPUT("AMIC5"),
+	SND_SOC_DAPM_ADC_E("ADC5", NULL, TAPAN_A_TX_5_EN, 7, 0,
+		tapan_codec_enable_adc, SND_SOC_DAPM_POST_PMU),
+
+	SND_SOC_DAPM_MUX("ANC1 MUX", SND_SOC_NOPM, 0, 0, &anc1_mux),
+	SND_SOC_DAPM_MUX("ANC2 MUX", SND_SOC_NOPM, 0, 0, &anc2_mux),
+
+	SND_SOC_DAPM_OUTPUT("ANC HEADPHONE"),
+	SND_SOC_DAPM_PGA_E("ANC HPHL", SND_SOC_NOPM, 5, 0, NULL, 0,
+		tapan_codec_enable_anc_hph,
+		SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_PRE_PMD |
+		SND_SOC_DAPM_POST_PMD | SND_SOC_DAPM_POST_PMU),
+	SND_SOC_DAPM_PGA_E("ANC HPHR", SND_SOC_NOPM, 4, 0, NULL, 0,
+		tapan_codec_enable_anc_hph, SND_SOC_DAPM_PRE_PMU |
+		SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD |
+		SND_SOC_DAPM_POST_PMU),
+	SND_SOC_DAPM_OUTPUT("ANC EAR"),
+	SND_SOC_DAPM_PGA_E("ANC EAR PA", SND_SOC_NOPM, 0, 0, NULL, 0,
+		tapan_codec_enable_anc_ear,
+		SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_PRE_PMD |
+		SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
+	SND_SOC_DAPM_MUX("ANC1 FB MUX", SND_SOC_NOPM, 0, 0, &anc1_fb_mux),
+
+	SND_SOC_DAPM_MICBIAS_E("MIC BIAS3 External", TAPAN_A_MICB_3_CTL, 7, 0,
+		tapan_codec_enable_micbias, SND_SOC_DAPM_PRE_PMU |
+		SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
+	SND_SOC_DAPM_MICBIAS_E("MIC BIAS3 Internal1", TAPAN_A_MICB_3_CTL, 7, 0,
+		tapan_codec_enable_micbias, SND_SOC_DAPM_PRE_PMU |
+		SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
+	SND_SOC_DAPM_MICBIAS_E("MIC BIAS3 Internal2", TAPAN_A_MICB_3_CTL, 7, 0,
+		tapan_codec_enable_micbias, SND_SOC_DAPM_PRE_PMU |
+		SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
+
+	SND_SOC_DAPM_ADC_E("DMIC3", NULL, SND_SOC_NOPM, 0, 0,
+		tapan_codec_enable_dmic, SND_SOC_DAPM_PRE_PMU |
+		SND_SOC_DAPM_POST_PMD),
+
+	SND_SOC_DAPM_ADC_E("DMIC4", NULL, SND_SOC_NOPM, 0, 0,
+		tapan_codec_enable_dmic, SND_SOC_DAPM_PRE_PMU |
+		SND_SOC_DAPM_POST_PMD),
+};
 
 /* Todo: Have seperate dapm widgets for I2S and Slimbus.
  * Might Need to have callbacks registered only for slimbus
  */
-static const struct snd_soc_dapm_widget tapan_dapm_widgets[] = {
+static const struct snd_soc_dapm_widget tapan_common_dapm_widgets[] = {
 
 	SND_SOC_DAPM_AIF_IN_E("AIF1 PB", "AIF1 Playback", 0, SND_SOC_NOPM,
 				AIF1_PB, 0, tapan_codec_enable_slimrx,
@@ -3824,14 +4250,6 @@
 	SND_SOC_DAPM_MUX("RX3 MIX1 INP3", SND_SOC_NOPM, 0, 0,
 		&rx3_mix1_inp2_mux),
 
-	/* RX4 MIX1 mux inputs */
-	SND_SOC_DAPM_MUX("RX4 MIX1 INP1", SND_SOC_NOPM, 0, 0,
-		&rx4_mix1_inp1_mux),
-	SND_SOC_DAPM_MUX("RX4 MIX1 INP2", SND_SOC_NOPM, 0, 0,
-		&rx4_mix1_inp2_mux),
-	SND_SOC_DAPM_MUX("RX4 MIX1 INP3", SND_SOC_NOPM, 0, 0,
-		&rx4_mix1_inp2_mux),
-
 	/* RX1 MIX2 mux inputs */
 	SND_SOC_DAPM_MUX("RX1 MIX2 INP1", SND_SOC_NOPM, 0, 0,
 		&rx1_mix2_inp1_mux),
@@ -3844,16 +4262,8 @@
 	SND_SOC_DAPM_MUX("RX2 MIX2 INP2", SND_SOC_NOPM, 0, 0,
 		&rx2_mix2_inp2_mux),
 
-	/* RX4 MIX2 mux inputs */
-	SND_SOC_DAPM_MUX("RX4 MIX2 INP1", SND_SOC_NOPM, 0, 0,
-		&rx4_mix2_inp1_mux),
-	SND_SOC_DAPM_MUX("RX4 MIX2 INP2", SND_SOC_NOPM, 0, 0,
-		&rx4_mix2_inp2_mux),
-
-
 	SND_SOC_DAPM_MIXER("RX1 MIX1", SND_SOC_NOPM, 0, 0, NULL, 0),
 	SND_SOC_DAPM_MIXER("RX2 MIX1", SND_SOC_NOPM, 0, 0, NULL, 0),
-	SND_SOC_DAPM_MIXER("RX4 MIX1", SND_SOC_NOPM, 0, 0, NULL, 0),
 
 	SND_SOC_DAPM_MIXER_E("RX1 MIX2", TAPAN_A_CDC_CLK_RX_B1_CTL, 0, 0, NULL,
 		0, tapan_codec_enable_interpolator, SND_SOC_DAPM_PRE_PMU |
@@ -3864,9 +4274,6 @@
 	SND_SOC_DAPM_MIXER_E("RX3 MIX1", TAPAN_A_CDC_CLK_RX_B1_CTL, 2, 0, NULL,
 		0, tapan_codec_enable_interpolator, SND_SOC_DAPM_PRE_PMU |
 		SND_SOC_DAPM_POST_PMU),
-	SND_SOC_DAPM_MIXER_E("RX4 MIX2", TAPAN_A_CDC_CLK_RX_B1_CTL, 3, 0, NULL,
-		0, tapan_codec_enable_interpolator, SND_SOC_DAPM_PRE_PMU |
-		SND_SOC_DAPM_POST_PMU),
 
 	SND_SOC_DAPM_MIXER("RX1 CHAIN", TAPAN_A_CDC_RX1_B6_CTL, 5, 0,
 						NULL, 0),
@@ -3882,6 +4289,11 @@
 		tapan_codec_enable_rx_bias, SND_SOC_DAPM_PRE_PMU |
 		SND_SOC_DAPM_POST_PMD),
 
+	/* CDC_CP_VDD */
+	SND_SOC_DAPM_SUPPLY("CDC_CP_VDD", SND_SOC_NOPM, 0, 0,
+		tapan_codec_chargepump_vdd_event, SND_SOC_DAPM_PRE_PMU |
+		SND_SOC_DAPM_POST_PMD),
+
 	/*EAR */
 	SND_SOC_DAPM_PGA_E("EAR PA", TAPAN_A_RX_EAR_EN, 4, 0, NULL, 0,
 			tapan_codec_enable_ear_pa, SND_SOC_DAPM_POST_PMU |
@@ -3922,6 +4334,13 @@
 	SND_SOC_DAPM_MUX("RDAC5 MUX", SND_SOC_NOPM, 0, 0,
 		&rx_dac5_mux),
 
+	/* LINEOUT1*/
+	SND_SOC_DAPM_MUX("RDAC4 MUX", SND_SOC_NOPM, 0, 0,
+		&rx_dac4_mux),
+
+	SND_SOC_DAPM_MUX("RDAC3 MUX", SND_SOC_NOPM, 0, 0,
+		&rx_dac3_mux),
+
 	SND_SOC_DAPM_DAC_E("LINEOUT2 DAC", NULL, TAPAN_A_RX_LINE_2_DAC_CTL, 7, 0
 		, tapan_lineout_dac_event,
 		SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
@@ -3984,29 +4403,9 @@
 		SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU |
 		SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD),
 
-	SND_SOC_DAPM_MUX_E("DEC3 MUX", TAPAN_A_CDC_CLK_TX_CLK_EN_B1_CTL, 2, 0,
-		&dec3_mux, tapan_codec_enable_dec,
-		SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU |
-		SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD),
-
-	SND_SOC_DAPM_MUX_E("DEC4 MUX", TAPAN_A_CDC_CLK_TX_CLK_EN_B1_CTL, 3, 0,
-		&dec4_mux, tapan_codec_enable_dec,
-		SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU |
-		SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD),
-
 	SND_SOC_DAPM_SUPPLY("LDO_H", TAPAN_A_LDO_H_MODE_1, 7, 0,
 		tapan_codec_enable_ldo_h, SND_SOC_DAPM_POST_PMU),
 
-	SND_SOC_DAPM_SUPPLY("COMP0_CLK", SND_SOC_NOPM, 0, 0,
-		tapan_config_compander, SND_SOC_DAPM_PRE_PMU |
-		SND_SOC_DAPM_PRE_PMD),
-	SND_SOC_DAPM_SUPPLY("COMP1_CLK", SND_SOC_NOPM, 1, 0,
-		tapan_config_compander, SND_SOC_DAPM_PRE_PMU |
-		SND_SOC_DAPM_PRE_PMD),
-	SND_SOC_DAPM_SUPPLY("COMP2_CLK", SND_SOC_NOPM, 2, 0,
-		tapan_config_compander, SND_SOC_DAPM_PRE_PMU |
-		SND_SOC_DAPM_PRE_PMD),
-
 	SND_SOC_DAPM_INPUT("AMIC1"),
 	SND_SOC_DAPM_MICBIAS_E("MIC BIAS1 External", TAPAN_A_MICB_1_CTL, 7, 0,
 		tapan_codec_enable_micbias, SND_SOC_DAPM_PRE_PMU |
@@ -4035,29 +4434,6 @@
 		tapan_codec_enable_adc, SND_SOC_DAPM_PRE_PMU |
 		SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
 
-	SND_SOC_DAPM_INPUT("AMIC5"),
-	SND_SOC_DAPM_ADC_E("ADC5", NULL, TAPAN_A_TX_5_EN, 7, 0,
-		tapan_codec_enable_adc, SND_SOC_DAPM_POST_PMU),
-
-	SND_SOC_DAPM_MUX("ANC1 MUX", SND_SOC_NOPM, 0, 0, &anc1_mux),
-	SND_SOC_DAPM_MUX("ANC2 MUX", SND_SOC_NOPM, 0, 0, &anc2_mux),
-
-	SND_SOC_DAPM_OUTPUT("ANC HEADPHONE"),
-	SND_SOC_DAPM_PGA_E("ANC HPHL", SND_SOC_NOPM, 5, 0, NULL, 0,
-		tapan_codec_enable_anc_hph,
-		SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_PRE_PMD |
-		SND_SOC_DAPM_POST_PMD | SND_SOC_DAPM_POST_PMU),
-	SND_SOC_DAPM_PGA_E("ANC HPHR", SND_SOC_NOPM, 4, 0, NULL, 0,
-		tapan_codec_enable_anc_hph, SND_SOC_DAPM_PRE_PMU |
-		SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD |
-		SND_SOC_DAPM_POST_PMU),
-	SND_SOC_DAPM_OUTPUT("ANC EAR"),
-	SND_SOC_DAPM_PGA_E("ANC EAR PA", SND_SOC_NOPM, 0, 0, NULL, 0,
-		tapan_codec_enable_anc_ear,
-		SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_PRE_PMD |
-		SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
-	SND_SOC_DAPM_MUX("ANC1 FB MUX", SND_SOC_NOPM, 0, 0, &anc1_fb_mux),
-
 	SND_SOC_DAPM_INPUT("AMIC2"),
 	SND_SOC_DAPM_MICBIAS_E("MIC BIAS2 External", TAPAN_A_MICB_2_CTL, 7, 0,
 		tapan_codec_enable_micbias, SND_SOC_DAPM_PRE_PMU |
@@ -4071,15 +4447,6 @@
 	SND_SOC_DAPM_MICBIAS_E("MIC BIAS2 Internal3", TAPAN_A_MICB_2_CTL, 7, 0,
 		tapan_codec_enable_micbias, SND_SOC_DAPM_PRE_PMU |
 		SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
-	SND_SOC_DAPM_MICBIAS_E("MIC BIAS3 External", TAPAN_A_MICB_3_CTL, 7, 0,
-		tapan_codec_enable_micbias, SND_SOC_DAPM_PRE_PMU |
-		SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
-	SND_SOC_DAPM_MICBIAS_E("MIC BIAS3 Internal1", TAPAN_A_MICB_3_CTL, 7, 0,
-		tapan_codec_enable_micbias, SND_SOC_DAPM_PRE_PMU |
-		SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
-	SND_SOC_DAPM_MICBIAS_E("MIC BIAS3 Internal2", TAPAN_A_MICB_3_CTL, 7, 0,
-		tapan_codec_enable_micbias, SND_SOC_DAPM_PRE_PMU |
-		SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
 
 	SND_SOC_DAPM_AIF_OUT_E("AIF1 CAP", "AIF1 Capture", 0, SND_SOC_NOPM,
 		AIF1_CAP, 0, tapan_codec_enable_slimtx,
@@ -4102,14 +4469,6 @@
 		tapan_codec_enable_dmic, SND_SOC_DAPM_PRE_PMU |
 		SND_SOC_DAPM_POST_PMD),
 
-	SND_SOC_DAPM_ADC_E("DMIC3", NULL, SND_SOC_NOPM, 0, 0,
-		tapan_codec_enable_dmic, SND_SOC_DAPM_PRE_PMU |
-		SND_SOC_DAPM_POST_PMD),
-
-	SND_SOC_DAPM_ADC_E("DMIC4", NULL, SND_SOC_NOPM, 0, 0,
-		tapan_codec_enable_dmic, SND_SOC_DAPM_PRE_PMU |
-		SND_SOC_DAPM_POST_PMD),
-
 	/* Sidetone */
 	SND_SOC_DAPM_MUX("IIR1 INP1 MUX", SND_SOC_NOPM, 0, 0, &iir1_inp1_mux),
 	SND_SOC_DAPM_PGA("IIR1", TAPAN_A_CDC_CLK_SD_CTL, 0, 0, NULL, 0),
@@ -4530,6 +4889,46 @@
 	{TAPAN_A_RX_HPH_CHOP_CTL, 0xFF, 0x24},
 };
 
+void *tapan_get_afe_config(struct snd_soc_codec *codec,
+			   enum afe_config_type config_type)
+{
+	struct tapan_priv *priv = snd_soc_codec_get_drvdata(codec);
+
+	switch (config_type) {
+	case AFE_SLIMBUS_SLAVE_CONFIG:
+		return &priv->slimbus_slave_cfg;
+	case AFE_CDC_REGISTERS_CONFIG:
+		return &tapan_audio_reg_cfg;
+	case AFE_AANC_VERSION:
+		return &tapan_cdc_aanc_version;
+	default:
+		pr_err("%s: Unknown config_type 0x%x\n", __func__, config_type);
+		return NULL;
+	}
+}
+
+static void tapan_init_slim_slave_cfg(struct snd_soc_codec *codec)
+{
+	struct tapan_priv *priv = snd_soc_codec_get_drvdata(codec);
+	struct afe_param_cdc_slimbus_slave_cfg *cfg;
+	struct wcd9xxx *wcd9xxx = codec->control_data;
+	uint64_t eaddr = 0;
+
+	pr_debug("%s\n", __func__);
+	cfg = &priv->slimbus_slave_cfg;
+	cfg->minor_version = 1;
+	cfg->tx_slave_port_offset = 0;
+	cfg->rx_slave_port_offset = 16;
+
+	memcpy(&eaddr, &wcd9xxx->slim->e_addr, sizeof(wcd9xxx->slim->e_addr));
+	/* e-addr is 6-byte elemental address of the device */
+	WARN_ON(sizeof(wcd9xxx->slim->e_addr) != 6);
+	cfg->device_enum_addr_lsw = eaddr & 0xFFFFFFFF;
+	cfg->device_enum_addr_msw = eaddr >> 32;
+
+	pr_debug("%s: slimbus logical address 0x%llx\n", __func__, eaddr);
+}
+
 static void tapan_codec_init_reg(struct snd_soc_codec *codec)
 {
 	u32 i;
@@ -4553,8 +4952,10 @@
 {
 	int ret = 0;
 	struct snd_soc_codec *codec = tapan->codec;
+	struct wcd9xxx *wcd9xxx = codec->control_data;
+	struct wcd9xxx_core_resource *core_res = &wcd9xxx->core_res;
 
-	ret = wcd9xxx_request_irq(codec->control_data, WCD9XXX_IRQ_SLIMBUS,
+	ret = wcd9xxx_request_irq(core_res, WCD9XXX_IRQ_SLIMBUS,
 				  tapan_slimbus_irq, "SLIMBUS Slave", tapan);
 	if (ret)
 		pr_err("%s: Failed to request irq %d\n", __func__,
@@ -4568,7 +4969,9 @@
 static void tapan_cleanup_irqs(struct tapan_priv *tapan)
 {
 	struct snd_soc_codec *codec = tapan->codec;
-	wcd9xxx_free_irq(codec->control_data, WCD9XXX_IRQ_SLIMBUS, tapan);
+	struct wcd9xxx *wcd9xxx = codec->control_data;
+	struct wcd9xxx_core_resource *core_res = &wcd9xxx->core_res;
+	wcd9xxx_free_irq(core_res, WCD9XXX_IRQ_SLIMBUS, tapan);
 }
 
 
@@ -4589,7 +4992,7 @@
 					   struct wcd9xxx_mbhc *mbhc)
 {
 	snd_soc_update_bits(codec, WCD9XXX_A_CDC_MBHC_B1_CTL,
-			    0x0C, 0x04);
+			    0x04, 0x04);
 	snd_soc_update_bits(codec, WCD9XXX_A_TX_7_MBHC_EN, 0xE0, 0xE0);
 }
 
@@ -4612,6 +5015,8 @@
 
 	cfilt_mode.cur_mode_val =
 		snd_soc_read(codec, mbhc->mbhc_bias_regs.cfilt_ctl) & 0x30;
+	cfilt_mode.reg_mask = 0x30;
+
 	return cfilt_mode;
 }
 
@@ -4623,8 +5028,264 @@
 
 static void tapan_free_irq(struct wcd9xxx_mbhc *mbhc)
 {
-	void *cdata = mbhc->codec->control_data;
-	wcd9xxx_free_irq(cdata, WCD9306_IRQ_MBHC_JACK_SWITCH, mbhc);
+	struct wcd9xxx *wcd9xxx = mbhc->codec->control_data;
+	struct wcd9xxx_core_resource *core_res =
+			&wcd9xxx->core_res;
+	wcd9xxx_free_irq(core_res, WCD9306_IRQ_MBHC_JACK_SWITCH, mbhc);
+}
+
+enum wcd9xxx_cdc_type tapan_get_cdc_type(void)
+{
+	return WCD9XXX_CDC_TYPE_TAPAN;
+}
+
+static void wcd9xxx_prepare_hph_pa(struct wcd9xxx_mbhc *mbhc,
+				   struct list_head *lh)
+{
+	int i;
+	struct snd_soc_codec *codec = mbhc->codec;
+	u32 delay;
+
+	const struct wcd9xxx_reg_mask_val reg_set_paon[] = {
+		{WCD9XXX_A_CDC_CLSH_B1_CTL, 0x0F, 0x00},
+		{WCD9XXX_A_RX_HPH_CHOP_CTL, 0xFF, 0xA4},
+		{WCD9XXX_A_RX_HPH_OCP_CTL, 0xFF, 0x67},
+		{WCD9XXX_A_RX_HPH_L_TEST, 0x1, 0x0},
+		{WCD9XXX_A_RX_HPH_R_TEST, 0x1, 0x0},
+		{WCD9XXX_A_RX_HPH_BIAS_WG_OCP, 0xFF, 0x1A},
+		{WCD9XXX_A_RX_HPH_CNP_WG_CTL, 0xFF, 0xDB},
+		{WCD9XXX_A_RX_HPH_CNP_WG_TIME, 0xFF, 0x2A},
+		{TAPAN_A_CDC_CONN_RX2_B2_CTL, 0xFF, 0x10},
+		{WCD9XXX_A_CDC_CLK_OTHR_CTL, 0xFF, 0x05},
+		{WCD9XXX_A_CDC_RX1_B6_CTL, 0xFF, 0x81},
+		{WCD9XXX_A_CDC_CLK_RX_B1_CTL, 0x03, 0x03},
+		{WCD9XXX_A_RX_HPH_L_GAIN, 0xFF, 0x2C},
+		{WCD9XXX_A_CDC_RX2_B6_CTL, 0xFF, 0x81},
+		{WCD9XXX_A_RX_HPH_R_GAIN, 0xFF, 0x2C},
+		{WCD9XXX_A_BUCK_CTRL_CCL_4, 0xFF, 0x50},
+		{WCD9XXX_A_BUCK_CTRL_VCL_1, 0xFF, 0x08},
+		{WCD9XXX_A_BUCK_CTRL_CCL_1, 0xFF, 0x5B},
+		{WCD9XXX_A_NCP_CLK, 0xFF, 0x9C},
+		{WCD9XXX_A_NCP_CLK, 0xFF, 0xFC},
+		{WCD9XXX_A_BUCK_MODE_3, 0xFF, 0xCE},
+		{WCD9XXX_A_BUCK_CTRL_CCL_3, 0xFF, 0x6B},
+		{WCD9XXX_A_BUCK_CTRL_CCL_3, 0xFF, 0x6F},
+		{TAPAN_A_RX_BUCK_BIAS1, 0xFF, 0x62},
+		{TAPAN_A_RX_HPH_BIAS_PA, 0xFF, 0x7A},
+		{TAPAN_A_CDC_CLK_RDAC_CLK_EN_CTL, 0xFF, 0x02},
+		{TAPAN_A_CDC_CLK_RDAC_CLK_EN_CTL, 0xFF, 0x06},
+		{WCD9XXX_A_RX_COM_BIAS, 0xFF, 0x80},
+		{WCD9XXX_A_BUCK_MODE_3, 0xFF, 0xC6},
+		{WCD9XXX_A_BUCK_MODE_4, 0xFF, 0xE6},
+		{WCD9XXX_A_BUCK_MODE_5, 0xFF, 0x02},
+		{WCD9XXX_A_BUCK_MODE_1, 0xFF, 0xA1},
+		/* Delay 1ms */
+		{WCD9XXX_A_NCP_EN, 0xFF, 0xFF},
+		/* Delay 1ms */
+		{WCD9XXX_A_BUCK_MODE_5, 0xFF, 0x03},
+		{WCD9XXX_A_BUCK_MODE_5, 0xFF, 0x7B},
+		{WCD9XXX_A_CDC_CLSH_B1_CTL, 0xFF, 0xE6},
+		{WCD9XXX_A_RX_HPH_L_DAC_CTL, 0xFF, 0x40},
+		{WCD9XXX_A_RX_HPH_L_DAC_CTL, 0xFF, 0xC0},
+		{WCD9XXX_A_RX_HPH_R_DAC_CTL, 0xFF, 0x40},
+		{WCD9XXX_A_RX_HPH_R_DAC_CTL, 0xFF, 0xC0},
+		{WCD9XXX_A_NCP_STATIC, 0xFF, 0x08},
+		{WCD9XXX_A_RX_HPH_L_DAC_CTL, 0x03, 0x01},
+		{WCD9XXX_A_RX_HPH_R_DAC_CTL, 0x03, 0x01},
+	};
+
+	/*
+	 * Configure PA in class-AB, -18dB gain,
+	 * companding off, OCP off, Chopping ON
+	 */
+	for (i = 0; i < ARRAY_SIZE(reg_set_paon); i++) {
+		/*
+		 * Some of the codec registers like BUCK_MODE_1
+		 * and NCP_EN requires 1ms wait time for them
+		 * to take effect. Other register writes for
+		 * PA configuration do not require any wait time.
+		 */
+		if (reg_set_paon[i].reg == WCD9XXX_A_BUCK_MODE_1 ||
+		    reg_set_paon[i].reg == WCD9XXX_A_NCP_EN)
+			delay = 1000;
+		else
+			delay = 0;
+		wcd9xxx_soc_update_bits_push(codec, lh,
+					     reg_set_paon[i].reg,
+					     reg_set_paon[i].mask,
+					     reg_set_paon[i].val, delay);
+	}
+	pr_debug("%s: PAs are prepared\n", __func__);
+	return;
+}
+
+static int wcd9xxx_enable_static_pa(struct wcd9xxx_mbhc *mbhc, bool enable)
+{
+	struct snd_soc_codec *codec = mbhc->codec;
+	int wg_time = snd_soc_read(codec, WCD9XXX_A_RX_HPH_CNP_WG_TIME) *
+				   TAPAN_WG_TIME_FACTOR_US;
+	/*
+	 * Tapan requires additional time to enable PA.
+	 * It is observed during experiments that we need
+	 * an additional wait time about 0.35 times of
+	 * the WG_TIME
+	 */
+	wg_time += (int) (wg_time * 35) / 100;
+
+	snd_soc_update_bits(codec, WCD9XXX_A_RX_HPH_CNP_EN, 0x30,
+			    enable ? 0x30 : 0x0);
+	/* Wait for wave gen time to avoid pop noise */
+	usleep_range(wg_time, wg_time + WCD9XXX_USLEEP_RANGE_MARGIN_US);
+	pr_debug("%s: PAs are %s as static mode (wg_time %d)\n", __func__,
+		 enable ? "enabled" : "disabled", wg_time);
+	return 0;
+}
+
+static int tapan_setup_zdet(struct wcd9xxx_mbhc *mbhc,
+			    enum mbhc_impedance_detect_stages stage)
+{
+
+	int ret = 0;
+	struct snd_soc_codec *codec = mbhc->codec;
+	struct tapan_priv *tapan = snd_soc_codec_get_drvdata(codec);
+	const int mux_wait_us = 25;
+
+	switch (stage) {
+
+	case PRE_MEAS:
+		INIT_LIST_HEAD(&tapan->reg_save_restore);
+		/* Configure PA */
+		wcd9xxx_prepare_hph_pa(mbhc, &tapan->reg_save_restore);
+
+#define __wr(reg, mask, value)						  \
+	do {								  \
+		ret = wcd9xxx_soc_update_bits_push(codec,		  \
+						   &tapan->reg_save_restore, \
+						   reg, mask, value, 0);  \
+		if (ret < 0)						  \
+			return ret;					  \
+	} while (0)
+
+		/* Setup MBHC */
+		__wr(WCD9XXX_A_MBHC_SCALING_MUX_1, 0x7F, 0x40);
+		__wr(WCD9XXX_A_MBHC_SCALING_MUX_2, 0xFF, 0xF0);
+		__wr(WCD9XXX_A_TX_7_MBHC_TEST_CTL, 0xFF, 0x78);
+		__wr(WCD9XXX_A_TX_7_MBHC_EN, 0xFF, 0xEC);
+		__wr(WCD9XXX_A_CDC_MBHC_TIMER_B4_CTL, 0xFF, 0x45);
+		__wr(WCD9XXX_A_CDC_MBHC_TIMER_B5_CTL, 0xFF, 0x80);
+
+		__wr(WCD9XXX_A_CDC_MBHC_CLK_CTL, 0xFF, 0x0A);
+		snd_soc_write(codec, WCD9XXX_A_CDC_MBHC_EN_CTL, 0x2);
+		__wr(WCD9XXX_A_CDC_MBHC_CLK_CTL, 0xFF, 0x02);
+
+		/* Enable Impedance Detection */
+		__wr(WCD9XXX_A_MBHC_HPH, 0xFF, 0xC8);
+
+		/*
+		 * CnP setup for 0mV
+		 * Route static data as input to noise shaper
+		 */
+		__wr(TAPAN_A_CDC_RX1_B3_CTL, 0xFF, 0x02);
+		__wr(TAPAN_A_CDC_RX2_B3_CTL, 0xFF, 0x02);
+
+		snd_soc_update_bits(codec, WCD9XXX_A_RX_HPH_L_TEST,
+				    0x02, 0x00);
+		snd_soc_update_bits(codec, WCD9XXX_A_RX_HPH_R_TEST,
+				    0x02, 0x00);
+
+		/* Reset the HPHL static data pointer */
+		__wr(TAPAN_A_CDC_RX1_B2_CTL, 0xFF, 0x00);
+		/* Four consecutive writes to set 0V as static data input */
+		snd_soc_write(codec, TAPAN_A_CDC_RX1_B1_CTL, 0x00);
+		snd_soc_write(codec, TAPAN_A_CDC_RX1_B1_CTL, 0x00);
+		snd_soc_write(codec, TAPAN_A_CDC_RX1_B1_CTL, 0x00);
+		snd_soc_write(codec, TAPAN_A_CDC_RX1_B1_CTL, 0x00);
+
+		/* Reset the HPHR static data pointer */
+		__wr(TAPAN_A_CDC_RX2_B2_CTL, 0xFF, 0x00);
+		/* Four consecutive writes to set 0V as static data input */
+		snd_soc_write(codec, TAPAN_A_CDC_RX2_B1_CTL, 0x00);
+		snd_soc_write(codec, TAPAN_A_CDC_RX2_B1_CTL, 0x00);
+		snd_soc_write(codec, TAPAN_A_CDC_RX2_B1_CTL, 0x00);
+		snd_soc_write(codec, TAPAN_A_CDC_RX2_B1_CTL, 0x00);
+
+		/* Enable the HPHL and HPHR PA */
+		wcd9xxx_enable_static_pa(mbhc, true);
+		break;
+	case POST_MEAS:
+		/* Turn off ICAL */
+		snd_soc_write(codec, WCD9XXX_A_MBHC_SCALING_MUX_2, 0xF0);
+
+		wcd9xxx_enable_static_pa(mbhc, false);
+
+		/*
+		 * Setup CnP wavegen to ramp to the desired
+		 * output using a 40ms ramp
+		 */
+
+		/* CnP wavegen current to 0.5uA */
+		snd_soc_write(codec, WCD9XXX_A_RX_HPH_BIAS_WG_OCP, 0x1A);
+		/* Set the current division ratio to 2000 */
+		snd_soc_write(codec, WCD9XXX_A_RX_HPH_CNP_WG_CTL, 0xDF);
+		/* Set the wavegen timer to max (60msec) */
+		snd_soc_write(codec, WCD9XXX_A_RX_HPH_CNP_WG_TIME, 0xA0);
+		/* Set the CnP reference current to sc_bias */
+		snd_soc_write(codec, WCD9XXX_A_RX_HPH_OCP_CTL, 0x6D);
+
+		snd_soc_write(codec, TAPAN_A_CDC_RX1_B2_CTL, 0x00);
+		/* Four consecutive writes to set -10mV as static data input */
+		snd_soc_write(codec, TAPAN_A_CDC_RX1_B1_CTL, 0x00);
+		snd_soc_write(codec, TAPAN_A_CDC_RX1_B1_CTL, 0x1F);
+		snd_soc_write(codec, TAPAN_A_CDC_RX1_B1_CTL, 0x19);
+		snd_soc_write(codec, TAPAN_A_CDC_RX1_B1_CTL, 0xAA);
+
+		snd_soc_write(codec, TAPAN_A_CDC_RX2_B2_CTL, 0x00);
+		/* Four consecutive writes to set -10mV as static data input */
+		snd_soc_write(codec, TAPAN_A_CDC_RX2_B1_CTL, 0x00);
+		snd_soc_write(codec, TAPAN_A_CDC_RX2_B1_CTL, 0x1F);
+		snd_soc_write(codec, TAPAN_A_CDC_RX2_B1_CTL, 0x19);
+		snd_soc_write(codec, TAPAN_A_CDC_RX2_B1_CTL, 0xAA);
+
+		snd_soc_update_bits(codec, WCD9XXX_A_RX_HPH_L_TEST,
+				    0x02, 0x02);
+		snd_soc_update_bits(codec, WCD9XXX_A_RX_HPH_R_TEST,
+				    0x02, 0x02);
+		/* Enable the HPHL and HPHR PA and wait for 60mS */
+		wcd9xxx_enable_static_pa(mbhc, true);
+
+		snd_soc_update_bits(codec, WCD9XXX_A_MBHC_SCALING_MUX_1,
+				    0x7F, 0x40);
+		usleep_range(mux_wait_us,
+				mux_wait_us + WCD9XXX_USLEEP_RANGE_MARGIN_US);
+		break;
+	case PA_DISABLE:
+		wcd9xxx_enable_static_pa(mbhc, false);
+		wcd9xxx_restore_registers(codec, &tapan->reg_save_restore);
+		break;
+	}
+#undef __wr
+
+	return ret;
+}
+
+static void tapan_compute_impedance(s16 *l, s16 *r, uint32_t *zl, uint32_t *zr)
+{
+	int zln, zld;
+	int zrn, zrd;
+	int rl = 0, rr = 0;
+
+	zln = (l[1] - l[0]) * TAPAN_ZDET_MUL_FACTOR;
+	zld = (l[2] - l[0]);
+	if (zld)
+		rl = zln / zld;
+
+	zrn = (r[1] - r[0]) * TAPAN_ZDET_MUL_FACTOR;
+	zrd = (r[2] - r[0]);
+	if (zrd)
+		rr = zrn / zrd;
+
+	*zl = rl;
+	*zr = rr;
 }
 
 static const struct wcd9xxx_mbhc_cb mbhc_cb = {
@@ -4635,6 +5296,9 @@
 	.switch_cfilt_mode = tapan_codec_switch_cfilt_mode,
 	.select_cfilt = tapan_select_cfilt,
 	.free_irq = tapan_free_irq,
+	.get_cdc_type = tapan_get_cdc_type,
+	.setup_zdet = tapan_setup_zdet,
+	.compute_impedance = tapan_compute_impedance,
 };
 
 int tapan_hs_detect(struct snd_soc_codec *codec,
@@ -4643,7 +5307,34 @@
 	struct tapan_priv *tapan = snd_soc_codec_get_drvdata(codec);
 	return wcd9xxx_mbhc_start(&tapan->mbhc, mbhc_cfg);
 }
-EXPORT_SYMBOL_GPL(tapan_hs_detect);
+EXPORT_SYMBOL(tapan_hs_detect);
+
+void tapan_hs_detect_exit(struct snd_soc_codec *codec)
+{
+	struct tapan_priv *tapan = snd_soc_codec_get_drvdata(codec);
+	wcd9xxx_mbhc_stop(&tapan->mbhc);
+}
+EXPORT_SYMBOL(tapan_hs_detect_exit);
+
+void tapan_event_register(
+	int (*machine_event_cb)(struct snd_soc_codec *codec,
+				enum wcd9xxx_codec_event),
+	struct snd_soc_codec *codec)
+{
+	struct tapan_priv *tapan = snd_soc_codec_get_drvdata(codec);
+	tapan->machine_codec_event_cb = machine_event_cb;
+}
+EXPORT_SYMBOL(tapan_event_register);
+
+static int tapan_device_down(struct wcd9xxx *wcd9xxx)
+{
+	struct snd_soc_codec *codec;
+
+	codec = (struct snd_soc_codec *)(wcd9xxx->ssr_priv);
+	snd_soc_card_change_online_state(codec->card, 0);
+
+	return 0;
+}
 
 static int tapan_post_reset_cb(struct wcd9xxx *wcd9xxx)
 {
@@ -4654,8 +5345,10 @@
 
 	codec = (struct snd_soc_codec *)(wcd9xxx->ssr_priv);
 	tapan = snd_soc_codec_get_drvdata(codec);
-	mutex_lock(&codec->mutex);
 
+	snd_soc_card_change_online_state(codec->card, 1);
+
+	mutex_lock(&codec->mutex);
 	if (codec->reg_def_copy) {
 		pr_debug("%s: Update ASOC cache", __func__);
 		kfree(codec->reg_cache);
@@ -4690,11 +5383,20 @@
 		rco_clk_rate = TAPAN_MCLK_CLK_9P6MHZ;
 
 	ret = wcd9xxx_mbhc_init(&tapan->mbhc, &tapan->resmgr, codec, NULL,
-				&mbhc_cb, rco_clk_rate, false);
+				&mbhc_cb, rco_clk_rate,
+				TAPAN_CDC_ZDET_SUPPORTED);
 	if (ret)
 		pr_err("%s: mbhc init failed %d\n", __func__, ret);
 	else
 		wcd9xxx_mbhc_start(&tapan->mbhc, tapan->mbhc.mbhc_cfg);
+
+	tapan_cleanup_irqs(tapan);
+	ret = tapan_setup_irqs(tapan);
+	if (ret)
+		pr_err("%s: Failed to setup irq: %d\n", __func__, ret);
+
+	tapan->machine_codec_event_cb(codec, WCD9XXX_CODEC_EVENT_CODEC_UP);
+
 	mutex_unlock(&codec->mutex);
 	return ret;
 }
@@ -4703,13 +5405,124 @@
 };
 
 static int wcd9xxx_ssr_register(struct wcd9xxx *control,
-		int (*post_reset_cb)(struct wcd9xxx *wcd9xxx), void *priv)
+				int (*device_down_cb)(struct wcd9xxx *wcd9xxx),
+				int (*device_up_cb)(struct wcd9xxx *wcd9xxx),
+				void *priv)
 {
-	control->post_reset = post_reset_cb;
+	control->dev_down = device_down_cb;
+	control->post_reset = device_up_cb;
 	control->ssr_priv = priv;
 	return 0;
 }
 
+static struct regulator *tapan_codec_find_regulator(
+	struct snd_soc_codec *codec,
+	const char *name)
+{
+	int i;
+	struct wcd9xxx *core = dev_get_drvdata(codec->dev->parent);
+
+	for (i = 0; i < core->num_of_supplies; i++) {
+		if (core->supplies[i].supply &&
+			!strcmp(core->supplies[i].supply, name))
+				return core->supplies[i].consumer;
+	}
+	return NULL;
+}
+
+static void tapan_enable_config_rco(struct wcd9xxx *core, bool enable)
+{
+	struct wcd9xxx_core_resource *core_res = &core->core_res;
+
+	if (enable) {
+		wcd9xxx_reg_update(core, WCD9XXX_A_BIAS_CENTRAL_BG_CTL,
+				   0x80, 0x80);
+		wcd9xxx_reg_update(core, WCD9XXX_A_BIAS_CENTRAL_BG_CTL,
+				   0x04, 0x04);
+		wcd9xxx_reg_update(core, WCD9XXX_A_BIAS_CENTRAL_BG_CTL,
+				   0x01, 0x01);
+		usleep_range(1000, 1000);
+		wcd9xxx_reg_update(core, WCD9XXX_A_BIAS_CENTRAL_BG_CTL,
+				   0x80, 0x00);
+
+		/* Enable RC Oscillator */
+		wcd9xxx_reg_update(core, WCD9XXX_A_RC_OSC_FREQ, 0x10, 0x00);
+		wcd9xxx_reg_write(core_res, WCD9XXX_A_BIAS_OSC_BG_CTL, 0x17);
+		usleep_range(5, 5);
+		wcd9xxx_reg_update(core, WCD9XXX_A_RC_OSC_FREQ, 0x80, 0x80);
+		wcd9xxx_reg_update(core, WCD9XXX_A_RC_OSC_TEST, 0x80, 0x80);
+		usleep_range(10, 10);
+		wcd9xxx_reg_update(core, WCD9XXX_A_RC_OSC_TEST, 0x80, 0x00);
+		usleep_range(20, 20);
+		wcd9xxx_reg_update(core, WCD9XXX_A_CLK_BUFF_EN1, 0x08, 0x08);
+		/* Enable MCLK and wait 1ms till it gets enabled */
+		wcd9xxx_reg_write(core_res, WCD9XXX_A_CLK_BUFF_EN2, 0x02);
+		usleep_range(1000, 1000);
+		/* Enable CLK BUFF and wait for 1.2ms */
+		wcd9xxx_reg_update(core, WCD9XXX_A_CLK_BUFF_EN1, 0x01, 0x01);
+		usleep_range(1000, 1200);
+
+		wcd9xxx_reg_update(core, WCD9XXX_A_CLK_BUFF_EN2, 0x02, 0x00);
+		wcd9xxx_reg_update(core, WCD9XXX_A_CLK_BUFF_EN2, 0x04, 0x04);
+		wcd9xxx_reg_update(core, WCD9XXX_A_CDC_CLK_MCLK_CTL,
+				   0x01, 0x01);
+		usleep_range(50, 50);
+	} else {
+		wcd9xxx_reg_update(core, WCD9XXX_A_CLK_BUFF_EN2, 0x04, 0x00);
+		usleep_range(50, 50);
+		wcd9xxx_reg_update(core, WCD9XXX_A_CLK_BUFF_EN2, 0x02, 0x02);
+		wcd9xxx_reg_update(core, WCD9XXX_A_CLK_BUFF_EN1, 0x05, 0x00);
+		usleep_range(50, 50);
+
+		wcd9xxx_reg_update(core, WCD9XXX_A_RC_OSC_FREQ, 0x80, 0x00);
+		usleep_range(10, 10);
+		wcd9xxx_reg_write(core_res, WCD9XXX_A_BIAS_OSC_BG_CTL, 0x16);
+		wcd9xxx_reg_update(core, WCD9XXX_A_BIAS_CENTRAL_BG_CTL,
+				   0x03, 0x00);
+		usleep_range(100, 100);
+	}
+
+}
+
+static bool tapan_check_wcd9306(struct device *cdc_dev, bool sensed)
+{
+	struct wcd9xxx *core = dev_get_drvdata(cdc_dev->parent);
+	u8 reg_val;
+	bool ret = true;
+	unsigned long timeout;
+	bool timedout;
+	struct wcd9xxx_core_resource *core_res = &core->core_res;
+
+	if (!core) {
+		dev_err(cdc_dev, "%s: core not initialized\n", __func__);
+		return -EINVAL;
+	}
+
+	tapan_enable_config_rco(core, 1);
+
+	if (sensed == false) {
+		reg_val = wcd9xxx_reg_read(core_res, TAPAN_A_QFUSE_CTL);
+		wcd9xxx_reg_write(core_res, TAPAN_A_QFUSE_CTL,
+					(reg_val | 0x03));
+	}
+
+	timeout = jiffies + HZ;
+	do {
+		if ((wcd9xxx_reg_read(core_res, TAPAN_A_QFUSE_STATUS)))
+			break;
+	} while (!(timedout = time_after(jiffies, timeout)));
+
+	if (wcd9xxx_reg_read(core_res, TAPAN_A_QFUSE_DATA_OUT1) ||
+	    wcd9xxx_reg_read(core_res, TAPAN_A_QFUSE_DATA_OUT2)) {
+		dev_info(cdc_dev, "%s: wcd9302 detected\n", __func__);
+		ret = false;
+	} else
+		dev_info(cdc_dev, "%s: wcd9306 detected\n", __func__);
+
+	tapan_enable_config_rco(core, 0);
+	return ret;
+};
+
 static int tapan_codec_probe(struct snd_soc_codec *codec)
 {
 	struct wcd9xxx *control;
@@ -4720,11 +5533,13 @@
 	int ret = 0;
 	int i, rco_clk_rate;
 	void *ptr = NULL;
+	struct wcd9xxx_core_resource *core_res;
 
 	codec->control_data = dev_get_drvdata(codec->dev->parent);
 	control = codec->control_data;
 
-	wcd9xxx_ssr_register(control, tapan_post_reset_cb, (void *)codec);
+	wcd9xxx_ssr_register(control, tapan_device_down,
+			     tapan_post_reset_cb, (void *)codec);
 
 	dev_info(codec->dev, "%s()\n", __func__);
 
@@ -4744,14 +5559,20 @@
 
 	/* codec resmgr module init */
 	wcd9xxx = codec->control_data;
+	core_res = &wcd9xxx->core_res;
 	pdata = dev_get_platdata(codec->dev->parent);
-	ret = wcd9xxx_resmgr_init(&tapan->resmgr, codec, wcd9xxx, pdata,
-				  &tapan_reg_address);
+	ret = wcd9xxx_resmgr_init(&tapan->resmgr, codec, core_res, pdata,
+				  &tapan_reg_address, WCD9XXX_CDC_TYPE_TAPAN);
 	if (ret) {
 		pr_err("%s: wcd9xxx init failed %d\n", __func__, ret);
 		return ret;
 	}
 
+	tapan->cp_regulators[CP_REG_BUCK] = tapan_codec_find_regulator(codec,
+					WCD9XXX_SUPPLY_BUCK_NAME);
+	tapan->cp_regulators[CP_REG_BHELPER] = tapan_codec_find_regulator(codec,
+					"cdc-vdd-buckhelper");
+
 	tapan->clsh_d.buck_mv = tapan_codec_get_buck_mv(codec);
 	/*
 	 * If 1.8 volts is requested on the vdd_cp line, then
@@ -4768,7 +5589,8 @@
 		rco_clk_rate = TAPAN_MCLK_CLK_9P6MHZ;
 
 	ret = wcd9xxx_mbhc_init(&tapan->mbhc, &tapan->resmgr, codec, NULL,
-				&mbhc_cb, rco_clk_rate, false);
+				&mbhc_cb, rco_clk_rate,
+				TAPAN_CDC_ZDET_SUPPORTED);
 
 	if (ret) {
 		pr_err("%s: mbhc init failed %d\n", __func__, ret);
@@ -4820,6 +5642,19 @@
 			INIT_LIST_HEAD(&tapan->dai[i].wcd9xxx_ch_list);
 			init_waitqueue_head(&tapan->dai[i].dai_wait);
 		}
+		tapan_init_slim_slave_cfg(codec);
+	}
+
+	if (codec_ver == WCD9306) {
+		snd_soc_add_codec_controls(codec, tapan_9306_snd_controls,
+					   ARRAY_SIZE(tapan_9306_snd_controls));
+		snd_soc_dapm_new_controls(dapm, tapan_9306_dapm_widgets,
+					  ARRAY_SIZE(tapan_9306_dapm_widgets));
+		snd_soc_dapm_add_routes(dapm, wcd9306_map,
+					ARRAY_SIZE(wcd9306_map));
+	} else {
+		snd_soc_dapm_add_routes(dapm, wcd9302_map,
+					ARRAY_SIZE(wcd9302_map));
 	}
 
 	control->num_rx_port = TAPAN_RX_MAX;
@@ -4835,11 +5670,13 @@
 
 	atomic_set(&kp_tapan_priv, (unsigned long)tapan);
 	mutex_lock(&dapm->codec->mutex);
-	snd_soc_dapm_disable_pin(dapm, "ANC HPHL");
-	snd_soc_dapm_disable_pin(dapm, "ANC HPHR");
-	snd_soc_dapm_disable_pin(dapm, "ANC HEADPHONE");
-	snd_soc_dapm_disable_pin(dapm, "ANC EAR PA");
-	snd_soc_dapm_disable_pin(dapm, "ANC EAR");
+	if (codec_ver == WCD9306) {
+		snd_soc_dapm_disable_pin(dapm, "ANC HPHL");
+		snd_soc_dapm_disable_pin(dapm, "ANC HPHR");
+		snd_soc_dapm_disable_pin(dapm, "ANC HEADPHONE");
+		snd_soc_dapm_disable_pin(dapm, "ANC EAR PA");
+		snd_soc_dapm_disable_pin(dapm, "ANC EAR");
+	}
 	snd_soc_dapm_sync(dapm);
 	mutex_unlock(&dapm->codec->mutex);
 
@@ -4860,6 +5697,7 @@
 static int tapan_codec_remove(struct snd_soc_codec *codec)
 {
 	struct tapan_priv *tapan = snd_soc_codec_get_drvdata(codec);
+	int index = 0;
 
 	WCD9XXX_BG_CLK_LOCK(&tapan->resmgr);
 	atomic_set(&kp_tapan_priv, 0);
@@ -4876,6 +5714,9 @@
 	/* cleanup resmgr */
 	wcd9xxx_resmgr_deinit(&tapan->resmgr);
 
+	for (index = 0; index < CP_REG_MAX; index++)
+		tapan->cp_regulators[index] = NULL;
+
 	kfree(tapan);
 	return 0;
 }
@@ -4894,10 +5735,10 @@
 	.reg_cache_default = tapan_reset_reg_defaults,
 	.reg_word_size = 1,
 
-	.controls = tapan_snd_controls,
-	.num_controls = ARRAY_SIZE(tapan_snd_controls),
-	.dapm_widgets = tapan_dapm_widgets,
-	.num_dapm_widgets = ARRAY_SIZE(tapan_dapm_widgets),
+	.controls = tapan_common_snd_controls,
+	.num_controls = ARRAY_SIZE(tapan_common_snd_controls),
+	.dapm_widgets = tapan_common_dapm_widgets,
+	.num_dapm_widgets = ARRAY_SIZE(tapan_common_dapm_widgets),
 	.dapm_routes = audio_map,
 	.num_dapm_routes = ARRAY_SIZE(audio_map),
 };
@@ -4928,12 +5769,36 @@
 static int __devinit tapan_probe(struct platform_device *pdev)
 {
 	int ret = 0;
-	if (wcd9xxx_get_intf_type() == WCD9XXX_INTERFACE_TYPE_SLIMBUS)
-		ret = snd_soc_register_codec(&pdev->dev, &soc_codec_dev_tapan,
-			tapan_dai, ARRAY_SIZE(tapan_dai));
-	else if (wcd9xxx_get_intf_type() == WCD9XXX_INTERFACE_TYPE_I2C)
-		ret = snd_soc_register_codec(&pdev->dev, &soc_codec_dev_tapan,
-			tapan_i2s_dai, ARRAY_SIZE(tapan_i2s_dai));
+	bool is_wcd9306;
+
+	is_wcd9306 = tapan_check_wcd9306(&pdev->dev, false);
+	if (is_wcd9306 < 0) {
+		dev_info(&pdev->dev, "%s: cannot find codec type, default to 9306\n",
+			 __func__);
+		is_wcd9306 = true;
+	}
+	codec_ver = is_wcd9306 ? WCD9306 : WCD9302;
+
+	if (!is_wcd9306) {
+		if (wcd9xxx_get_intf_type() == WCD9XXX_INTERFACE_TYPE_SLIMBUS)
+			ret = snd_soc_register_codec(&pdev->dev,
+				&soc_codec_dev_tapan,
+				tapan9302_dai, ARRAY_SIZE(tapan9302_dai));
+		else if (wcd9xxx_get_intf_type() == WCD9XXX_INTERFACE_TYPE_I2C)
+			ret = snd_soc_register_codec(&pdev->dev,
+				&soc_codec_dev_tapan,
+				tapan_i2s_dai, ARRAY_SIZE(tapan_i2s_dai));
+	} else {
+		if (wcd9xxx_get_intf_type() == WCD9XXX_INTERFACE_TYPE_SLIMBUS)
+			ret = snd_soc_register_codec(&pdev->dev,
+				&soc_codec_dev_tapan,
+				tapan_dai, ARRAY_SIZE(tapan_dai));
+		else if (wcd9xxx_get_intf_type() == WCD9XXX_INTERFACE_TYPE_I2C)
+			ret = snd_soc_register_codec(&pdev->dev,
+				&soc_codec_dev_tapan,
+				tapan_i2s_dai, ARRAY_SIZE(tapan_i2s_dai));
+	}
+
 	return ret;
 }
 static int __devexit tapan_remove(struct platform_device *pdev)
diff --git a/sound/soc/codecs/wcd9306.h b/sound/soc/codecs/wcd9306.h
index fdd62d1..07b2175 100644
--- a/sound/soc/codecs/wcd9306.h
+++ b/sound/soc/codecs/wcd9306.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2012, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2012-2013, The Linux Foundation. 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 and
@@ -14,9 +14,11 @@
 
 #include <sound/soc.h>
 #include <sound/jack.h>
+#include <sound/apr_audio-v2.h>
 #include <linux/mfd/wcd9xxx/wcd9xxx-slimslave.h>
 #include "wcd9xxx-mbhc.h"
 #include "wcd9xxx-resmgr.h"
+#include "wcd9xxx-common.h"
 
 #define TAPAN_NUM_REGISTERS 0x400
 #define TAPAN_MAX_REGISTER (TAPAN_NUM_REGISTERS-1)
@@ -24,6 +26,8 @@
 
 #define TAPAN_REG_VAL(reg, val)		{reg, 0, val}
 
+#define TAPAN_CDC_ZDET_SUPPORTED  true
+
 extern const u8 tapan_reg_readable[TAPAN_CACHE_SIZE];
 extern const u8 tapan_reset_reg_defaults[TAPAN_CACHE_SIZE];
 struct tapan_codec_dai_data {
@@ -75,5 +79,10 @@
 			     bool dapm);
 extern int tapan_hs_detect(struct snd_soc_codec *codec,
 			   struct wcd9xxx_mbhc_config *mbhc_cfg);
-
+extern void *tapan_get_afe_config(struct snd_soc_codec *codec,
+				  enum afe_config_type config_type);
+extern void tapan_event_register(
+	int (*machine_event_cb)(struct snd_soc_codec *codec,
+				 enum wcd9xxx_codec_event),
+	struct snd_soc_codec *codec);
 #endif
diff --git a/sound/soc/codecs/wcd9310.c b/sound/soc/codecs/wcd9310.c
index 212924fd..673b634 100644
--- a/sound/soc/codecs/wcd9310.c
+++ b/sound/soc/codecs/wcd9310.c
@@ -5949,11 +5949,12 @@
 {
 	int r = 0;
 	struct wcd9xxx *core = dev_get_drvdata(tabla->codec->dev->parent);
+	struct wcd9xxx_core_resource *core_res = &core->core_res;
 
 	if (cancel_delayed_work_sync(&tabla->mbhc_btn_dwork)) {
 		/* if scheduled mbhc_btn_dwork is canceled from here,
 		* we have to unlock from here instead btn_work */
-		wcd9xxx_unlock_sleep(core);
+		wcd9xxx_unlock_sleep(core_res);
 		r = 1;
 	}
 	return r;
@@ -6332,12 +6333,14 @@
 	short bias_value;
 	int dce_mv, sta_mv;
 	struct wcd9xxx *core;
+	struct wcd9xxx_core_resource *core_res;
 
 	pr_debug("%s:\n", __func__);
 
 	delayed_work = to_delayed_work(work);
 	tabla = container_of(delayed_work, struct tabla_priv, mbhc_btn_dwork);
 	core = dev_get_drvdata(tabla->codec->dev->parent);
+	core_res = &core->core_res;
 
 	if (tabla) {
 		if (tabla->mbhc_cfg.button_jack) {
@@ -6360,7 +6363,7 @@
 	}
 
 	pr_debug("%s: leave\n", __func__);
-	wcd9xxx_unlock_sleep(core);
+	wcd9xxx_unlock_sleep(core_res);
 }
 
 static u16 tabla_get_cfilt_reg(struct snd_soc_codec *codec, u8 cfilt)
@@ -6816,6 +6819,7 @@
 	short btnmeas[d->n_btn_meas + 1];
 	struct snd_soc_codec *codec = priv->codec;
 	struct wcd9xxx *core = dev_get_drvdata(priv->codec->dev->parent);
+	struct wcd9xxx_core_resource *core_res = &core->core_res;
 	int n_btn_meas = d->n_btn_meas;
 	u8 mbhc_status = snd_soc_read(codec, TABLA_A_CDC_MBHC_B1_STATUS) & 0x3E;
 
@@ -6917,12 +6921,12 @@
 		tabla_mbhc_set_rel_thres(codec, btn_high[btn]);
 		mask = tabla_get_button_mask(btn);
 		priv->buttons_pressed |= mask;
-		wcd9xxx_lock_sleep(core);
+		wcd9xxx_lock_sleep(core_res);
 		if (schedule_delayed_work(&priv->mbhc_btn_dwork,
 					  msecs_to_jiffies(400)) == 0) {
 			WARN(1, "Button pressed twice without release"
 			     "event\n");
-			wcd9xxx_unlock_sleep(core);
+			wcd9xxx_unlock_sleep(core_res);
 		}
 	} else {
 		pr_debug("%s: bogus button press, too short press?\n",
@@ -7248,9 +7252,11 @@
 static void tabla_schedule_hs_detect_plug(struct tabla_priv *tabla,
 	struct work_struct *correct_plug_work)
 {
+	struct wcd9xxx *core = tabla->codec->control_data;
+	struct wcd9xxx_core_resource *core_res = &core->core_res;
 	pr_debug("%s: scheduling tabla_hs_correct_gpio_plug\n", __func__);
 	tabla->hs_detect_work_stop = false;
-	wcd9xxx_lock_sleep(tabla->codec->control_data);
+	wcd9xxx_lock_sleep(core_res);
 	schedule_work(correct_plug_work);
 }
 
@@ -7258,13 +7264,15 @@
 static void tabla_cancel_hs_detect_plug(struct tabla_priv *tabla,
 		struct work_struct *correct_plug_work)
 {
+	struct wcd9xxx *core = tabla->codec->control_data;
+	struct wcd9xxx_core_resource *core_res = &core->core_res;
 	pr_debug("%s: canceling hs_correct_plug_work\n", __func__);
 	tabla->hs_detect_work_stop = true;
 	wmb();
 	TABLA_RELEASE_LOCK(tabla->codec_resource_lock);
 	if (cancel_work_sync(correct_plug_work)) {
 		pr_debug("%s: hs_correct_plug_work is canceled\n", __func__);
-		wcd9xxx_unlock_sleep(tabla->codec->control_data);
+		wcd9xxx_unlock_sleep(core_res);
 	}
 	TABLA_ACQUIRE_LOCK(tabla->codec_resource_lock);
 }
@@ -7470,9 +7478,13 @@
 	bool correction = false;
 	enum tabla_mbhc_plug_type plug_type = PLUG_TYPE_INVALID;
 	unsigned long timeout;
+	struct wcd9xxx *core;
+	struct wcd9xxx_core_resource *core_res;
 
 	tabla = container_of(work, struct tabla_priv, hs_correct_plug_work);
 	codec = tabla->codec;
+	core = tabla->codec->control_data;
+	core_res = &core->core_res;
 
 	pr_debug("%s: enter\n", __func__);
 	tabla->mbhc_cfg.mclk_cb_fn(codec, 1, false);
@@ -7581,7 +7593,7 @@
 	pr_debug("%s: leave current_plug(%d)\n",
 		 __func__, tabla->current_plug);
 	/* unlock sleep */
-	wcd9xxx_unlock_sleep(tabla->codec->control_data);
+	wcd9xxx_unlock_sleep(core_res);
 }
 
 /* called under codec_resource_lock acquisition */
@@ -7738,6 +7750,7 @@
 	int ret;
 	struct snd_soc_codec *codec = priv->codec;
 	struct wcd9xxx *core = dev_get_drvdata(priv->codec->dev->parent);
+	struct wcd9xxx_core_resource *core_res = &core->core_res;
 	struct tabla_priv *tabla = snd_soc_codec_get_drvdata(codec);
 
 	/* Cancel possibly running hs_detect_work */
@@ -7766,12 +7779,12 @@
 	} else if (is_mb_trigger && !is_removal) {
 		pr_debug("%s: Waiting for Headphone left trigger\n",
 			__func__);
-		wcd9xxx_lock_sleep(core);
+		wcd9xxx_lock_sleep(core_res);
 		if (schedule_delayed_work(&priv->mbhc_insert_dwork,
 					  usecs_to_jiffies(1000000)) == 0) {
 			pr_err("%s: mbhc_insert_dwork is already scheduled\n",
 			       __func__);
-			wcd9xxx_unlock_sleep(core);
+			wcd9xxx_unlock_sleep(core_res);
 		}
 		tabla_codec_enable_hs_detect(codec, 1, MBHC_USE_HPHL_TRIGGER,
 					     false);
@@ -7781,7 +7794,7 @@
 			pr_debug("%s: Complete plug insertion, Detecting plug "
 				 "type\n", __func__);
 			tabla_codec_detect_plug_type(codec);
-			wcd9xxx_unlock_sleep(core);
+			wcd9xxx_unlock_sleep(core_res);
 		} else {
 			wcd9xxx_enable_irq(codec->control_data,
 					   WCD9XXX_IRQ_MBHC_INSERTION);
@@ -8058,11 +8071,13 @@
 	struct tabla_priv *tabla;
 	struct snd_soc_codec *codec;
 	struct wcd9xxx *tabla_core;
+	struct wcd9xxx_core_resource *core_res;
 
 	dwork = to_delayed_work(work);
 	tabla = container_of(dwork, struct tabla_priv, mbhc_insert_dwork);
 	codec = tabla->codec;
 	tabla_core = dev_get_drvdata(codec->dev->parent);
+	core_res = &tabla_core->core_res;
 
 	pr_debug("%s:\n", __func__);
 
@@ -8073,7 +8088,7 @@
 	wcd9xxx_disable_irq_sync(codec->control_data,
 				 WCD9XXX_IRQ_MBHC_INSERTION);
 	tabla_codec_detect_plug_type(codec);
-	wcd9xxx_unlock_sleep(tabla_core);
+	wcd9xxx_unlock_sleep(core_res);
 }
 
 static void tabla_hs_gpio_handler(struct snd_soc_codec *codec)
@@ -8090,7 +8105,7 @@
 	usleep_range(TABLA_GPIO_IRQ_DEBOUNCE_TIME_US,
 		     TABLA_GPIO_IRQ_DEBOUNCE_TIME_US);
 
-	wcd9xxx_nested_irq_lock(core);
+	wcd9xxx_nested_irq_lock(&core->core_res);
 	TABLA_ACQUIRE_LOCK(tabla->codec_resource_lock);
 
 	/* cancel pending button press */
@@ -8163,7 +8178,7 @@
 
 	tabla->in_gpio_handler = false;
 	TABLA_RELEASE_LOCK(tabla->codec_resource_lock);
-	wcd9xxx_nested_irq_unlock(core);
+	wcd9xxx_nested_irq_unlock(&core->core_res);
 	pr_debug("%s: leave\n", __func__);
 }
 
@@ -8172,8 +8187,10 @@
 	int r = IRQ_HANDLED;
 	struct snd_soc_codec *codec = data;
 	struct tabla_priv *tabla = snd_soc_codec_get_drvdata(codec);
+	struct wcd9xxx *core = codec->control_data;
+	struct wcd9xxx_core_resource *core_res = &core->core_res;
 
-	if (unlikely(wcd9xxx_lock_sleep(codec->control_data) == false)) {
+	if (unlikely(wcd9xxx_lock_sleep(core_res) == false)) {
 		pr_warn("%s: failed to hold suspend\n", __func__);
 		/*
 		 * Give up this IRQ for now and resend this IRQ so IRQ can be
@@ -8186,7 +8203,7 @@
 		r = IRQ_NONE;
 	} else {
 		tabla_hs_gpio_handler(codec);
-		wcd9xxx_unlock_sleep(codec->control_data);
+		wcd9xxx_unlock_sleep(core_res);
 	}
 
 	return r;
@@ -8200,6 +8217,8 @@
 	int retry = 0;
 	enum tabla_mbhc_plug_type plug_type;
 	bool is_headset = false;
+	struct wcd9xxx *core;
+	struct wcd9xxx_core_resource *core_res;
 
 	pr_debug("%s(): Poll Microphone voltage for %d seconds\n",
 			 __func__, TABLA_HS_DETECT_PLUG_TIME_MS / 1000);
@@ -8207,6 +8226,8 @@
 	tabla = container_of(work, struct tabla_priv,
 						 hs_correct_plug_work_nogpio);
 	codec = tabla->codec;
+	core = codec->control_data;
+	core_res = &core->core_res;
 
 	/* Make sure the MBHC mux is connected to MIC Path */
 	snd_soc_write(codec, TABLA_A_MBHC_SCALING_MUX_1, 0x84);
@@ -8261,7 +8282,7 @@
 		tabla_codec_cleanup_hs_polling(codec);
 		tabla_codec_enable_hs_detect(codec, 0, 0, false);
 	}
-	wcd9xxx_unlock_sleep(codec->control_data);
+	wcd9xxx_unlock_sleep(core_res);
 }
 
 static int tabla_mbhc_init_and_calibrate(struct tabla_priv *tabla)
@@ -8933,9 +8954,11 @@
 	int ret = 0;
 	int i;
 	void *ptr = NULL;
+	struct wcd9xxx_core_resource *core_res;
 
 	codec->control_data = dev_get_drvdata(codec->dev->parent);
 	control = codec->control_data;
+	core_res = &control->core_res;
 
 	tabla = kzalloc(sizeof(struct tabla_priv), GFP_KERNEL);
 	if (!tabla) {
@@ -9049,7 +9072,7 @@
 
 	snd_soc_dapm_sync(dapm);
 
-	ret = wcd9xxx_request_irq(codec->control_data,
+	ret = wcd9xxx_request_irq(core_res,
 				  WCD9XXX_IRQ_MBHC_INSERTION,
 		tabla_hs_insert_irq, "Headset insert detect", tabla);
 	if (ret) {
@@ -9057,9 +9080,9 @@
 		       WCD9XXX_IRQ_MBHC_INSERTION);
 		goto err_insert_irq;
 	}
-	wcd9xxx_disable_irq(codec->control_data, WCD9XXX_IRQ_MBHC_INSERTION);
+	wcd9xxx_disable_irq(core_res, WCD9XXX_IRQ_MBHC_INSERTION);
 
-	ret = wcd9xxx_request_irq(codec->control_data,
+	ret = wcd9xxx_request_irq(core_res,
 				  WCD9XXX_IRQ_MBHC_REMOVAL,
 				  tabla_hs_remove_irq,
 				  "Headset remove detect", tabla);
@@ -9069,7 +9092,7 @@
 		goto err_remove_irq;
 	}
 
-	ret = wcd9xxx_request_irq(codec->control_data,
+	ret = wcd9xxx_request_irq(core_res,
 				  WCD9XXX_IRQ_MBHC_POTENTIAL,
 				  tabla_dce_handler, "DC Estimation detect",
 				  tabla);
@@ -9079,7 +9102,7 @@
 		goto err_potential_irq;
 	}
 
-	ret = wcd9xxx_request_irq(codec->control_data, WCD9XXX_IRQ_MBHC_RELEASE,
+	ret = wcd9xxx_request_irq(core_res, WCD9XXX_IRQ_MBHC_RELEASE,
 				  tabla_release_handler,
 				  "Button Release detect", tabla);
 	if (ret) {
@@ -9088,7 +9111,7 @@
 		goto err_release_irq;
 	}
 
-	ret = wcd9xxx_request_irq(codec->control_data, WCD9XXX_IRQ_SLIMBUS,
+	ret = wcd9xxx_request_irq(core_res, WCD9XXX_IRQ_SLIMBUS,
 				  tabla_slimbus_irq, "SLIMBUS Slave", tabla);
 	if (ret) {
 		pr_err("%s: Failed to request irq %d\n", __func__,
@@ -9097,10 +9120,10 @@
 	}
 
 	for (i = 0; i < WCD9XXX_SLIM_NUM_PORT_REG; i++)
-		wcd9xxx_interface_reg_write(codec->control_data,
-			TABLA_SLIM_PGD_PORT_INT_EN0 + i, 0xFF);
+		wcd9xxx_interface_reg_write(control,
+				TABLA_SLIM_PGD_PORT_INT_EN0 + i, 0xFF);
 
-	ret = wcd9xxx_request_irq(codec->control_data,
+	ret = wcd9xxx_request_irq(core_res,
 				  WCD9XXX_IRQ_HPH_PA_OCPL_FAULT,
 				  tabla_hphl_ocp_irq,
 				  "HPH_L OCP detect", tabla);
@@ -9109,9 +9132,9 @@
 		       WCD9XXX_IRQ_HPH_PA_OCPL_FAULT);
 		goto err_hphl_ocp_irq;
 	}
-	wcd9xxx_disable_irq(codec->control_data, WCD9XXX_IRQ_HPH_PA_OCPL_FAULT);
+	wcd9xxx_disable_irq(core_res, WCD9XXX_IRQ_HPH_PA_OCPL_FAULT);
 
-	ret = wcd9xxx_request_irq(codec->control_data,
+	ret = wcd9xxx_request_irq(core_res,
 				  WCD9XXX_IRQ_HPH_PA_OCPR_FAULT,
 				  tabla_hphr_ocp_irq,
 				  "HPH_R OCP detect", tabla);
@@ -9120,7 +9143,7 @@
 		       WCD9XXX_IRQ_HPH_PA_OCPR_FAULT);
 		goto err_hphr_ocp_irq;
 	}
-	wcd9xxx_disable_irq(codec->control_data, WCD9XXX_IRQ_HPH_PA_OCPR_FAULT);
+	wcd9xxx_disable_irq(core_res, WCD9XXX_IRQ_HPH_PA_OCPR_FAULT);
 
 	/*
 	 * Register suspend lock and notifier to resend edge triggered
@@ -9151,19 +9174,19 @@
 	return ret;
 
 err_hphr_ocp_irq:
-	wcd9xxx_free_irq(codec->control_data,
+	wcd9xxx_free_irq(core_res,
 			WCD9XXX_IRQ_HPH_PA_OCPL_FAULT, tabla);
 err_hphl_ocp_irq:
-	wcd9xxx_free_irq(codec->control_data, WCD9XXX_IRQ_SLIMBUS, tabla);
+	wcd9xxx_free_irq(core_res, WCD9XXX_IRQ_SLIMBUS, tabla);
 err_slimbus_irq:
-	wcd9xxx_free_irq(codec->control_data, WCD9XXX_IRQ_MBHC_RELEASE, tabla);
+	wcd9xxx_free_irq(core_res, WCD9XXX_IRQ_MBHC_RELEASE, tabla);
 err_release_irq:
-	wcd9xxx_free_irq(codec->control_data, WCD9XXX_IRQ_MBHC_POTENTIAL,
+	wcd9xxx_free_irq(core_res, WCD9XXX_IRQ_MBHC_POTENTIAL,
 			 tabla);
 err_potential_irq:
-	wcd9xxx_free_irq(codec->control_data, WCD9XXX_IRQ_MBHC_REMOVAL, tabla);
+	wcd9xxx_free_irq(core_res, WCD9XXX_IRQ_MBHC_REMOVAL, tabla);
 err_remove_irq:
-	wcd9xxx_free_irq(codec->control_data, WCD9XXX_IRQ_MBHC_INSERTION,
+	wcd9xxx_free_irq(core_res, WCD9XXX_IRQ_MBHC_INSERTION,
 			 tabla);
 err_insert_irq:
 err_pdata:
diff --git a/sound/soc/codecs/wcd9320.c b/sound/soc/codecs/wcd9320.c
index c27e085..4ce9b4a 100644
--- a/sound/soc/codecs/wcd9320.c
+++ b/sound/soc/codecs/wcd9320.c
@@ -49,6 +49,9 @@
 
 #define DAPM_MICBIAS2_EXTERNAL_STANDALONE "MIC BIAS2 External Standalone"
 
+/* RX_HPH_CNP_WG_TIME increases by 0.24ms */
+#define TAIKO_WG_TIME_FACTOR_US	240
+
 static atomic_t kp_taiko_priv;
 static int spkr_drv_wrnd_param_set(const char *val,
 				   const struct kernel_param *kp);
@@ -69,63 +72,6 @@
 	.num_channels = 1
 };
 
-enum {
-	RESERVED = 0,
-	AANC_LPF_FF_FB = 1,
-	AANC_LPF_COEFF_MSB,
-	AANC_LPF_COEFF_LSB,
-	HW_MAD_AUDIO_ENABLE,
-	HW_MAD_ULTR_ENABLE,
-	HW_MAD_BEACON_ENABLE,
-	HW_MAD_AUDIO_SLEEP_TIME,
-	HW_MAD_ULTR_SLEEP_TIME,
-	HW_MAD_BEACON_SLEEP_TIME,
-	HW_MAD_TX_AUDIO_SWITCH_OFF,
-	HW_MAD_TX_ULTR_SWITCH_OFF,
-	HW_MAD_TX_BEACON_SWITCH_OFF,
-	MAD_AUDIO_INT_DEST_SELECT_REG,
-	MAD_ULT_INT_DEST_SELECT_REG,
-	MAD_BEACON_INT_DEST_SELECT_REG,
-	MAD_CLIP_INT_DEST_SELECT_REG,
-	MAD_VBAT_INT_DEST_SELECT_REG,
-	MAD_AUDIO_INT_MASK_REG,
-	MAD_ULT_INT_MASK_REG,
-	MAD_BEACON_INT_MASK_REG,
-	MAD_CLIP_INT_MASK_REG,
-	MAD_VBAT_INT_MASK_REG,
-	MAD_AUDIO_INT_STATUS_REG,
-	MAD_ULT_INT_STATUS_REG,
-	MAD_BEACON_INT_STATUS_REG,
-	MAD_CLIP_INT_STATUS_REG,
-	MAD_VBAT_INT_STATUS_REG,
-	MAD_AUDIO_INT_CLEAR_REG,
-	MAD_ULT_INT_CLEAR_REG,
-	MAD_BEACON_INT_CLEAR_REG,
-	MAD_CLIP_INT_CLEAR_REG,
-	MAD_VBAT_INT_CLEAR_REG,
-	SB_PGD_PORT_TX_WATERMARK_n,
-	SB_PGD_PORT_TX_ENABLE_n,
-	SB_PGD_PORT_RX_WATERMARK_n,
-	SB_PGD_PORT_RX_ENABLE_n,
-	SB_PGD_TX_PORTn_MULTI_CHNL_0,
-	SB_PGD_TX_PORTn_MULTI_CHNL_1,
-	SB_PGD_RX_PORTn_MULTI_CHNL_0,
-	SB_PGD_RX_PORTn_MULTI_CHNL_1,
-	AANC_FF_GAIN_ADAPTIVE,
-	AANC_FFGAIN_ADAPTIVE_EN,
-	AANC_GAIN_CONTROL,
-	SPKR_CLIP_PIPE_BANK_SEL,
-	SPKR_CLIPDET_VAL0,
-	SPKR_CLIPDET_VAL1,
-	SPKR_CLIPDET_VAL2,
-	SPKR_CLIPDET_VAL3,
-	SPKR_CLIPDET_VAL4,
-	SPKR_CLIPDET_VAL5,
-	SPKR_CLIPDET_VAL6,
-	SPKR_CLIPDET_VAL7,
-	MAX_CFG_REGISTERS,
-};
-
 static struct afe_param_cdc_reg_cfg audio_reg_cfg[] = {
 	{
 		1,
@@ -165,22 +111,22 @@
 	{
 		1,
 		(TAIKO_REGISTER_START_OFFSET + TAIKO_SB_PGD_PORT_TX_BASE),
-		SB_PGD_PORT_TX_WATERMARK_n, 0x1E, 8, 0x1
+		SB_PGD_PORT_TX_WATERMARK_N, 0x1E, 8, 0x1
 	},
 	{
 		1,
 		(TAIKO_REGISTER_START_OFFSET + TAIKO_SB_PGD_PORT_TX_BASE),
-		SB_PGD_PORT_TX_ENABLE_n, 0x1, 8, 0x1
+		SB_PGD_PORT_TX_ENABLE_N, 0x1, 8, 0x1
 	},
 	{
 		1,
 		(TAIKO_REGISTER_START_OFFSET + TAIKO_SB_PGD_PORT_RX_BASE),
-		SB_PGD_PORT_RX_WATERMARK_n, 0x1E, 8, 0x1
+		SB_PGD_PORT_RX_WATERMARK_N, 0x1E, 8, 0x1
 	},
 	{
 		1,
 		(TAIKO_REGISTER_START_OFFSET + TAIKO_SB_PGD_PORT_RX_BASE),
-		SB_PGD_PORT_RX_ENABLE_n, 0x1, 8, 0x1
+		SB_PGD_PORT_RX_ENABLE_N, 0x1, 8, 0x1
 	},
 	{	1,
 		(TAIKO_REGISTER_START_OFFSET + TAIKO_A_CDC_ANC1_IIR_B1_CTL),
@@ -509,6 +455,12 @@
 
 	int (*machine_codec_event_cb)(struct snd_soc_codec *codec,
 			enum wcd9xxx_codec_event);
+
+	/*
+	 * list used to save/restore registers at start and
+	 * end of impedance measurement
+	 */
+	struct list_head reg_save_restore;
 };
 
 static const u32 comp_shift[] = {
@@ -4051,6 +4003,7 @@
 	unsigned int value)
 {
 	int ret;
+	struct wcd9xxx *wcd9xxx = codec->control_data;
 
 	if (reg == SND_SOC_NOPM)
 		return 0;
@@ -4064,7 +4017,7 @@
 				reg, ret);
 	}
 
-	return wcd9xxx_reg_write(codec->control_data, reg, value);
+	return wcd9xxx_reg_write(&wcd9xxx->core_res, reg, value);
 }
 static unsigned int taiko_read(struct snd_soc_codec *codec,
 				unsigned int reg)
@@ -4072,6 +4025,8 @@
 	unsigned int val;
 	int ret;
 
+	struct wcd9xxx *wcd9xxx = codec->control_data;
+
 	if (reg == SND_SOC_NOPM)
 		return 0;
 
@@ -4087,7 +4042,7 @@
 				reg, ret);
 	}
 
-	val = wcd9xxx_reg_read(codec->control_data, reg);
+	val = wcd9xxx_reg_read(&wcd9xxx->core_res, reg);
 	return val;
 }
 
@@ -6151,8 +6106,11 @@
 {
 	int ret = 0;
 	struct snd_soc_codec *codec = taiko->codec;
+	struct wcd9xxx *wcd9xxx = codec->control_data;
+	struct wcd9xxx_core_resource *core_res =
+				&wcd9xxx->core_res;
 
-	ret = wcd9xxx_request_irq(codec->control_data, WCD9XXX_IRQ_SLIMBUS,
+	ret = wcd9xxx_request_irq(core_res, WCD9XXX_IRQ_SLIMBUS,
 				  taiko_slimbus_irq, "SLIMBUS Slave", taiko);
 	if (ret)
 		pr_err("%s: Failed to request irq %d\n", __func__,
@@ -6166,8 +6124,11 @@
 static void taiko_cleanup_irqs(struct taiko_priv *taiko)
 {
 	struct snd_soc_codec *codec = taiko->codec;
+	struct wcd9xxx *wcd9xxx = codec->control_data;
+	struct wcd9xxx_core_resource *core_res =
+				&wcd9xxx->core_res;
 
-	wcd9xxx_free_irq(codec->control_data, WCD9XXX_IRQ_SLIMBUS, taiko);
+	wcd9xxx_free_irq(core_res, WCD9XXX_IRQ_SLIMBUS, taiko);
 }
 
 int taiko_hs_detect(struct snd_soc_codec *codec,
@@ -6180,7 +6141,15 @@
 		taiko->mbhc_started = true;
 	return rc;
 }
-EXPORT_SYMBOL_GPL(taiko_hs_detect);
+EXPORT_SYMBOL(taiko_hs_detect);
+
+void taiko_hs_detect_exit(struct snd_soc_codec *codec)
+{
+	struct taiko_priv *taiko = snd_soc_codec_get_drvdata(codec);
+	wcd9xxx_mbhc_stop(&taiko->mbhc);
+	taiko->mbhc_started = false;
+}
+EXPORT_SYMBOL(taiko_hs_detect_exit);
 
 void taiko_event_register(
 	int (*machine_event_cb)(struct snd_soc_codec *codec,
@@ -6190,7 +6159,7 @@
 	struct taiko_priv *taiko = snd_soc_codec_get_drvdata(codec);
 	taiko->machine_codec_event_cb = machine_event_cb;
 }
-EXPORT_SYMBOL_GPL(taiko_event_register);
+EXPORT_SYMBOL(taiko_event_register);
 
 static void taiko_init_slim_slave_cfg(struct snd_soc_codec *codec)
 {
@@ -6212,6 +6181,208 @@
 	pr_debug("%s: slimbus logical address 0x%llx\n", __func__, eaddr);
 }
 
+static int taiko_device_down(struct wcd9xxx *wcd9xxx)
+{
+	struct snd_soc_codec *codec;
+
+	codec = (struct snd_soc_codec *)(wcd9xxx->ssr_priv);
+	snd_soc_card_change_online_state(codec->card, 0);
+
+	return 0;
+}
+
+static int wcd9xxx_prepare_static_pa(struct wcd9xxx_mbhc *mbhc,
+				     struct list_head *lh)
+{
+	int i;
+	struct snd_soc_codec *codec = mbhc->codec;
+
+	const struct wcd9xxx_reg_mask_val reg_set_paon[] = {
+		{WCD9XXX_A_RX_HPH_OCP_CTL, 0x18, 0x00},
+		{WCD9XXX_A_RX_HPH_L_TEST, 0x1, 0x0},
+		{WCD9XXX_A_RX_HPH_R_TEST, 0x1, 0x0},
+		{WCD9XXX_A_RX_HPH_BIAS_WG_OCP, 0xff, 0x1A},
+		{WCD9XXX_A_RX_HPH_CNP_WG_CTL, 0xff, 0xDB},
+		{WCD9XXX_A_RX_HPH_CNP_WG_TIME, 0xff, 0x15},
+		{WCD9XXX_A_CDC_RX1_B6_CTL, 0xff, 0x81},
+		{WCD9XXX_A_CDC_CLK_RX_B1_CTL, 0x01, 0x01},
+		{WCD9XXX_A_RX_HPH_CHOP_CTL, 0xff, 0xA4},
+		{WCD9XXX_A_RX_HPH_L_GAIN, 0xff, 0x2C},
+		{WCD9XXX_A_CDC_RX2_B6_CTL, 0xff, 0x81},
+		{WCD9XXX_A_CDC_CLK_RX_B1_CTL, 0x02, 0x02},
+		{WCD9XXX_A_RX_HPH_R_GAIN, 0xff, 0x2C},
+		{WCD9XXX_A_NCP_CLK, 0xff, 0xFC},
+		{WCD9XXX_A_BUCK_CTRL_CCL_3, 0xff, 0x60},
+		{WCD9XXX_A_RX_COM_BIAS, 0xff, 0x80},
+		{WCD9XXX_A_BUCK_MODE_3, 0xff, 0xC6},
+		{WCD9XXX_A_BUCK_MODE_4, 0xff, 0xE6},
+		{WCD9XXX_A_BUCK_MODE_5, 0xff, 0x02},
+		{WCD9XXX_A_BUCK_MODE_1, 0xff, 0xA1},
+		{WCD9XXX_A_NCP_EN, 0xff, 0xFF},
+		{WCD9XXX_A_BUCK_MODE_5, 0xff, 0x7B},
+		{WCD9XXX_A_CDC_CLSH_B1_CTL, 0xff, 0xE6},
+		{WCD9XXX_A_RX_HPH_L_DAC_CTL, 0xff, 0xC0},
+		{WCD9XXX_A_RX_HPH_R_DAC_CTL, 0xff, 0xC0},
+	};
+
+	for (i = 0; i < ARRAY_SIZE(reg_set_paon); i++)
+		wcd9xxx_soc_update_bits_push(codec, lh,
+					     reg_set_paon[i].reg,
+					     reg_set_paon[i].mask,
+					     reg_set_paon[i].val, 0);
+	pr_debug("%s: PAs are prepared\n", __func__);
+
+	return 0;
+}
+
+static int wcd9xxx_enable_static_pa(struct wcd9xxx_mbhc *mbhc, bool enable)
+{
+	struct snd_soc_codec *codec = mbhc->codec;
+	const int wg_time = snd_soc_read(codec, WCD9XXX_A_RX_HPH_CNP_WG_TIME) *
+			    TAIKO_WG_TIME_FACTOR_US;
+
+	snd_soc_update_bits(codec, WCD9XXX_A_RX_HPH_CNP_EN, 0x30,
+			    enable ? 0x30 : 0x0);
+	/* Wait for wave gen time to avoid pop noise */
+	usleep_range(wg_time, wg_time + WCD9XXX_USLEEP_RANGE_MARGIN_US);
+	pr_debug("%s: PAs are %s as static mode (wg_time %d)\n", __func__,
+		 enable ? "enabled" : "disabled", wg_time);
+	return 0;
+}
+
+static int taiko_setup_zdet(struct wcd9xxx_mbhc *mbhc,
+			    enum mbhc_impedance_detect_stages stage)
+{
+	int ret = 0;
+	struct snd_soc_codec *codec = mbhc->codec;
+	struct taiko_priv *taiko = snd_soc_codec_get_drvdata(codec);
+	const int ramp_wait_us = 18 * 1000;
+
+#define __wr(reg, mask, value)						  \
+	do {								  \
+		ret = wcd9xxx_soc_update_bits_push(codec,		  \
+						   &taiko->reg_save_restore, \
+						   reg, mask, value, 0);  \
+		if (ret < 0)						  \
+			return ret;					  \
+	} while (0)
+
+	switch (stage) {
+
+	case PRE_MEAS:
+		INIT_LIST_HEAD(&taiko->reg_save_restore);
+		wcd9xxx_prepare_static_pa(mbhc, &taiko->reg_save_restore);
+		wcd9xxx_enable_static_pa(mbhc, true);
+
+		/*
+		 * save old value of registers and write the new value to
+		 * restore old value back, WCD9XXX_A_CDC_PA_RAMP_B{1,2,3,4}_CTL
+		 * registers don't need to be restored as those are solely used
+		 * by impedance detection.
+		 */
+		/* Phase 1 */
+		/* Reset the PA Ramp */
+		snd_soc_write(codec, WCD9XXX_A_CDC_PA_RAMP_B1_CTL, 0x1C);
+		/*
+		 * Connect the PA Ramp to PA chain and release reset with
+		 * keep it connected.
+		 */
+		snd_soc_write(codec, WCD9XXX_A_CDC_PA_RAMP_B1_CTL, 0x1F);
+		snd_soc_write(codec, WCD9XXX_A_CDC_PA_RAMP_B1_CTL, 0x03);
+		/*
+		 * Program the PA Ramp to FS_48K, L shift 1 and sample
+		 * num to 24
+		 */
+		snd_soc_write(codec, WCD9XXX_A_CDC_PA_RAMP_B3_CTL,
+			      0x3 << 4 | 0x6);
+		/* 0x56 for 10mv.  0xC0 is for 50mv */
+		snd_soc_write(codec, WCD9XXX_A_CDC_PA_RAMP_B4_CTL, 0xC0);
+		/* Enable MBHC MUX, Set MUX current to 37.5uA and ADC7 */
+		__wr(WCD9XXX_A_MBHC_SCALING_MUX_1, 0xFF, 0xC0);
+		__wr(WCD9XXX_A_MBHC_SCALING_MUX_2, 0xFF, 0xF0);
+		__wr(WCD9XXX_A_TX_7_MBHC_TEST_CTL, 0xFF, 0x78);
+		__wr(WCD9XXX_A_TX_7_MBHC_EN, 0xFF, 0x8C);
+		/* Change NSA and NAVG */
+		__wr(WCD9XXX_A_CDC_MBHC_TIMER_B4_CTL, 0x4 << 4, 0x4 << 4);
+		__wr(WCD9XXX_A_CDC_MBHC_TIMER_B5_CTL, 0xFF, 0x10);
+		/* Reset MBHC and set it up for STA */
+		__wr(WCD9XXX_A_CDC_MBHC_CLK_CTL, 0xFF, 0x0A);
+		__wr(WCD9XXX_A_CDC_MBHC_EN_CTL, 0xFF, 0x02);
+		__wr(WCD9XXX_A_CDC_MBHC_CLK_CTL, 0xFF, 0x02);
+
+		/* Set HPH_MBHC for zdet */
+		__wr(WCD9XXX_A_MBHC_HPH, 0xB3, 0x80);
+		break;
+	case POST_MEAS:
+		/* Phase 2 */
+		/* Start the PA ramp on HPH L and R */
+		snd_soc_write(codec, WCD9XXX_A_CDC_PA_RAMP_B2_CTL, 0x05);
+		/* Ramp generator takes ~17ms */
+		usleep_range(ramp_wait_us,
+				ramp_wait_us + WCD9XXX_USLEEP_RANGE_MARGIN_US);
+
+		/* Disable Ical */
+		snd_soc_write(codec, WCD9XXX_A_CDC_PA_RAMP_B2_CTL, 0x00);
+		/* Ramp generator takes ~17ms */
+		usleep_range(ramp_wait_us,
+				ramp_wait_us + WCD9XXX_USLEEP_RANGE_MARGIN_US);
+		break;
+	case PA_DISABLE:
+		/* Ramp HPH L & R back to Zero */
+		snd_soc_write(codec, WCD9XXX_A_CDC_PA_RAMP_B2_CTL, 0x0A);
+		/* Ramp generator takes ~17ms */
+		usleep_range(ramp_wait_us,
+				ramp_wait_us + WCD9XXX_USLEEP_RANGE_MARGIN_US);
+		snd_soc_write(codec, WCD9XXX_A_CDC_PA_RAMP_B2_CTL, 0x00);
+
+		/* Clean up starts */
+		/* Turn off PA ramp generator */
+		snd_soc_write(codec, WCD9XXX_A_CDC_PA_RAMP_B1_CTL, 0x0);
+		wcd9xxx_enable_static_pa(mbhc, false);
+		wcd9xxx_restore_registers(codec, &taiko->reg_save_restore);
+		break;
+	}
+#undef __wr
+
+	return ret;
+}
+
+static void taiko_compute_impedance(s16 *l, s16 *r, uint32_t *zl, uint32_t *zr)
+{
+
+	int64_t rl, rr = 0; /* milliohm */
+	const int alphal = 364; /* 0.005555 * 65536 = 364.05 */
+	const int alphar = 364; /* 0.005555 * 65536 = 364.05 */
+	const int beta = 3855; /* 0.011765 * 5 * 65536 = 3855.15 */
+	const int rref = 11333; /* not scaled up */
+	const int shift = 16;
+
+	rl = (int)(l[0] - l[1]) * 1000 / (l[0] - l[2]);
+	rl = rl * rref * alphal;
+	rl = rl >> shift;
+	rl = rl * beta;
+	rl = rl >> shift;
+	*zl = rl;
+
+	rr = (int)(r[0] - r[1]) * 1000 / (r[0] - r[2]);
+	rr = rr * rref  * alphar;
+	rr = rr >> shift;
+	rr = rr * beta;
+	rr = rr >> shift;
+	*zr = rr;
+}
+
+static enum wcd9xxx_cdc_type taiko_get_cdc_type(void)
+{
+	return WCD9XXX_CDC_TYPE_TAIKO;
+}
+
+static const struct wcd9xxx_mbhc_cb mbhc_cb = {
+	.get_cdc_type = taiko_get_cdc_type,
+	.setup_zdet = taiko_setup_zdet,
+	.compute_impedance = taiko_compute_impedance,
+};
+
 static int taiko_post_reset_cb(struct wcd9xxx *wcd9xxx)
 {
 	int ret = 0;
@@ -6221,8 +6392,10 @@
 
 	codec = (struct snd_soc_codec *)(wcd9xxx->ssr_priv);
 	taiko = snd_soc_codec_get_drvdata(codec);
-	mutex_lock(&codec->mutex);
 
+	snd_soc_card_change_online_state(codec->card, 1);
+
+	mutex_lock(&codec->mutex);
 	if (codec->reg_def_copy) {
 		pr_debug("%s: Update ASOC cache", __func__);
 		kfree(codec->reg_cache);
@@ -6255,18 +6428,19 @@
 
 		ret = wcd9xxx_mbhc_init(&taiko->mbhc, &taiko->resmgr, codec,
 					taiko_enable_mbhc_micbias,
-					NULL, rco_clk_rate, true);
-		if (ret) {
+					&mbhc_cb, rco_clk_rate, true);
+		if (ret)
 			pr_err("%s: mbhc init failed %d\n", __func__, ret);
-		} else {
-			ret = wcd9xxx_mbhc_start(&taiko->mbhc,
-						 taiko->mbhc.mbhc_cfg);
-			if (!ret)
-				taiko->mbhc_started = true;
-		}
+		else
+			taiko_hs_detect(codec, taiko->mbhc.mbhc_cfg);
 	}
 	taiko->machine_codec_event_cb(codec, WCD9XXX_CODEC_EVENT_CODEC_UP);
 
+	taiko_cleanup_irqs(taiko);
+	ret = taiko_setup_irqs(taiko);
+	if (ret)
+		pr_err("%s: Failed to setup irq: %d\n", __func__, ret);
+
 	mutex_unlock(&codec->mutex);
 	return ret;
 }
@@ -6309,9 +6483,12 @@
 };
 
 static int wcd9xxx_ssr_register(struct wcd9xxx *control,
-		int (*post_reset_cb)(struct wcd9xxx *wcd9xxx), void *priv)
+				int (*device_down_cb)(struct wcd9xxx *wcd9xxx),
+				int (*device_up_cb)(struct wcd9xxx *wcd9xxx),
+				void *priv)
 {
-	control->post_reset = post_reset_cb;
+	control->dev_down = device_down_cb;
+	control->post_reset = device_up_cb;
 	control->ssr_priv = priv;
 	return 0;
 }
@@ -6392,11 +6569,13 @@
 	int i, rco_clk_rate;
 	void *ptr = NULL;
 	struct wcd9xxx *core = dev_get_drvdata(codec->dev->parent);
+	struct wcd9xxx_core_resource *core_res;
 
 	codec->control_data = dev_get_drvdata(codec->dev->parent);
 	control = codec->control_data;
 
-	wcd9xxx_ssr_register(control, taiko_post_reset_cb, (void *)codec);
+	wcd9xxx_ssr_register(control, taiko_device_down,
+			     taiko_post_reset_cb, (void *)codec);
 
 	dev_info(codec->dev, "%s()\n", __func__);
 
@@ -6416,9 +6595,10 @@
 
 	/* codec resmgr module init */
 	wcd9xxx = codec->control_data;
+	core_res = &wcd9xxx->core_res;
 	pdata = dev_get_platdata(codec->dev->parent);
-	ret = wcd9xxx_resmgr_init(&taiko->resmgr, codec, wcd9xxx, pdata,
-				  &taiko_reg_address);
+	ret = wcd9xxx_resmgr_init(&taiko->resmgr, codec, core_res, pdata,
+				  &taiko_reg_address, WCD9XXX_CDC_TYPE_TAIKO);
 	if (ret) {
 		pr_err("%s: wcd9xxx init failed %d\n", __func__, ret);
 		goto err_init;
@@ -6437,7 +6617,7 @@
 	/* init and start mbhc */
 	ret = wcd9xxx_mbhc_init(&taiko->mbhc, &taiko->resmgr, codec,
 				taiko_enable_mbhc_micbias,
-				NULL, rco_clk_rate, true);
+				&mbhc_cb, rco_clk_rate, true);
 	if (ret) {
 		pr_err("%s: mbhc init failed %d\n", __func__, ret);
 		goto err_init;
diff --git a/sound/soc/codecs/wcd9320.h b/sound/soc/codecs/wcd9320.h
index 8f222ad..5ab5200 100644
--- a/sound/soc/codecs/wcd9320.h
+++ b/sound/soc/codecs/wcd9320.h
@@ -146,6 +146,7 @@
 			     bool dapm);
 extern int taiko_hs_detect(struct snd_soc_codec *codec,
 			   struct wcd9xxx_mbhc_config *mbhc_cfg);
+extern void taiko_hs_detect_exit(struct snd_soc_codec *codec);
 extern void *taiko_get_afe_config(struct snd_soc_codec *codec,
 				  enum afe_config_type config_type);
 
diff --git a/sound/soc/codecs/wcd9xxx-common.c b/sound/soc/codecs/wcd9xxx-common.c
index d00b843..05f2191 100644
--- a/sound/soc/codecs/wcd9xxx-common.c
+++ b/sound/soc/codecs/wcd9xxx-common.c
@@ -11,6 +11,7 @@
  */
 
 #include <linux/module.h>
+#include <linux/slab.h>
 #include <sound/soc.h>
 #include <linux/kernel.h>
 #include <linux/delay.h>
@@ -32,6 +33,8 @@
 
 #define MAX_IMPED_PARAMS 13
 
+#define USLEEP_RANGE_MARGIN_US 100
+
 struct wcd9xxx_imped_val {
 	u32 imped_val;
 	u8 index;
@@ -614,6 +617,46 @@
 	}
 }
 
+
+int wcd9xxx_soc_update_bits_push(struct snd_soc_codec *codec,
+					struct list_head *list,
+					uint16_t reg, uint8_t mask,
+					uint8_t value, int delay)
+{
+	int rc;
+	struct wcd9xxx_register_save_node *node;
+
+	node = kmalloc(sizeof(*node), GFP_KERNEL);
+	if (unlikely(!node)) {
+		pr_err("%s: Not enough memory\n", __func__);
+		return -ENOMEM;
+	}
+	node->reg = reg;
+	node->value = snd_soc_read(codec, reg);
+	list_add(&node->lh, list);
+	if (mask == 0xFF)
+		rc = snd_soc_write(codec, reg, value);
+	else
+		rc = snd_soc_update_bits(codec, reg, mask, value);
+	if (delay)
+		usleep_range(delay, delay + USLEEP_RANGE_MARGIN_US);
+	return rc;
+}
+EXPORT_SYMBOL(wcd9xxx_soc_update_bits_push);
+
+void wcd9xxx_restore_registers(struct snd_soc_codec *codec,
+			       struct list_head *lh)
+{
+	struct wcd9xxx_register_save_node *node, *nodetmp;
+
+	list_for_each_entry_safe(node, nodetmp, lh, lh) {
+		snd_soc_write(codec, node->reg, node->value);
+		list_del(&node->lh);
+		kfree(node);
+	}
+}
+EXPORT_SYMBOL(wcd9xxx_restore_registers);
+
 static void wcd9xxx_enable_buck_mode(struct snd_soc_codec *codec,
 		u8 buck_vref)
 {
diff --git a/sound/soc/codecs/wcd9xxx-common.h b/sound/soc/codecs/wcd9xxx-common.h
index 654964e..e63d36a 100644
--- a/sound/soc/codecs/wcd9xxx-common.h
+++ b/sound/soc/codecs/wcd9xxx-common.h
@@ -81,4 +81,73 @@
 	WCD9XXX_CODEC_EVENT_CODEC_UP = 0,
 };
 
+struct wcd9xxx_register_save_node {
+	struct list_head lh;
+	u16 reg;
+	u16 value;
+};
+
+extern int wcd9xxx_soc_update_bits_push(struct snd_soc_codec *codec,
+					struct list_head *lh,
+					uint16_t reg, uint8_t mask,
+					uint8_t value, int delay);
+extern void wcd9xxx_restore_registers(struct snd_soc_codec *codec,
+				      struct list_head *lh);
+enum {
+	RESERVED = 0,
+	AANC_LPF_FF_FB = 1,
+	AANC_LPF_COEFF_MSB,
+	AANC_LPF_COEFF_LSB,
+	HW_MAD_AUDIO_ENABLE,
+	HW_MAD_ULTR_ENABLE,
+	HW_MAD_BEACON_ENABLE,
+	HW_MAD_AUDIO_SLEEP_TIME,
+	HW_MAD_ULTR_SLEEP_TIME,
+	HW_MAD_BEACON_SLEEP_TIME,
+	HW_MAD_TX_AUDIO_SWITCH_OFF,
+	HW_MAD_TX_ULTR_SWITCH_OFF,
+	HW_MAD_TX_BEACON_SWITCH_OFF,
+	MAD_AUDIO_INT_DEST_SELECT_REG,
+	MAD_ULT_INT_DEST_SELECT_REG,
+	MAD_BEACON_INT_DEST_SELECT_REG,
+	MAD_CLIP_INT_DEST_SELECT_REG,
+	MAD_VBAT_INT_DEST_SELECT_REG,
+	MAD_AUDIO_INT_MASK_REG,
+	MAD_ULT_INT_MASK_REG,
+	MAD_BEACON_INT_MASK_REG,
+	MAD_CLIP_INT_MASK_REG,
+	MAD_VBAT_INT_MASK_REG,
+	MAD_AUDIO_INT_STATUS_REG,
+	MAD_ULT_INT_STATUS_REG,
+	MAD_BEACON_INT_STATUS_REG,
+	MAD_CLIP_INT_STATUS_REG,
+	MAD_VBAT_INT_STATUS_REG,
+	MAD_AUDIO_INT_CLEAR_REG,
+	MAD_ULT_INT_CLEAR_REG,
+	MAD_BEACON_INT_CLEAR_REG,
+	MAD_CLIP_INT_CLEAR_REG,
+	MAD_VBAT_INT_CLEAR_REG,
+	SB_PGD_PORT_TX_WATERMARK_N,
+	SB_PGD_PORT_TX_ENABLE_N,
+	SB_PGD_PORT_RX_WATERMARK_N,
+	SB_PGD_PORT_RX_ENABLE_N,
+	SB_PGD_TX_PORTn_MULTI_CHNL_0,
+	SB_PGD_TX_PORTn_MULTI_CHNL_1,
+	SB_PGD_RX_PORTn_MULTI_CHNL_0,
+	SB_PGD_RX_PORTn_MULTI_CHNL_1,
+	AANC_FF_GAIN_ADAPTIVE,
+	AANC_FFGAIN_ADAPTIVE_EN,
+	AANC_GAIN_CONTROL,
+	SPKR_CLIP_PIPE_BANK_SEL,
+	SPKR_CLIPDET_VAL0,
+	SPKR_CLIPDET_VAL1,
+	SPKR_CLIPDET_VAL2,
+	SPKR_CLIPDET_VAL3,
+	SPKR_CLIPDET_VAL4,
+	SPKR_CLIPDET_VAL5,
+	SPKR_CLIPDET_VAL6,
+	SPKR_CLIPDET_VAL7,
+	MAX_CFG_REGISTERS,
+};
+
 #endif
diff --git a/sound/soc/codecs/wcd9xxx-mbhc.c b/sound/soc/codecs/wcd9xxx-mbhc.c
index 6fc8e13..c2d626b 100644
--- a/sound/soc/codecs/wcd9xxx-mbhc.c
+++ b/sound/soc/codecs/wcd9xxx-mbhc.c
@@ -20,6 +20,7 @@
 #include <linux/debugfs.h>
 #include <linux/list.h>
 #include <linux/mfd/wcd9xxx/core.h>
+#include <linux/mfd/wcd9xxx/core-resource.h>
 #include <linux/mfd/wcd9xxx/wcd9xxx_registers.h>
 #include <linux/mfd/wcd9xxx/wcd9320_registers.h>
 #include <linux/mfd/wcd9xxx/pdata.h>
@@ -33,6 +34,7 @@
 #include <linux/pm_runtime.h>
 #include <linux/kernel.h>
 #include <linux/gpio.h>
+#include <linux/input.h>
 #include "wcd9320.h"
 #include "wcd9306.h"
 #include "wcd9xxx-mbhc.h"
@@ -65,6 +67,7 @@
 #define HS_DETECT_PLUG_INERVAL_MS 100
 #define SWCH_REL_DEBOUNCE_TIME_MS 50
 #define SWCH_IRQ_DEBOUNCE_TIME_US 5000
+#define BTN_RELEASE_DEBOUNCE_TIME_MS 25
 
 #define GND_MIC_SWAP_THRESHOLD 2
 #define OCP_ATTEMPT 1
@@ -90,6 +93,22 @@
 #define WCD9XXX_MEAS_DELTA_MAX_MV 50
 #define WCD9XXX_MEAS_INVALD_RANGE_LOW_MV 20
 #define WCD9XXX_MEAS_INVALD_RANGE_HIGH_MV 80
+
+/*
+ * Invalid voltage range for the detection
+ * of plug type with current source
+ */
+#define WCD9XXX_CS_MEAS_INVALD_RANGE_LOW_MV 110
+#define WCD9XXX_CS_MEAS_INVALD_RANGE_HIGH_MV 265
+
+/*
+ * Threshold used to detect euro headset
+ * with current source
+ */
+#define WCD9XXX_CS_GM_SWAP_THRES_MIN_MV 10
+#define WCD9XXX_CS_GM_SWAP_THRES_MAX_MV 40
+
+#define WCD9XXX_MBHC_NSC_CS 9
 #define WCD9XXX_GM_SWAP_THRES_MIN_MV 150
 #define WCD9XXX_GM_SWAP_THRES_MAX_MV 650
 #define WCD9XXX_THRESHOLD_MIC_THRESHOLD 200
@@ -101,6 +120,11 @@
 
 #define WCD9XXX_IRQ_MBHC_JACK_SWITCH_DEFAULT 28
 
+#define WCD9XXX_V_CS_HS_MAX 500
+#define WCD9XXX_V_CS_NO_MIC 5
+#define WCD9XXX_MB_MEAS_DELTA_MAX_MV 80
+#define WCD9XXX_CS_MEAS_DELTA_MAX_MV 10
+
 static bool detect_use_vddio_switch = true;
 
 struct wcd9xxx_mbhc_detect {
@@ -110,6 +134,7 @@
 	bool swap_gnd;
 	bool vddio;
 	bool hwvalue;
+	bool mic_bias;
 	/* internal purpose from here */
 	bool _above_no_mic;
 	bool _below_v_hs_max;
@@ -117,12 +142,6 @@
 	enum wcd9xxx_mbhc_plug_type _type;
 };
 
-struct wcd9xxx_register_save_node {
-	struct list_head lh;
-	u16 reg;
-	u16 value;
-};
-
 enum meas_type {
 	STA = 0,
 	DCE,
@@ -157,15 +176,19 @@
 				    uint32_t *zr);
 static s16 wcd9xxx_get_current_v(struct wcd9xxx_mbhc *mbhc,
 				 const enum wcd9xxx_current_v_idx idx);
+static void wcd9xxx_get_z(struct wcd9xxx_mbhc *mbhc, s16 *dce_z, s16 *sta_z);
+static void wcd9xxx_mbhc_calc_thres(struct wcd9xxx_mbhc *mbhc);
 
 static bool wcd9xxx_mbhc_polling(struct wcd9xxx_mbhc *mbhc)
 {
 	return mbhc->polling_active;
 }
 
-static void wcd9xxx_turn_onoff_override(struct snd_soc_codec *codec, bool on)
+static void wcd9xxx_turn_onoff_override(struct wcd9xxx_mbhc *mbhc, bool on)
 {
-	snd_soc_update_bits(codec, WCD9XXX_A_CDC_MBHC_B1_CTL, 0x04, on << 2);
+	struct snd_soc_codec *codec = mbhc->codec;
+	snd_soc_update_bits(codec, WCD9XXX_A_CDC_MBHC_B1_CTL,
+			    0x04, on ? 0x04 : 0x00);
 }
 
 /* called under codec_resource_lock acquisition */
@@ -234,6 +257,17 @@
 	pr_debug("%s: leave\n", __func__);
 }
 
+static int __wcd9xxx_resmgr_get_k_val(struct wcd9xxx_mbhc *mbhc,
+		unsigned int cfilt_mv)
+{
+	if (mbhc->mbhc_cb &&
+			mbhc->mbhc_cb->get_cdc_type() ==
+					WCD9XXX_CDC_TYPE_HELICON)
+		return 0x18;
+
+	return wcd9xxx_resmgr_get_k_val(mbhc->resmgr, cfilt_mv);
+}
+
 /*
  * called under codec_resource_lock acquisition
  * return old status
@@ -264,10 +298,10 @@
 		override = snd_soc_read(codec, WCD9XXX_A_CDC_MBHC_B1_CTL) &
 			   0x04;
 		if (!override)
-			wcd9xxx_turn_onoff_override(codec, true);
+			wcd9xxx_turn_onoff_override(mbhc, true);
 		/* Adjust threshold if Mic Bias voltage changes */
 		if (d->micb_mv != VDDIO_MICBIAS_MV) {
-			cfilt_k_val = wcd9xxx_resmgr_get_k_val(mbhc->resmgr,
+			cfilt_k_val = __wcd9xxx_resmgr_get_k_val(mbhc,
 							      VDDIO_MICBIAS_MV);
 			usleep_range(10000, 10000);
 			snd_soc_update_bits(codec,
@@ -306,7 +340,7 @@
 		snd_soc_update_bits(codec, mbhc->mbhc_bias_regs.mbhc_reg,
 				    0x10, 0x00);
 		if (!override)
-			wcd9xxx_turn_onoff_override(codec, false);
+			wcd9xxx_turn_onoff_override(mbhc, false);
 		if (restartpolling)
 			wcd9xxx_start_hs_polling(mbhc);
 
@@ -319,7 +353,7 @@
 		/* Reprogram thresholds */
 		if (d->micb_mv != VDDIO_MICBIAS_MV) {
 			cfilt_k_val =
-			    wcd9xxx_resmgr_get_k_val(mbhc->resmgr,
+			    __wcd9xxx_resmgr_get_k_val(mbhc,
 						     d->micb_mv);
 			snd_soc_update_bits(codec,
 					mbhc->mbhc_bias_regs.cfilt_val,
@@ -429,7 +463,7 @@
 
 	return ret;
 }
-EXPORT_SYMBOL_GPL(wcd9xxx_mbhc_cal_btn_det_mp);
+EXPORT_SYMBOL(wcd9xxx_mbhc_cal_btn_det_mp);
 
 static void wcd9xxx_calibrate_hs_polling(struct wcd9xxx_mbhc *mbhc)
 {
@@ -464,34 +498,36 @@
 {
 	struct snd_soc_codec *codec = mbhc->codec;
 	struct wcd9xxx_cfilt_mode cfilt_mode;
-	u8 reg_mode_val, cur_mode_val;
 
 	if (mbhc->mbhc_cb && mbhc->mbhc_cb->switch_cfilt_mode) {
 		cfilt_mode = mbhc->mbhc_cb->switch_cfilt_mode(mbhc, fast);
-		reg_mode_val = cfilt_mode.reg_mode_val;
-		cur_mode_val = cfilt_mode.cur_mode_val;
 	} else {
 		if (fast)
-			reg_mode_val = WCD9XXX_CFILT_FAST_MODE;
+			cfilt_mode.reg_mode_val = WCD9XXX_CFILT_FAST_MODE;
 		else
-			reg_mode_val = WCD9XXX_CFILT_SLOW_MODE;
+			cfilt_mode.reg_mode_val = WCD9XXX_CFILT_SLOW_MODE;
 
-		cur_mode_val =
+		cfilt_mode.reg_mask = 0x40;
+		cfilt_mode.cur_mode_val =
 		    snd_soc_read(codec, mbhc->mbhc_bias_regs.cfilt_ctl) & 0x40;
 	}
-	if (cur_mode_val != reg_mode_val) {
+
+	if (cfilt_mode.cur_mode_val
+			!= cfilt_mode.reg_mode_val) {
 		if (mbhc->polling_active)
 			wcd9xxx_pause_hs_polling(mbhc);
 		snd_soc_update_bits(codec,
 				    mbhc->mbhc_bias_regs.cfilt_ctl,
-				    0x40, reg_mode_val);
+					cfilt_mode.reg_mask,
+					cfilt_mode.reg_mode_val);
 		if (mbhc->polling_active)
 			wcd9xxx_start_hs_polling(mbhc);
 		pr_debug("%s: CFILT mode change (%x to %x)\n", __func__,
-			cur_mode_val, reg_mode_val);
+			cfilt_mode.cur_mode_val,
+			cfilt_mode.reg_mode_val);
 	} else {
 		pr_debug("%s: CFILT Value is already %x\n",
-			 __func__, cur_mode_val);
+			 __func__, cfilt_mode.cur_mode_val);
 	}
 }
 
@@ -533,7 +569,7 @@
 			mbhc->hphlocp_cnt = 0;
 		else
 			mbhc->hphrocp_cnt = 0;
-		wcd9xxx_enable_irq(codec->control_data, irq);
+		wcd9xxx_enable_irq(mbhc->resmgr->core_res, irq);
 	}
 }
 
@@ -555,6 +591,18 @@
 	unsigned int cfilt;
 	struct wcd9xxx_pdata *pdata = mbhc->resmgr->pdata;
 
+	if (mbhc->mbhc_cb &&
+			mbhc->mbhc_cb->get_cdc_type() ==
+					WCD9XXX_CDC_TYPE_HELICON) {
+		micbias_regs->mbhc_reg = WCD9XXX_A_MICB_1_MBHC;
+		micbias_regs->int_rbias = WCD9XXX_A_MICB_1_INT_RBIAS;
+		micbias_regs->ctl_reg = WCD9XXX_A_MICB_1_CTL;
+		micbias_regs->cfilt_val = WCD9XXX_A_MICB_CFILT_1_VAL;
+		micbias_regs->cfilt_ctl = WCD9XXX_A_MICB_CFILT_1_CTL;
+		mbhc->mbhc_data.micb_mv = 1800;
+		return;
+	}
+
 	switch (mbhc->mbhc_cfg->micbias) {
 	case MBHC_MICBIAS1:
 		cfilt = pdata->micbias.bias1_cfilt_sel;
@@ -662,7 +710,7 @@
 	if (r)
 		/* if scheduled mbhc.mbhc_btn_dwork is canceled from here,
 		 * we have to unlock from here instead btn_work */
-		wcd9xxx_unlock_sleep(mbhc->resmgr->core);
+		wcd9xxx_unlock_sleep(mbhc->resmgr->core_res);
 	return r;
 }
 
@@ -805,6 +853,7 @@
 		} else if (jack_type == SND_JACK_HEADSET) {
 			mbhc->polling_active = BUTTON_POLLING_SUPPORTED;
 			mbhc->current_plug = PLUG_TYPE_HEADSET;
+			mbhc->update_z = true;
 		} else if (jack_type == SND_JACK_LINEOUT) {
 			mbhc->current_plug = PLUG_TYPE_HIGH_HPH;
 		}
@@ -813,8 +862,10 @@
 			pr_debug("%s: Enabling micbias\n", __func__);
 			mbhc->micbias_enable_cb(mbhc->codec, true);
 		}
+
 		if (mbhc->impedance_detect)
 			wcd9xxx_detect_impedance(mbhc, &mbhc->zl, &mbhc->zr);
+
 		pr_debug("%s: Reporting insertion %d(%x)\n", __func__,
 			 jack_type, mbhc->hph_status);
 		wcd9xxx_jack_report(mbhc, &mbhc->headset_jack,
@@ -834,7 +885,7 @@
 	pr_debug("%s: scheduling wcd9xxx_correct_swch_plug\n", __func__);
 	WCD9XXX_BCL_ASSERT_LOCKED(mbhc->resmgr);
 	mbhc->hs_detect_work_stop = false;
-	wcd9xxx_lock_sleep(mbhc->resmgr->core);
+	wcd9xxx_lock_sleep(mbhc->resmgr->core_res);
 	schedule_work(work);
 }
 
@@ -850,7 +901,7 @@
 	if (cancel_work_sync(work)) {
 		pr_debug("%s: correct_plug_swch is canceled\n",
 			 __func__);
-		wcd9xxx_unlock_sleep(mbhc->resmgr->core);
+		wcd9xxx_unlock_sleep(mbhc->resmgr->core_res);
 	}
 	WCD9XXX_BCL_LOCK(mbhc->resmgr);
 }
@@ -859,8 +910,8 @@
 {
 	int r;
 	int vddio_k, mb_k;
-	vddio_k = wcd9xxx_resmgr_get_k_val(mbhc->resmgr, VDDIO_MICBIAS_MV);
-	mb_k = wcd9xxx_resmgr_get_k_val(mbhc->resmgr, mbhc->mbhc_data.micb_mv);
+	vddio_k = __wcd9xxx_resmgr_get_k_val(mbhc, VDDIO_MICBIAS_MV);
+	mb_k = __wcd9xxx_resmgr_get_k_val(mbhc, mbhc->mbhc_data.micb_mv);
 	if (tovddio)
 		r = v * (vddio_k + 4) / (mb_k + 4);
 	else
@@ -916,10 +967,11 @@
 	short bias_value;
 	struct snd_soc_codec *codec = mbhc->codec;
 
-	wcd9xxx_disable_irq(mbhc->resmgr->core, WCD9XXX_IRQ_MBHC_POTENTIAL);
+	wcd9xxx_disable_irq(mbhc->resmgr->core_res, WCD9XXX_IRQ_MBHC_POTENTIAL);
 	if (noreldetection)
 		wcd9xxx_turn_onoff_rel_detection(codec, false);
 
+	snd_soc_update_bits(codec, WCD9XXX_A_CDC_MBHC_CLK_CTL, 0x2, 0x0);
 	/* Turn on the override */
 	if (!override_bypass)
 		snd_soc_update_bits(codec, WCD9XXX_A_CDC_MBHC_B1_CTL, 0x4, 0x4);
@@ -929,6 +981,8 @@
 		snd_soc_write(codec, WCD9XXX_A_CDC_MBHC_EN_CTL, 0x4);
 		snd_soc_update_bits(codec, WCD9XXX_A_CDC_MBHC_CLK_CTL, 0x8,
 				    0x0);
+		snd_soc_update_bits(codec, WCD9XXX_A_CDC_MBHC_CLK_CTL, 0x2,
+				    0x2);
 		usleep_range(mbhc->mbhc_data.t_sta_dce,
 			     mbhc->mbhc_data.t_sta_dce);
 		snd_soc_write(codec, WCD9XXX_A_CDC_MBHC_EN_CTL, 0x4);
@@ -940,6 +994,8 @@
 		snd_soc_write(codec, WCD9XXX_A_CDC_MBHC_EN_CTL, 0x2);
 		snd_soc_update_bits(codec, WCD9XXX_A_CDC_MBHC_CLK_CTL, 0x8,
 				    0x0);
+		snd_soc_update_bits(codec, WCD9XXX_A_CDC_MBHC_CLK_CTL, 0x2,
+				    0x2);
 		usleep_range(mbhc->mbhc_data.t_sta_dce,
 			     mbhc->mbhc_data.t_sta_dce);
 		snd_soc_write(codec, WCD9XXX_A_CDC_MBHC_EN_CTL, 0x2);
@@ -957,7 +1013,7 @@
 
 	if (noreldetection)
 		wcd9xxx_turn_onoff_rel_detection(codec, true);
-	wcd9xxx_enable_irq(mbhc->resmgr->core, WCD9XXX_IRQ_MBHC_POTENTIAL);
+	wcd9xxx_enable_irq(mbhc->resmgr->core_res, WCD9XXX_IRQ_MBHC_POTENTIAL);
 
 	return bias_value;
 }
@@ -969,7 +1025,7 @@
 }
 
 static s32 __wcd9xxx_codec_sta_dce_v(struct wcd9xxx_mbhc *mbhc, s8 dce,
-				     u16 bias_value, s16 z)
+				     u16 bias_value, s16 z, u32 micb_mv)
 {
 	s16 value, mb;
 	s32 mv;
@@ -977,10 +1033,10 @@
 	value = bias_value;
 	if (dce) {
 		mb = (mbhc->mbhc_data.dce_mb);
-		mv = (value - z) * (s32)mbhc->mbhc_data.micb_mv / (mb - z);
+		mv = (value - z) * (s32)micb_mv / (mb - z);
 	} else {
 		mb = (mbhc->mbhc_data.sta_mb);
-		mv = (value - z) * (s32)mbhc->mbhc_data.micb_mv / (mb - z);
+		mv = (value - z) * (s32)micb_mv / (mb - z);
 	}
 
 	return mv;
@@ -991,15 +1047,21 @@
 {
 	s16 z;
 	z = dce ? (s16)mbhc->mbhc_data.dce_z : (s16)mbhc->mbhc_data.sta_z;
-	return __wcd9xxx_codec_sta_dce_v(mbhc, dce, bias_value, z);
+	return __wcd9xxx_codec_sta_dce_v(mbhc, dce, bias_value, z,
+					 mbhc->mbhc_data.micb_mv);
 }
 
 /* called only from interrupt which is under codec_resource_lock acquisition */
-static short wcd9xxx_mbhc_setup_hs_polling(struct wcd9xxx_mbhc *mbhc)
+static short wcd9xxx_mbhc_setup_hs_polling(struct wcd9xxx_mbhc *mbhc,
+					   bool is_cs_enable)
 {
 	struct snd_soc_codec *codec = mbhc->codec;
 	short bias_value;
 	u8 cfilt_mode;
+	s16 reg;
+	int change;
+	struct wcd9xxx_mbhc_btn_detect_cfg *btn_det;
+	s16 sta_z = 0, dce_z = 0;
 
 	WCD9XXX_BCL_ASSERT_LOCKED(mbhc->resmgr);
 
@@ -1009,6 +1071,11 @@
 		return -ENODEV;
 	}
 
+	btn_det = WCD9XXX_MBHC_CAL_BTN_DET_PTR(mbhc->mbhc_cfg->calibration);
+	/* Enable external voltage source to micbias if present */
+	if (mbhc->mbhc_cb && mbhc->mbhc_cb->enable_mb_source)
+		mbhc->mbhc_cb->enable_mb_source(codec, true);
+
 	/*
 	 * Request BG and clock.
 	 * These will be released by wcd9xxx_cleanup_hs_polling
@@ -1047,13 +1114,48 @@
 	snd_soc_update_bits(codec, WCD9XXX_A_CDC_MBHC_B1_CTL, 0x2, 0x2);
 	snd_soc_update_bits(codec, WCD9XXX_A_CDC_MBHC_CLK_CTL, 0x8, 0x8);
 
-	wcd9xxx_calibrate_hs_polling(mbhc);
-
 	/* don't flip override */
 	bias_value = __wcd9xxx_codec_sta_dce(mbhc, 1, true, true);
 	snd_soc_write(codec, mbhc->mbhc_bias_regs.cfilt_ctl, cfilt_mode);
 	snd_soc_update_bits(codec, WCD9XXX_A_MBHC_HPH, 0x13, 0x00);
 
+	/* recalibrate dce_z and sta_z */
+	reg = snd_soc_read(codec, WCD9XXX_A_CDC_MBHC_B1_CTL);
+	change = snd_soc_update_bits(codec, WCD9XXX_A_CDC_MBHC_B1_CTL, 0x78,
+				     btn_det->mbhc_nsc << 3);
+	wcd9xxx_get_z(mbhc, &dce_z, &sta_z);
+	if (change)
+		snd_soc_write(codec, WCD9XXX_A_CDC_MBHC_B1_CTL, reg);
+	if (dce_z && sta_z) {
+		pr_debug("%s: sta_z 0x%x -> 0x%x, dce_z 0x%x -> 0x%x\n",
+			 __func__,
+			 mbhc->mbhc_data.sta_z, sta_z & 0xffff,
+			 mbhc->mbhc_data.dce_z, dce_z & 0xffff);
+		mbhc->mbhc_data.dce_z = dce_z;
+		mbhc->mbhc_data.sta_z = sta_z;
+		wcd9xxx_mbhc_calc_thres(mbhc);
+		wcd9xxx_calibrate_hs_polling(mbhc);
+	} else {
+		pr_warn("%s: failed get new dce_z/sta_z 0x%x/0x%x\n", __func__,
+			dce_z, sta_z);
+	}
+
+	if (is_cs_enable) {
+		/* recalibrate dce_nsc_cs_z */
+		reg = snd_soc_read(mbhc->codec, WCD9XXX_A_CDC_MBHC_B1_CTL);
+		snd_soc_update_bits(mbhc->codec, WCD9XXX_A_CDC_MBHC_B1_CTL,
+				    0x78, WCD9XXX_MBHC_NSC_CS << 3);
+		wcd9xxx_get_z(mbhc, &dce_z, NULL);
+		snd_soc_write(mbhc->codec, WCD9XXX_A_CDC_MBHC_B1_CTL, reg);
+		if (dce_z) {
+			pr_debug("%s: dce_nsc_cs_z 0x%x -> 0x%x\n", __func__,
+				 mbhc->mbhc_data.dce_nsc_cs_z, dce_z & 0xffff);
+			mbhc->mbhc_data.dce_nsc_cs_z = dce_z;
+		} else {
+			pr_debug("%s: failed get new dce_nsc_cs_z\n", __func__);
+		}
+	}
+
 	return bias_value;
 }
 
@@ -1087,6 +1189,8 @@
 
 static void wcd9xxx_cleanup_hs_polling(struct wcd9xxx_mbhc *mbhc)
 {
+
+	pr_debug("%s: enter\n", __func__);
 	WCD9XXX_BCL_ASSERT_LOCKED(mbhc->resmgr);
 
 	wcd9xxx_shutdown_hs_removal_detect(mbhc);
@@ -1097,8 +1201,13 @@
 	wcd9xxx_resmgr_put_bandgap(mbhc->resmgr, WCD9XXX_BANDGAP_MBHC_MODE);
 	WCD9XXX_BG_CLK_UNLOCK(mbhc->resmgr);
 
+	/* Disable external voltage source to micbias if present */
+	if (mbhc->mbhc_cb && mbhc->mbhc_cb->enable_mb_source)
+		mbhc->mbhc_cb->enable_mb_source(mbhc->codec, false);
+
 	mbhc->polling_active = false;
 	mbhc->mbhc_state = MBHC_STATE_NONE;
+	pr_debug("%s: leave\n", __func__);
 }
 
 /* called under codec_resource_lock acquisition */
@@ -1112,6 +1221,12 @@
 static void wcd9xxx_onoff_vddio_switch(struct wcd9xxx_mbhc *mbhc, bool on)
 {
 	pr_debug("%s: vddio %d\n", __func__, on);
+
+	if (mbhc->mbhc_cb && mbhc->mbhc_cb->pull_mb_to_vddio) {
+		mbhc->mbhc_cb->pull_mb_to_vddio(mbhc->codec, on);
+		goto exit;
+	}
+
 	if (on) {
 		snd_soc_update_bits(mbhc->codec, mbhc->mbhc_bias_regs.mbhc_reg,
 				    1 << 7, 1 << 7);
@@ -1123,6 +1238,12 @@
 		snd_soc_update_bits(mbhc->codec, mbhc->mbhc_bias_regs.mbhc_reg,
 				    1 << 7, 0);
 	}
+
+exit:
+	/*
+	 * Wait for the micbias to settle down to vddio
+	 * when the micbias to vddio switch is enabled.
+	 */
 	if (on)
 		usleep_range(10000, 10000);
 }
@@ -1143,6 +1264,158 @@
 	return status;
 }
 
+static enum wcd9xxx_mbhc_plug_type
+wcd9xxx_cs_find_plug_type(struct wcd9xxx_mbhc *mbhc,
+			  struct wcd9xxx_mbhc_detect *dt, const int size,
+			  bool highhph,
+			  unsigned long event_state)
+{
+	int i;
+	int vdce, mb_mv;
+	int ch, sz, delta_thr;
+	int minv = 0, maxv = INT_MIN;
+	struct wcd9xxx_mbhc_detect *d = dt;
+	struct wcd9xxx_mbhc_detect *dprev = d, *dmicbias = NULL, *dgnd = NULL;
+	enum wcd9xxx_mbhc_plug_type type = PLUG_TYPE_INVALID;
+
+	const struct wcd9xxx_mbhc_plug_type_cfg *plug_type =
+	    WCD9XXX_MBHC_CAL_PLUG_TYPE_PTR(mbhc->mbhc_cfg->calibration);
+	s16 hs_max, no_mic, dce_z;
+
+	pr_debug("%s: enter\n", __func__);
+	pr_debug("%s: event_state 0x%lx\n", __func__, event_state);
+
+	sz = size - 1;
+	for (i = 0, d = dt, ch = 0; i < sz; i++, d++) {
+		if (d->mic_bias) {
+			dce_z = mbhc->mbhc_data.dce_z;
+			mb_mv = mbhc->mbhc_data.micb_mv;
+			hs_max = plug_type->v_hs_max;
+			no_mic = plug_type->v_no_mic;
+		} else {
+			dce_z = mbhc->mbhc_data.dce_nsc_cs_z;
+			mb_mv = VDDIO_MICBIAS_MV;
+			hs_max = WCD9XXX_V_CS_HS_MAX;
+			no_mic = WCD9XXX_V_CS_NO_MIC;
+		}
+
+		vdce = __wcd9xxx_codec_sta_dce_v(mbhc, true, d->dce,
+						 dce_z, (u32)mb_mv);
+
+		d->_vdces = vdce;
+		if (d->_vdces < no_mic)
+			d->_type = PLUG_TYPE_HEADPHONE;
+		else if (d->_vdces >= hs_max)
+			d->_type = PLUG_TYPE_HIGH_HPH;
+		else
+			d->_type = PLUG_TYPE_HEADSET;
+
+		pr_debug("%s: DCE #%d, %04x, V %04d(%04d), HPHL %d TYPE %d\n",
+			 __func__, i, d->dce, vdce, d->_vdces,
+			 d->hphl_status & 0x01,
+			 d->_type);
+
+		ch += d->hphl_status & 0x01;
+		if (!d->swap_gnd && !d->mic_bias) {
+			if (maxv < d->_vdces)
+				maxv = d->_vdces;
+			if (!minv || minv > d->_vdces)
+				minv = d->_vdces;
+		}
+		if ((!d->mic_bias &&
+		    (d->_vdces >= WCD9XXX_CS_MEAS_INVALD_RANGE_LOW_MV &&
+		     d->_vdces <= WCD9XXX_CS_MEAS_INVALD_RANGE_HIGH_MV)) ||
+		    (d->mic_bias &&
+		    (d->_vdces >= WCD9XXX_MEAS_INVALD_RANGE_LOW_MV &&
+		     d->_vdces <= WCD9XXX_MEAS_INVALD_RANGE_HIGH_MV))) {
+			pr_debug("%s: within invalid range\n", __func__);
+			type = PLUG_TYPE_INVALID;
+			goto exit;
+		}
+	}
+
+	if (event_state & (1 << MBHC_EVENT_PA_HPHL)) {
+		pr_debug("%s: HPHL PA was ON\n", __func__);
+	} else if (ch != sz && ch > 0) {
+		pr_debug("%s: Invalid, inconsistent HPHL\n", __func__);
+		type = PLUG_TYPE_INVALID;
+		goto exit;
+	}
+
+	delta_thr = highhph ? WCD9XXX_MB_MEAS_DELTA_MAX_MV :
+			      WCD9XXX_CS_MEAS_DELTA_MAX_MV;
+
+	for (i = 0, d = dt; i < sz; i++, d++) {
+		if ((i > 0) && !d->mic_bias && !d->swap_gnd &&
+		    (d->_type != dprev->_type)) {
+			pr_debug("%s: Invalid, inconsistent types\n", __func__);
+			type = PLUG_TYPE_INVALID;
+			goto exit;
+		}
+
+		if (!d->swap_gnd && !d->mic_bias &&
+		    (abs(minv - d->_vdces) > delta_thr ||
+		     abs(maxv - d->_vdces) > delta_thr)) {
+			pr_debug("%s: Invalid, delta %dmv, %dmv and %dmv\n",
+				 __func__, d->_vdces, minv, maxv);
+			type = PLUG_TYPE_INVALID;
+			goto exit;
+		} else if (d->swap_gnd) {
+			dgnd = d;
+		}
+
+		if (!d->mic_bias && !d->swap_gnd)
+			dprev = d;
+		else if (d->mic_bias)
+			dmicbias = d;
+	}
+	if (dgnd && dt->_type != PLUG_TYPE_HEADSET &&
+	    dt->_type != dgnd->_type) {
+		pr_debug("%s: Invalid, inconsistent types\n", __func__);
+		type = PLUG_TYPE_INVALID;
+		goto exit;
+	}
+
+	type = dt->_type;
+	if (dmicbias) {
+		if (dmicbias->_type == PLUG_TYPE_HEADSET &&
+		    (dt->_type == PLUG_TYPE_HIGH_HPH ||
+		     dt->_type == PLUG_TYPE_HEADSET)) {
+			type = PLUG_TYPE_HEADSET;
+			if (dt->_type == PLUG_TYPE_HIGH_HPH) {
+				pr_debug("%s: Headset with threshold on MIC detected\n",
+					 __func__);
+				if (mbhc->mbhc_cfg->micbias_enable_flags &
+				 (1 << MBHC_MICBIAS_ENABLE_THRESHOLD_HEADSET))
+					mbhc->micbias_enable = true;
+			}
+		}
+	}
+
+	if (!(event_state & (1UL << MBHC_EVENT_PA_HPHL))) {
+		if (((type == PLUG_TYPE_HEADSET ||
+		      type == PLUG_TYPE_HEADPHONE) && ch != sz)) {
+			pr_debug("%s: Invalid, not fully inserted, TYPE %d\n",
+				 __func__, type);
+			type = PLUG_TYPE_INVALID;
+		}
+	}
+	if (type == PLUG_TYPE_HEADSET && dgnd && !dgnd->mic_bias) {
+		if ((dgnd->_vdces + WCD9XXX_CS_GM_SWAP_THRES_MIN_MV <
+		     minv) &&
+		    (dgnd->_vdces + WCD9XXX_CS_GM_SWAP_THRES_MAX_MV >
+		     maxv))
+			type = PLUG_TYPE_GND_MIC_SWAP;
+		else if (dgnd->_type != PLUG_TYPE_HEADSET) {
+			pr_debug("%s: Invalid, inconsistent types\n", __func__);
+			type = PLUG_TYPE_INVALID;
+		}
+	}
+exit:
+	pr_debug("%s: Plug type %d detected\n", __func__, type);
+	return type;
+}
+
 /*
  * wcd9xxx_find_plug_type : Find out and return the best plug type with given
  *			    list of wcd9xxx_mbhc_detect structure.
@@ -1328,6 +1601,112 @@
 	return 0;
 }
 
+void wcd9xxx_turn_onoff_current_source(struct wcd9xxx_mbhc *mbhc, bool on,
+				       bool highhph)
+{
+
+	struct snd_soc_codec *codec;
+	struct wcd9xxx_mbhc_btn_detect_cfg *btn_det;
+	const struct wcd9xxx_mbhc_plug_detect_cfg *plug_det =
+	    WCD9XXX_MBHC_CAL_PLUG_DET_PTR(mbhc->mbhc_cfg->calibration);
+
+	btn_det = WCD9XXX_MBHC_CAL_BTN_DET_PTR(mbhc->mbhc_cfg->calibration);
+	codec = mbhc->codec;
+
+	if (on) {
+		pr_debug("%s: enabling current source\n", __func__);
+		/* Nsc to 9 */
+		snd_soc_update_bits(codec, WCD9XXX_A_CDC_MBHC_B1_CTL,
+				    0x78, 0x48);
+		/* pull down diode bit to 0 */
+		snd_soc_update_bits(codec, mbhc->mbhc_bias_regs.mbhc_reg,
+				    0x01, 0x00);
+		/*
+		 * Keep the low power insertion/removal
+		 * detection (reg 0x3DD) disabled
+		 */
+		snd_soc_update_bits(codec, WCD9XXX_A_CDC_MBHC_INT_CTL,
+				    0x01, 0x00);
+		/*
+		 * Enable the Mic Bias current source
+		 * Write bits[6:5] of register MICB_2_MBHC to 0x3 (V_20_UA)
+		 * Write bit[7] of register MICB_2_MBHC to 1
+		 * (INS_DET_ISRC_EN__ENABLE)
+		 * MICB_2_MBHC__SCHT_TRIG_EN to 1
+		 */
+		snd_soc_update_bits(codec, mbhc->mbhc_bias_regs.mbhc_reg,
+				    0xF0, 0xF0);
+		/* Disconnect MBHC Override from MicBias and LDOH */
+		snd_soc_update_bits(codec, WCD9XXX_A_MAD_ANA_CTRL, 0x10, 0x00);
+	} else {
+		pr_debug("%s: disabling current source\n", __func__);
+		/* Connect MBHC Override from MicBias and LDOH */
+		snd_soc_update_bits(codec, WCD9XXX_A_MAD_ANA_CTRL, 0x10, 0x10);
+		/* INS_DET_ISRC_CTL to acdb value */
+		snd_soc_update_bits(codec, mbhc->mbhc_bias_regs.mbhc_reg,
+				    0x60, plug_det->mic_current << 5);
+		if (!highhph) {
+			/* INS_DET_ISRC_EN__ENABLE to 0 */
+			snd_soc_update_bits(codec,
+					    mbhc->mbhc_bias_regs.mbhc_reg,
+					    0x80, 0x00);
+			/* MICB_2_MBHC__SCHT_TRIG_EN  to 0 */
+			snd_soc_update_bits(codec,
+					    mbhc->mbhc_bias_regs.mbhc_reg,
+					    0x10, 0x00);
+		}
+		/* Nsc to acdb value */
+		snd_soc_update_bits(codec, WCD9XXX_A_CDC_MBHC_B1_CTL, 0x78,
+				    btn_det->mbhc_nsc << 3);
+	}
+}
+
+static enum wcd9xxx_mbhc_plug_type
+wcd9xxx_codec_cs_get_plug_type(struct wcd9xxx_mbhc *mbhc, bool highhph)
+{
+	struct snd_soc_codec *codec = mbhc->codec;
+	struct wcd9xxx_mbhc_detect rt[NUM_DCE_PLUG_INS_DETECT];
+	enum wcd9xxx_mbhc_plug_type type = PLUG_TYPE_INVALID;
+	int i;
+
+	pr_debug("%s: enter\n", __func__);
+	WCD9XXX_BCL_ASSERT_LOCKED(mbhc->resmgr);
+
+	BUG_ON(NUM_DCE_PLUG_INS_DETECT < 4);
+
+	rt[0].swap_gnd = false;
+	rt[0].vddio = false;
+	rt[0].hwvalue = true;
+	rt[0].hphl_status = wcd9xxx_hphl_status(mbhc);
+	rt[0].dce = wcd9xxx_mbhc_setup_hs_polling(mbhc, true);
+	rt[0].mic_bias = false;
+
+	for (i = 1; i < NUM_DCE_PLUG_INS_DETECT - 1; i++) {
+		rt[i].swap_gnd = (i == NUM_DCE_PLUG_INS_DETECT - 3);
+		rt[i].mic_bias = ((i == NUM_DCE_PLUG_INS_DETECT - 4) &&
+				   highhph);
+		rt[i].hphl_status = wcd9xxx_hphl_status(mbhc);
+		if (rt[i].swap_gnd)
+			wcd9xxx_codec_hphr_gnd_switch(codec, true);
+
+		if (rt[i].mic_bias)
+			wcd9xxx_turn_onoff_current_source(mbhc, false, false);
+
+		rt[i].dce = __wcd9xxx_codec_sta_dce(mbhc, 1, !highhph, true);
+		if (rt[i].mic_bias)
+			wcd9xxx_turn_onoff_current_source(mbhc, true, false);
+		if (rt[i].swap_gnd)
+			wcd9xxx_codec_hphr_gnd_switch(codec, false);
+	}
+
+	type = wcd9xxx_cs_find_plug_type(mbhc, rt, ARRAY_SIZE(rt), highhph,
+					 mbhc->event_state);
+
+	pr_debug("%s: plug_type:%d\n", __func__, type);
+
+	return type;
+}
+
 static enum wcd9xxx_mbhc_plug_type
 wcd9xxx_codec_get_plug_type(struct wcd9xxx_mbhc *mbhc, bool highhph)
 {
@@ -1364,7 +1743,7 @@
 	(void) wcd9xxx_pull_down_micbias(mbhc,
 					 WCD9XXX_MICBIAS_PULLDOWN_SETTLE_US);
 	rt[0].hphl_status = wcd9xxx_hphl_status(mbhc);
-	rt[0].dce = wcd9xxx_mbhc_setup_hs_polling(mbhc);
+	rt[0].dce = wcd9xxx_mbhc_setup_hs_polling(mbhc, false);
 	rt[0].swap_gnd = false;
 	rt[0].vddio = false;
 	rt[0].hwvalue = true;
@@ -1512,12 +1891,12 @@
 	if (snd_soc_read(codec, WCD9XXX_A_CDC_MBHC_B1_CTL) & 0x4) {
 		/* called by interrupt */
 		if (!is_clk_active(codec)) {
-			wcd9xxx_resmgr_enable_config_mode(codec, 1);
+			wcd9xxx_resmgr_enable_config_mode(mbhc->resmgr, 1);
 			snd_soc_update_bits(codec, WCD9XXX_A_CDC_MBHC_B1_CTL,
 					0x06, 0);
 			usleep_range(generic->t_shutdown_plug_rem,
 					generic->t_shutdown_plug_rem);
-			wcd9xxx_resmgr_enable_config_mode(codec, 0);
+			wcd9xxx_resmgr_enable_config_mode(mbhc->resmgr, 0);
 		} else
 			snd_soc_update_bits(codec, WCD9XXX_A_CDC_MBHC_B1_CTL,
 					0x06, 0);
@@ -1545,11 +1924,11 @@
 					    0);
 	}
 
-	if (mbhc->resmgr->reg_addr->micb_4_mbhc)
+	if (mbhc->resmgr->reg_addr && mbhc->resmgr->reg_addr->micb_4_mbhc)
 		snd_soc_update_bits(codec, mbhc->resmgr->reg_addr->micb_4_mbhc,
 				    0x3, mbhc->mbhc_cfg->micbias);
 
-	wcd9xxx_enable_irq(mbhc->resmgr->core, WCD9XXX_IRQ_MBHC_INSERTION);
+	wcd9xxx_enable_irq(mbhc->resmgr->core_res, WCD9XXX_IRQ_MBHC_INSERTION);
 	snd_soc_update_bits(codec, WCD9XXX_A_CDC_MBHC_INT_CTL, 0x1, 0x1);
 	pr_debug("%s: leave\n", __func__);
 
@@ -1633,15 +2012,23 @@
 static void wcd9xxx_mbhc_decide_swch_plug(struct wcd9xxx_mbhc *mbhc)
 {
 	enum wcd9xxx_mbhc_plug_type plug_type;
-	struct snd_soc_codec *codec = mbhc->codec;
+	bool current_source_enable;
 
 	pr_debug("%s: enter\n", __func__);
 
 	WCD9XXX_BCL_ASSERT_LOCKED(mbhc->resmgr);
+	current_source_enable = ((mbhc->mbhc_cfg->cs_enable_flags &
+				  (1 << MBHC_CS_ENABLE_INSERTION)) != 0);
 
-	wcd9xxx_turn_onoff_override(codec, true);
-	plug_type = wcd9xxx_codec_get_plug_type(mbhc, true);
-	wcd9xxx_turn_onoff_override(codec, false);
+	if (current_source_enable) {
+		wcd9xxx_turn_onoff_current_source(mbhc, true, false);
+		plug_type = wcd9xxx_codec_cs_get_plug_type(mbhc, false);
+		wcd9xxx_turn_onoff_current_source(mbhc, false, false);
+	} else {
+		wcd9xxx_turn_onoff_override(mbhc, true);
+		plug_type = wcd9xxx_codec_get_plug_type(mbhc, true);
+		wcd9xxx_turn_onoff_override(mbhc, false);
+	}
 
 	if (wcd9xxx_swch_level_remove(mbhc)) {
 		pr_debug("%s: Switch level is low when determining plug\n",
@@ -1651,13 +2038,16 @@
 
 	if (plug_type == PLUG_TYPE_INVALID ||
 	    plug_type == PLUG_TYPE_GND_MIC_SWAP) {
+		wcd9xxx_cleanup_hs_polling(mbhc);
 		wcd9xxx_schedule_hs_detect_plug(mbhc,
 						&mbhc->correct_plug_swch);
 	} else if (plug_type == PLUG_TYPE_HEADPHONE) {
 		wcd9xxx_report_plug(mbhc, 1, SND_JACK_HEADPHONE);
+		wcd9xxx_cleanup_hs_polling(mbhc);
 		wcd9xxx_schedule_hs_detect_plug(mbhc,
 						&mbhc->correct_plug_swch);
 	} else if (plug_type == PLUG_TYPE_HIGH_HPH) {
+		wcd9xxx_cleanup_hs_polling(mbhc);
 		wcd9xxx_schedule_hs_detect_plug(mbhc,
 						&mbhc->correct_plug_swch);
 	} else {
@@ -1671,26 +2061,9 @@
 /* called under codec_resource_lock acquisition */
 static void wcd9xxx_mbhc_detect_plug_type(struct wcd9xxx_mbhc *mbhc)
 {
-	struct snd_soc_codec *codec = mbhc->codec;
-	const struct wcd9xxx_mbhc_plug_detect_cfg *plug_det =
-		WCD9XXX_MBHC_CAL_PLUG_DET_PTR(mbhc->mbhc_cfg->calibration);
-
 	pr_debug("%s: enter\n", __func__);
 	WCD9XXX_BCL_ASSERT_LOCKED(mbhc->resmgr);
 
-	/*
-	 * Turn on the override,
-	 * wcd9xxx_mbhc_setup_hs_polling requires override on
-	 */
-	wcd9xxx_turn_onoff_override(codec, true);
-	if (plug_det->t_ins_complete > 20)
-		msleep(plug_det->t_ins_complete);
-	else
-		usleep_range(plug_det->t_ins_complete * 1000,
-			     plug_det->t_ins_complete * 1000);
-	/* Turn off the override */
-	wcd9xxx_turn_onoff_override(codec, false);
-
 	if (wcd9xxx_swch_level_remove(mbhc))
 		pr_debug("%s: Switch level low when determining plug\n",
 			 __func__);
@@ -1739,14 +2112,21 @@
 	}
 }
 
-static bool is_valid_mic_voltage(struct wcd9xxx_mbhc *mbhc, s32 mic_mv)
+static bool is_valid_mic_voltage(struct wcd9xxx_mbhc *mbhc, s32 mic_mv,
+				 bool cs_enable)
 {
 	const struct wcd9xxx_mbhc_plug_type_cfg *plug_type =
 	    WCD9XXX_MBHC_CAL_PLUG_TYPE_PTR(mbhc->mbhc_cfg->calibration);
 	const s16 v_hs_max = wcd9xxx_get_current_v_hs_max(mbhc);
 
-	return (!(mic_mv > 10 && mic_mv < 80) && (mic_mv > plug_type->v_no_mic)
-		&& (mic_mv < v_hs_max)) ? true : false;
+	if (cs_enable)
+		return ((mic_mv > WCD9XXX_V_CS_NO_MIC) &&
+			 (mic_mv < WCD9XXX_V_CS_HS_MAX)) ? true : false;
+	else
+		return (!(mic_mv > WCD9XXX_MEAS_INVALD_RANGE_LOW_MV &&
+			  mic_mv < WCD9XXX_MEAS_INVALD_RANGE_HIGH_MV) &&
+			(mic_mv > plug_type->v_no_mic) &&
+			(mic_mv < v_hs_max)) ? true : false;
 }
 
 /*
@@ -1761,6 +2141,13 @@
 	s32 mic_mv[NUM_DCE_PLUG_DETECT];
 	short mb_v[NUM_DCE_PLUG_DETECT];
 	unsigned long retry = 0, timeout;
+	bool cs_enable;
+
+	cs_enable = ((mbhc->mbhc_cfg->cs_enable_flags &
+		      (1 << MBHC_CS_ENABLE_REMOVAL)) != 0);
+
+	if (cs_enable)
+		wcd9xxx_turn_onoff_current_source(mbhc, true, false);
 
 	timeout = jiffies + msecs_to_jiffies(HS_DETECT_PLUG_TIME_MS);
 	while (!(timedout = time_after(jiffies, timeout))) {
@@ -1780,11 +2167,28 @@
 			break;
 		}
 
-		for (i = 0; i < NUM_DCE_PLUG_DETECT; i++) {
-			mb_v[i] = wcd9xxx_codec_sta_dce(mbhc, 1,  true);
-			mic_mv[i] = wcd9xxx_codec_sta_dce_v(mbhc, 1 , mb_v[i]);
-			pr_debug("%s : DCE run %lu, mic_mv = %d(%x)\n",
-				 __func__, retry, mic_mv[i], mb_v[i]);
+		if (cs_enable) {
+			for (i = 0; i < NUM_DCE_PLUG_DETECT; i++) {
+				mb_v[i] = __wcd9xxx_codec_sta_dce(mbhc, 1,
+								  true, true);
+				mic_mv[i] = __wcd9xxx_codec_sta_dce_v(mbhc,
+								      true,
+								      mb_v[i],
+						mbhc->mbhc_data.dce_nsc_cs_z,
+						(u32)VDDIO_MICBIAS_MV);
+				pr_debug("%s : DCE run %lu, mic_mv = %d(%x)\n",
+					 __func__, retry, mic_mv[i], mb_v[i]);
+			}
+		} else {
+			for (i = 0; i < NUM_DCE_PLUG_DETECT; i++) {
+				mb_v[i] = wcd9xxx_codec_sta_dce(mbhc, 1,
+								true);
+				mic_mv[i] = wcd9xxx_codec_sta_dce_v(mbhc, 1,
+								mb_v[i]);
+				pr_debug("%s : DCE run %lu, mic_mv = %d(%x)\n",
+					 __func__, retry, mic_mv[i],
+								mb_v[i]);
+			}
 		}
 
 		if (wcd9xxx_swch_level_remove(mbhc)) {
@@ -1799,7 +2203,7 @@
 		}
 
 		for (i = 0; i < NUM_DCE_PLUG_DETECT; i++)
-			if (!is_valid_mic_voltage(mbhc, mic_mv[i]))
+			if (!is_valid_mic_voltage(mbhc, mic_mv[i], cs_enable))
 				break;
 
 		if (i == NUM_DCE_PLUG_DETECT) {
@@ -1810,6 +2214,9 @@
 		}
 	}
 
+	if (cs_enable)
+		wcd9xxx_turn_onoff_current_source(mbhc, false, false);
+
 	if (timedout)
 		pr_debug("%s: Microphone did not settle in %d seconds\n",
 			 __func__, HS_DETECT_PLUG_TIME_MS);
@@ -1828,12 +2235,15 @@
 /* called only from interrupt which is under codec_resource_lock acquisition */
 static void wcd9xxx_hs_remove_irq_noswch(struct wcd9xxx_mbhc *mbhc)
 {
-	s16 dce;
+	s16 dce, dcez;
 	unsigned long timeout;
 	bool removed = true;
 	struct snd_soc_codec *codec = mbhc->codec;
 	const struct wcd9xxx_mbhc_general_cfg *generic =
 		WCD9XXX_MBHC_CAL_GENERAL_PTR(mbhc->mbhc_cfg->calibration);
+	bool cs_enable;
+	s16 cur_v_ins_h;
+	u32 mb_mv;
 
 	pr_debug("%s: enter\n", __func__);
 	if (mbhc->current_plug != PLUG_TYPE_HEADSET) {
@@ -1847,13 +2257,32 @@
 	usleep_range(generic->t_shutdown_plug_rem,
 		     generic->t_shutdown_plug_rem);
 
+	cs_enable = ((mbhc->mbhc_cfg->cs_enable_flags &
+		      (1 << MBHC_CS_ENABLE_REMOVAL)) != 0);
+	if (cs_enable)
+		wcd9xxx_turn_onoff_current_source(mbhc, true, false);
+
 	timeout = jiffies + msecs_to_jiffies(FAKE_REMOVAL_MIN_PERIOD_MS);
 	do {
-		dce = wcd9xxx_codec_sta_dce(mbhc, 1,  true);
+		if (cs_enable) {
+			dce = __wcd9xxx_codec_sta_dce(mbhc, 1,  true, true);
+			dcez = mbhc->mbhc_data.dce_nsc_cs_z;
+			mb_mv = VDDIO_MICBIAS_MV;
+		} else {
+			dce = wcd9xxx_codec_sta_dce(mbhc, 1,  true);
+			dcez = mbhc->mbhc_data.dce_z;
+			mb_mv = mbhc->mbhc_data.micb_mv;
+		}
+
 		pr_debug("%s: DCE 0x%x,%d\n", __func__, dce,
-			 wcd9xxx_codec_sta_dce_v(mbhc, 1, dce));
-		if (dce <
-		    wcd9xxx_get_current_v(mbhc, WCD9XXX_CURRENT_V_INS_H)) {
+			  __wcd9xxx_codec_sta_dce_v(mbhc, true, dce,
+						    dcez, mb_mv));
+
+		cur_v_ins_h = cs_enable ? (s16) mbhc->mbhc_data.v_cs_ins_h :
+					  (wcd9xxx_get_current_v(mbhc,
+					   WCD9XXX_CURRENT_V_INS_H));
+
+		if (dce < cur_v_ins_h) {
 			removed = false;
 			break;
 		}
@@ -1861,6 +2290,9 @@
 	pr_debug("%s: headset %sactually removed\n", __func__,
 		  removed ? "" : "not ");
 
+	if (cs_enable)
+		wcd9xxx_turn_onoff_current_source(mbhc, false, false);
+
 	if (removed) {
 		if (mbhc->mbhc_cfg->detect_extn_cable) {
 			if (!wcd9xxx_swch_level_remove(mbhc)) {
@@ -1962,7 +2394,7 @@
 
 	pr_debug("%s: enter\n", __func__);
 	WCD9XXX_BCL_LOCK(mbhc->resmgr);
-	wcd9xxx_disable_irq(codec->control_data, WCD9XXX_IRQ_MBHC_INSERTION);
+	wcd9xxx_disable_irq(mbhc->resmgr->core_res, WCD9XXX_IRQ_MBHC_INSERTION);
 
 	is_mb_trigger = !!(snd_soc_read(codec, mbhc->mbhc_bias_regs.mbhc_reg) &
 			   0x10);
@@ -2008,7 +2440,7 @@
 			    mbhc->buttons_pressed);
 
 	pr_debug("%s: leave\n", __func__);
-	wcd9xxx_unlock_sleep(mbhc->resmgr->core);
+	wcd9xxx_unlock_sleep(mbhc->resmgr->core_res);
 }
 
 static void wcd9xxx_mbhc_insert_work(struct work_struct *work)
@@ -2016,12 +2448,12 @@
 	struct delayed_work *dwork;
 	struct wcd9xxx_mbhc *mbhc;
 	struct snd_soc_codec *codec;
-	struct wcd9xxx *core;
+	struct wcd9xxx_core_resource *core_res;
 
 	dwork = to_delayed_work(work);
 	mbhc = container_of(dwork, struct wcd9xxx_mbhc, mbhc_insert_dwork);
 	codec = mbhc->codec;
-	core = mbhc->resmgr->core;
+	core_res = mbhc->resmgr->core_res;
 
 	pr_debug("%s:\n", __func__);
 
@@ -2029,9 +2461,9 @@
 	snd_soc_update_bits(codec, mbhc->mbhc_bias_regs.mbhc_reg, 0x90, 0x00);
 	snd_soc_update_bits(codec, WCD9XXX_A_MBHC_HPH, 0x13, 0x00);
 	snd_soc_update_bits(codec, mbhc->mbhc_bias_regs.ctl_reg, 0x01, 0x00);
-	wcd9xxx_disable_irq_sync(core, WCD9XXX_IRQ_MBHC_INSERTION);
+	wcd9xxx_disable_irq_sync(core_res, WCD9XXX_IRQ_MBHC_INSERTION);
 	wcd9xxx_mbhc_detect_plug_type(mbhc);
-	wcd9xxx_unlock_sleep(core);
+	wcd9xxx_unlock_sleep(core_res);
 }
 
 static bool wcd9xxx_mbhc_fw_validate(const struct firmware *fw)
@@ -2069,22 +2501,29 @@
 }
 
 static u16 wcd9xxx_codec_v_sta_dce(struct wcd9xxx_mbhc *mbhc,
-				   enum meas_type dce, s16 vin_mv)
+				   enum meas_type dce, s16 vin_mv,
+				   bool cs_enable)
 {
 	s16 diff, zero;
 	u32 mb_mv, in;
 	u16 value;
+	s16 dce_z;
 
 	mb_mv = mbhc->mbhc_data.micb_mv;
+	dce_z = mbhc->mbhc_data.dce_z;
 
 	if (mb_mv == 0) {
 		pr_err("%s: Mic Bias voltage is set to zero\n", __func__);
 		return -EINVAL;
 	}
+	if (cs_enable) {
+		mb_mv = VDDIO_MICBIAS_MV;
+		dce_z = mbhc->mbhc_data.dce_nsc_cs_z;
+	}
 
 	if (dce) {
-		diff = (mbhc->mbhc_data.dce_mb) - (mbhc->mbhc_data.dce_z);
-		zero = (mbhc->mbhc_data.dce_z);
+		diff = (mbhc->mbhc_data.dce_mb) - (dce_z);
+		zero = (dce_z);
 	} else {
 		diff = (mbhc->mbhc_data.sta_mb) - (mbhc->mbhc_data.sta_z);
 		zero = (mbhc->mbhc_data.sta_z);
@@ -2111,9 +2550,9 @@
 	plug_type = WCD9XXX_MBHC_CAL_PLUG_TYPE_PTR(mbhc->mbhc_cfg->calibration);
 
 	mbhc->mbhc_data.v_ins_hu[MBHC_V_IDX_CFILT] =
-	    wcd9xxx_codec_v_sta_dce(mbhc, STA, plug_type->v_hs_max);
+	    wcd9xxx_codec_v_sta_dce(mbhc, STA, plug_type->v_hs_max, false);
 	mbhc->mbhc_data.v_ins_h[MBHC_V_IDX_CFILT] =
-	    wcd9xxx_codec_v_sta_dce(mbhc, DCE, plug_type->v_hs_max);
+	    wcd9xxx_codec_v_sta_dce(mbhc, DCE, plug_type->v_hs_max, false);
 
 	mbhc->mbhc_data.v_inval_ins_low = FAKE_INS_LOW;
 	mbhc->mbhc_data.v_inval_ins_high = FAKE_INS_HIGH;
@@ -2122,9 +2561,9 @@
 		adj_v_hs_max = scale_v_micb_vddio(mbhc, plug_type->v_hs_max,
 						  true);
 		mbhc->mbhc_data.v_ins_hu[MBHC_V_IDX_VDDIO] =
-		    wcd9xxx_codec_v_sta_dce(mbhc, STA, adj_v_hs_max);
+		    wcd9xxx_codec_v_sta_dce(mbhc, STA, adj_v_hs_max, false);
 		mbhc->mbhc_data.v_ins_h[MBHC_V_IDX_VDDIO] =
-		    wcd9xxx_codec_v_sta_dce(mbhc, DCE, adj_v_hs_max);
+		    wcd9xxx_codec_v_sta_dce(mbhc, DCE, adj_v_hs_max, false);
 		mbhc->mbhc_data.v_inval_ins_low =
 		    scale_v_micb_vddio(mbhc, mbhc->mbhc_data.v_inval_ins_low,
 				       false);
@@ -2132,6 +2571,11 @@
 		    scale_v_micb_vddio(mbhc, mbhc->mbhc_data.v_inval_ins_high,
 				       false);
 	}
+	mbhc->mbhc_data.v_cs_ins_h = wcd9xxx_codec_v_sta_dce(mbhc, DCE,
+							WCD9XXX_V_CS_HS_MAX,
+							true);
+	pr_debug("%s: v_ins_h for current source: 0x%x\n", __func__,
+		  mbhc->mbhc_data.v_cs_ins_h);
 
 	btn_high = wcd9xxx_mbhc_cal_btn_det_mp(btn_det,
 					       MBHC_BTN_DET_V_BTN_HIGH);
@@ -2146,13 +2590,17 @@
 	    scale_v_micb_vddio(mbhc, btn_mv_dce[MBHC_V_IDX_CFILT], true);
 
 	mbhc->mbhc_data.v_b1_hu[MBHC_V_IDX_CFILT] =
-	    wcd9xxx_codec_v_sta_dce(mbhc, STA, btn_mv_sta[MBHC_V_IDX_CFILT]);
+	    wcd9xxx_codec_v_sta_dce(mbhc, STA, btn_mv_sta[MBHC_V_IDX_CFILT],
+				    false);
 	mbhc->mbhc_data.v_b1_h[MBHC_V_IDX_CFILT] =
-	    wcd9xxx_codec_v_sta_dce(mbhc, DCE, btn_mv_dce[MBHC_V_IDX_CFILT]);
+	    wcd9xxx_codec_v_sta_dce(mbhc, DCE, btn_mv_dce[MBHC_V_IDX_CFILT],
+				    false);
 	mbhc->mbhc_data.v_b1_hu[MBHC_V_IDX_VDDIO] =
-	    wcd9xxx_codec_v_sta_dce(mbhc, STA, btn_mv_sta[MBHC_V_IDX_VDDIO]);
+	    wcd9xxx_codec_v_sta_dce(mbhc, STA, btn_mv_sta[MBHC_V_IDX_VDDIO],
+				    false);
 	mbhc->mbhc_data.v_b1_h[MBHC_V_IDX_VDDIO] =
-	    wcd9xxx_codec_v_sta_dce(mbhc, DCE, btn_mv_dce[MBHC_V_IDX_VDDIO]);
+	    wcd9xxx_codec_v_sta_dce(mbhc, DCE, btn_mv_dce[MBHC_V_IDX_VDDIO],
+				    false);
 
 	mbhc->mbhc_data.v_brh[MBHC_V_IDX_CFILT] =
 	    mbhc->mbhc_data.v_b1_h[MBHC_V_IDX_CFILT];
@@ -2162,7 +2610,7 @@
 	mbhc->mbhc_data.v_brl = BUTTON_MIN;
 
 	mbhc->mbhc_data.v_no_mic =
-	    wcd9xxx_codec_v_sta_dce(mbhc, STA, plug_type->v_no_mic);
+	    wcd9xxx_codec_v_sta_dce(mbhc, STA, plug_type->v_no_mic, false);
 	pr_debug("%s: leave\n", __func__);
 }
 
@@ -2176,6 +2624,16 @@
 	 mbhc->mbhc_cfg->mclk_cb_fn(mbhc->codec, on, false);
 }
 
+/*
+ * Mic Bias Enable Decision
+ * Return true if high_hph_cnt is a power of 2 (!= 2)
+ * otherwise return false
+ */
+static bool wcd9xxx_mbhc_enable_mb_decision(int high_hph_cnt)
+{
+	return (high_hph_cnt > 2) && !(high_hph_cnt & (high_hph_cnt - 1));
+}
+
 static void wcd9xxx_correct_swch_plug(struct work_struct *work)
 {
 	struct wcd9xxx_mbhc *mbhc;
@@ -2183,13 +2641,17 @@
 	enum wcd9xxx_mbhc_plug_type plug_type = PLUG_TYPE_INVALID;
 	unsigned long timeout;
 	int retry = 0, pt_gnd_mic_swap_cnt = 0;
+	int highhph_cnt = 0;
 	bool correction = false;
-	bool wrk_complete = true;
+	bool current_source_enable;
+	bool wrk_complete = true, highhph = false;
 
 	pr_debug("%s: enter\n", __func__);
 
 	mbhc = container_of(work, struct wcd9xxx_mbhc, correct_plug_swch);
 	codec = mbhc->codec;
+	current_source_enable = ((mbhc->mbhc_cfg->cs_enable_flags &
+				  (1 << MBHC_CS_ENABLE_POLLING)) != 0);
 
 	wcd9xxx_onoff_ext_mclk(mbhc, true);
 
@@ -2203,7 +2665,11 @@
 	 * DAPM doesn't use any MBHC block as this work only runs with
 	 * headphone detection.
 	 */
-	wcd9xxx_turn_onoff_override(codec, true);
+	if (current_source_enable)
+		wcd9xxx_turn_onoff_current_source(mbhc, true,
+						  false);
+	else
+		wcd9xxx_turn_onoff_override(mbhc, true);
 
 	timeout = jiffies + msecs_to_jiffies(HS_DETECT_PLUG_TIME_MS);
 	while (!time_after(jiffies, timeout)) {
@@ -2224,11 +2690,20 @@
 
 		/* can race with removal interrupt */
 		WCD9XXX_BCL_LOCK(mbhc->resmgr);
-		plug_type = wcd9xxx_codec_get_plug_type(mbhc, true);
+		if (current_source_enable)
+			plug_type = wcd9xxx_codec_cs_get_plug_type(mbhc,
+								   highhph);
+		else
+			plug_type = wcd9xxx_codec_get_plug_type(mbhc, true);
 		WCD9XXX_BCL_UNLOCK(mbhc->resmgr);
 
 		pr_debug("%s: attempt(%d) current_plug(%d) new_plug(%d)\n",
 			 __func__, retry, mbhc->current_plug, plug_type);
+
+		highhph_cnt = (plug_type == PLUG_TYPE_HIGH_HPH) ?
+					(highhph_cnt + 1) :
+					0;
+		highhph = wcd9xxx_mbhc_enable_mb_decision(highhph_cnt);
 		if (plug_type == PLUG_TYPE_INVALID) {
 			pr_debug("Invalid plug in attempt # %d\n", retry);
 			if (!mbhc->mbhc_cfg->detect_extn_cable &&
@@ -2274,8 +2749,12 @@
 				pt_gnd_mic_swap_cnt = 0;
 
 			WCD9XXX_BCL_LOCK(mbhc->resmgr);
-			/* Turn off override */
-			wcd9xxx_turn_onoff_override(codec, false);
+			/* Turn off override/current source */
+			if (current_source_enable)
+				wcd9xxx_turn_onoff_current_source(mbhc, false,
+								  false);
+			else
+				wcd9xxx_turn_onoff_override(mbhc, false);
 			/*
 			 * The valid plug also includes PLUG_TYPE_GND_MIC_SWAP
 			 */
@@ -2288,16 +2767,20 @@
 		}
 	}
 
-	if (plug_type == PLUG_TYPE_HIGH_HPH) {
+	highhph = false;
+	if (wrk_complete && plug_type == PLUG_TYPE_HIGH_HPH) {
 		pr_debug("%s: polling is done, still HPH, so enabling MIC trigger\n",
 			 __func__);
 		WCD9XXX_BCL_LOCK(mbhc->resmgr);
 		wcd9xxx_find_plug_and_report(mbhc, plug_type);
+		highhph = true;
 		WCD9XXX_BCL_UNLOCK(mbhc->resmgr);
 	}
-	/* Turn off override */
-	if (!correction)
-		wcd9xxx_turn_onoff_override(codec, false);
+
+	if (!correction && current_source_enable)
+		wcd9xxx_turn_onoff_current_source(mbhc, false, highhph);
+	else if (!correction)
+		wcd9xxx_turn_onoff_override(mbhc, false);
 
 	wcd9xxx_onoff_ext_mclk(mbhc, false);
 
@@ -2316,7 +2799,7 @@
 	}
 	pr_debug("%s: leave current_plug(%d)\n", __func__, mbhc->current_plug);
 	/* unlock sleep */
-	wcd9xxx_unlock_sleep(mbhc->resmgr->core);
+	wcd9xxx_unlock_sleep(mbhc->resmgr->core_res);
 }
 
 static void wcd9xxx_swch_irq_handler(struct wcd9xxx_mbhc *mbhc)
@@ -2396,7 +2879,7 @@
 			snd_soc_update_bits(codec, WCD9XXX_A_CDC_MBHC_CLK_CTL,
 					    0x08, 0x00);
 			/* Turn off override */
-			wcd9xxx_turn_onoff_override(codec, false);
+			wcd9xxx_turn_onoff_override(mbhc, false);
 		}
 	}
 
@@ -2411,25 +2894,24 @@
 	struct wcd9xxx_mbhc *mbhc = data;
 
 	pr_debug("%s: enter\n", __func__);
-	if (unlikely(wcd9xxx_lock_sleep(mbhc->resmgr->core) == false)) {
+	if (unlikely(wcd9xxx_lock_sleep(mbhc->resmgr->core_res) == false)) {
 		pr_warn("%s: failed to hold suspend\n", __func__);
 		r = IRQ_NONE;
 	} else {
 		/* Call handler */
 		wcd9xxx_swch_irq_handler(mbhc);
-		wcd9xxx_unlock_sleep(mbhc->resmgr->core);
+		wcd9xxx_unlock_sleep(mbhc->resmgr->core_res);
 	}
 
 	pr_debug("%s: leave %d\n", __func__, r);
 	return r;
 }
 
-static int wcd9xxx_is_fake_press(struct wcd9xxx_mbhc *mbhc)
+static int wcd9xxx_is_false_press(struct wcd9xxx_mbhc *mbhc)
 {
-	int i;
 	s16 mb_v;
+	int i = 0;
 	int r = 0;
-	const int dces = NUM_DCE_PLUG_DETECT;
 	const s16 v_ins_hu =
 	    wcd9xxx_get_current_v(mbhc, WCD9XXX_CURRENT_V_INS_HU);
 	const s16 v_ins_h =
@@ -2438,9 +2920,16 @@
 	    wcd9xxx_get_current_v(mbhc, WCD9XXX_CURRENT_V_B1_HU);
 	const s16 v_b1_h =
 	    wcd9xxx_get_current_v(mbhc, WCD9XXX_CURRENT_V_B1_H);
+	const unsigned long timeout =
+	    jiffies + msecs_to_jiffies(BTN_RELEASE_DEBOUNCE_TIME_MS);
 
-	for (i = 0; i < dces; i++) {
-		usleep_range(10000, 10000);
+	while (time_before(jiffies, timeout)) {
+		/*
+		 * This function needs to run measurements just few times during
+		 * release debounce time.  Make 1ms interval to avoid
+		 * unnecessary excessive measurements.
+		 */
+		usleep_range(1000, 1000 + WCD9XXX_USLEEP_RANGE_MARGIN_US);
 		if (i == 0) {
 			mb_v = wcd9xxx_codec_sta_dce(mbhc, 0, true);
 			pr_debug("%s: STA[0]: %d,%d\n", __func__, mb_v,
@@ -2458,6 +2947,7 @@
 				break;
 			}
 		}
+		i++;
 	}
 
 	return r;
@@ -2523,9 +3013,10 @@
 	return mask;
 }
 
-void wcd9xxx_get_z(struct wcd9xxx_mbhc *mbhc, s16 *dce_z, s16 *sta_z)
+static void wcd9xxx_get_z(struct wcd9xxx_mbhc *mbhc, s16 *dce_z, s16 *sta_z)
 {
 	s16 reg0, reg1;
+	int change;
 	struct snd_soc_codec *codec = mbhc->codec;
 
 	WCD9XXX_BCL_ASSERT_LOCKED(mbhc->resmgr);
@@ -2536,18 +3027,41 @@
 	snd_soc_update_bits(codec, mbhc->mbhc_bias_regs.mbhc_reg, 1 << 7, 0);
 
 	/* Disconnect override from micbias */
-	snd_soc_update_bits(codec, WCD9XXX_A_MAD_ANA_CTRL, 1 << 4, 1 << 0);
+	change = snd_soc_update_bits(codec, WCD9XXX_A_MAD_ANA_CTRL, 1 << 4,
+				     1 << 0);
 	usleep_range(1000, 1000 + 1000);
-	*sta_z = wcd9xxx_codec_sta_dce(mbhc, 0, false);
-	*dce_z = wcd9xxx_codec_sta_dce(mbhc, 1, false);
+	if (sta_z)
+		*sta_z = wcd9xxx_codec_sta_dce(mbhc, 0, false);
+	if (dce_z)
+		*dce_z = wcd9xxx_codec_sta_dce(mbhc, 1, false);
+
+	pr_debug("%s: sta_z 0x%x, dce_z 0x%x\n", __func__, *sta_z & 0xFFFF,
+		 *dce_z & 0xFFFF);
 
 	/* Connect override from micbias */
-	snd_soc_update_bits(codec, WCD9XXX_A_MAD_ANA_CTRL, 1 << 4, 1 << 4);
+	if (change)
+		snd_soc_update_bits(codec, WCD9XXX_A_MAD_ANA_CTRL, 1 << 4,
+				    1 << 4);
 	/* Disable pull down micbias to ground */
 	snd_soc_write(codec, mbhc->mbhc_bias_regs.mbhc_reg, reg1);
 	snd_soc_write(codec, mbhc->mbhc_bias_regs.ctl_reg, reg0);
 }
 
+void wcd9xxx_update_z(struct wcd9xxx_mbhc *mbhc)
+{
+	const u16 sta_z = mbhc->mbhc_data.sta_z;
+	const u16 dce_z = mbhc->mbhc_data.dce_z;
+
+	wcd9xxx_get_z(mbhc, &mbhc->mbhc_data.dce_z, &mbhc->mbhc_data.sta_z);
+	pr_debug("%s: sta_z 0x%x,dce_z 0x%x -> sta_z 0x%x,dce_z 0x%x\n",
+		 __func__, sta_z & 0xFFFF, dce_z & 0xFFFF,
+		 mbhc->mbhc_data.sta_z & 0xFFFF,
+		 mbhc->mbhc_data.dce_z & 0xFFFF);
+
+	wcd9xxx_mbhc_calc_thres(mbhc);
+	wcd9xxx_calibrate_hs_polling(mbhc);
+}
+
 /*
  * wcd9xxx_update_rel_threshold : update mbhc release upper bound threshold
  *				  to ceilmv + buffer
@@ -2565,11 +3079,11 @@
 	pr_debug("%s: reprogram vb1hu/vbrh to %dmv\n", __func__, mv);
 
 	/* update LSB first so mbhc hardware block doesn't see too low value */
-	v_b1_hu = wcd9xxx_codec_v_sta_dce(mbhc, STA, mv);
+	v_b1_hu = wcd9xxx_codec_v_sta_dce(mbhc, STA, mv, false);
 	snd_soc_write(codec, WCD9XXX_A_CDC_MBHC_VOLT_B3_CTL, v_b1_hu & 0xFF);
 	snd_soc_write(codec, WCD9XXX_A_CDC_MBHC_VOLT_B4_CTL,
 		      (v_b1_hu >> 8) & 0xFF);
-	v_brh = wcd9xxx_codec_v_sta_dce(mbhc, DCE, mv);
+	v_brh = wcd9xxx_codec_v_sta_dce(mbhc, DCE, mv, false);
 	snd_soc_write(codec, WCD9XXX_A_CDC_MBHC_VOLT_B9_CTL, v_brh & 0xFF);
 	snd_soc_write(codec, WCD9XXX_A_CDC_MBHC_VOLT_B10_CTL,
 		      (v_brh >> 8) & 0xFF);
@@ -2593,7 +3107,7 @@
 	short dce[d->n_btn_meas + 1], sta;
 	s32 mv[d->n_btn_meas + 1], mv_s[d->n_btn_meas + 1];
 	struct snd_soc_codec *codec = mbhc->codec;
-	struct wcd9xxx *core = mbhc->resmgr->core;
+	struct wcd9xxx_core_resource *core_res = mbhc->resmgr->core_res;
 	int n_btn_meas = d->n_btn_meas;
 	void *calibration = mbhc->mbhc_cfg->calibration;
 
@@ -2628,6 +3142,9 @@
 	vddio = (mbhc->mbhc_data.micb_mv != VDDIO_MICBIAS_MV &&
 		 mbhc->mbhc_micbias_switched);
 
+	dce_z = mbhc->mbhc_data.dce_z;
+	sta_z = mbhc->mbhc_data.sta_z;
+
 	/* Measure scaled HW STA */
 	dce[0] = wcd9xxx_read_dce_result(codec);
 	sta = wcd9xxx_read_sta_result(codec);
@@ -2640,15 +3157,19 @@
 		} else {
 			pr_debug("%s: Button is released without resume",
 				 __func__);
-			wcd9xxx_get_z(mbhc, &dce_z, &sta_z);
-			stamv = __wcd9xxx_codec_sta_dce_v(mbhc, 0, sta, sta_z);
+			if (mbhc->update_z) {
+				wcd9xxx_update_z(mbhc);
+				mbhc->update_z = false;
+			}
+			stamv = __wcd9xxx_codec_sta_dce_v(mbhc, 0, sta, sta_z,
+						mbhc->mbhc_data.micb_mv);
 			if (vddio)
 				stamv_s = scale_v_micb_vddio(mbhc, stamv,
 							     false);
 			else
 				stamv_s = stamv;
 			mv[0] = __wcd9xxx_codec_sta_dce_v(mbhc, 1, dce[0],
-							  dce_z);
+					  dce_z, mbhc->mbhc_data.micb_mv);
 			mv_s[0] = vddio ? scale_v_micb_vddio(mbhc, mv[0],
 							     false) : mv[0];
 			btn = wcd9xxx_determine_button(mbhc, mv_s[0]);
@@ -2662,9 +3183,13 @@
 	     meas++)
 		dce[meas] = wcd9xxx_codec_sta_dce(mbhc, 1, false);
 
-	wcd9xxx_get_z(mbhc, &dce_z, &sta_z);
+	if (mbhc->update_z) {
+		wcd9xxx_update_z(mbhc);
+		mbhc->update_z = false;
+	}
 
-	stamv = __wcd9xxx_codec_sta_dce_v(mbhc, 0, sta, sta_z);
+	stamv = __wcd9xxx_codec_sta_dce_v(mbhc, 0, sta, sta_z,
+					  mbhc->mbhc_data.micb_mv);
 	if (vddio)
 		stamv_s = scale_v_micb_vddio(mbhc, stamv, false);
 	else
@@ -2673,7 +3198,8 @@
 		 sta & 0xFFFF, stamv, stamv_s);
 
 	/* determine pressed button */
-	mv[0] = __wcd9xxx_codec_sta_dce_v(mbhc, 1, dce[0], dce_z);
+	mv[0] = __wcd9xxx_codec_sta_dce_v(mbhc, 1, dce[0], dce_z,
+					  mbhc->mbhc_data.micb_mv);
 	mv_s[0] = vddio ? scale_v_micb_vddio(mbhc, mv[0], false) : mv[0];
 	btnmeas[0] = wcd9xxx_determine_button(mbhc, mv_s[0]);
 	pr_debug("%s: Meas HW - DCE 0x%x,%d,%d button %d\n", __func__,
@@ -2682,7 +3208,8 @@
 		btn = btnmeas[0];
 	for (meas = 1; (n_btn_meas && d->n_btn_meas &&
 			(meas < (d->n_btn_meas + 1))); meas++) {
-		mv[meas] = __wcd9xxx_codec_sta_dce_v(mbhc, 1, dce[meas], dce_z);
+		mv[meas] = __wcd9xxx_codec_sta_dce_v(mbhc, 1, dce[meas], dce_z,
+						     mbhc->mbhc_data.micb_mv);
 		mv_s[meas] = vddio ? scale_v_micb_vddio(mbhc, mv[meas], false) :
 				     mv[meas];
 		btnmeas[meas] = wcd9xxx_determine_button(mbhc, mv_s[meas]);
@@ -2729,11 +3256,11 @@
 
 		mask = wcd9xxx_get_button_mask(btn);
 		mbhc->buttons_pressed |= mask;
-		wcd9xxx_lock_sleep(core);
+		wcd9xxx_lock_sleep(core_res);
 		if (schedule_delayed_work(&mbhc->mbhc_btn_dwork,
 					  msecs_to_jiffies(400)) == 0) {
 			WARN(1, "Button pressed twice without release event\n");
-			wcd9xxx_unlock_sleep(core);
+			wcd9xxx_unlock_sleep(core_res);
 		}
 	} else {
 		pr_debug("%s: bogus button press, too short press?\n",
@@ -2749,6 +3276,7 @@
 static irqreturn_t wcd9xxx_release_handler(int irq, void *data)
 {
 	int ret;
+	bool waitdebounce = true;
 	struct wcd9xxx_mbhc *mbhc = data;
 
 	pr_debug("%s: enter\n", __func__);
@@ -2763,7 +3291,7 @@
 			wcd9xxx_jack_report(mbhc, &mbhc->button_jack, 0,
 					    mbhc->buttons_pressed);
 		} else {
-			if (wcd9xxx_is_fake_press(mbhc)) {
+			if (wcd9xxx_is_false_press(mbhc)) {
 				pr_debug("%s: Fake button press interrupt\n",
 					 __func__);
 			} else {
@@ -2782,6 +3310,7 @@
 					wcd9xxx_jack_report(mbhc,
 						      &mbhc->button_jack,
 						      0, mbhc->buttons_pressed);
+					waitdebounce = false;
 				}
 			}
 		}
@@ -2791,7 +3320,8 @@
 
 	wcd9xxx_calibrate_hs_polling(mbhc);
 
-	msleep(SWCH_REL_DEBOUNCE_TIME_MS);
+	if (waitdebounce)
+		msleep(SWCH_REL_DEBOUNCE_TIME_MS);
 	wcd9xxx_start_hs_polling(mbhc);
 
 	pr_debug("%s: leave\n", __func__);
@@ -2817,7 +3347,7 @@
 			snd_soc_update_bits(codec, WCD9XXX_A_RX_HPH_OCP_CTL,
 					    0x10, 0x10);
 		} else {
-			wcd9xxx_disable_irq(codec->control_data,
+			wcd9xxx_disable_irq(mbhc->resmgr->core_res,
 					  WCD9XXX_IRQ_HPH_PA_OCPL_FAULT);
 			mbhc->hph_status |= SND_JACK_OC_HPHL;
 			wcd9xxx_jack_report(mbhc, &mbhc->headset_jack,
@@ -2847,7 +3377,7 @@
 		snd_soc_update_bits(codec, WCD9XXX_A_RX_HPH_OCP_CTL, 0x10,
 				    0x10);
 	} else {
-		wcd9xxx_disable_irq(mbhc->resmgr->core,
+		wcd9xxx_disable_irq(mbhc->resmgr->core_res,
 				    WCD9XXX_IRQ_HPH_PA_OCPR_FAULT);
 		mbhc->hph_status |= SND_JACK_OC_HPHR;
 		wcd9xxx_jack_report(mbhc, &mbhc->headset_jack,
@@ -2924,11 +3454,11 @@
 static void wcd9xxx_mbhc_cal(struct wcd9xxx_mbhc *mbhc)
 {
 	u8 cfilt_mode;
-	u16 reg0, reg1;
+	u16 reg0, reg1, reg2;
 	struct snd_soc_codec *codec = mbhc->codec;
 
 	pr_debug("%s: enter\n", __func__);
-	wcd9xxx_disable_irq(codec->control_data, WCD9XXX_IRQ_MBHC_POTENTIAL);
+	wcd9xxx_disable_irq(mbhc->resmgr->core_res, WCD9XXX_IRQ_MBHC_POTENTIAL);
 	wcd9xxx_turn_onoff_rel_detection(codec, false);
 
 	/* t_dce and t_sta are updated by wcd9xxx_update_mbhc_clk_rate() */
@@ -2939,7 +3469,13 @@
 	 * LDOH and CFILT are already configured during pdata handling.
 	 * Only need to make sure CFILT and bandgap are in Fast mode.
 	 * Need to restore defaults once calculation is done.
+	 *
+	 * In case when Micbias is powered by external source, request
+	 * turn on the external voltage source for Calibration.
 	 */
+	if (mbhc->mbhc_cb && mbhc->mbhc_cb->enable_mb_source)
+		mbhc->mbhc_cb->enable_mb_source(codec, true);
+
 	cfilt_mode = snd_soc_read(codec, mbhc->mbhc_bias_regs.cfilt_ctl);
 	if (mbhc->mbhc_cb && mbhc->mbhc_cb->cfilt_fast_mode)
 		mbhc->mbhc_cb->cfilt_fast_mode(codec, mbhc);
@@ -2987,10 +3523,26 @@
 	snd_soc_write(codec, WCD9XXX_A_CDC_MBHC_CLK_CTL, 0x0A);
 	snd_soc_write(codec, WCD9XXX_A_CDC_MBHC_CLK_CTL, 0x02);
 	mbhc->mbhc_data.dce_z = __wcd9xxx_codec_sta_dce(mbhc, 1, true, false);
+
+	/* compute dce_z for current source */
+	reg2 = snd_soc_read(codec, WCD9XXX_A_CDC_MBHC_B1_CTL);
+	snd_soc_update_bits(codec, WCD9XXX_A_CDC_MBHC_B1_CTL, 0x78,
+			    WCD9XXX_MBHC_NSC_CS << 3);
+
+	snd_soc_write(codec, WCD9XXX_A_CDC_MBHC_CLK_CTL, 0x0A);
+	snd_soc_write(codec, WCD9XXX_A_CDC_MBHC_CLK_CTL, 0x02);
+	mbhc->mbhc_data.dce_nsc_cs_z = __wcd9xxx_codec_sta_dce(mbhc, 1, true,
+							       false);
+	pr_debug("%s: dce_z with nsc cs: 0x%x\n", __func__,
+						 mbhc->mbhc_data.dce_nsc_cs_z);
+
+	snd_soc_write(codec, WCD9XXX_A_CDC_MBHC_B1_CTL, reg2);
+
 	/* STA measurement for 0 voltage */
 	snd_soc_write(codec, WCD9XXX_A_CDC_MBHC_CLK_CTL, 0x0A);
 	snd_soc_write(codec, WCD9XXX_A_CDC_MBHC_CLK_CTL, 0x02);
 	mbhc->mbhc_data.sta_z = __wcd9xxx_codec_sta_dce(mbhc, 0, true, false);
+
 	/* Restore registers */
 	snd_soc_write(codec, mbhc->mbhc_bias_regs.ctl_reg, reg0);
 	snd_soc_write(codec, WCD9XXX_A_MAD_ANA_CTRL, reg1);
@@ -3043,7 +3595,10 @@
 				    0x80, 0x80);
 	usleep_range(100, 100);
 
-	wcd9xxx_enable_irq(codec->control_data, WCD9XXX_IRQ_MBHC_POTENTIAL);
+	if (mbhc->mbhc_cb && mbhc->mbhc_cb->enable_mb_source)
+		mbhc->mbhc_cb->enable_mb_source(codec, false);
+
+	wcd9xxx_enable_irq(mbhc->resmgr->core_res, WCD9XXX_IRQ_MBHC_POTENTIAL);
 	wcd9xxx_turn_onoff_rel_detection(codec, true);
 
 	pr_debug("%s: leave\n", __func__);
@@ -3086,9 +3641,14 @@
 	snd_soc_update_bits(codec, WCD9XXX_A_CDC_MBHC_B1_CTL, 0x78,
 			    btn_det->mbhc_nsc << 3);
 
-	if (mbhc->resmgr->reg_addr->micb_4_mbhc)
-		snd_soc_update_bits(codec, mbhc->resmgr->reg_addr->micb_4_mbhc,
-				    0x03, MBHC_MICBIAS2);
+	if (mbhc->mbhc_cb &&
+			mbhc->mbhc_cb->get_cdc_type() !=
+					WCD9XXX_CDC_TYPE_HELICON) {
+		if (mbhc->resmgr->reg_addr->micb_4_mbhc)
+			snd_soc_update_bits(codec,
+					mbhc->resmgr->reg_addr->micb_4_mbhc,
+					0x03, MBHC_MICBIAS2);
+	}
 
 	snd_soc_update_bits(codec, WCD9XXX_A_CDC_MBHC_B1_CTL, 0x02, 0x02);
 
@@ -3104,8 +3664,8 @@
 static int wcd9xxx_setup_jack_detect_irq(struct wcd9xxx_mbhc *mbhc)
 {
 	int ret = 0;
-	void *core = mbhc->resmgr->core;
 	struct snd_soc_codec *codec = mbhc->codec;
+	void *core_res = mbhc->resmgr->core_res;
 	int jack_irq;
 
 	if (mbhc->mbhc_cb && mbhc->mbhc_cb->jack_detect_irq)
@@ -3134,7 +3694,7 @@
 		snd_soc_update_bits(mbhc->codec, WCD9XXX_A_RX_HPH_OCP_CTL,
 				    1 << 1, 1 << 1);
 
-		ret = wcd9xxx_request_irq(core, jack_irq,
+		ret = wcd9xxx_request_irq(core_res, jack_irq,
 					  wcd9xxx_mech_plug_detect_irq,
 					  "Jack Detect",
 					  mbhc);
@@ -3169,9 +3729,9 @@
 	if (!IS_ERR_VALUE(ret)) {
 		snd_soc_update_bits(codec, WCD9XXX_A_RX_HPH_OCP_CTL, 0x10,
 				    0x10);
-		wcd9xxx_enable_irq(codec->control_data,
+		wcd9xxx_enable_irq(mbhc->resmgr->core_res,
 				   WCD9XXX_IRQ_HPH_PA_OCPL_FAULT);
-		wcd9xxx_enable_irq(codec->control_data,
+		wcd9xxx_enable_irq(mbhc->resmgr->core_res,
 				   WCD9XXX_IRQ_HPH_PA_OCPR_FAULT);
 
 		/* Initialize mechanical mbhc */
@@ -3262,6 +3822,11 @@
 		      p->dce_z, wcd9xxx_codec_sta_dce_v(mbhc, 1, p->dce_z));
 	n += scnprintf(buffer + n, size - n, "dce_mb = %x(%dmv)\n",
 		       p->dce_mb, wcd9xxx_codec_sta_dce_v(mbhc, 1, p->dce_mb));
+	n += scnprintf(buffer + n, size - n, "dce_nsc_cs_z = %x(%dmv)\n",
+		      p->dce_nsc_cs_z,
+		      __wcd9xxx_codec_sta_dce_v(mbhc, 1, p->dce_nsc_cs_z,
+						p->dce_nsc_cs_z,
+						VDDIO_MICBIAS_MV));
 	n += scnprintf(buffer + n, size - n, "sta_z = %x(%dmv)\n",
 		       p->sta_z, wcd9xxx_codec_sta_dce_v(mbhc, 0, p->sta_z));
 	n += scnprintf(buffer + n, size - n, "sta_mb = %x(%dmv)\n",
@@ -3392,16 +3957,52 @@
 		snd_soc_update_bits(codec, mbhc->mbhc_bias_regs.cfilt_ctl,
 		0x40, WCD9XXX_CFILT_FAST_MODE);
 
-	if (!mbhc->mbhc_cfg->read_fw_bin)
+	/*
+	 * setup internal micbias if codec uses internal micbias for
+	 * headset detection
+	 */
+	if (mbhc->mbhc_cfg->use_int_rbias) {
+		if (mbhc->mbhc_cb && mbhc->mbhc_cb->setup_int_rbias)
+			mbhc->mbhc_cb->setup_int_rbias(codec, true);
+		else
+			pr_info("%s: internal bias is requested but codec did not provide callback\n",
+				__func__);
+	}
+
+	/*
+	 * If codec has specific clock gating for MBHC,
+	 * remove the clock gate
+	 */
+	if (mbhc->mbhc_cb &&
+			mbhc->mbhc_cb->enable_clock_gate)
+		mbhc->mbhc_cb->enable_clock_gate(mbhc->codec, true);
+
+	if (!mbhc->mbhc_cfg->read_fw_bin ||
+	    (mbhc->mbhc_cfg->read_fw_bin && mbhc->mbhc_fw)) {
 		rc = wcd9xxx_init_and_calibrate(mbhc);
-	else
-		schedule_delayed_work(&mbhc->mbhc_firmware_dwork,
-				      usecs_to_jiffies(FW_READ_TIMEOUT));
+	} else {
+		if (!mbhc->mbhc_fw)
+			schedule_delayed_work(&mbhc->mbhc_firmware_dwork,
+					     usecs_to_jiffies(FW_READ_TIMEOUT));
+		else
+			pr_debug("%s: Skipping to read mbhc fw, 0x%p\n",
+				 __func__, mbhc->mbhc_fw);
+	}
 
 	pr_debug("%s: leave %d\n", __func__, rc);
 	return rc;
 }
-EXPORT_SYMBOL_GPL(wcd9xxx_mbhc_start);
+EXPORT_SYMBOL(wcd9xxx_mbhc_start);
+
+void wcd9xxx_mbhc_stop(struct wcd9xxx_mbhc *mbhc)
+{
+	if (mbhc->mbhc_fw) {
+		cancel_delayed_work_sync(&mbhc->mbhc_firmware_dwork);
+		release_firmware(mbhc->mbhc_fw);
+		mbhc->mbhc_fw = NULL;
+	}
+}
+EXPORT_SYMBOL(wcd9xxx_mbhc_stop);
 
 static enum wcd9xxx_micbias_num
 wcd9xxx_event_to_micbias(const enum wcd9xxx_notify_event event)
@@ -3493,6 +4094,15 @@
 	return cfilt;
 }
 
+static void wcd9xxx_enable_mbhc_txfe(struct wcd9xxx_mbhc *mbhc, bool on)
+{
+	if (mbhc->mbhc_cb && mbhc->mbhc_cb->enable_mbhc_txfe)
+		mbhc->mbhc_cb->enable_mbhc_txfe(mbhc->codec, on);
+	else
+		snd_soc_update_bits(mbhc->codec, WCD9XXX_A_TX_7_MBHC_TEST_CTL,
+				    0x40, on ? 0x40 : 0x00);
+}
+
 static int wcd9xxx_event_notify(struct notifier_block *self, unsigned long val,
 				void *data)
 {
@@ -3510,14 +4120,22 @@
 	case WCD9XXX_EVENT_PRE_MICBIAS_2_ON:
 	case WCD9XXX_EVENT_PRE_MICBIAS_3_ON:
 	case WCD9XXX_EVENT_PRE_MICBIAS_4_ON:
-		if (mbhc->mbhc_cfg->micbias == wcd9xxx_event_to_micbias(event))
+		if (mbhc->mbhc_cfg && mbhc->mbhc_cfg->micbias ==
+		    wcd9xxx_event_to_micbias(event)) {
 			wcd9xxx_switch_micbias(mbhc, 0);
+			/*
+			 * Enable MBHC TxFE whenever  micbias is
+			 * turned ON and polling is active
+			 */
+			if (mbhc->polling_active)
+				wcd9xxx_enable_mbhc_txfe(mbhc, true);
+		}
 		break;
 	case WCD9XXX_EVENT_POST_MICBIAS_1_ON:
 	case WCD9XXX_EVENT_POST_MICBIAS_2_ON:
 	case WCD9XXX_EVENT_POST_MICBIAS_3_ON:
 	case WCD9XXX_EVENT_POST_MICBIAS_4_ON:
-		if (mbhc->mbhc_cfg->micbias ==
+		if (mbhc->mbhc_cfg && mbhc->mbhc_cfg->micbias ==
 		    wcd9xxx_event_to_micbias(event) &&
 		    wcd9xxx_mbhc_polling(mbhc)) {
 			/* if polling is on, restart it */
@@ -3529,11 +4147,17 @@
 	case WCD9XXX_EVENT_POST_MICBIAS_2_OFF:
 	case WCD9XXX_EVENT_POST_MICBIAS_3_OFF:
 	case WCD9XXX_EVENT_POST_MICBIAS_4_OFF:
-		if (mbhc->mbhc_cfg->micbias ==
-		    wcd9xxx_event_to_micbias(event) &&
-		    (mbhc->event_state &
-		     (1 << MBHC_EVENT_PA_HPHL | 1 << MBHC_EVENT_PA_HPHR)))
-			wcd9xxx_switch_micbias(mbhc, 1);
+		if (mbhc->mbhc_cfg && mbhc->mbhc_cfg->micbias ==
+		    wcd9xxx_event_to_micbias(event)) {
+			if (mbhc->event_state &
+			   (1 << MBHC_EVENT_PA_HPHL | 1 << MBHC_EVENT_PA_HPHR))
+				wcd9xxx_switch_micbias(mbhc, 1);
+			/*
+			 * Disable MBHC TxFE, in case it was enabled
+			 * earlier when micbias was enabled.
+			 */
+			wcd9xxx_enable_mbhc_txfe(mbhc, false);
+		}
 		break;
 	/* PA usage change */
 	case WCD9XXX_EVENT_PRE_HPHL_PA_ON:
@@ -3656,107 +4280,6 @@
 	return ret;
 }
 
-static int wcd9xxx_soc_update_bits_push(struct snd_soc_codec *codec,
-					struct list_head *list,
-					uint16_t reg, uint8_t mask,
-					uint8_t value)
-{
-	int rc;
-	struct wcd9xxx_register_save_node *node;
-
-	node = kmalloc(sizeof(*node), GFP_KERNEL);
-	if (unlikely(!node)) {
-		pr_err("%s: Not enough memory\n", __func__);
-		return -ENOMEM;
-	}
-	node->reg = reg;
-	node->value = snd_soc_read(codec, reg);
-	list_add(&node->lh, list);
-	if (mask == 0xFF)
-		rc = snd_soc_write(codec, reg, value);
-	else
-		rc = snd_soc_update_bits(codec, reg, mask, value);
-	return rc;
-}
-
-static int wcd9xxx_prepare_static_pa(struct wcd9xxx_mbhc *mbhc,
-				     struct list_head *lh)
-{
-	int i;
-	struct snd_soc_codec *codec = mbhc->codec;
-
-	const struct wcd9xxx_reg_mask_val reg_set_paon[] = {
-		{WCD9XXX_A_RX_HPH_OCP_CTL, 0x18, 0x00},
-		{WCD9XXX_A_RX_HPH_L_TEST, 0x1, 0x0},
-		{WCD9XXX_A_RX_HPH_R_TEST, 0x1, 0x0},
-		{WCD9XXX_A_RX_HPH_BIAS_WG_OCP, 0xff, 0x1A},
-		{WCD9XXX_A_RX_HPH_CNP_WG_CTL, 0xff, 0xDB},
-		{WCD9XXX_A_RX_HPH_CNP_WG_TIME, 0xff, 0x15},
-		{WCD9XXX_A_CDC_RX1_B6_CTL, 0xff, 0x81},
-		{WCD9XXX_A_CDC_CLK_RX_B1_CTL, 0x01, 0x01},
-		{WCD9XXX_A_RX_HPH_CHOP_CTL, 0xff, 0xA4},
-		{WCD9XXX_A_RX_HPH_L_GAIN, 0xff, 0x2C},
-		{WCD9XXX_A_CDC_RX2_B6_CTL, 0xff, 0x81},
-		{WCD9XXX_A_CDC_CLK_RX_B1_CTL, 0x02, 0x02},
-		{WCD9XXX_A_RX_HPH_R_GAIN, 0xff, 0x2C},
-		{WCD9XXX_A_NCP_CLK, 0xff, 0xFC},
-		{WCD9XXX_A_BUCK_CTRL_CCL_3, 0xff, 0x60},
-		{WCD9XXX_A_RX_COM_BIAS, 0xff, 0x80},
-		{WCD9XXX_A_BUCK_MODE_3, 0xff, 0xC6},
-		{WCD9XXX_A_BUCK_MODE_4, 0xff, 0xE6},
-		{WCD9XXX_A_BUCK_MODE_5, 0xff, 0x02},
-		{WCD9XXX_A_BUCK_MODE_1, 0xff, 0xA1},
-		{WCD9XXX_A_NCP_EN, 0xff, 0xFF},
-		{WCD9XXX_A_BUCK_MODE_5, 0xff, 0x7B},
-		{WCD9XXX_A_CDC_CLSH_B1_CTL, 0xff, 0xE6},
-		{WCD9XXX_A_RX_HPH_L_DAC_CTL, 0xff, 0xC0},
-		{WCD9XXX_A_RX_HPH_R_DAC_CTL, 0xff, 0xC0},
-	};
-
-	for (i = 0; i < ARRAY_SIZE(reg_set_paon); i++)
-		wcd9xxx_soc_update_bits_push(codec, lh,
-					     reg_set_paon[i].reg,
-					     reg_set_paon[i].mask,
-					     reg_set_paon[i].val);
-	pr_debug("%s: PAs are prepared\n", __func__);
-
-	return 0;
-}
-
-static void wcd9xxx_restore_registers(struct wcd9xxx_mbhc *mbhc,
-				      struct list_head *lh)
-{
-	struct wcd9xxx_register_save_node *node, *nodetmp;
-	struct snd_soc_codec *codec = mbhc->codec;
-
-	list_for_each_entry_safe(node, nodetmp, lh, lh) {
-		snd_soc_write(codec, node->reg, node->value);
-		list_del(&node->lh);
-		kfree(node);
-	}
-}
-
-static void wcd9xxx_unprepare_static_pa(struct wcd9xxx_mbhc *mbhc,
-					struct list_head *lh)
-{
-	wcd9xxx_restore_registers(mbhc, lh);
-}
-
-static int wcd9xxx_enable_static_pa(struct wcd9xxx_mbhc *mbhc, bool enable)
-{
-	struct snd_soc_codec *codec = mbhc->codec;
-	const int wg_time = snd_soc_read(codec, WCD9XXX_A_RX_HPH_CNP_WG_TIME) *
-			    WCD9XXX_WG_TIME_FACTOR_US;
-
-	snd_soc_update_bits(codec, WCD9XXX_A_RX_HPH_CNP_EN, 0x30,
-			    enable ? 0x30 : 0x0);
-	/* Wait for wave gen time to avoid pop noise */
-	usleep_range(wg_time, wg_time + WCD9XXX_USLEEP_RANGE_MARGIN_US);
-	pr_debug("%s: PAs are %s as static mode (wg_time %d)\n", __func__,
-		 enable ? "enabled" : "disabled", wg_time);
-	return 0;
-}
-
 static int wcd9xxx_detect_impedance(struct wcd9xxx_mbhc *mbhc, uint32_t *zl,
 				    uint32_t *zr)
 {
@@ -3766,17 +4289,8 @@
 	s16 *z[] = {
 		&l[0], &r[0], &r[1], &l[1], &l[2], &r[2],
 	};
-	LIST_HEAD(lh);
-	LIST_HEAD(lhpa);
 	struct snd_soc_codec *codec = mbhc->codec;
-	const int ramp_wait_us = 18 * 1000;
 	const int mux_wait_us = 25;
-	const int alphal = 364; /* 0.005555 * 65536 = 364.05 */
-	const int alphar = 364; /* 0.005555 * 65536 = 364.05 */
-	const int beta = 3855; /* 0.011765 * 5 * 65536 = 3855.15 */
-	const int rref = 11333; /* not scaled up */
-	const int shift = 16;
-	int64_t rl, rr = 0; /* milliohm */
 	const struct wcd9xxx_reg_mask_val reg_set_mux[] = {
 		/* Phase 1 */
 		/* Set MBHC_MUX for HPHL without ical */
@@ -3797,6 +4311,11 @@
 	pr_debug("%s: enter\n", __func__);
 	WCD9XXX_BCL_ASSERT_LOCKED(mbhc->resmgr);
 
+	if (!mbhc->mbhc_cb || !mbhc->mbhc_cb->setup_zdet ||
+	    !mbhc->mbhc_cb->compute_impedance || !zl ||
+	    !zr)
+		return -EINVAL;
+
 	/*
 	 * Impedance detection is an intrusive function as it mutes RX paths,
 	 * enable PAs and etc.  Therefore codec drvier including ALSA
@@ -3815,127 +4334,66 @@
 	wcd9xxx_resmgr_get_clk_block(mbhc->resmgr, WCD9XXX_CLK_RCO);
 	WCD9XXX_BG_CLK_UNLOCK(mbhc->resmgr);
 
+	wcd9xxx_turn_onoff_override(mbhc, true);
 	pr_debug("%s: Setting impedance detection\n", __func__);
-	wcd9xxx_prepare_static_pa(mbhc, &lhpa);
-	wcd9xxx_enable_static_pa(mbhc, true);
 
-	/*
-	 * save old value of registers and write the new value to restore old
-	 * value back, WCD9XXX_A_CDC_PA_RAMP_B{1,2,3,4}_CTL registers don't
-	 * need to be restored as those are solely used by impedance detection.
-	 */
-#define __w(reg, mask, value)						  \
-	do {								  \
-		ret = wcd9xxx_soc_update_bits_push(codec, &lh, reg, mask, \
-						   value);		  \
-		if (ret < 0)						  \
-			return ret;					  \
-	} while (0)
-
-	/* Reset the PA Ramp */
-	snd_soc_write(codec, WCD9XXX_A_CDC_PA_RAMP_B1_CTL, 0x1C);
-	/*
-	 * Connect the PA Ramp to PA chain and release reset with keep it
-	 * connected.
-	 */
-	snd_soc_write(codec, WCD9XXX_A_CDC_PA_RAMP_B1_CTL, 0x1F);
-	snd_soc_write(codec, WCD9XXX_A_CDC_PA_RAMP_B1_CTL, 0x03);
-	/* Program the PA Ramp to FS_48K, L shift 1 and sample num to 24 */
-	snd_soc_write(codec, WCD9XXX_A_CDC_PA_RAMP_B3_CTL, 0x3 << 4 | 0x6);
-	/* 0x56 for 10mv.  0xC0 is for 50mv */
-	snd_soc_write(codec, WCD9XXX_A_CDC_PA_RAMP_B4_CTL, 0xC0);
-	/* Enable MBHC MUX, Set MUX current to 37.5uA and ADC7 */
-	__w(WCD9XXX_A_MBHC_SCALING_MUX_1, 0xFF, 0xC0);
-	__w(WCD9XXX_A_MBHC_SCALING_MUX_2, 0xFF, 0xF0);
-	__w(WCD9XXX_A_TX_7_MBHC_TEST_CTL, 0xFF, 0x78);
-	__w(WCD9XXX_A_TX_7_MBHC_EN, 0xFF, 0x8C);
-	/* Change NSA and NAVG */
-	__w(WCD9XXX_A_CDC_MBHC_TIMER_B4_CTL, 0x4 << 4, 0x4 << 4);
-	__w(WCD9XXX_A_CDC_MBHC_TIMER_B5_CTL, 0xFF, 0x10);
-	/* Reset MBHC and set it up for STA */
-	__w(WCD9XXX_A_CDC_MBHC_CLK_CTL, 0xFF, 0x0A);
-	__w(WCD9XXX_A_CDC_MBHC_EN_CTL, 0xFF, 0x02);
-	__w(WCD9XXX_A_CDC_MBHC_CLK_CTL, 0xFF, 0x02);
-
-	/* Set HPH_MBHC for zdet */
-	__w(WCD9XXX_A_MBHC_HPH, 0xB3, 0x80);
+	/* Codec specific setup for L0, R0, L1 and R1 measurements */
+	mbhc->mbhc_cb->setup_zdet(mbhc, PRE_MEAS);
 
 	pr_debug("%s: Performing impedance detection\n", __func__);
-	/* Phase 1 */
 	for (i = 0; i < ARRAY_SIZE(reg_set_mux) - 2; i++) {
-		__w(reg_set_mux[i].reg, reg_set_mux[i].mask,
-		    reg_set_mux[i].val);
+		snd_soc_update_bits(codec, reg_set_mux[i].reg,
+				    reg_set_mux[i].mask,
+				    reg_set_mux[i].val);
+		if (mbhc->mbhc_cb && mbhc->mbhc_cb->enable_mux_bias_block)
+			mbhc->mbhc_cb->enable_mux_bias_block(codec);
+		else
+			snd_soc_update_bits(codec,
+					    WCD9XXX_A_MBHC_SCALING_MUX_1,
+					    0x80, 0x80);
 		/* 25us is required after mux change to settle down */
 		usleep_range(mux_wait_us,
 			     mux_wait_us + WCD9XXX_USLEEP_RANGE_MARGIN_US);
-		*(z[i]) = __wcd9xxx_codec_sta_dce(mbhc, 0, false, false);
+		*(z[i]) = __wcd9xxx_codec_sta_dce(mbhc, 0, true, false);
 	}
 
-	/* Phase 2 */
-	/* Start the PA ramp on HPH L and R */
-	snd_soc_write(codec, WCD9XXX_A_CDC_PA_RAMP_B2_CTL, 0x05);
-	/* Ramp generator takes ~17ms */
-	usleep_range(ramp_wait_us,
-		     ramp_wait_us + WCD9XXX_USLEEP_RANGE_MARGIN_US);
+	/* Codec specific setup for L2 and R2 measurements */
+	mbhc->mbhc_cb->setup_zdet(mbhc, POST_MEAS);
 
-	/* Disable Ical */
-	snd_soc_write(codec, WCD9XXX_A_CDC_PA_RAMP_B2_CTL, 0x00);
-	/* Ramp generator takes ~17ms */
-	usleep_range(ramp_wait_us,
-		     ramp_wait_us + WCD9XXX_USLEEP_RANGE_MARGIN_US);
 	for (; i < ARRAY_SIZE(reg_set_mux); i++) {
-		__w(reg_set_mux[i].reg, reg_set_mux[i].mask,
-		    reg_set_mux[i].val);
+		snd_soc_update_bits(codec, reg_set_mux[i].reg,
+				    reg_set_mux[i].mask,
+				    reg_set_mux[i].val);
+		if (mbhc->mbhc_cb && mbhc->mbhc_cb->enable_mux_bias_block)
+			mbhc->mbhc_cb->enable_mux_bias_block(codec);
+		else
+			snd_soc_update_bits(codec,
+					    WCD9XXX_A_MBHC_SCALING_MUX_1,
+					    0x80, 0x80);
 		/* 25us is required after mux change to settle down */
 		usleep_range(mux_wait_us,
 			     mux_wait_us + WCD9XXX_USLEEP_RANGE_MARGIN_US);
-		*(z[i]) = __wcd9xxx_codec_sta_dce(mbhc, 0, false, false);
+		*(z[i]) = __wcd9xxx_codec_sta_dce(mbhc, 0, true, false);
 	}
 
-	/* Ramp HPH L & R back to Zero */
-	snd_soc_write(codec, WCD9XXX_A_CDC_PA_RAMP_B2_CTL, 0x0A);
-	/* Ramp generator takes ~17ms */
-	usleep_range(ramp_wait_us,
-		     ramp_wait_us + WCD9XXX_USLEEP_RANGE_MARGIN_US);
-	snd_soc_write(codec, WCD9XXX_A_CDC_PA_RAMP_B2_CTL, 0x00);
-#undef __w
-
-	/* Clean up starts */
-	/* Turn off PA ramp generator */
-	snd_soc_write(codec, WCD9XXX_A_CDC_PA_RAMP_B1_CTL, 0x0);
-	wcd9xxx_enable_static_pa(mbhc, false);
-	wcd9xxx_restore_registers(mbhc, &lh);
-	wcd9xxx_unprepare_static_pa(mbhc, &lhpa);
+	mbhc->mbhc_cb->setup_zdet(mbhc, PA_DISABLE);
 
 	mutex_unlock(&codec->mutex);
 
 	WCD9XXX_BG_CLK_LOCK(mbhc->resmgr);
-	wcd9xxx_resmgr_put_bandgap(mbhc->resmgr, WCD9XXX_BANDGAP_MBHC_MODE);
+	wcd9xxx_resmgr_put_bandgap(mbhc->resmgr, WCD9XXX_BANDGAP_AUDIO_MODE);
 	wcd9xxx_resmgr_put_clk_block(mbhc->resmgr, WCD9XXX_CLK_RCO);
 	WCD9XXX_BG_CLK_UNLOCK(mbhc->resmgr);
 
-	rl = (int)(l[0] - l[1]) * 1000 / (l[0] - l[2]);
-	rl = rl * rref * alphal;
-	rl = rl >> shift;
-	rl = rl * beta;
-	rl = rl >> shift;
-	*zl = rl;
+	wcd9xxx_turn_onoff_override(mbhc, false);
+	mbhc->mbhc_cb->compute_impedance(l, r, zl, zr);
 
-	rr = (int)(r[0] - r[1]) * 1000 / (r[0] - r[2]);
-	rr = rr * rref  * alphar;
-	rr = rr >> shift;
-	rr = rr * beta;
-	rr = rr >> shift;
-	*zr = rr;
-
-	pr_debug("%s: L0: 0x%x(%d), L1: 0x%x(%d), L2: 0x%x(%d), rl: %lld\n",
+	pr_debug("%s: L0: 0x%x(%d), L1: 0x%x(%d), L2: 0x%x(%d)\n",
 		 __func__,
-		 l[0] & 0xffff, l[0], l[1] & 0xffff, l[1], l[2] & 0xffff, l[2],
-		 rl);
-	pr_debug("%s: R0: 0x%x(%d), R1: 0x%x(%d), R2: 0x%x(%d), rr: %lld\n",
+		 l[0] & 0xffff, l[0], l[1] & 0xffff, l[1], l[2] & 0xffff, l[2]);
+	pr_debug("%s: R0: 0x%x(%d), R1: 0x%x(%d), R2: 0x%x(%d)\n",
 		 __func__,
-		 r[0] & 0xffff, r[0], r[1] & 0xffff, r[1], r[2] & 0xffff, r[2],
-		 rr);
+		 r[0] & 0xffff, r[0], r[1] & 0xffff, r[1], r[2] & 0xffff, r[2]);
 	pr_debug("%s: RL %d milliohm, RR %d milliohm\n", __func__, *zl, *zr);
 	pr_debug("%s: Impedance detection completed\n", __func__);
 
@@ -3968,7 +4426,7 @@
 		      bool impedance_det_en)
 {
 	int ret;
-	void *core;
+	void *core_res;
 
 	pr_debug("%s: enter\n", __func__);
 	memset(&mbhc->mbhc_bias_regs, 0, sizeof(struct mbhc_micbias_regs));
@@ -4009,6 +4467,15 @@
 			return ret;
 		}
 
+		ret = snd_jack_set_key(mbhc->button_jack.jack,
+				       SND_JACK_BTN_0,
+				       KEY_MEDIA);
+		if (ret) {
+			pr_err("%s: Failed to set code for btn-0\n",
+				__func__);
+			return ret;
+		}
+
 		INIT_DELAYED_WORK(&mbhc->mbhc_firmware_dwork,
 				  wcd9xxx_mbhc_fw_read);
 		INIT_DELAYED_WORK(&mbhc->mbhc_btn_dwork, wcd9xxx_btn_lpress_fn);
@@ -4026,18 +4493,18 @@
 
 	wcd9xxx_init_debugfs(mbhc);
 
-	core = mbhc->resmgr->core;
-	ret = wcd9xxx_request_irq(core, WCD9XXX_IRQ_MBHC_INSERTION,
+	core_res = mbhc->resmgr->core_res;
+	ret = wcd9xxx_request_irq(core_res, WCD9XXX_IRQ_MBHC_INSERTION,
 				  wcd9xxx_hs_insert_irq,
 				  "Headset insert detect", mbhc);
 	if (ret) {
-		pr_err("%s: Failed to request irq %d\n", __func__,
-		       WCD9XXX_IRQ_MBHC_INSERTION);
+		pr_err("%s: Failed to request irq %d, ret = %d\n", __func__,
+		       WCD9XXX_IRQ_MBHC_INSERTION, ret);
 		goto err_insert_irq;
 	}
-	wcd9xxx_disable_irq(core, WCD9XXX_IRQ_MBHC_INSERTION);
+	wcd9xxx_disable_irq(core_res, WCD9XXX_IRQ_MBHC_INSERTION);
 
-	ret = wcd9xxx_request_irq(core, WCD9XXX_IRQ_MBHC_REMOVAL,
+	ret = wcd9xxx_request_irq(core_res, WCD9XXX_IRQ_MBHC_REMOVAL,
 				  wcd9xxx_hs_remove_irq,
 				  "Headset remove detect", mbhc);
 	if (ret) {
@@ -4046,7 +4513,7 @@
 		goto err_remove_irq;
 	}
 
-	ret = wcd9xxx_request_irq(core, WCD9XXX_IRQ_MBHC_POTENTIAL,
+	ret = wcd9xxx_request_irq(core_res, WCD9XXX_IRQ_MBHC_POTENTIAL,
 				  wcd9xxx_dce_handler, "DC Estimation detect",
 				  mbhc);
 	if (ret) {
@@ -4055,7 +4522,7 @@
 		goto err_potential_irq;
 	}
 
-	ret = wcd9xxx_request_irq(core, WCD9XXX_IRQ_MBHC_RELEASE,
+	ret = wcd9xxx_request_irq(core_res, WCD9XXX_IRQ_MBHC_RELEASE,
 				  wcd9xxx_release_handler,
 				  "Button Release detect", mbhc);
 	if (ret) {
@@ -4064,7 +4531,7 @@
 		goto err_release_irq;
 	}
 
-	ret = wcd9xxx_request_irq(core, WCD9XXX_IRQ_HPH_PA_OCPL_FAULT,
+	ret = wcd9xxx_request_irq(core_res, WCD9XXX_IRQ_HPH_PA_OCPL_FAULT,
 				  wcd9xxx_hphl_ocp_irq, "HPH_L OCP detect",
 				  mbhc);
 	if (ret) {
@@ -4072,9 +4539,9 @@
 		       WCD9XXX_IRQ_HPH_PA_OCPL_FAULT);
 		goto err_hphl_ocp_irq;
 	}
-	wcd9xxx_disable_irq(core, WCD9XXX_IRQ_HPH_PA_OCPL_FAULT);
+	wcd9xxx_disable_irq(core_res, WCD9XXX_IRQ_HPH_PA_OCPL_FAULT);
 
-	ret = wcd9xxx_request_irq(core, WCD9XXX_IRQ_HPH_PA_OCPR_FAULT,
+	ret = wcd9xxx_request_irq(core_res, WCD9XXX_IRQ_HPH_PA_OCPR_FAULT,
 				  wcd9xxx_hphr_ocp_irq, "HPH_R OCP detect",
 				  mbhc);
 	if (ret) {
@@ -4082,7 +4549,7 @@
 		       WCD9XXX_IRQ_HPH_PA_OCPR_FAULT);
 		goto err_hphr_ocp_irq;
 	}
-	wcd9xxx_disable_irq(codec->control_data, WCD9XXX_IRQ_HPH_PA_OCPR_FAULT);
+	wcd9xxx_disable_irq(core_res, WCD9XXX_IRQ_HPH_PA_OCPR_FAULT);
 
 	wcd9xxx_regmgr_cond_register(resmgr, 1 << WCD9XXX_COND_HPH_MIC |
 					     1 << WCD9XXX_COND_HPH);
@@ -4091,52 +4558,50 @@
 	return ret;
 
 err_hphr_ocp_irq:
-	wcd9xxx_free_irq(core, WCD9XXX_IRQ_HPH_PA_OCPL_FAULT, mbhc);
+	wcd9xxx_free_irq(core_res, WCD9XXX_IRQ_HPH_PA_OCPL_FAULT, mbhc);
 err_hphl_ocp_irq:
-	wcd9xxx_free_irq(core, WCD9XXX_IRQ_MBHC_RELEASE, mbhc);
+	wcd9xxx_free_irq(core_res, WCD9XXX_IRQ_MBHC_RELEASE, mbhc);
 err_release_irq:
-	wcd9xxx_free_irq(core, WCD9XXX_IRQ_MBHC_POTENTIAL, mbhc);
+	wcd9xxx_free_irq(core_res, WCD9XXX_IRQ_MBHC_POTENTIAL, mbhc);
 err_potential_irq:
-	wcd9xxx_free_irq(core, WCD9XXX_IRQ_MBHC_REMOVAL, mbhc);
+	wcd9xxx_free_irq(core_res, WCD9XXX_IRQ_MBHC_REMOVAL, mbhc);
 err_remove_irq:
-	wcd9xxx_free_irq(core, WCD9XXX_IRQ_MBHC_INSERTION, mbhc);
+	wcd9xxx_free_irq(core_res, WCD9XXX_IRQ_MBHC_INSERTION, mbhc);
 err_insert_irq:
 	wcd9xxx_resmgr_unregister_notifier(mbhc->resmgr, &mbhc->nblock);
 
 	pr_debug("%s: leave ret %d\n", __func__, ret);
 	return ret;
 }
-EXPORT_SYMBOL_GPL(wcd9xxx_mbhc_init);
+EXPORT_SYMBOL(wcd9xxx_mbhc_init);
 
 void wcd9xxx_mbhc_deinit(struct wcd9xxx_mbhc *mbhc)
 {
-	void *cdata = mbhc->codec->control_data;
+	struct wcd9xxx_core_resource *core_res =
+				mbhc->resmgr->core_res;
 
 	wcd9xxx_regmgr_cond_deregister(mbhc->resmgr, 1 << WCD9XXX_COND_HPH_MIC |
 						     1 << WCD9XXX_COND_HPH);
 
-	wcd9xxx_free_irq(cdata, WCD9XXX_IRQ_MBHC_RELEASE, mbhc);
-	wcd9xxx_free_irq(cdata, WCD9XXX_IRQ_MBHC_POTENTIAL, mbhc);
-	wcd9xxx_free_irq(cdata, WCD9XXX_IRQ_MBHC_REMOVAL, mbhc);
-	wcd9xxx_free_irq(cdata, WCD9XXX_IRQ_MBHC_INSERTION, mbhc);
+	wcd9xxx_free_irq(core_res, WCD9XXX_IRQ_MBHC_RELEASE, mbhc);
+	wcd9xxx_free_irq(core_res, WCD9XXX_IRQ_MBHC_POTENTIAL, mbhc);
+	wcd9xxx_free_irq(core_res, WCD9XXX_IRQ_MBHC_REMOVAL, mbhc);
+	wcd9xxx_free_irq(core_res, WCD9XXX_IRQ_MBHC_INSERTION, mbhc);
 
 	if (mbhc->mbhc_cb && mbhc->mbhc_cb->free_irq)
 		mbhc->mbhc_cb->free_irq(mbhc);
 	else
-		wcd9xxx_free_irq(cdata, WCD9320_IRQ_MBHC_JACK_SWITCH,
+		wcd9xxx_free_irq(core_res, WCD9320_IRQ_MBHC_JACK_SWITCH,
 				 mbhc);
 
-	wcd9xxx_free_irq(cdata, WCD9XXX_IRQ_HPH_PA_OCPL_FAULT, mbhc);
-	wcd9xxx_free_irq(cdata, WCD9XXX_IRQ_HPH_PA_OCPR_FAULT, mbhc);
-
-	if (mbhc->mbhc_fw)
-		release_firmware(mbhc->mbhc_fw);
+	wcd9xxx_free_irq(core_res, WCD9XXX_IRQ_HPH_PA_OCPL_FAULT, mbhc);
+	wcd9xxx_free_irq(core_res, WCD9XXX_IRQ_HPH_PA_OCPR_FAULT, mbhc);
 
 	wcd9xxx_resmgr_unregister_notifier(mbhc->resmgr, &mbhc->nblock);
 
 	wcd9xxx_cleanup_debugfs(mbhc);
 }
-EXPORT_SYMBOL_GPL(wcd9xxx_mbhc_deinit);
+EXPORT_SYMBOL(wcd9xxx_mbhc_deinit);
 
 MODULE_DESCRIPTION("wcd9xxx MBHC module");
 MODULE_LICENSE("GPL v2");
diff --git a/sound/soc/codecs/wcd9xxx-mbhc.h b/sound/soc/codecs/wcd9xxx-mbhc.h
index 0599ccb..91280e4 100644
--- a/sound/soc/codecs/wcd9xxx-mbhc.h
+++ b/sound/soc/codecs/wcd9xxx-mbhc.h
@@ -19,6 +19,8 @@
 #define WCD9XXX_CFILT_EXT_PRCHG_EN 0x30
 #define WCD9XXX_CFILT_EXT_PRCHG_DSBL 0x00
 
+#define WCD9XXX_USLEEP_RANGE_MARGIN_US 100
+
 struct mbhc_micbias_regs {
 	u16 cfilt_val;
 	u16 cfilt_ctl;
@@ -40,9 +42,16 @@
 	MBHC_CAL_NUM,
 };
 
+enum mbhc_impedance_detect_stages {
+	PRE_MEAS,
+	POST_MEAS,
+	PA_DISABLE,
+};
+
 /* Data used by MBHC */
 struct mbhc_internal_cal_data {
 	u16 dce_z;
+	u16 dce_nsc_cs_z;
 	u16 dce_mb;
 	u16 sta_z;
 	u16 sta_mb;
@@ -59,6 +68,7 @@
 	u16 v_no_mic;
 	s16 v_inval_ins_low;
 	s16 v_inval_ins_high;
+	u16 v_cs_ins_h;
 };
 
 enum wcd9xxx_mbhc_plug_type {
@@ -83,6 +93,12 @@
 	MBHC_MICBIAS_ENABLE_REGULAR_HEADSET,
 };
 
+enum wcd9xx_mbhc_cs_enable_bits {
+	MBHC_CS_ENABLE_POLLING,
+	MBHC_CS_ENABLE_INSERTION,
+	MBHC_CS_ENABLE_REMOVAL,
+};
+
 enum wcd9xxx_mbhc_state {
 	MBHC_STATE_NONE = -1,
 	MBHC_STATE_POTENTIAL,
@@ -210,11 +226,14 @@
 	unsigned long micbias_enable_flags;
 	/* swap_gnd_mic returns true if extern GND/MIC swap switch toggled */
 	bool (*swap_gnd_mic) (struct snd_soc_codec *);
+	unsigned long cs_enable_flags;
+	bool use_int_rbias;
 };
 
 struct wcd9xxx_cfilt_mode {
 	u8 reg_mode_val;
 	u8 cur_mode_val;
+	u8 reg_mask;
 };
 
 struct wcd9xxx_mbhc_cb {
@@ -227,6 +246,15 @@
 							bool);
 	void (*select_cfilt) (struct snd_soc_codec *, struct wcd9xxx_mbhc *);
 	void (*free_irq) (struct wcd9xxx_mbhc *);
+	enum wcd9xxx_cdc_type (*get_cdc_type) (void);
+	void (*enable_clock_gate) (struct snd_soc_codec *, bool);
+	int (*setup_zdet) (struct wcd9xxx_mbhc *,
+			   enum mbhc_impedance_detect_stages stage);
+	void (*compute_impedance) (s16 *, s16 *, uint32_t *, uint32_t *);
+	void (*enable_mbhc_txfe) (struct snd_soc_codec *, bool);
+	int (*enable_mb_source) (struct snd_soc_codec *, bool);
+	void (*setup_int_rbias) (struct snd_soc_codec *, bool);
+	void (*pull_mb_to_vddio) (struct snd_soc_codec *, bool);
 };
 
 struct wcd9xxx_mbhc {
@@ -297,6 +325,8 @@
 
 	u32 rco_clk_rate;
 
+	bool update_z;
+
 #ifdef CONFIG_DEBUG_FS
 	struct dentry *debugfs_poke;
 	struct dentry *debugfs_mbhc;
@@ -360,6 +390,7 @@
 
 int wcd9xxx_mbhc_start(struct wcd9xxx_mbhc *mbhc,
 		       struct wcd9xxx_mbhc_config *mbhc_cfg);
+void wcd9xxx_mbhc_stop(struct wcd9xxx_mbhc *mbhc);
 int wcd9xxx_mbhc_init(struct wcd9xxx_mbhc *mbhc, struct wcd9xxx_resmgr *resmgr,
 		      struct snd_soc_codec *codec,
 		      int (*micbias_enable_cb) (struct snd_soc_codec*,  bool),
diff --git a/sound/soc/codecs/wcd9xxx-resmgr.c b/sound/soc/codecs/wcd9xxx-resmgr.c
index 9633cc0..95244c0 100644
--- a/sound/soc/codecs/wcd9xxx-resmgr.c
+++ b/sound/soc/codecs/wcd9xxx-resmgr.c
@@ -33,6 +33,7 @@
 #include <linux/kernel.h>
 #include <linux/gpio.h>
 #include "wcd9xxx-resmgr.h"
+#include "msm8x10_wcd_registers.h"
 
 static char wcd9xxx_event_string[][64] = {
 	"WCD9XXX_EVENT_INVALID",
@@ -168,7 +169,9 @@
 	 * mclk should be off or clk buff source souldn't be VBG
 	 * Let's turn off mclk always
 	 */
-	WARN_ON(snd_soc_read(codec, WCD9XXX_A_CLK_BUFF_EN2) & (1 << 2));
+	if (resmgr->codec_type != WCD9XXX_CDC_TYPE_HELICON)
+		WARN_ON(snd_soc_read(codec, WCD9XXX_A_CLK_BUFF_EN2) & (1 << 2));
+
 	wcd9xxx_enable_bg(resmgr);
 	/* Notify bandgap mode change */
 	wcd9xxx_resmgr_notifier_call(resmgr, WCD9XXX_EVENT_POST_BG_MBHC_ON);
@@ -188,11 +191,13 @@
 		wcd9xxx_resmgr_notifier_call(resmgr,
 					     WCD9XXX_EVENT_PRE_MCLK_OFF);
 	/* Disable clock */
-	snd_soc_update_bits(codec, WCD9XXX_A_CLK_BUFF_EN2, 0x04, 0x00);
-	usleep_range(50, 50);
-	snd_soc_update_bits(codec, WCD9XXX_A_CLK_BUFF_EN2, 0x02, 0x02);
-	snd_soc_update_bits(codec, WCD9XXX_A_CLK_BUFF_EN1, 0x05, 0x00);
-	usleep_range(50, 50);
+	if (resmgr->codec_type != WCD9XXX_CDC_TYPE_HELICON) {
+		snd_soc_update_bits(codec, WCD9XXX_A_CLK_BUFF_EN2, 0x04, 0x00);
+		usleep_range(50, 50);
+		snd_soc_update_bits(codec, WCD9XXX_A_CLK_BUFF_EN2, 0x02, 0x02);
+		snd_soc_update_bits(codec, WCD9XXX_A_CLK_BUFF_EN1, 0x05, 0x00);
+		usleep_range(50, 50);
+	}
 	/* Notify */
 	if (resmgr->clk_type == WCD9XXX_CLK_RCO)
 		wcd9xxx_resmgr_notifier_call(resmgr,
@@ -375,8 +380,10 @@
 	}
 }
 
-int wcd9xxx_resmgr_enable_config_mode(struct snd_soc_codec *codec, int enable)
+int wcd9xxx_resmgr_enable_config_mode(struct wcd9xxx_resmgr *resmgr, int enable)
 {
+	struct snd_soc_codec *codec = resmgr->codec;
+
 	pr_debug("%s: enable = %d\n", __func__, enable);
 	if (enable) {
 		snd_soc_update_bits(codec, WCD9XXX_A_RC_OSC_FREQ, 0x10, 0);
@@ -388,10 +395,20 @@
 		usleep_range(10, 10);
 		snd_soc_update_bits(codec, WCD9XXX_A_RC_OSC_TEST, 0x80, 0);
 		usleep_range(10000, 10000);
-		snd_soc_update_bits(codec, WCD9XXX_A_CLK_BUFF_EN1, 0x08, 0x08);
+		if (resmgr->codec_type != WCD9XXX_CDC_TYPE_HELICON)
+			snd_soc_update_bits(codec, WCD9XXX_A_CLK_BUFF_EN1,
+					0x08, 0x08);
+		else
+			snd_soc_update_bits(codec,
+					MSM8X10_WCD_A_CDC_TOP_CLK_CTL,
+					0x20, 0x20);
 	} else {
 		snd_soc_update_bits(codec, WCD9XXX_A_BIAS_OSC_BG_CTL, 0x1, 0);
 		snd_soc_update_bits(codec, WCD9XXX_A_RC_OSC_FREQ, 0x80, 0);
+		if (resmgr->codec_type == WCD9XXX_CDC_TYPE_HELICON)
+			snd_soc_update_bits(codec,
+					MSM8X10_WCD_A_CDC_TOP_CLK_CTL,
+					0x20, 0x00);
 	}
 
 	return 0;
@@ -403,38 +420,60 @@
 	struct snd_soc_codec *codec = resmgr->codec;
 
 	pr_debug("%s: config_mode = %d\n", __func__, config_mode);
+
 	/* transit to RCO requires mclk off */
-	WARN_ON(snd_soc_read(codec, WCD9XXX_A_CLK_BUFF_EN2) & (1 << 2));
+	if (resmgr->codec_type != WCD9XXX_CDC_TYPE_HELICON)
+		WARN_ON(snd_soc_read(codec, WCD9XXX_A_CLK_BUFF_EN2) & (1 << 2));
+
 	if (config_mode) {
 		/* Notify */
 		wcd9xxx_resmgr_notifier_call(resmgr, WCD9XXX_EVENT_PRE_RCO_ON);
 		/* enable RCO and switch to it */
-		wcd9xxx_resmgr_enable_config_mode(codec, 1);
-		snd_soc_write(codec, WCD9XXX_A_CLK_BUFF_EN2, 0x02);
+		wcd9xxx_resmgr_enable_config_mode(resmgr, 1);
+		if (resmgr->codec_type != WCD9XXX_CDC_TYPE_HELICON)
+			snd_soc_write(codec, WCD9XXX_A_CLK_BUFF_EN2, 0x02);
 		usleep_range(1000, 1000);
 	} else {
 		/* Notify */
 		wcd9xxx_resmgr_notifier_call(resmgr, WCD9XXX_EVENT_PRE_MCLK_ON);
 		/* switch to MCLK */
-		snd_soc_update_bits(codec, WCD9XXX_A_CLK_BUFF_EN1, 0x08, 0x00);
+		if (resmgr->codec_type != WCD9XXX_CDC_TYPE_HELICON) {
+			snd_soc_update_bits(codec, WCD9XXX_A_CLK_BUFF_EN1,
+				0x08, 0x00);
+		} else {
+			snd_soc_update_bits(codec,
+					MSM8X10_WCD_A_CDC_CLK_PDM_CTL,
+					0x03, 0x03);
+			snd_soc_update_bits(codec,
+					MSM8X10_WCD_A_CDC_TOP_CLK_CTL,
+					0x0f, 0x0d);
+		}
 		/* if RCO is enabled, switch from it */
 		if (snd_soc_read(codec, WCD9XXX_A_RC_OSC_FREQ) & 0x80) {
-			snd_soc_write(codec, WCD9XXX_A_CLK_BUFF_EN2, 0x02);
-			wcd9xxx_resmgr_enable_config_mode(codec, 0);
+			if (resmgr->codec_type != WCD9XXX_CDC_TYPE_HELICON)
+				snd_soc_write(codec, WCD9XXX_A_CLK_BUFF_EN2,
+							  0x02);
+			wcd9xxx_resmgr_enable_config_mode(resmgr, 0);
 		}
 		/* clk source to ext clk and clk buff ref to VBG */
-		snd_soc_update_bits(codec, WCD9XXX_A_CLK_BUFF_EN1, 0x0C, 0x04);
+		if (resmgr->codec_type != WCD9XXX_CDC_TYPE_HELICON)
+			snd_soc_update_bits(codec, WCD9XXX_A_CLK_BUFF_EN1,
+				0x0C, 0x04);
 	}
 
-	snd_soc_update_bits(codec, WCD9XXX_A_CLK_BUFF_EN1, 0x01, 0x01);
-	/* sleep time required by codec hardware to enable clock buffer */
-	usleep_range(1000, 1200);
-
-	snd_soc_update_bits(codec, WCD9XXX_A_CLK_BUFF_EN2, 0x02, 0x00);
-
-	/* on MCLK */
-	snd_soc_update_bits(codec, WCD9XXX_A_CLK_BUFF_EN2, 0x04, 0x04);
-	snd_soc_update_bits(codec, WCD9XXX_A_CDC_CLK_MCLK_CTL, 0x01, 0x01);
+	if (resmgr->codec_type != WCD9XXX_CDC_TYPE_HELICON) {
+		snd_soc_update_bits(codec, WCD9XXX_A_CLK_BUFF_EN1, 0x01, 0x01);
+		/* sleep required by codec hardware to enable clock buffer */
+		usleep_range(1000, 1200);
+		snd_soc_update_bits(codec, WCD9XXX_A_CLK_BUFF_EN2, 0x02, 0x00);
+		/* on MCLK */
+		snd_soc_update_bits(codec, WCD9XXX_A_CLK_BUFF_EN2, 0x04, 0x04);
+		snd_soc_update_bits(codec, WCD9XXX_A_CDC_CLK_MCLK_CTL,
+				0x01, 0x01);
+	} else {
+		snd_soc_update_bits(codec, MSM8X10_WCD_A_CDC_CLK_MCLK_CTL,
+				0x01, 0x01);
+	}
 	usleep_range(50, 50);
 
 	/* Notify */
@@ -493,7 +532,7 @@
 					       WCD9XXX_A_RC_OSC_FREQ) & 0x80));
 			/* disable clock block */
 			wcd9xxx_disable_clock_block(resmgr);
-			/* switch to RCO */
+			/* switch to MCLK */
 			wcd9xxx_enable_clock_block(resmgr, 0);
 			resmgr->clk_type = WCD9XXX_CLK_MCLK;
 		}
@@ -797,9 +836,10 @@
 
 int wcd9xxx_resmgr_init(struct wcd9xxx_resmgr *resmgr,
 			struct snd_soc_codec *codec,
-			struct wcd9xxx *wcd9xxx,
+			struct wcd9xxx_core_resource *core_res,
 			struct wcd9xxx_pdata *pdata,
-			struct wcd9xxx_reg_address *reg_addr)
+			struct wcd9xxx_reg_address *reg_addr,
+			enum wcd9xxx_cdc_type cdc_type)
 {
 	WARN(ARRAY_SIZE(wcd9xxx_event_string) != WCD9XXX_EVENT_LAST + 1,
 	     "Event string table isn't up to date!, %d != %d\n",
@@ -807,8 +847,9 @@
 
 	resmgr->bandgap_type = WCD9XXX_BANDGAP_OFF;
 	resmgr->codec = codec;
+	resmgr->codec_type = cdc_type;
 	/* This gives access of core handle to lock/unlock suspend */
-	resmgr->core = wcd9xxx;
+	resmgr->core_res = core_res;
 	resmgr->pdata = pdata;
 	resmgr->reg_addr = reg_addr;
 
diff --git a/sound/soc/codecs/wcd9xxx-resmgr.h b/sound/soc/codecs/wcd9xxx-resmgr.h
index e6a8f5d..7fb5820 100644
--- a/sound/soc/codecs/wcd9xxx-resmgr.h
+++ b/sound/soc/codecs/wcd9xxx-resmgr.h
@@ -13,6 +13,7 @@
 #define __WCD9XXX_COMMON_H__
 
 #include <linux/notifier.h>
+#include <linux/mfd/wcd9xxx/core-resource.h>
 #include <linux/mfd/wcd9xxx/wcd9xxx_registers.h>
 
 enum wcd9xxx_bandgap_type {
@@ -21,6 +22,13 @@
 	WCD9XXX_BANDGAP_MBHC_MODE,
 };
 
+enum wcd9xxx_cdc_type {
+	WCD9XXX_CDC_TYPE_INVALID = 0,
+	WCD9XXX_CDC_TYPE_TAIKO,
+	WCD9XXX_CDC_TYPE_TAPAN,
+	WCD9XXX_CDC_TYPE_HELICON,
+};
+
 enum wcd9xxx_clock_type {
 	WCD9XXX_CLK_OFF,
 	WCD9XXX_CLK_RCO,
@@ -102,7 +110,7 @@
 
 struct wcd9xxx_resmgr {
 	struct snd_soc_codec *codec;
-	struct wcd9xxx *core;
+	struct wcd9xxx_core_resource *core_res;
 
 	u32 rx_bias_count;
 
@@ -146,16 +154,20 @@
 	 */
 	struct mutex codec_resource_lock;
 	struct mutex codec_bg_clk_lock;
+
+	enum wcd9xxx_cdc_type codec_type;
 };
 
 int wcd9xxx_resmgr_init(struct wcd9xxx_resmgr *resmgr,
 			struct snd_soc_codec *codec,
-			struct wcd9xxx *wcd9xxx,
+			struct wcd9xxx_core_resource *core_res,
 			struct wcd9xxx_pdata *pdata,
-			struct wcd9xxx_reg_address *reg_addr);
+			struct wcd9xxx_reg_address *reg_addr,
+			enum wcd9xxx_cdc_type cdc_type);
 void wcd9xxx_resmgr_deinit(struct wcd9xxx_resmgr *resmgr);
 
-int wcd9xxx_resmgr_enable_config_mode(struct snd_soc_codec *codec, int enable);
+int wcd9xxx_resmgr_enable_config_mode(struct wcd9xxx_resmgr *resmgr,
+				int enable);
 
 void wcd9xxx_resmgr_enable_rx_bias(struct wcd9xxx_resmgr *resmgr, u32 enable);
 void wcd9xxx_resmgr_get_clk_block(struct wcd9xxx_resmgr *resmgr,
diff --git a/sound/soc/msm/Kconfig b/sound/soc/msm/Kconfig
index 40661ff..86dd840 100644
--- a/sound/soc/msm/Kconfig
+++ b/sound/soc/msm/Kconfig
@@ -215,6 +215,7 @@
 	select SND_SOC_MSM_HOSTLESS_PCM
 	select SND_SOC_WCD9306
 	select SND_DYNAMIC_MINORS
+	select DOLBY_DAP
 	help
 	 To add support for SoC audio on MSM8226.
 	 This will enable sound soc drivers which
diff --git a/sound/soc/msm/msm8226.c b/sound/soc/msm/msm8226.c
index d3ba3d5..9460ec0 100644
--- a/sound/soc/msm/msm8226.c
+++ b/sound/soc/msm/msm8226.c
@@ -17,16 +17,20 @@
 #include <linux/platform_device.h>
 #include <linux/slab.h>
 #include <linux/mfd/pm8xxx/pm8921.h>
+#include <linux/io.h>
 #include <sound/core.h>
 #include <sound/soc.h>
 #include <sound/soc-dapm.h>
 #include <sound/pcm.h>
 #include <sound/jack.h>
+#include <sound/q6afe-v2.h>
 #include <asm/mach-types.h>
 #include <mach/socinfo.h>
+#include <mach/subsystem_notif.h>
 #include <qdsp6v2/msm-pcm-routing-v2.h>
+#include "qdsp6v2/q6core.h"
+#include "../codecs/wcd9xxx-common.h"
 #include "../codecs/wcd9306.h"
-#include <linux/io.h>
 
 #define DRV_NAME "msm8226-asoc-tapan"
 
@@ -50,6 +54,10 @@
 #define LO_1_SPK_AMP   0x1
 #define LO_2_SPK_AMP   0x2
 
+#define ADSP_STATE_READY_TIMEOUT_MS 3000
+
+static void *adsp_state_notifier;
+
 static int msm8226_auxpcm_rate = 8000;
 static atomic_t auxpcm_rsc_ref;
 static const char *const auxpcm_rate_text[] = {"rate_8000", "rate_16000"};
@@ -83,6 +91,9 @@
 	.micbias_enable_flags = 1 << MBHC_MICBIAS_ENABLE_THRESHOLD_HEADSET,
 	.insert_detect = true,
 	.swap_gnd_mic = NULL,
+	.cs_enable_flags = (1 << MBHC_CS_ENABLE_POLLING |
+			    1 << MBHC_CS_ENABLE_INSERTION |
+			    1 << MBHC_CS_ENABLE_REMOVAL),
 };
 
 struct msm_auxpcm_gpio {
@@ -333,6 +344,9 @@
 	SND_SOC_DAPM_MIC("Digital Mic5", NULL),
 	SND_SOC_DAPM_MIC("Digital Mic6", NULL),
 
+	SND_SOC_DAPM_MIC("Analog Mic3", NULL),
+	SND_SOC_DAPM_MIC("Analog Mic4", NULL),
+
 	SND_SOC_DAPM_SPK("Lineout_1 amp", msm8226_ext_spkramp_event),
 	SND_SOC_DAPM_SPK("Lineout_2 amp", msm8226_ext_spkramp_event),
 
@@ -693,6 +707,107 @@
 			msm_proxy_rx_ch_get, msm_proxy_rx_ch_put),
 };
 
+static int msm_afe_set_config(struct snd_soc_codec *codec)
+{
+	int rc;
+	void *config_data;
+
+	pr_debug("%s: enter\n", __func__);
+	config_data = tapan_get_afe_config(codec, AFE_CDC_REGISTERS_CONFIG);
+	rc = afe_set_config(AFE_CDC_REGISTERS_CONFIG, config_data, 0);
+	if (rc) {
+		pr_err("%s: Failed to set codec registers config %d\n",
+			__func__, rc);
+		return rc;
+	}
+	config_data = tapan_get_afe_config(codec, AFE_SLIMBUS_SLAVE_CONFIG);
+	rc = afe_set_config(AFE_SLIMBUS_SLAVE_CONFIG, config_data, 0);
+	if (rc) {
+		pr_err("%s: Failed to set slimbus slave config %d\n", __func__,
+			rc);
+		return rc;
+	}
+	config_data = tapan_get_afe_config(codec, AFE_AANC_VERSION);
+	rc = afe_set_config(AFE_AANC_VERSION, config_data, 0);
+	if (rc) {
+		pr_err("%s: Failed to set AANC version %d\n", __func__,
+			rc);
+		return rc;
+	}
+	return 0;
+}
+
+static void msm_afe_clear_config(void)
+{
+	afe_clear_config(AFE_CDC_REGISTERS_CONFIG);
+	afe_clear_config(AFE_SLIMBUS_SLAVE_CONFIG);
+	afe_clear_config(AFE_AANC_VERSION);
+}
+
+static int  msm8226_adsp_state_callback(struct notifier_block *nb,
+		unsigned long value, void *priv)
+{
+	if (value == SUBSYS_BEFORE_SHUTDOWN) {
+		pr_debug("%s: ADSP is about to shutdown. Clearing AFE config\n",
+			 __func__);
+		msm_afe_clear_config();
+	} else if (value == SUBSYS_AFTER_POWERUP) {
+		pr_debug("%s: ADSP is up\n", __func__);
+	}
+
+	return NOTIFY_OK;
+}
+
+static struct notifier_block adsp_state_notifier_block = {
+	.notifier_call = msm8226_adsp_state_callback,
+	.priority = -INT_MAX,
+};
+
+static int msm8226_tapan_codec_up(struct snd_soc_codec *codec)
+{
+	int err;
+	unsigned long timeout;
+	int adsp_ready = 0;
+
+	pr_debug("%s\n", __func__);
+	timeout = jiffies +
+		msecs_to_jiffies(ADSP_STATE_READY_TIMEOUT_MS);
+
+	do {
+		if (!q6core_is_adsp_ready()) {
+			pr_err("%s: ADSP Audio isn't ready\n", __func__);
+		} else {
+			pr_debug("%s: ADSP Audio is ready\n", __func__);
+			adsp_ready = 1;
+			break;
+		}
+	} while (time_after(timeout, jiffies));
+
+	if (!adsp_ready) {
+		pr_err("%s: timed out waiting for ADSP Audio\n", __func__);
+		return -ETIMEDOUT;
+	}
+
+	err = msm_afe_set_config(codec);
+	if (err)
+		pr_err("%s: Failed to set AFE config. err %d\n",
+			__func__, err);
+	return err;
+}
+
+static int msm8226_tapan_event_cb(struct snd_soc_codec *codec,
+	enum wcd9xxx_codec_event codec_event)
+{
+	switch (codec_event) {
+	case WCD9XXX_CODEC_EVENT_CODEC_UP:
+		return msm8226_tapan_codec_up(codec);
+	default:
+		pr_err("%s: UnSupported codec event %d\n",
+			__func__, codec_event);
+		return -EINVAL;
+	}
+}
+
 static int msm_audrx_init(struct snd_soc_pcm_runtime *rtd)
 {
 	int err;
@@ -733,13 +848,37 @@
 	snd_soc_dai_set_channel_map(codec_dai, ARRAY_SIZE(tx_ch),
 				    tx_ch, ARRAY_SIZE(rx_ch), rx_ch);
 
+	err = msm_afe_set_config(codec);
+	if (err) {
+		pr_err("%s: Failed to set AFE config %d\n",
+			__func__, err);
+		return err;
+	}
+
 	/* start mbhc */
 	mbhc_cfg.calibration = def_tapan_mbhc_cal();
-	if (mbhc_cfg.calibration)
+	if (mbhc_cfg.calibration) {
 		err = tapan_hs_detect(codec, &mbhc_cfg);
-	else
+	} else {
 		err = -ENOMEM;
+		goto out;
+	}
 
+	adsp_state_notifier =
+		subsys_notif_register_notifier("adsp",
+			&adsp_state_notifier_block);
+
+	if (!adsp_state_notifier) {
+		pr_err("%s: Failed to register adsp state notifier\n",
+			__func__);
+		err = -EFAULT;
+		goto out;
+	}
+
+	tapan_event_register(msm8226_tapan_event_cb, rtd->codec);
+	return 0;
+
+out:
 	return err;
 }
 
@@ -788,7 +927,7 @@
 	S(c[1], 124);
 	S(nc, 1);
 	S(n_meas, 5);
-	S(mbhc_nsc, 11);
+	S(mbhc_nsc, 10);
 	S(n_btn_meas, 1);
 	S(n_btn_con, 2);
 	S(num_btn, WCD9XXX_MBHC_DEF_BUTTONS);
@@ -901,7 +1040,7 @@
 };
 
 /* Digital audio interface glue - connects codec <---> CPU */
-static struct snd_soc_dai_link msm8226_dai[] = {
+static struct snd_soc_dai_link msm8226_common_dai[] = {
 	/* FrontEnd DAI Links */
 	{
 		.name = "MSM8226 Media1",
@@ -1146,6 +1285,54 @@
 		.ignore_pmdown_time = 1,
 		.be_id = MSM_FRONTEND_DAI_MULTIMEDIA9,
 	},
+	{
+		.name = "VoLTE",
+		.stream_name = "VoLTE",
+		.cpu_dai_name   = "VoLTE",
+		.platform_name  = "msm-pcm-voice",
+		.dynamic = 1,
+		.trigger = {SND_SOC_DPCM_TRIGGER_POST,
+			    SND_SOC_DPCM_TRIGGER_POST},
+		.no_host_mode = SND_SOC_DAI_LINK_NO_HOST,
+		.ignore_suspend = 1,
+		/* this dainlink has playback support */
+		.ignore_pmdown_time = 1,
+		.codec_dai_name = "snd-soc-dummy-dai",
+		.codec_name = "snd-soc-dummy",
+		.be_id = MSM_FRONTEND_DAI_VOLTE,
+	},
+	{
+		.name = "QCHAT",
+		.stream_name = "QCHAT",
+		.cpu_dai_name   = "QCHAT",
+		.platform_name  = "msm-pcm-voice",
+		.dynamic = 1,
+		.trigger = {SND_SOC_DPCM_TRIGGER_POST,
+			    SND_SOC_DPCM_TRIGGER_POST},
+		.no_host_mode = SND_SOC_DAI_LINK_NO_HOST,
+		.ignore_suspend = 1,
+		/* this dainlink has playback support */
+		.ignore_pmdown_time = 1,
+		.codec_dai_name = "snd-soc-dummy-dai",
+		.codec_name = "snd-soc-dummy",
+		.be_id = MSM_FRONTEND_DAI_QCHAT,
+	},
+	/* LSM FE */
+	{
+		.name = "Listen Audio Service",
+		.stream_name = "Listen Audio Service",
+		.cpu_dai_name = "LSM",
+		.platform_name = "msm-lsm-client",
+		.dynamic = 1,
+		.trigger = {SND_SOC_DPCM_TRIGGER_POST,
+			    SND_SOC_DPCM_TRIGGER_POST },
+		.no_host_mode = SND_SOC_DAI_LINK_NO_HOST,
+		.ignore_suspend = 1,
+		.ignore_pmdown_time = 1,
+		.codec_dai_name = "snd-soc-dummy-dai",
+		.codec_name = "snd-soc-dummy",
+		.be_id = MSM_FRONTEND_DAI_LSM1,
+	},
 	/* Backend BT/FM DAI Links */
 	{
 		.name = LPASS_BE_INT_BT_SCO_RX,
@@ -1270,6 +1457,61 @@
 		.ops = &msm_auxpcm_be_ops,
 		.ignore_suspend = 1
 	},
+	/* Incall Record Uplink BACK END DAI Link */
+	{
+		.name = LPASS_BE_INCALL_RECORD_TX,
+		.stream_name = "Voice Uplink Capture",
+		.cpu_dai_name = "msm-dai-q6-dev.32772",
+		.platform_name = "msm-pcm-routing",
+		.codec_name     = "msm-stub-codec.1",
+		.codec_dai_name = "msm-stub-tx",
+		.no_pcm = 1,
+		.be_id = MSM_BACKEND_DAI_INCALL_RECORD_TX,
+		.be_hw_params_fixup = msm_be_hw_params_fixup,
+		.ignore_suspend = 1,
+	},
+	/* Incall Record Downlink BACK END DAI Link */
+	{
+		.name = LPASS_BE_INCALL_RECORD_RX,
+		.stream_name = "Voice Downlink Capture",
+		.cpu_dai_name = "msm-dai-q6-dev.32771",
+		.platform_name = "msm-pcm-routing",
+		.codec_name     = "msm-stub-codec.1",
+		.codec_dai_name = "msm-stub-tx",
+		.no_pcm = 1,
+		.be_id = MSM_BACKEND_DAI_INCALL_RECORD_RX,
+		.be_hw_params_fixup = msm_be_hw_params_fixup,
+		.ignore_suspend = 1,
+	},
+	/* Incall Music BACK END DAI Link */
+	{
+		.name = LPASS_BE_VOICE_PLAYBACK_TX,
+		.stream_name = "Voice Farend Playback",
+		.cpu_dai_name = "msm-dai-q6-dev.32773",
+		.platform_name = "msm-pcm-routing",
+		.codec_name     = "msm-stub-codec.1",
+		.codec_dai_name = "msm-stub-rx",
+		.no_pcm = 1,
+		.be_id = MSM_BACKEND_DAI_VOICE_PLAYBACK_TX,
+		.be_hw_params_fixup = msm_be_hw_params_fixup,
+		.ignore_suspend = 1,
+	},
+	/* Incall Music 2 BACK END DAI Link */
+	{
+		.name = LPASS_BE_VOICE2_PLAYBACK_TX,
+		.stream_name = "Voice2 Farend Playback",
+		.cpu_dai_name = "msm-dai-q6-dev.32770",
+		.platform_name = "msm-pcm-routing",
+		.codec_name     = "msm-stub-codec.1",
+		.codec_dai_name = "msm-stub-rx",
+		.no_pcm = 1,
+		.be_id = MSM_BACKEND_DAI_VOICE2_PLAYBACK_TX,
+		.be_hw_params_fixup = msm_be_hw_params_fixup,
+		.ignore_suspend = 1,
+	},
+};
+
+static struct snd_soc_dai_link msm8226_9306_dai[] = {
 	/* Backend DAI Links */
 	{
 		.name = LPASS_BE_SLIMBUS_0_RX,
@@ -1383,64 +1625,168 @@
 		.ops = &msm8226_be_ops,
 		.ignore_suspend = 1,
 	},
-	/* Incall Record Uplink BACK END DAI Link */
 	{
-		.name = LPASS_BE_INCALL_RECORD_TX,
-		.stream_name = "Voice Uplink Capture",
-		.cpu_dai_name = "msm-dai-q6-dev.32772",
+		.name = LPASS_BE_SLIMBUS_5_TX,
+		.stream_name = "Slimbus5 Capture",
+		.cpu_dai_name = "msm-dai-q6-dev.16395",
 		.platform_name = "msm-pcm-routing",
-		.codec_name     = "msm-stub-codec.1",
-		.codec_dai_name = "msm-stub-tx",
+		.codec_name = "tapan_codec",
+		.codec_dai_name = "tapan_tx1",
 		.no_pcm = 1,
-		.be_id = MSM_BACKEND_DAI_INCALL_RECORD_TX,
-		.be_hw_params_fixup = msm_be_hw_params_fixup,
-		.ignore_suspend = 1,
-	},
-	/* Incall Record Downlink BACK END DAI Link */
-	{
-		.name = LPASS_BE_INCALL_RECORD_RX,
-		.stream_name = "Voice Downlink Capture",
-		.cpu_dai_name = "msm-dai-q6-dev.32771",
-		.platform_name = "msm-pcm-routing",
-		.codec_name     = "msm-stub-codec.1",
-		.codec_dai_name = "msm-stub-tx",
-		.no_pcm = 1,
-		.be_id = MSM_BACKEND_DAI_INCALL_RECORD_RX,
-		.be_hw_params_fixup = msm_be_hw_params_fixup,
-		.ignore_suspend = 1,
-	},
-	/* Incall Music BACK END DAI Link */
-	{
-		.name = LPASS_BE_VOICE_PLAYBACK_TX,
-		.stream_name = "Voice Farend Playback",
-		.cpu_dai_name = "msm-dai-q6-dev.32773",
-		.platform_name = "msm-pcm-routing",
-		.codec_name     = "msm-stub-codec.1",
-		.codec_dai_name = "msm-stub-rx",
-		.no_pcm = 1,
-		.be_id = MSM_BACKEND_DAI_VOICE_PLAYBACK_TX,
-		.be_hw_params_fixup = msm_be_hw_params_fixup,
-		.ignore_suspend = 1,
-	},
-	/* Incall Music 2 BACK END DAI Link */
-	{
-		.name = LPASS_BE_VOICE2_PLAYBACK_TX,
-		.stream_name = "Voice2 Farend Playback",
-		.cpu_dai_name = "msm-dai-q6-dev.32770",
-		.platform_name = "msm-pcm-routing",
-		.codec_name     = "msm-stub-codec.1",
-		.codec_dai_name = "msm-stub-rx",
-		.no_pcm = 1,
-		.be_id = MSM_BACKEND_DAI_VOICE2_PLAYBACK_TX,
-		.be_hw_params_fixup = msm_be_hw_params_fixup,
+		.be_id = MSM_BACKEND_DAI_SLIMBUS_5_TX,
+		.be_hw_params_fixup = msm_slim_0_tx_be_hw_params_fixup,
+		.ops = &msm8226_be_ops,
 		.ignore_suspend = 1,
 	},
 };
 
+static struct snd_soc_dai_link msm8226_9302_dai[] = {
+	/* Backend DAI Links */
+	{
+		.name = LPASS_BE_SLIMBUS_0_RX,
+		.stream_name = "Slimbus Playback",
+		.cpu_dai_name = "msm-dai-q6-dev.16384",
+		.platform_name = "msm-pcm-routing",
+		.codec_name = "tapan_codec",
+		.codec_dai_name	= "tapan9302_rx1",
+		.no_pcm = 1,
+		.be_id = MSM_BACKEND_DAI_SLIMBUS_0_RX,
+		.init = &msm_audrx_init,
+		.be_hw_params_fixup = msm_slim_0_rx_be_hw_params_fixup,
+		.ops = &msm8226_be_ops,
+		.ignore_pmdown_time = 1, /* dai link has playback support */
+		.ignore_suspend = 1,
+	},
+	{
+		.name = LPASS_BE_SLIMBUS_0_TX,
+		.stream_name = "Slimbus Capture",
+		.cpu_dai_name = "msm-dai-q6-dev.16385",
+		.platform_name = "msm-pcm-routing",
+		.codec_name = "tapan_codec",
+		.codec_dai_name	= "tapan9302_tx1",
+		.no_pcm = 1,
+		.be_id = MSM_BACKEND_DAI_SLIMBUS_0_TX,
+		.be_hw_params_fixup = msm_slim_0_tx_be_hw_params_fixup,
+		.ops = &msm8226_be_ops,
+		.ignore_suspend = 1,
+	},
+	{
+		.name = LPASS_BE_SLIMBUS_1_RX,
+		.stream_name = "Slimbus1 Playback",
+		.cpu_dai_name = "msm-dai-q6-dev.16386",
+		.platform_name = "msm-pcm-routing",
+		.codec_name = "tapan_codec",
+		.codec_dai_name	= "tapan9302_rx1",
+		.no_pcm = 1,
+		.be_id = MSM_BACKEND_DAI_SLIMBUS_1_RX,
+		.be_hw_params_fixup = msm_slim_0_rx_be_hw_params_fixup,
+		.ops = &msm8226_be_ops,
+		/* dai link has playback support */
+		.ignore_pmdown_time = 1,
+		.ignore_suspend = 1,
+	},
+	{
+		.name = LPASS_BE_SLIMBUS_1_TX,
+		.stream_name = "Slimbus1 Capture",
+		.cpu_dai_name = "msm-dai-q6-dev.16387",
+		.platform_name = "msm-pcm-routing",
+		.codec_name = "tapan_codec",
+		.codec_dai_name	= "tapan9302_tx1",
+		.no_pcm = 1,
+		.be_id = MSM_BACKEND_DAI_SLIMBUS_1_TX,
+		.be_hw_params_fixup = msm_slim_0_tx_be_hw_params_fixup,
+		.ops = &msm8226_be_ops,
+		.ignore_suspend = 1,
+	},
+	{
+		.name = LPASS_BE_SLIMBUS_3_RX,
+		.stream_name = "Slimbus3 Playback",
+		.cpu_dai_name = "msm-dai-q6-dev.16390",
+		.platform_name = "msm-pcm-routing",
+		.codec_name = "tapan_codec",
+		.codec_dai_name	= "tapan9302_rx1",
+		.no_pcm = 1,
+		.be_id = MSM_BACKEND_DAI_SLIMBUS_3_RX,
+		.be_hw_params_fixup = msm_slim_0_rx_be_hw_params_fixup,
+		.ops = &msm8226_be_ops,
+		/* dai link has playback support */
+		.ignore_pmdown_time = 1,
+		.ignore_suspend = 1,
+	},
+	{
+		.name = LPASS_BE_SLIMBUS_3_TX,
+		.stream_name = "Slimbus3 Capture",
+		.cpu_dai_name = "msm-dai-q6-dev.16391",
+		.platform_name = "msm-pcm-routing",
+		.codec_name = "tapan_codec",
+		.codec_dai_name	= "tapan9302_tx1",
+		.no_pcm = 1,
+		.be_id = MSM_BACKEND_DAI_SLIMBUS_3_TX,
+		.be_hw_params_fixup = msm_slim_0_tx_be_hw_params_fixup,
+		.ops = &msm8226_be_ops,
+		.ignore_suspend = 1,
+	},
+	{
+		.name = LPASS_BE_SLIMBUS_4_RX,
+		.stream_name = "Slimbus4 Playback",
+		.cpu_dai_name = "msm-dai-q6-dev.16392",
+		.platform_name = "msm-pcm-routing",
+		.codec_name = "tapan_codec",
+		.codec_dai_name	= "tapan9302_rx1",
+		.no_pcm = 1,
+		.be_id = MSM_BACKEND_DAI_SLIMBUS_4_RX,
+		.be_hw_params_fixup = msm_slim_0_rx_be_hw_params_fixup,
+		.ops = &msm8226_be_ops,
+		/* dai link has playback support */
+		.ignore_pmdown_time = 1,
+		.ignore_suspend = 1,
+	},
+	{
+		.name = LPASS_BE_SLIMBUS_4_TX,
+		.stream_name = "Slimbus4 Capture",
+		.cpu_dai_name = "msm-dai-q6-dev.16393",
+		.platform_name = "msm-pcm-routing",
+		.codec_name = "tapan_codec",
+		.codec_dai_name	= "tapan9302_tx1",
+		.no_pcm = 1,
+		.be_id = MSM_BACKEND_DAI_SLIMBUS_4_TX,
+		.be_hw_params_fixup = msm_slim_0_tx_be_hw_params_fixup,
+		.ops = &msm8226_be_ops,
+		.ignore_suspend = 1,
+	},
+	{
+		.name = LPASS_BE_SLIMBUS_5_TX,
+		.stream_name = "Slimbus5 Capture",
+		.cpu_dai_name = "msm-dai-q6-dev.16395",
+		.platform_name = "msm-pcm-routing",
+		.codec_name = "tapan_codec",
+		.codec_dai_name = "tapan9302_tx1",
+		.no_pcm = 1,
+		.be_id = MSM_BACKEND_DAI_SLIMBUS_5_TX,
+		.be_hw_params_fixup = msm_slim_0_tx_be_hw_params_fixup,
+		.ops = &msm8226_be_ops,
+		.ignore_suspend = 1,
+	},
+};
+
+static struct snd_soc_dai_link msm8226_9306_dai_links[
+				ARRAY_SIZE(msm8226_common_dai) +
+				ARRAY_SIZE(msm8226_9306_dai)];
+
+static struct snd_soc_dai_link msm8226_9302_dai_links[
+				ARRAY_SIZE(msm8226_common_dai) +
+				ARRAY_SIZE(msm8226_9302_dai)];
+
 struct snd_soc_card snd_soc_card_msm8226 = {
 	.name		= "msm8226-tapan-snd-card",
-	.dai_link	= msm8226_dai,
-	.num_links	= ARRAY_SIZE(msm8226_dai),
+	.dai_link	= msm8226_9306_dai_links,
+	.num_links	= ARRAY_SIZE(msm8226_9306_dai_links),
+};
+
+struct snd_soc_card snd_soc_card_9302_msm8226 = {
+	.name		= "msm8226-tapan9302-snd-card",
+	.dai_link	= msm8226_9302_dai_links,
+	.num_links	= ARRAY_SIZE(msm8226_9302_dai_links),
 };
 
 static int msm8226_dtparse_auxpcm(struct platform_device *pdev,
@@ -1515,7 +1861,7 @@
 		ret = gpio_request(pdata->mclk_gpio, "TAPAN_CODEC_PMIC_MCLK");
 		if (ret) {
 			dev_err(card->dev,
-				"%s: Failed to request taiko mclk gpio %d\n",
+				"%s: Failed to request tapan mclk gpio %d\n",
 				__func__, pdata->mclk_gpio);
 			return ret;
 		}
@@ -1561,9 +1907,36 @@
 	return 0;
 }
 
+static struct snd_soc_card *populate_snd_card_dailinks(struct device *dev)
+{
+
+	struct snd_soc_card *card;
+
+	if (of_property_read_bool(dev->of_node,
+					"qcom,tapan-codec-9302")) {
+		card = &snd_soc_card_9302_msm8226;
+
+		memcpy(msm8226_9302_dai_links, msm8226_common_dai,
+				sizeof(msm8226_common_dai));
+		memcpy(msm8226_9302_dai_links + ARRAY_SIZE(msm8226_common_dai),
+			msm8226_9302_dai, sizeof(msm8226_9302_dai));
+
+	} else {
+
+		card = &snd_soc_card_msm8226;
+
+		memcpy(msm8226_9306_dai_links, msm8226_common_dai,
+				sizeof(msm8226_common_dai));
+		memcpy(msm8226_9306_dai_links + ARRAY_SIZE(msm8226_common_dai),
+			msm8226_9306_dai, sizeof(msm8226_9306_dai));
+	}
+
+	return card;
+}
+
 static __devinit int msm8226_asoc_machine_probe(struct platform_device *pdev)
 {
-	struct snd_soc_card *card = &snd_soc_card_msm8226;
+	struct snd_soc_card *card;
 	struct msm8226_asoc_mach_data *pdata;
 	int ret;
 	const char *auxpcm_pri_gpio_set = NULL;
@@ -1581,14 +1954,7 @@
 		goto err;
 	}
 
-	/* Parse AUXPCM info from DT */
-	ret = msm8226_dtparse_auxpcm(pdev, &pdata->auxpcm_ctrl,
-					msm_auxpcm_gpio_name);
-	if (ret) {
-		dev_err(&pdev->dev,
-		"%s: Auxpcm pin data parse failed\n", __func__);
-		goto err;
-	}
+	card = populate_snd_card_dailinks(&pdev->dev);
 
 	card->dev = &pdev->dev;
 	platform_set_drvdata(pdev, card);
@@ -1630,6 +1996,33 @@
 		goto err;
 	}
 
+	ret = msm8226_prepare_codec_mclk(card);
+	if (ret)
+		goto err1;
+
+	mutex_init(&cdc_mclk_mutex);
+
+	mbhc_cfg.gpio_level_insert = of_property_read_bool(pdev->dev.of_node,
+					"qcom,headset-jack-type-NO");
+
+	ret = snd_soc_register_card(card);
+	if (ret == -EPROBE_DEFER)
+		goto err;
+	else if (ret) {
+		dev_err(&pdev->dev, "snd_soc_register_card failed (%d)\n",
+			ret);
+		goto err;
+	}
+
+	/* Parse AUXPCM info from DT */
+	ret = msm8226_dtparse_auxpcm(pdev, &pdata->auxpcm_ctrl,
+					msm_auxpcm_gpio_name);
+	if (ret) {
+		dev_err(&pdev->dev,
+		"%s: Auxpcm pin data parse failed\n", __func__);
+		goto err;
+	}
+
 	vdd_spkr_gpio = of_get_named_gpio(pdev->dev.of_node,
 				"qcom,cdc-vdd-spkr-gpios", 0);
 	if (vdd_spkr_gpio < 0) {
@@ -1667,22 +2060,8 @@
 		}
 	}
 
-	mbhc_cfg.gpio_level_insert = of_property_read_bool(pdev->dev.of_node,
-					"qcom,headset-jack-type-NO");
 	msm8226_setup_hs_jack(pdev, pdata);
 
-	ret = msm8226_prepare_codec_mclk(card);
-	if (ret)
-		goto err_lineout_spkr;
-
-	ret = snd_soc_register_card(card);
-	if (ret) {
-		dev_err(&pdev->dev, "snd_soc_register_card failed (%d)\n",
-			ret);
-		goto err_lineout_spkr;
-	}
-	mutex_init(&cdc_mclk_mutex);
-
 	ret = of_property_read_string(pdev->dev.of_node,
 			"qcom,prim-auxpcm-gpio-set", &auxpcm_pri_gpio_set);
 	if (ret) {
@@ -1728,6 +2107,7 @@
 		gpio_free(pdata->mclk_gpio);
 		pdata->mclk_gpio = 0;
 	}
+err1:
 	devm_kfree(&pdev->dev, pdata);
 	return ret;
 }
diff --git a/sound/soc/msm/msm8974.c b/sound/soc/msm/msm8974.c
index b28f0f49..e612eec 100644
--- a/sound/soc/msm/msm8974.c
+++ b/sound/soc/msm/msm8974.c
@@ -133,6 +133,9 @@
 	.micbias_enable_flags = 1 << MBHC_MICBIAS_ENABLE_THRESHOLD_HEADSET,
 	.insert_detect = true,
 	.swap_gnd_mic = NULL,
+	.cs_enable_flags = (1 << MBHC_CS_ENABLE_POLLING |
+			    1 << MBHC_CS_ENABLE_INSERTION |
+			    1 << MBHC_CS_ENABLE_REMOVAL),
 };
 
 struct msm_auxpcm_gpio {
@@ -266,7 +269,9 @@
 static void msm8974_liquid_ext_ult_spk_power_amp_enable(u32 on)
 {
 	if (on) {
-		regulator_enable(ext_spk_amp_regulator);
+		if (regulator_enable(ext_spk_amp_regulator))
+			pr_err("%s: enable failed ext_spk_amp_reg\n",
+				__func__);
 		gpio_direction_output(ext_ult_spk_amp_gpio, 1);
 		/* time takes enable the external power class AB amplifier */
 		usleep_range(EXT_CLASS_AB_EN_DELAY,
@@ -286,7 +291,9 @@
 static void msm8974_liquid_ext_spk_power_amp_enable(u32 on)
 {
 	if (on) {
-		regulator_enable(ext_spk_amp_regulator);
+		if (regulator_enable(ext_spk_amp_regulator))
+			pr_err("%s: enable failed ext_spk_amp_reg\n",
+				__func__);
 		gpio_direction_output(ext_spk_amp_gpio, on);
 		/*time takes enable the external power amplifier*/
 		usleep_range(EXT_CLASS_D_EN_DELAY,
@@ -1622,6 +1629,7 @@
 		pr_err("%s: Failed to register adsp state notifier\n",
 		       __func__);
 		err = -EFAULT;
+		taiko_hs_detect_exit(codec);
 		goto out;
 	}
 
@@ -2656,24 +2664,6 @@
 		return -ENOMEM;
 	}
 
-	/* Parse Primary AUXPCM info from DT */
-	ret = msm8974_dtparse_auxpcm(pdev, &pdata->pri_auxpcm_ctrl,
-					msm_prim_auxpcm_gpio_name);
-	if (ret) {
-		dev_err(&pdev->dev,
-		"%s: Primary Auxpcm pin data parse failed\n", __func__);
-		goto err;
-	}
-
-	/* Parse Secondary AUXPCM info from DT */
-	ret = msm8974_dtparse_auxpcm(pdev, &pdata->sec_auxpcm_ctrl,
-					msm_sec_auxpcm_gpio_name);
-	if (ret) {
-		dev_err(&pdev->dev,
-		"%s: Secondary Auxpcm pin data parse failed\n", __func__);
-		goto err;
-	}
-
 	card->dev = &pdev->dev;
 	platform_set_drvdata(pdev, card);
 	snd_soc_card_set_drvdata(card, pdata);
@@ -2714,26 +2704,9 @@
 		goto err;
 	}
 
-	ext_ult_lo_amp_gpio = of_get_named_gpio(pdev->dev.of_node,
-						prop_name_ult_lo_gpio, 0);
-	if (!gpio_is_valid(ext_ult_lo_amp_gpio)) {
-		dev_dbg(&pdev->dev,
-			"Couldn't find %s property in node %s, %d\n",
-			prop_name_ult_lo_gpio, pdev->dev.of_node->full_name,
-			ext_ult_lo_amp_gpio);
-	} else {
-		ret = gpio_request(ext_ult_lo_amp_gpio, "US_AMP_GPIO");
-		if (ret) {
-			dev_err(card->dev,
-				"%s: Failed to request US amp gpio %d\n",
-				__func__, ext_ult_lo_amp_gpio);
-			goto err;
-		}
-	}
-
 	ret = msm8974_prepare_codec_mclk(card);
 	if (ret)
-		goto err1;
+		goto err;
 
 	if (of_property_read_bool(pdev->dev.of_node, "qcom,hdmi-audio-rx")) {
 		dev_info(&pdev->dev, "%s(): hdmi audio support present\n",
@@ -2753,6 +2726,58 @@
 		card->dai_link	= msm8974_common_dai_links;
 		card->num_links	= ARRAY_SIZE(msm8974_common_dai_links);
 	}
+	mutex_init(&cdc_mclk_mutex);
+	atomic_set(&prim_auxpcm_rsc_ref, 0);
+	atomic_set(&sec_auxpcm_rsc_ref, 0);
+	spdev = pdev;
+	ext_spk_amp_regulator = NULL;
+	msm8974_liquid_dock_dev = NULL;
+
+	ret = snd_soc_register_card(card);
+	if (ret == -EPROBE_DEFER)
+		goto err;
+	else if (ret) {
+		dev_err(&pdev->dev, "snd_soc_register_card failed (%d)\n",
+			ret);
+		goto err;
+	}
+
+	/* Parse Primary AUXPCM info from DT */
+	ret = msm8974_dtparse_auxpcm(pdev, &pdata->pri_auxpcm_ctrl,
+					msm_prim_auxpcm_gpio_name);
+	if (ret) {
+		dev_err(&pdev->dev,
+		"%s: Primary Auxpcm pin data parse failed\n", __func__);
+		goto err;
+	}
+
+	/* Parse Secondary AUXPCM info from DT */
+	ret = msm8974_dtparse_auxpcm(pdev, &pdata->sec_auxpcm_ctrl,
+					msm_sec_auxpcm_gpio_name);
+	if (ret) {
+		dev_err(&pdev->dev,
+		"%s: Secondary Auxpcm pin data parse failed\n", __func__);
+		goto err;
+	}
+
+
+	ext_ult_lo_amp_gpio = of_get_named_gpio(pdev->dev.of_node,
+						prop_name_ult_lo_gpio, 0);
+	if (!gpio_is_valid(ext_ult_lo_amp_gpio)) {
+		dev_dbg(&pdev->dev,
+			"Couldn't find %s property in node %s, %d\n",
+			prop_name_ult_lo_gpio, pdev->dev.of_node->full_name,
+			ext_ult_lo_amp_gpio);
+	} else {
+		ret = gpio_request(ext_ult_lo_amp_gpio, "US_AMP_GPIO");
+		if (ret) {
+			dev_err(card->dev,
+				"%s: Failed to request US amp gpio %d\n",
+				__func__, ext_ult_lo_amp_gpio);
+			goto err;
+		}
+	}
+
 
 	pdata->us_euro_gpio = of_get_named_gpio(pdev->dev.of_node,
 				"qcom,us-euro-gpios", 0);
@@ -2771,20 +2796,6 @@
 		dev_err(&pdev->dev, "msm8974_prepare_us_euro failed (%d)\n",
 			ret);
 
-	mutex_init(&cdc_mclk_mutex);
-	atomic_set(&prim_auxpcm_rsc_ref, 0);
-	atomic_set(&sec_auxpcm_rsc_ref, 0);
-	spdev = pdev;
-	ext_spk_amp_regulator = NULL;
-	msm8974_liquid_dock_dev = NULL;
-
-	ret = snd_soc_register_card(card);
-	if (ret) {
-		dev_err(&pdev->dev, "snd_soc_register_card failed (%d)\n",
-			ret);
-		goto err1;
-	}
-
 	ret = of_property_read_string(pdev->dev.of_node,
 			"qcom,prim-auxpcm-gpio-set", &auxpcm_pri_gpio_set);
 	if (ret) {
@@ -2817,7 +2828,8 @@
 	return 0;
 
 err1:
-	gpio_free(ext_ult_lo_amp_gpio);
+	if (ext_ult_lo_amp_gpio >= 0)
+		gpio_free(ext_ult_lo_amp_gpio);
 	ext_ult_lo_amp_gpio = -1;
 err:
 	if (pdata->mclk_gpio > 0) {
@@ -2832,6 +2844,7 @@
 		gpio_free(pdata->us_euro_gpio);
 		pdata->us_euro_gpio = 0;
 	}
+	mutex_destroy(&cdc_mclk_mutex);
 	devm_kfree(&pdev->dev, pdata);
 	return ret;
 }
diff --git a/sound/soc/msm/msm8x10.c b/sound/soc/msm/msm8x10.c
index 340d3db..4b61db6 100644
--- a/sound/soc/msm/msm8x10.c
+++ b/sound/soc/msm/msm8x10.c
@@ -39,15 +39,41 @@
 #define EXT_CLASS_D_DIS_DELAY 3000
 #define EXT_CLASS_D_DELAY_DELTA 2000
 
+#define CDC_EXT_CLK_RATE 9600000
+#define WCD9XXX_MBHC_DEF_BUTTONS 8
+#define WCD9XXX_MBHC_DEF_RLOADS 5
 
 static int msm_btsco_rate = BTSCO_RATE_8KHZ;
 static int msm_btsco_ch = 1;
 
 static int msm_proxy_rx_ch = 2;
-static struct snd_soc_jack hs_jack;
 static struct platform_device *spdev;
 static int ext_spk_amp_gpio = -1;
 
+/* pointers for digital codec register mappings */
+static void __iomem *pcbcr;
+static void __iomem *prcgr;
+
+static int msm_sec_mi2s_rx_ch = 1;
+static int msm_pri_mi2s_tx_ch = 1;
+
+static void *def_msm8x10_wcd_mbhc_cal(void);
+static int msm8x10_enable_codec_ext_clk(struct snd_soc_codec *codec, int enable,
+					bool dapm);
+static struct wcd9xxx_mbhc_config mbhc_cfg = {
+	.read_fw_bin = false,
+	.calibration = NULL,
+	.micbias = MBHC_MICBIAS1,
+	.mclk_cb_fn = msm8x10_enable_codec_ext_clk,
+	.mclk_rate = CDC_EXT_CLK_RATE,
+	.gpio = 0,
+	.gpio_irq = 0,
+	.gpio_level_insert = 0,
+	.detect_extn_cable = false,
+	.insert_detect = true,
+	.swap_gnd_mic = NULL,
+	.use_int_rbias = false,
+};
 
 /*
  * There is limitation for the clock root selection from
@@ -105,7 +131,7 @@
 	SND_SOC_DAPM_SPK("Lineout amp", msm_ext_spkramp_event),
 	SND_SOC_DAPM_MIC("Handset Mic", NULL),
 	SND_SOC_DAPM_MIC("Headset Mic", NULL),
-
+	SND_SOC_DAPM_MIC("Secondary Mic", NULL),
 };
 static int msm8x10_ext_spk_power_amp_init(void)
 {
@@ -160,10 +186,9 @@
 
 static int msm_config_mclk(u16 port_id, struct afe_digital_clk_cfg *cfg)
 {
-	iowrite32(0x1, ioremap(MSM8X10_DINO_LPASS_DIGCODEC_CBCR, 4));
+	iowrite32(0x1, pcbcr);
 	/* Set the update bit to make the settings go through */
-	iowrite32(0x1, ioremap(MSM8X10_DINO_LPASS_DIGCODEC_CMD_RCGR, 4));
-
+	iowrite32(0x1, prcgr);
 	return 0;
 
 }
@@ -180,6 +205,109 @@
 	return 0;
 }
 
+static int msm_rx_be_hw_params_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);
+
+	pr_debug("%s(): channel:%d\n", __func__, msm_pri_mi2s_tx_ch);
+	rate->min = rate->max = 48000;
+	channels->min = channels->max = msm_sec_mi2s_rx_ch;
+
+	return 0;
+}
+
+static int msm_tx_be_hw_params_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);
+
+	pr_debug("%s(), channel:%d\n", __func__, msm_pri_mi2s_tx_ch);
+	rate->min = rate->max = 48000;
+	channels->min = channels->max = msm_pri_mi2s_tx_ch;
+
+	return 0;
+}
+
+
+static const char *const btsco_rate_text[] = {"8000", "16000"};
+static const struct soc_enum msm_btsco_enum[] = {
+	SOC_ENUM_SINGLE_EXT(2, btsco_rate_text),
+};
+static const char *const sec_mi2s_rx_ch_text[] = {"One", "Two"};
+static const char *const pri_mi2s_tx_ch_text[] = {"One", "Two"};
+
+static int msm_btsco_rate_get(struct snd_kcontrol *kcontrol,
+			      struct snd_ctl_elem_value *ucontrol)
+{
+	pr_debug("%s: msm_btsco_rate  = %d", __func__, msm_btsco_rate);
+
+	ucontrol->value.integer.value[0] = msm_btsco_rate;
+	return 0;
+}
+
+static int msm_btsco_rate_put(struct snd_kcontrol *kcontrol,
+			      struct snd_ctl_elem_value *ucontrol)
+{
+	switch (ucontrol->value.integer.value[0]) {
+	case 8000:
+		msm_btsco_rate = BTSCO_RATE_8KHZ;
+		break;
+	case 16000:
+		msm_btsco_rate = BTSCO_RATE_16KHZ;
+		break;
+	default:
+		msm_btsco_rate = BTSCO_RATE_8KHZ;
+		break;
+	}
+
+	pr_debug("%s: msm_btsco_rate = %d\n", __func__, msm_btsco_rate);
+	return 0;
+}
+
+static int msm_sec_mi2s_rx_ch_get(struct snd_kcontrol *kcontrol,
+	struct snd_ctl_elem_value *ucontrol)
+{
+	pr_debug("%s: msm_sec_mi2s_rx_ch  = %d\n", __func__,
+		 msm_sec_mi2s_rx_ch);
+	ucontrol->value.integer.value[0] = msm_sec_mi2s_rx_ch - 1;
+	return 0;
+}
+
+static int msm_sec_mi2s_rx_ch_put(struct snd_kcontrol *kcontrol,
+	struct snd_ctl_elem_value *ucontrol)
+{
+	msm_sec_mi2s_rx_ch = ucontrol->value.integer.value[0] + 1;
+
+	pr_debug("%s: msm_sec_mi2s_rx_ch = %d\n", __func__,
+		 msm_sec_mi2s_rx_ch);
+	return 1;
+}
+
+static int msm_pri_mi2s_tx_ch_get(struct snd_kcontrol *kcontrol,
+	struct snd_ctl_elem_value *ucontrol)
+{
+	pr_debug("%s: msm_pri_mi2s_tx_ch  = %d\n", __func__,
+		 msm_pri_mi2s_tx_ch);
+	ucontrol->value.integer.value[0] = msm_pri_mi2s_tx_ch - 1;
+	return 0;
+}
+
+static int msm_pri_mi2s_tx_ch_put(struct snd_kcontrol *kcontrol,
+	struct snd_ctl_elem_value *ucontrol)
+{
+	msm_pri_mi2s_tx_ch = ucontrol->value.integer.value[0] + 1;
+
+	pr_debug("%s: msm_pri_mi2s_tx_ch = %d\n", __func__, msm_pri_mi2s_tx_ch);
+	return 1;
+}
+
 static int msm_btsco_be_hw_params_fixup(struct snd_soc_pcm_runtime *rtd,
 					struct snd_pcm_hw_params *params)
 {
@@ -318,6 +446,20 @@
 	return ret;
 }
 
+static const struct soc_enum msm_snd_enum[] = {
+	SOC_ENUM_SINGLE_EXT(2, sec_mi2s_rx_ch_text),
+	SOC_ENUM_SINGLE_EXT(2, pri_mi2s_tx_ch_text),
+};
+
+static const struct snd_kcontrol_new msm_snd_controls[] = {
+	SOC_ENUM_EXT("Internal BTSCO SampleRate", msm_btsco_enum[0],
+		     msm_btsco_rate_get, msm_btsco_rate_put),
+	SOC_ENUM_EXT("MI2S_RX Channels", msm_snd_enum[0],
+			msm_sec_mi2s_rx_ch_get, msm_sec_mi2s_rx_ch_put),
+	SOC_ENUM_EXT("MI2S_TX Channels", msm_snd_enum[1],
+			msm_pri_mi2s_tx_ch_get, msm_pri_mi2s_tx_ch_put),
+};
+
 static int msm_audrx_init(struct snd_soc_pcm_runtime *rtd)
 {
 
@@ -328,21 +470,116 @@
 
 	pr_debug("%s(),dev_name%s\n", __func__, dev_name(cpu_dai->dev));
 	msm8x10_ext_spk_power_amp_init();
+
+	mbhc_cfg.calibration = def_msm8x10_wcd_mbhc_cal();
+	if (mbhc_cfg.calibration) {
+		ret = msm8x10_wcd_hs_detect(codec, &mbhc_cfg);
+		if (ret) {
+			pr_err("%s: msm8x10_wcd_hs_detect failed\n", __func__);
+			goto exit;
+		}
+	} else {
+		ret = -ENOMEM;
+		goto exit;
+	}
+
 	snd_soc_dapm_new_controls(dapm, msm8x10_dapm_widgets,
 				ARRAY_SIZE(msm8x10_dapm_widgets));
 
 	snd_soc_dapm_enable_pin(dapm, "Lineout amp");
 	snd_soc_dapm_sync(dapm);
 
-	ret = snd_soc_jack_new(codec, "Headset Jack",
-			SND_JACK_HEADSET, &hs_jack);
-	if (ret) {
-		pr_err("%s: Failed to create headset jack\n", __func__);
-	}
+	ret = snd_soc_add_codec_controls(codec, msm_snd_controls,
+					 ARRAY_SIZE(msm_snd_controls));
+	if (ret < 0)
+		return ret;
+
+exit:
+	if (gpio_is_valid(ext_spk_amp_gpio))
+		gpio_free(ext_spk_amp_gpio);
 
 	return ret;
 }
 
+static void *def_msm8x10_wcd_mbhc_cal(void)
+{
+	void *msm8x10_wcd_cal;
+	struct wcd9xxx_mbhc_btn_detect_cfg *btn_cfg;
+	u16 *btn_low, *btn_high;
+	u8 *n_ready, *n_cic, *gain;
+
+	msm8x10_wcd_cal = kzalloc(WCD9XXX_MBHC_CAL_SIZE(
+						WCD9XXX_MBHC_DEF_BUTTONS,
+						WCD9XXX_MBHC_DEF_RLOADS),
+					GFP_KERNEL);
+	if (!msm8x10_wcd_cal) {
+		pr_err("%s: out of memory\n", __func__);
+		return NULL;
+	}
+
+#define S(X, Y) ((WCD9XXX_MBHC_CAL_GENERAL_PTR(msm8x10_wcd_cal)->X) = (Y))
+	S(t_ldoh, 100);
+	S(t_bg_fast_settle, 100);
+	S(t_shutdown_plug_rem, 255);
+	S(mbhc_nsa, 2);
+	S(mbhc_navg, 128);
+#undef S
+#define S(X, Y) ((WCD9XXX_MBHC_CAL_PLUG_DET_PTR(msm8x10_wcd_cal)->X) = (Y))
+	S(mic_current, MSM8X10_WCD_PID_MIC_5_UA);
+	S(hph_current, MSM8X10_WCD_PID_MIC_5_UA);
+	S(t_mic_pid, 100);
+	S(t_ins_complete, 250);
+	S(t_ins_retry, 200);
+#undef S
+#define S(X, Y) ((WCD9XXX_MBHC_CAL_PLUG_TYPE_PTR(msm8x10_wcd_cal)->X) = (Y))
+	S(v_no_mic, 30);
+	S(v_hs_max, 1650);
+#undef S
+#define S(X, Y) ((WCD9XXX_MBHC_CAL_BTN_DET_PTR(msm8x10_wcd_cal)->X) = (Y))
+	S(c[0], 62);
+	S(c[1], 124);
+	S(nc, 1);
+	S(n_meas, 5);
+	S(mbhc_nsc, 10);
+	S(n_btn_meas, 1);
+	S(n_btn_con, 2);
+	S(num_btn, WCD9XXX_MBHC_DEF_BUTTONS);
+	S(v_btn_press_delta_sta, 100);
+	S(v_btn_press_delta_cic, 50);
+#undef S
+	btn_cfg = WCD9XXX_MBHC_CAL_BTN_DET_PTR(msm8x10_wcd_cal);
+	btn_low = wcd9xxx_mbhc_cal_btn_det_mp(btn_cfg, MBHC_BTN_DET_V_BTN_LOW);
+	btn_high = wcd9xxx_mbhc_cal_btn_det_mp(btn_cfg,
+					       MBHC_BTN_DET_V_BTN_HIGH);
+	btn_low[0] = -50;
+	btn_high[0] = 10;
+	btn_low[1] = 11;
+	btn_high[1] = 52;
+	btn_low[2] = 53;
+	btn_high[2] = 94;
+	btn_low[3] = 95;
+	btn_high[3] = 133;
+	btn_low[4] = 134;
+	btn_high[4] = 171;
+	btn_low[5] = 172;
+	btn_high[5] = 208;
+	btn_low[6] = 209;
+	btn_high[6] = 244;
+	btn_low[7] = 245;
+	btn_high[7] = 330;
+	n_ready = wcd9xxx_mbhc_cal_btn_det_mp(btn_cfg, MBHC_BTN_DET_N_READY);
+	n_ready[0] = 80;
+	n_ready[1] = 68;
+	n_cic = wcd9xxx_mbhc_cal_btn_det_mp(btn_cfg, MBHC_BTN_DET_N_CIC);
+	n_cic[0] = 60;
+	n_cic[1] = 47;
+	gain = wcd9xxx_mbhc_cal_btn_det_mp(btn_cfg, MBHC_BTN_DET_GAIN);
+	gain[0] = 11;
+	gain[1] = 14;
+
+	return msm8x10_wcd_cal;
+}
+
 static int msm_proxy_rx_be_hw_params_fixup(struct snd_soc_pcm_runtime *rtd,
 					struct snd_pcm_hw_params *params)
 {
@@ -581,6 +818,22 @@
 		.codec_dai_name = "snd-soc-dummy-dai",
 		.codec_name = "snd-soc-dummy",
 	},
+	{/* hw:x,14 */
+		.name = "QCHAT",
+		.stream_name = "QCHAT",
+		.cpu_dai_name   = "QCHAT",
+		.platform_name  = "msm-pcm-voice",
+		.dynamic = 1,
+		.trigger = {SND_SOC_DPCM_TRIGGER_POST,
+			    SND_SOC_DPCM_TRIGGER_POST},
+		.no_host_mode = SND_SOC_DAI_LINK_NO_HOST,
+		.ignore_suspend = 1,
+		/* this dainlink has playback support */
+		.ignore_pmdown_time = 1,
+		.codec_dai_name = "snd-soc-dummy-dai",
+		.codec_name = "snd-soc-dummy",
+		.be_id = MSM_FRONTEND_DAI_QCHAT,
+	},
 	/* Backend I2S DAI Links */
 	{
 		.name = LPASS_BE_SEC_MI2S_RX,
@@ -592,7 +845,7 @@
 		.no_pcm = 1,
 		.be_id = MSM_BACKEND_DAI_SECONDARY_MI2S_RX,
 		.init = &msm_audrx_init,
-		.be_hw_params_fixup = msm_be_hw_params_fixup,
+		.be_hw_params_fixup = msm_rx_be_hw_params_fixup,
 		.ops = &msm8x10_mi2s_be_ops,
 		.ignore_suspend = 1,
 	},
@@ -605,7 +858,7 @@
 		.codec_dai_name = "msm8x10_wcd_i2s_tx1",
 		.no_pcm = 1,
 		.be_id = MSM_BACKEND_DAI_PRI_MI2S_TX,
-		.be_hw_params_fixup = msm_be_hw_params_fixup,
+		.be_hw_params_fixup = msm_tx_be_hw_params_fixup,
 		.ops = &msm8x10_mi2s_be_ops,
 		.ignore_suspend = 1,
 	},
@@ -758,16 +1011,40 @@
 	if (ret)
 		goto err;
 
+	mutex_init(&cdc_mclk_mutex);
+	pcbcr = ioremap(MSM8X10_DINO_LPASS_DIGCODEC_CBCR, 4);
+	if (!pcbcr) {
+		ret = -ENOMEM;
+		goto err1;
+	}
+	prcgr = ioremap(MSM8X10_DINO_LPASS_DIGCODEC_CMD_RCGR, 4);
+	if (!prcgr) {
+		ret = -ENOMEM;
+		goto err1;
+	}
+	atomic_set(&mclk_rsc_ref, 0);
+	mbhc_cfg.gpio_level_insert = of_property_read_bool(pdev->dev.of_node,
+						"qcom,headset-jack-type-NC");
+	mbhc_cfg.use_int_rbias = of_property_read_bool(pdev->dev.of_node,
+						"qcom,mbhc-bias-internal");
+
 	spdev = pdev;
+
 	ret = snd_soc_register_card(card);
-	if (ret) {
+	if (ret == -EPROBE_DEFER)
+		goto err1;
+	else if (ret) {
 		dev_err(&pdev->dev, "snd_soc_register_card failed (%d)\n",
 			ret);
-		goto err;
+		goto err1;
 	}
-	mutex_init(&cdc_mclk_mutex);
-	atomic_set(&mclk_rsc_ref, 0);
 	return 0;
+err1:
+	mutex_destroy(&cdc_mclk_mutex);
+	if (pcbcr)
+		iounmap(pcbcr);
+	if (prcgr)
+		iounmap(prcgr);
 err:
 	return ret;
 }
@@ -780,6 +1057,9 @@
 		gpio_free(ext_spk_amp_gpio);
 	snd_soc_unregister_card(card);
 	mutex_destroy(&cdc_mclk_mutex);
+
+	iounmap(pcbcr);
+	iounmap(prcgr);
 	return 0;
 }
 
diff --git a/sound/soc/msm/qdsp6v2/audio_acdb.c b/sound/soc/msm/qdsp6v2/audio_acdb.c
index 2836b87..9a2d4d3 100644
--- a/sound/soc/msm/qdsp6v2/audio_acdb.c
+++ b/sound/soc/msm/qdsp6v2/audio_acdb.c
@@ -22,6 +22,11 @@
 #include "audio_acdb.h"
 #include "q6voice.h"
 
+#include <sound/q6adm-v2.h>
+#include <sound/q6afe-v2.h>
+#include <sound/q6asm-v2.h>
+#include <sound/q6lsm.h>
+
 
 #define MAX_NETWORKS			15
 #define MAX_IOCTL_DATA			(MAX_NETWORKS * 2)
@@ -31,6 +36,7 @@
 #define NUM_VOCPROC_BLOCKS		(6 * MAX_NETWORKS)
 #define ACDB_TOTAL_VOICE_ALLOCATION	(ACDB_BLOCK_SIZE * NUM_VOCPROC_BLOCKS)
 
+#define MAX_HW_DELAY_ENTRIES	25
 
 struct sidetone_atomic_cal {
 	atomic_t	enable;
@@ -93,6 +99,10 @@
 
 	/* Speaker protection */
 	struct msm_spk_prot_cfg spk_prot_cfg;
+
+	/* Av sync delay info */
+	struct hw_delay hw_delay_rx;
+	struct hw_delay hw_delay_tx;
 };
 
 static struct acdb_data		acdb_data;
@@ -366,6 +376,122 @@
 	return result;
 }
 
+int get_hw_delay(int32_t path, struct hw_delay_entry *entry)
+{
+	int i, result = 0;
+	struct hw_delay *delay = NULL;
+	struct hw_delay_entry *info = NULL;
+	pr_debug("%s,\n", __func__);
+
+	if (entry == NULL) {
+		pr_err("ACDB=> NULL pointer sent to %s\n", __func__);
+		result = -EINVAL;
+		goto ret;
+	}
+	if ((path >= MAX_AUDPROC_TYPES) || (path < 0)) {
+		pr_err("ACDB=> Bad path sent to %s, path: %d\n",
+		       __func__, path);
+		result = -EINVAL;
+		goto ret;
+	}
+	mutex_lock(&acdb_data.acdb_mutex);
+	if (path == RX_CAL)
+		delay = &acdb_data.hw_delay_rx;
+	else if (path == TX_CAL)
+		delay = &acdb_data.hw_delay_tx;
+
+	if ((delay == NULL) || ((delay != NULL) && delay->num_entries == 0)) {
+		pr_err("ACDB=> %s Invalid delay/ delay entries\n", __func__);
+		result = -EINVAL;
+		goto done;
+	}
+
+	info = (struct hw_delay_entry *)(delay->delay_info);
+	if (info == NULL) {
+		pr_err("ACDB=> %s Delay entries info is NULL\n", __func__);
+		result = -EFAULT;
+		goto done;
+	}
+	for (i = 0; i < delay->num_entries; i++) {
+		if (info[i].sample_rate == entry->sample_rate) {
+			entry->delay_usec = info[i].delay_usec;
+			break;
+		}
+	}
+	if (i == delay->num_entries) {
+		pr_err("ACDB=> %s: Unable to find delay for sample rate %d\n",
+		       __func__, entry->sample_rate);
+		result = -EFAULT;
+	}
+
+done:
+	mutex_unlock(&acdb_data.acdb_mutex);
+ret:
+	pr_debug("ACDB=> %s: Path = %d samplerate = %u usec = %u status %d\n",
+		 __func__, path, entry->sample_rate, entry->delay_usec, result);
+	return result;
+}
+
+int store_hw_delay(int32_t path, void *arg)
+{
+	int result = 0;
+	struct hw_delay delay;
+	struct hw_delay *delay_dest = NULL;
+	pr_debug("%s,\n", __func__);
+
+	if ((path >= MAX_AUDPROC_TYPES) || (path < 0) || (arg == NULL)) {
+		pr_err("ACDB=> Bad path/ pointer sent to %s, path: %d\n",
+		      __func__, path);
+		result = -EINVAL;
+		goto done;
+	}
+	result = copy_from_user((void *)&delay, (void *)arg,
+				sizeof(struct hw_delay));
+	if (result) {
+		pr_err("ACDB=> %s failed to copy hw delay: result=%d path=%d\n",
+		       __func__, result, path);
+		result = -EFAULT;
+		goto done;
+	}
+	if ((delay.num_entries <= 0) ||
+		(delay.num_entries > MAX_HW_DELAY_ENTRIES)) {
+		pr_err("ACDB=> %s incorrect no of hw delay entries: %d\n",
+		       __func__, delay.num_entries);
+		result = -EINVAL;
+		goto done;
+	}
+	if ((path >= MAX_AUDPROC_TYPES) || (path < 0)) {
+		pr_err("ACDB=> Bad path sent to %s, path: %d\n",
+		__func__, path);
+		result = -EINVAL;
+		goto done;
+	}
+
+	pr_debug("ACDB=> %s : Path = %d num_entries = %d\n",
+		 __func__, path, delay.num_entries);
+
+	mutex_lock(&acdb_data.acdb_mutex);
+	if (path == RX_CAL)
+		delay_dest = &acdb_data.hw_delay_rx;
+	else if (path == TX_CAL)
+		delay_dest = &acdb_data.hw_delay_tx;
+
+	delay_dest->num_entries = delay.num_entries;
+
+	result = copy_from_user(delay_dest->delay_info,
+				delay.delay_info,
+				(sizeof(struct hw_delay_entry)*
+				delay.num_entries));
+	if (result) {
+		pr_err("ACDB=> %s failed to copy hw delay info res=%d path=%d",
+		       __func__, result, path);
+		result = -EFAULT;
+	}
+	mutex_unlock(&acdb_data.acdb_mutex);
+done:
+	return result;
+}
+
 int get_anc_cal(struct acdb_cal_block *cal_block)
 {
 	int result = 0;
@@ -993,15 +1119,90 @@
 	atomic_set(&acdb_data.valid_adm_custom_top, 1);
 	atomic_set(&acdb_data.valid_asm_custom_top, 1);
 	atomic_inc(&usage_count);
+
+	/* Allocate memory for hw delay entries */
+	mutex_lock(&acdb_data.acdb_mutex);
+	acdb_data.hw_delay_rx.num_entries = 0;
+	acdb_data.hw_delay_tx.num_entries = 0;
+	acdb_data.hw_delay_rx.delay_info =
+				kmalloc(sizeof(struct hw_delay_entry)*
+					MAX_HW_DELAY_ENTRIES,
+					GFP_KERNEL);
+	if (acdb_data.hw_delay_rx.delay_info == NULL) {
+		pr_err("%s : Failed to allocate av sync delay entries rx\n",
+			__func__);
+	}
+	acdb_data.hw_delay_tx.delay_info =
+				kmalloc(sizeof(struct hw_delay_entry)*
+					MAX_HW_DELAY_ENTRIES,
+					GFP_KERNEL);
+	if (acdb_data.hw_delay_tx.delay_info == NULL) {
+		pr_err("%s : Failed to allocate av sync delay entries tx\n",
+			__func__);
+	}
+	mutex_unlock(&acdb_data.acdb_mutex);
+
+	return result;
+}
+
+static int unmap_cal_tables(void)
+{
+	int	result = 0;
+	int	result2 = 0;
+
+	result2 = adm_unmap_cal_blocks();
+	if (result2 < 0) {
+		pr_err("%s: adm_unmap_cal_blocks failed, err = %d\n",
+			__func__, result2);
+		result = result2;
+	}
+
+	result2 = afe_unmap_cal_blocks();
+	if (result2 < 0) {
+		pr_err("%s: afe_unmap_cal_blocks failed, err = %d\n",
+			__func__, result2);
+		result = result2;
+	}
+
+	result2 = q6lsm_unmap_cal_blocks();
+	if (result2 < 0) {
+		pr_err("%s: lsm_unmap_cal_blocks failed, err = %d\n",
+			__func__, result2);
+		result = result2;
+	}
+
+	result2 = q6asm_unmap_cal_blocks();
+	if (result2 < 0) {
+		pr_err("%s: asm_unmap_cal_blocks failed, err = %d\n",
+			__func__, result2);
+		result = result2;
+	}
+
+	result2 = voc_unmap_cal_blocks();
+	if (result2 < 0) {
+		pr_err("%s: voice_unmap_cal_blocks failed, err = %d\n",
+			__func__, result2);
+		result = result2;
+	}
+
 	return result;
 }
 
 static int deregister_memory(void)
 {
-	int i;
+	int	result = 0;
+	int	i;
+	pr_debug("%s\n", __func__);
 
 	if (atomic64_read(&acdb_data.mem_len)) {
 		mutex_lock(&acdb_data.acdb_mutex);
+		/* unmap all cal data */
+		result = unmap_cal_tables();
+		if (result < 0)
+			pr_err("%s: unmap_cal_tables failed, err = %d\n",
+				__func__, result);
+
+
 		atomic64_set(&acdb_data.mem_len, 0);
 
 		for (i = 0; i < MAX_VOCPROC_TYPES; i++) {
@@ -1009,9 +1210,11 @@
 			acdb_data.col_data[i] = NULL;
 		}
 		msm_audio_ion_free(acdb_data.ion_client, acdb_data.ion_handle);
+		acdb_data.ion_client = NULL;
+		acdb_data.ion_handle = NULL;
 		mutex_unlock(&acdb_data.acdb_mutex);
 	}
-	return 0;
+	return result;
 }
 
 static int register_memory(void)
@@ -1022,6 +1225,7 @@
 	void                    *kvptr;
 	unsigned long		kvaddr;
 	unsigned long		mem_len;
+	pr_debug("%s\n", __func__);
 
 	mutex_lock(&acdb_data.acdb_mutex);
 	for (i = 0; i < MAX_VOCPROC_TYPES; i++) {
@@ -1056,8 +1260,6 @@
 
 	return result;
 err_ion_handle:
-	msm_audio_ion_free(acdb_data.ion_client, acdb_data.ion_handle);
-
 	atomic64_set(&acdb_data.mem_len, 0);
 	mutex_unlock(&acdb_data.acdb_mutex);
 	return result;
@@ -1180,6 +1382,12 @@
 	case AUDIO_DEREGISTER_VOCPROC_VOL_TABLE:
 		result = deregister_vocvol_table();
 		goto done;
+	case AUDIO_SET_HW_DELAY_RX:
+		result = store_hw_delay(RX_CAL, (void *)arg);
+		goto done;
+	case AUDIO_SET_HW_DELAY_TX:
+		result = store_hw_delay(TX_CAL, (void *)arg);
+		goto done;
 	}
 
 	if (copy_from_user(&size, (void *) arg, sizeof(size))) {
@@ -1335,6 +1543,9 @@
 	else
 		result = deregister_memory();
 
+	kfree(acdb_data.hw_delay_rx.delay_info);
+	kfree(acdb_data.hw_delay_tx.delay_info);
+
 	return result;
 }
 
diff --git a/sound/soc/msm/qdsp6v2/audio_acdb.h b/sound/soc/msm/qdsp6v2/audio_acdb.h
index 1685894..e2ca395 100644
--- a/sound/soc/msm/qdsp6v2/audio_acdb.h
+++ b/sound/soc/msm/qdsp6v2/audio_acdb.h
@@ -19,7 +19,6 @@
 enum {
 	RX_CAL,
 	TX_CAL,
-	AANC_TX_CAL,
 	MAX_AUDPROC_TYPES
 };
 
@@ -42,6 +41,11 @@
 	atomic_t		cal_paddr;
 };
 
+struct hw_delay_entry {
+	uint32_t sample_rate;
+	uint32_t delay_usec;
+};
+
 uint32_t get_voice_rx_topology(void);
 uint32_t get_voice_tx_topology(void);
 uint32_t get_adm_rx_topology(void);
@@ -66,5 +70,6 @@
 int get_sidetone_cal(struct sidetone_cal *cal_data);
 int get_spk_protection_cfg(struct msm_spk_prot_cfg *prot_cfg);
 int get_aanc_cal(struct acdb_cal_block *cal_block);
+int get_hw_delay(int32_t path, struct hw_delay_entry *delay_info);
 
 #endif
diff --git a/sound/soc/msm/qdsp6v2/msm-dolby-dap-config.c b/sound/soc/msm/qdsp6v2/msm-dolby-dap-config.c
index cd08b39..307d63e 100644
--- a/sound/soc/msm/qdsp6v2/msm-dolby-dap-config.c
+++ b/sound/soc/msm/qdsp6v2/msm-dolby-dap-config.c
@@ -43,75 +43,190 @@
 
 const struct dolby_dap_endp_params_s
 			dolby_dap_endp_params[NUM_DOLBY_ENDP_DEVICE] = {
-	{EARPIECE,			2, DOLBY_ENDP_EXT_SPEAKERS,
-		{DOLBY_PARAM_ID_DVLO}, {DOLBY_ENDDEP_PARAM_DVLO_LENGTH},
-		{DOLBY_ENDDEP_PARAM_DVLO_OFFSET}, {-320} },
-	{SPEAKER,			2, DOLBY_ENDP_INT_SPEAKERS,
-		{DOLBY_PARAM_ID_DVLO}, {DOLBY_ENDDEP_PARAM_DVLO_LENGTH},
-		{DOLBY_ENDDEP_PARAM_DVLO_OFFSET}, {-320} },
-	{WIRED_HEADSET,			2, DOLBY_ENDP_HEADPHONES,
-		{DOLBY_PARAM_ID_DVLO}, {DOLBY_ENDDEP_PARAM_DVLO_LENGTH},
-		{DOLBY_ENDDEP_PARAM_DVLO_OFFSET}, {-320} },
-	{WIRED_HEADPHONE,		2, DOLBY_ENDP_HEADPHONES,
-		{DOLBY_PARAM_ID_DVLO}, {DOLBY_ENDDEP_PARAM_DVLO_LENGTH},
-		{DOLBY_ENDDEP_PARAM_DVLO_OFFSET}, {-320} },
-	{BLUETOOTH_SCO,			2, DOLBY_ENDP_EXT_SPEAKERS,
-		{DOLBY_PARAM_ID_DVLO}, {DOLBY_ENDDEP_PARAM_DVLO_LENGTH},
-		{DOLBY_ENDDEP_PARAM_DVLO_OFFSET}, {-320} },
-	{BLUETOOTH_SCO_HEADSET,		2, DOLBY_ENDP_EXT_SPEAKERS,
-		{DOLBY_PARAM_ID_DVLO}, {DOLBY_ENDDEP_PARAM_DVLO_LENGTH},
-		{DOLBY_ENDDEP_PARAM_DVLO_OFFSET}, {-320} },
-	{BLUETOOTH_SCO_CARKIT,		2, DOLBY_ENDP_EXT_SPEAKERS,
-		{DOLBY_PARAM_ID_DVLO}, {DOLBY_ENDDEP_PARAM_DVLO_LENGTH},
-		{DOLBY_ENDDEP_PARAM_DVLO_OFFSET}, {-320} },
-	{BLUETOOTH_A2DP,		2, DOLBY_ENDP_EXT_SPEAKERS,
-		{DOLBY_PARAM_ID_DVLO}, {DOLBY_ENDDEP_PARAM_DVLO_LENGTH},
-		{DOLBY_ENDDEP_PARAM_DVLO_OFFSET}, {-320} },
-	{BLUETOOTH_A2DP_HEADPHONES,	2, DOLBY_ENDP_HEADPHONES,
-		{DOLBY_PARAM_ID_DVLO}, {DOLBY_ENDDEP_PARAM_DVLO_LENGTH},
-		{DOLBY_ENDDEP_PARAM_DVLO_OFFSET}, {-320} },
-	{BLUETOOTH_A2DP_SPEAKER,	2, DOLBY_ENDP_EXT_SPEAKERS,
-		{DOLBY_PARAM_ID_DVLO}, {DOLBY_ENDDEP_PARAM_DVLO_LENGTH},
-		{DOLBY_ENDDEP_PARAM_DVLO_OFFSET}, {-320} },
-	{AUX_DIGITAL,			2, DOLBY_ENDP_HDMI,
-		{DOLBY_PARAM_ID_DVLO}, {DOLBY_ENDDEP_PARAM_DVLO_LENGTH},
-		{DOLBY_ENDDEP_PARAM_DVLO_OFFSET}, {-640} },
-	{AUX_DIGITAL,			6, DOLBY_ENDP_HDMI,
-		{DOLBY_PARAM_ID_DVLO}, {DOLBY_ENDDEP_PARAM_DVLO_LENGTH},
-		{DOLBY_ENDDEP_PARAM_DVLO_OFFSET}, {-640} },
-	{AUX_DIGITAL,			8, DOLBY_ENDP_HDMI,
-		{DOLBY_PARAM_ID_DVLO}, {DOLBY_ENDDEP_PARAM_DVLO_LENGTH},
-		{DOLBY_ENDDEP_PARAM_DVLO_OFFSET}, {-640} },
-	{ANLG_DOCK_HEADSET,		2, DOLBY_ENDP_HEADPHONES,
-		{DOLBY_PARAM_ID_DVLO}, {DOLBY_ENDDEP_PARAM_DVLO_LENGTH},
-		{DOLBY_ENDDEP_PARAM_DVLO_OFFSET}, {-320} },
-	{DGTL_DOCK_HEADSET,		2, DOLBY_ENDP_HEADPHONES,
-		{DOLBY_PARAM_ID_DVLO}, {DOLBY_ENDDEP_PARAM_DVLO_LENGTH},
-		{DOLBY_ENDDEP_PARAM_DVLO_OFFSET}, {-320} },
-	{USB_ACCESSORY,			2, DOLBY_ENDP_EXT_SPEAKERS,
-		{DOLBY_PARAM_ID_DVLO}, {DOLBY_ENDDEP_PARAM_DVLO_LENGTH},
-		{DOLBY_ENDDEP_PARAM_DVLO_OFFSET}, {-320} },
-	{USB_DEVICE,			2, DOLBY_ENDP_EXT_SPEAKERS,
-		{DOLBY_PARAM_ID_DVLO}, {DOLBY_ENDDEP_PARAM_DVLO_LENGTH},
-		{DOLBY_ENDDEP_PARAM_DVLO_OFFSET}, {-320} },
-	{REMOTE_SUBMIX,			2, DOLBY_ENDP_EXT_SPEAKERS,
-		{DOLBY_PARAM_ID_DVLO}, {DOLBY_ENDDEP_PARAM_DVLO_LENGTH},
-		{DOLBY_ENDDEP_PARAM_DVLO_OFFSET}, {-320} },
-	{ANC_HEADSET,			2, DOLBY_ENDP_HEADPHONES,
-		{DOLBY_PARAM_ID_DVLO}, {DOLBY_ENDDEP_PARAM_DVLO_LENGTH},
-		{DOLBY_ENDDEP_PARAM_DVLO_OFFSET}, {-320} },
-	{ANC_HEADPHONE,			2, DOLBY_ENDP_HEADPHONES,
-		{DOLBY_PARAM_ID_DVLO}, {DOLBY_ENDDEP_PARAM_DVLO_LENGTH},
-		{DOLBY_ENDDEP_PARAM_DVLO_OFFSET}, {-320} },
-	{PROXY,				2, DOLBY_ENDP_EXT_SPEAKERS,
-		{DOLBY_PARAM_ID_DVLO}, {DOLBY_ENDDEP_PARAM_DVLO_LENGTH},
-		{DOLBY_ENDDEP_PARAM_DVLO_OFFSET}, {-320} },
-	{FM,				2, DOLBY_ENDP_EXT_SPEAKERS,
-		{DOLBY_PARAM_ID_DVLO}, {DOLBY_ENDDEP_PARAM_DVLO_LENGTH},
-		{DOLBY_ENDDEP_PARAM_DVLO_OFFSET}, {-320} },
-	{FM_TX,				2, DOLBY_ENDP_EXT_SPEAKERS,
-		{DOLBY_PARAM_ID_DVLO}, {DOLBY_ENDDEP_PARAM_DVLO_LENGTH},
-		{DOLBY_ENDDEP_PARAM_DVLO_OFFSET}, {-320} },
+	{EARPIECE, 2, DOLBY_ENDP_EXT_SPEAKERS,
+		{DOLBY_PARAM_ID_DVLO, DOLBY_PARAM_ID_DVLI, DOLBY_PARAM_ID_VMB},
+		{DOLBY_ENDDEP_PARAM_DVLO_LENGTH, DOLBY_ENDDEP_PARAM_DVLI_LENGTH,
+		 DOLBY_ENDDEP_PARAM_VMB_LENGTH},
+		{DOLBY_ENDDEP_PARAM_DVLO_OFFSET, DOLBY_ENDDEP_PARAM_DVLI_OFFSET,
+		 DOLBY_ENDDEP_PARAM_VMB_OFFSET},
+		{-320, -320, 144}
+	},
+	{SPEAKER, 2, DOLBY_ENDP_INT_SPEAKERS,
+		{DOLBY_PARAM_ID_DVLO, DOLBY_PARAM_ID_DVLI, DOLBY_PARAM_ID_VMB},
+		{DOLBY_ENDDEP_PARAM_DVLO_LENGTH, DOLBY_ENDDEP_PARAM_DVLI_LENGTH,
+		 DOLBY_ENDDEP_PARAM_VMB_LENGTH},
+		{DOLBY_ENDDEP_PARAM_DVLO_OFFSET, DOLBY_ENDDEP_PARAM_DVLI_OFFSET,
+		 DOLBY_ENDDEP_PARAM_VMB_OFFSET},
+		{-320, -320, 144}
+	},
+	{WIRED_HEADSET,	2, DOLBY_ENDP_HEADPHONES,
+		{DOLBY_PARAM_ID_DVLO, DOLBY_PARAM_ID_DVLI, DOLBY_PARAM_ID_VMB},
+		{DOLBY_ENDDEP_PARAM_DVLO_LENGTH, DOLBY_ENDDEP_PARAM_DVLI_LENGTH,
+		 DOLBY_ENDDEP_PARAM_VMB_LENGTH},
+		{DOLBY_ENDDEP_PARAM_DVLO_OFFSET, DOLBY_ENDDEP_PARAM_DVLI_OFFSET,
+		 DOLBY_ENDDEP_PARAM_VMB_OFFSET},
+		{-320, -320, 144}
+	},
+	{WIRED_HEADPHONE, 2, DOLBY_ENDP_HEADPHONES,
+		{DOLBY_PARAM_ID_DVLO, DOLBY_PARAM_ID_DVLI, DOLBY_PARAM_ID_VMB},
+		{DOLBY_ENDDEP_PARAM_DVLO_LENGTH, DOLBY_ENDDEP_PARAM_DVLI_LENGTH,
+		 DOLBY_ENDDEP_PARAM_VMB_LENGTH},
+		{DOLBY_ENDDEP_PARAM_DVLO_OFFSET, DOLBY_ENDDEP_PARAM_DVLI_OFFSET,
+		 DOLBY_ENDDEP_PARAM_VMB_OFFSET},
+		{-320, -320, 144}
+	},
+	{BLUETOOTH_SCO,	2, DOLBY_ENDP_EXT_SPEAKERS,
+		{DOLBY_PARAM_ID_DVLO, DOLBY_PARAM_ID_DVLI, DOLBY_PARAM_ID_VMB},
+		{DOLBY_ENDDEP_PARAM_DVLO_LENGTH, DOLBY_ENDDEP_PARAM_DVLI_LENGTH,
+		 DOLBY_ENDDEP_PARAM_VMB_LENGTH},
+		{DOLBY_ENDDEP_PARAM_DVLO_OFFSET, DOLBY_ENDDEP_PARAM_DVLI_OFFSET,
+		 DOLBY_ENDDEP_PARAM_VMB_OFFSET},
+		{-320, -320, 144}
+	},
+	{BLUETOOTH_SCO_HEADSET,	2, DOLBY_ENDP_EXT_SPEAKERS,
+		{DOLBY_PARAM_ID_DVLO, DOLBY_PARAM_ID_DVLI, DOLBY_PARAM_ID_VMB},
+		{DOLBY_ENDDEP_PARAM_DVLO_LENGTH, DOLBY_ENDDEP_PARAM_DVLI_LENGTH,
+		 DOLBY_ENDDEP_PARAM_VMB_LENGTH},
+		{DOLBY_ENDDEP_PARAM_DVLO_OFFSET, DOLBY_ENDDEP_PARAM_DVLI_OFFSET,
+		 DOLBY_ENDDEP_PARAM_VMB_OFFSET},
+		{-320, -320, 144}
+	},
+	{BLUETOOTH_SCO_CARKIT, 2, DOLBY_ENDP_EXT_SPEAKERS,
+		{DOLBY_PARAM_ID_DVLO, DOLBY_PARAM_ID_DVLI, DOLBY_PARAM_ID_VMB},
+		{DOLBY_ENDDEP_PARAM_DVLO_LENGTH, DOLBY_ENDDEP_PARAM_DVLI_LENGTH,
+		 DOLBY_ENDDEP_PARAM_VMB_LENGTH},
+		{DOLBY_ENDDEP_PARAM_DVLO_OFFSET, DOLBY_ENDDEP_PARAM_DVLI_OFFSET,
+		 DOLBY_ENDDEP_PARAM_VMB_OFFSET},
+		{-320, -320, 144}
+	},
+	{BLUETOOTH_A2DP, 2, DOLBY_ENDP_EXT_SPEAKERS,
+		{DOLBY_PARAM_ID_DVLO, DOLBY_PARAM_ID_DVLI, DOLBY_PARAM_ID_VMB},
+		{DOLBY_ENDDEP_PARAM_DVLO_LENGTH, DOLBY_ENDDEP_PARAM_DVLI_LENGTH,
+		 DOLBY_ENDDEP_PARAM_VMB_LENGTH},
+		{DOLBY_ENDDEP_PARAM_DVLO_OFFSET, DOLBY_ENDDEP_PARAM_DVLI_OFFSET,
+		 DOLBY_ENDDEP_PARAM_VMB_OFFSET},
+		{-320, -320, 144}
+	},
+	{BLUETOOTH_A2DP_HEADPHONES, 2, DOLBY_ENDP_HEADPHONES,
+		{DOLBY_PARAM_ID_DVLO, DOLBY_PARAM_ID_DVLI, DOLBY_PARAM_ID_VMB},
+		{DOLBY_ENDDEP_PARAM_DVLO_LENGTH, DOLBY_ENDDEP_PARAM_DVLI_LENGTH,
+		 DOLBY_ENDDEP_PARAM_VMB_LENGTH},
+		{DOLBY_ENDDEP_PARAM_DVLO_OFFSET, DOLBY_ENDDEP_PARAM_DVLI_OFFSET,
+		 DOLBY_ENDDEP_PARAM_VMB_OFFSET},
+		{-320, -320, 144}
+	},
+	{BLUETOOTH_A2DP_SPEAKER, 2, DOLBY_ENDP_EXT_SPEAKERS,
+		{DOLBY_PARAM_ID_DVLO, DOLBY_PARAM_ID_DVLI, DOLBY_PARAM_ID_VMB},
+		{DOLBY_ENDDEP_PARAM_DVLO_LENGTH, DOLBY_ENDDEP_PARAM_DVLI_LENGTH,
+		 DOLBY_ENDDEP_PARAM_VMB_LENGTH},
+		{DOLBY_ENDDEP_PARAM_DVLO_OFFSET, DOLBY_ENDDEP_PARAM_DVLI_OFFSET,
+		 DOLBY_ENDDEP_PARAM_VMB_OFFSET},
+		{-320, -320, 144}
+	},
+	{AUX_DIGITAL, 2, DOLBY_ENDP_HDMI,
+		{DOLBY_PARAM_ID_DVLO, DOLBY_PARAM_ID_DVLI, DOLBY_PARAM_ID_VMB},
+		{DOLBY_ENDDEP_PARAM_DVLO_LENGTH, DOLBY_ENDDEP_PARAM_DVLI_LENGTH,
+		 DOLBY_ENDDEP_PARAM_VMB_LENGTH},
+		{DOLBY_ENDDEP_PARAM_DVLO_OFFSET, DOLBY_ENDDEP_PARAM_DVLI_OFFSET,
+		 DOLBY_ENDDEP_PARAM_VMB_OFFSET},
+		{-496, -496, 0}
+	},
+	{AUX_DIGITAL, 6, DOLBY_ENDP_HDMI,
+		{DOLBY_PARAM_ID_DVLO, DOLBY_PARAM_ID_DVLI, DOLBY_PARAM_ID_VMB},
+		{DOLBY_ENDDEP_PARAM_DVLO_LENGTH, DOLBY_ENDDEP_PARAM_DVLI_LENGTH,
+		 DOLBY_ENDDEP_PARAM_VMB_LENGTH},
+		{DOLBY_ENDDEP_PARAM_DVLO_OFFSET, DOLBY_ENDDEP_PARAM_DVLI_OFFSET,
+		 DOLBY_ENDDEP_PARAM_VMB_OFFSET},
+		{-496, -496, 0}
+	},
+	{AUX_DIGITAL, 8, DOLBY_ENDP_HDMI,
+		{DOLBY_PARAM_ID_DVLO, DOLBY_PARAM_ID_DVLI, DOLBY_PARAM_ID_VMB},
+		{DOLBY_ENDDEP_PARAM_DVLO_LENGTH, DOLBY_ENDDEP_PARAM_DVLI_LENGTH,
+		 DOLBY_ENDDEP_PARAM_VMB_LENGTH},
+		{DOLBY_ENDDEP_PARAM_DVLO_OFFSET, DOLBY_ENDDEP_PARAM_DVLI_OFFSET,
+		 DOLBY_ENDDEP_PARAM_VMB_OFFSET},
+		{-496, -496, 0}
+	},
+	{ANLG_DOCK_HEADSET, 2, DOLBY_ENDP_HEADPHONES,
+		{DOLBY_PARAM_ID_DVLO, DOLBY_PARAM_ID_DVLI, DOLBY_PARAM_ID_VMB},
+		{DOLBY_ENDDEP_PARAM_DVLO_LENGTH, DOLBY_ENDDEP_PARAM_DVLI_LENGTH,
+		 DOLBY_ENDDEP_PARAM_VMB_LENGTH},
+		{DOLBY_ENDDEP_PARAM_DVLO_OFFSET, DOLBY_ENDDEP_PARAM_DVLI_OFFSET,
+		 DOLBY_ENDDEP_PARAM_VMB_OFFSET},
+		{-320, -320, 144}
+	},
+	{DGTL_DOCK_HEADSET, 2, DOLBY_ENDP_HEADPHONES,
+		{DOLBY_PARAM_ID_DVLO, DOLBY_PARAM_ID_DVLI, DOLBY_PARAM_ID_VMB},
+		{DOLBY_ENDDEP_PARAM_DVLO_LENGTH, DOLBY_ENDDEP_PARAM_DVLI_LENGTH,
+		 DOLBY_ENDDEP_PARAM_VMB_LENGTH},
+		{DOLBY_ENDDEP_PARAM_DVLO_OFFSET, DOLBY_ENDDEP_PARAM_DVLI_OFFSET,
+		 DOLBY_ENDDEP_PARAM_VMB_OFFSET},
+		{-320, -320, 144}
+	},
+	{USB_ACCESSORY,	2, DOLBY_ENDP_EXT_SPEAKERS,
+		{DOLBY_PARAM_ID_DVLO, DOLBY_PARAM_ID_DVLI, DOLBY_PARAM_ID_VMB},
+		{DOLBY_ENDDEP_PARAM_DVLO_LENGTH, DOLBY_ENDDEP_PARAM_DVLI_LENGTH,
+		 DOLBY_ENDDEP_PARAM_VMB_LENGTH},
+		{DOLBY_ENDDEP_PARAM_DVLO_OFFSET, DOLBY_ENDDEP_PARAM_DVLI_OFFSET,
+		 DOLBY_ENDDEP_PARAM_VMB_OFFSET},
+		{-320, -320, 144}
+	},
+	{USB_DEVICE, 2, DOLBY_ENDP_EXT_SPEAKERS,
+		{DOLBY_PARAM_ID_DVLO, DOLBY_PARAM_ID_DVLI, DOLBY_PARAM_ID_VMB},
+		{DOLBY_ENDDEP_PARAM_DVLO_LENGTH, DOLBY_ENDDEP_PARAM_DVLI_LENGTH,
+		 DOLBY_ENDDEP_PARAM_VMB_LENGTH},
+		{DOLBY_ENDDEP_PARAM_DVLO_OFFSET, DOLBY_ENDDEP_PARAM_DVLI_OFFSET,
+		 DOLBY_ENDDEP_PARAM_VMB_OFFSET},
+		{-320, -320, 144}
+	},
+	{REMOTE_SUBMIX,	2, DOLBY_ENDP_EXT_SPEAKERS,
+		{DOLBY_PARAM_ID_DVLO, DOLBY_PARAM_ID_DVLI, DOLBY_PARAM_ID_VMB},
+		{DOLBY_ENDDEP_PARAM_DVLO_LENGTH, DOLBY_ENDDEP_PARAM_DVLI_LENGTH,
+		 DOLBY_ENDDEP_PARAM_VMB_LENGTH},
+		{DOLBY_ENDDEP_PARAM_DVLO_OFFSET, DOLBY_ENDDEP_PARAM_DVLI_OFFSET,
+		 DOLBY_ENDDEP_PARAM_VMB_OFFSET},
+		{-320, -320, 144}
+	},
+	{ANC_HEADSET, 2, DOLBY_ENDP_HEADPHONES,
+		{DOLBY_PARAM_ID_DVLO, DOLBY_PARAM_ID_DVLI, DOLBY_PARAM_ID_VMB},
+		{DOLBY_ENDDEP_PARAM_DVLO_LENGTH, DOLBY_ENDDEP_PARAM_DVLI_LENGTH,
+		 DOLBY_ENDDEP_PARAM_VMB_LENGTH},
+		{DOLBY_ENDDEP_PARAM_DVLO_OFFSET, DOLBY_ENDDEP_PARAM_DVLI_OFFSET,
+		 DOLBY_ENDDEP_PARAM_VMB_OFFSET},
+		{-320, -320, 144}
+	},
+	{ANC_HEADPHONE,	2, DOLBY_ENDP_HEADPHONES,
+		{DOLBY_PARAM_ID_DVLO, DOLBY_PARAM_ID_DVLI, DOLBY_PARAM_ID_VMB},
+		{DOLBY_ENDDEP_PARAM_DVLO_LENGTH, DOLBY_ENDDEP_PARAM_DVLI_LENGTH,
+		 DOLBY_ENDDEP_PARAM_VMB_LENGTH},
+		{DOLBY_ENDDEP_PARAM_DVLO_OFFSET, DOLBY_ENDDEP_PARAM_DVLI_OFFSET,
+		 DOLBY_ENDDEP_PARAM_VMB_OFFSET},
+		{-320, -320, 144}
+	},
+	{PROXY,	2, DOLBY_ENDP_EXT_SPEAKERS,
+		{DOLBY_PARAM_ID_DVLO, DOLBY_PARAM_ID_DVLI, DOLBY_PARAM_ID_VMB},
+		{DOLBY_ENDDEP_PARAM_DVLO_LENGTH, DOLBY_ENDDEP_PARAM_DVLI_LENGTH,
+		 DOLBY_ENDDEP_PARAM_VMB_LENGTH},
+		{DOLBY_ENDDEP_PARAM_DVLO_OFFSET, DOLBY_ENDDEP_PARAM_DVLI_OFFSET,
+		 DOLBY_ENDDEP_PARAM_VMB_OFFSET},
+		{-320, -320, 144}
+	},
+	{FM, 2, DOLBY_ENDP_EXT_SPEAKERS,
+		{DOLBY_PARAM_ID_DVLO, DOLBY_PARAM_ID_DVLI, DOLBY_PARAM_ID_VMB},
+		{DOLBY_ENDDEP_PARAM_DVLO_LENGTH, DOLBY_ENDDEP_PARAM_DVLI_LENGTH,
+		 DOLBY_ENDDEP_PARAM_VMB_LENGTH},
+		{DOLBY_ENDDEP_PARAM_DVLO_OFFSET, DOLBY_ENDDEP_PARAM_DVLI_OFFSET,
+		 DOLBY_ENDDEP_PARAM_VMB_OFFSET},
+		{-320, -320, 144}
+	},
+	{FM_TX,	2, DOLBY_ENDP_EXT_SPEAKERS,
+		{DOLBY_PARAM_ID_DVLO, DOLBY_PARAM_ID_DVLI, DOLBY_PARAM_ID_VMB},
+		{DOLBY_ENDDEP_PARAM_DVLO_LENGTH, DOLBY_ENDDEP_PARAM_DVLI_LENGTH,
+		 DOLBY_ENDDEP_PARAM_VMB_LENGTH},
+		{DOLBY_ENDDEP_PARAM_DVLO_OFFSET, DOLBY_ENDDEP_PARAM_DVLI_OFFSET,
+		 DOLBY_ENDDEP_PARAM_VMB_OFFSET},
+		{-320, -320, 144}
+	},
 };
 
 /* dolby param ids to/from dsp */
diff --git a/sound/soc/msm/qdsp6v2/msm-dolby-dap-config.h b/sound/soc/msm/qdsp6v2/msm-dolby-dap-config.h
index 58ea36d..4544fea 100644
--- a/sound/soc/msm/qdsp6v2/msm-dolby-dap-config.h
+++ b/sound/soc/msm/qdsp6v2/msm-dolby-dap-config.h
@@ -223,13 +223,20 @@
 					DOLBY_PARAM_VEN_LENGTH)
 
 #define DOLBY_PARAM_INT_ENDP_LENGTH		1
-#define DOLBY_PARAM_PAYLOAD_SIZE		4
+#define DOLBY_PARAM_PAYLOAD_SIZE		3
 #define DOLBY_MAX_LENGTH_INDIVIDUAL_PARAM	329
 
-#define DOLBY_NUM_ENDP_DEPENDENT_PARAMS		1
-#define DOLBY_ENDDEP_PARAM_DVLO_OFFSET		0
-#define DOLBY_ENDDEP_PARAM_DVLO_LENGTH		1
-#define DOLBY_ENDDEP_PARAM_LENGTH		DOLBY_ENDDEP_PARAM_DVLO_LENGTH
+#define DOLBY_NUM_ENDP_DEPENDENT_PARAMS	  3
+#define DOLBY_ENDDEP_PARAM_DVLO_OFFSET	  0
+#define DOLBY_ENDDEP_PARAM_DVLO_LENGTH	  1
+#define DOLBY_ENDDEP_PARAM_DVLI_OFFSET    (DOLBY_ENDDEP_PARAM_DVLO_OFFSET + \
+						DOLBY_ENDDEP_PARAM_DVLO_LENGTH)
+#define DOLBY_ENDDEP_PARAM_DVLI_LENGTH    1
+#define DOLBY_ENDDEP_PARAM_VMB_OFFSET     (DOLBY_ENDDEP_PARAM_DVLI_OFFSET + \
+						DOLBY_ENDDEP_PARAM_DVLI_LENGTH)
+#define DOLBY_ENDDEP_PARAM_VMB_LENGTH     1
+#define DOLBY_ENDDEP_PARAM_LENGTH         (DOLBY_ENDDEP_PARAM_DVLO_LENGTH + \
+		DOLBY_ENDDEP_PARAM_DVLI_LENGTH + DOLBY_ENDDEP_PARAM_VMB_LENGTH)
 
 #define MAX_DOLBY_PARAMS			47
 #define MAX_DOLBY_CTRL_PARAMS			5
diff --git a/sound/soc/msm/qdsp6v2/msm-lsm-client.c b/sound/soc/msm/qdsp6v2/msm-lsm-client.c
index f76d455..3f57078 100644
--- a/sound/soc/msm/qdsp6v2/msm-lsm-client.c
+++ b/sound/soc/msm/qdsp6v2/msm-lsm-client.c
@@ -252,7 +252,8 @@
 		return -ENOMEM;
 	}
 	prtd->substream = substream;
-	prtd->lsm_client = q6lsm_client_alloc((app_cb)lsm_event_handler, prtd);
+	prtd->lsm_client = q6lsm_client_alloc(
+				(lsm_app_cb)lsm_event_handler, prtd);
 	if (!prtd->lsm_client) {
 		pr_err("%s: Could not allocate memory\n", __func__);
 		kfree(prtd);
diff --git a/sound/soc/msm/qdsp6v2/msm-pcm-routing-v2.c b/sound/soc/msm/qdsp6v2/msm-pcm-routing-v2.c
index de60430..f6ea266 100644
--- a/sound/soc/msm/qdsp6v2/msm-pcm-routing-v2.c
+++ b/sound/soc/msm/qdsp6v2/msm-pcm-routing-v2.c
@@ -48,7 +48,6 @@
 	unsigned int  sample_rate;
 	unsigned int  channel;
 	unsigned int  format;
-	unsigned long perf_mode;
 };
 
 #define INVALID_SESSION -1
@@ -69,7 +68,8 @@
 	MADNONE,
 	MADAUDIO,
 	MADBEACON,
-	MADULTRASOUND
+	MADULTRASOUND,
+	MADSWAUDIO,
 };
 
 #define SLIMBUS_0_TX_TEXT "SLIMBUS_0_TX"
@@ -192,7 +192,7 @@
 		topology_id = get_adm_tx_topology();
 
 	if (topology_id  == 0)
-		topology_id = DEFAULT_COPP_TOPOLOGY;
+		topology_id = NULL_COPP_TOPOLOGY;
 
 	return topology_id;
 }
@@ -265,6 +265,11 @@
 	{INVALID_SESSION, INVALID_SESSION},
 };
 
+/* Track performance mode of all front-end multimedia sessions.
+ * Performance mode is only valid when session is valid.
+ */
+static bool fe_dai_perf_mode[MSM_FRONTEND_DAI_MM_SIZE][2];
+
 static uint8_t is_be_dai_extproc(int be_dai)
 {
 	if (be_dai == MSM_BACKEND_DAI_EXTPROC_RX ||
@@ -366,13 +371,13 @@
 
 	payload.num_copps = 0; /* only RX needs to use payload */
 	fe_dai_map[fedai_id][session_type] = dspst_id;
+	fe_dai_perf_mode[fedai_id][session_type] = perf_mode;
+
 	/* re-enable EQ if active */
 	if (eq_data[fedai_id].enable)
 		msm_send_eq_values(fedai_id);
 	topology = get_topology(path_type);
 	for (i = 0; i < MSM_BACKEND_DAI_MAX; i++) {
-		if (test_bit(fedai_id, &msm_bedais[i].fe_sessions) && perf_mode)
-			set_bit(fedai_id, &msm_bedais[i].perf_mode);
 		if (!is_be_dai_extproc(i) &&
 		   (afe_get_port_type(msm_bedais[i].port_id) == port_type) &&
 		   (msm_bedais[i].active) &&
@@ -395,8 +400,7 @@
 				path_type,
 				msm_bedais[i].sample_rate,
 				msm_bedais[i].channel,
-				topology,
-				test_bit(fedai_id, &msm_bedais[i].perf_mode),
+				topology, perf_mode,
 				bits_per_sample);
 			else
 				adm_open(msm_bedais[i].port_id,
@@ -453,9 +457,9 @@
 		   (msm_bedais[i].active) &&
 		   (test_bit(fedai_id, &msm_bedais[i].fe_sessions))) {
 			adm_close(msm_bedais[i].port_id,
-				test_bit(fedai_id, &msm_bedais[i].perf_mode));
+				  fe_dai_perf_mode[fedai_id][session_type]);
 			if ((DOLBY_ADM_COPP_TOPOLOGY_ID == topology) &&
-			    (!test_bit(fedai_id, &msm_bedais[i].perf_mode)))
+			    (fe_dai_perf_mode[fedai_id][session_type] == false))
 				dolby_dap_deinit(msm_bedais[i].port_id);
 		}
 	}
@@ -487,7 +491,6 @@
 	int session_type, path_type, port_id, topology;
 	u32 channels;
 	uint16_t bits_per_sample = 16;
-	bool perf_mode = false;
 
 	pr_debug("%s: reg %x val %x set %x\n", __func__, reg, val, set);
 
@@ -527,14 +530,12 @@
 
 			if ((session_type == SESSION_TYPE_RX) &&
 				(channels > 0)) {
-				perf_mode = test_bit(val,
-						&msm_bedais[reg].perf_mode);
 				adm_multi_ch_copp_open(msm_bedais[reg].port_id,
 				path_type,
 				msm_bedais[reg].sample_rate,
 				channels,
 				topology,
-				perf_mode,
+				fe_dai_perf_mode[val][session_type],
 				bits_per_sample);
 			} else
 				adm_open(msm_bedais[reg].port_id,
@@ -544,11 +545,11 @@
 
 			msm_pcm_routing_build_matrix(val,
 				fe_dai_map[val][session_type], path_type,
-				perf_mode);
+				fe_dai_perf_mode[val][session_type]);
 			port_id = srs_port_id = msm_bedais[reg].port_id;
 			srs_send_params(srs_port_id, 1, 0);
 			if ((DOLBY_ADM_COPP_TOPOLOGY_ID == topology) &&
-			    (!perf_mode))
+			    (fe_dai_perf_mode[val][session_type] == false))
 				if (dolby_dap_init(port_id, channels) < 0)
 					pr_err("%s: Err init dolby dap\n",
 						__func__);
@@ -561,14 +562,14 @@
 		clear_bit(val, &msm_bedais[reg].fe_sessions);
 		if (msm_bedais[reg].active && fe_dai_map[val][session_type] !=
 			INVALID_SESSION) {
-			perf_mode = test_bit(val, &msm_bedais[reg].perf_mode);
-			adm_close(msm_bedais[reg].port_id, perf_mode);
+			adm_close(msm_bedais[reg].port_id,
+				  fe_dai_perf_mode[val][session_type]);
 			if ((DOLBY_ADM_COPP_TOPOLOGY_ID == topology) &&
-			    (!perf_mode))
+			    (fe_dai_perf_mode[val][session_type] == false))
 				dolby_dap_deinit(msm_bedais[reg].port_id);
 			msm_pcm_routing_build_matrix(val,
 				fe_dai_map[val][session_type], path_type,
-				perf_mode);
+				fe_dai_perf_mode[val][session_type]);
 		}
 	}
 	if ((msm_bedais[reg].port_id == VOICE_RECORD_RX)
@@ -882,6 +883,9 @@
 	case MAD_HW_ULTRASOUND:
 		ucontrol->value.integer.value[0] = MADULTRASOUND;
 		break;
+	case MAD_SW_AUDIO:
+		ucontrol->value.integer.value[0] = MADSWAUDIO;
+	break;
 	default:
 		WARN(1, "Unknown\n");
 		return -EINVAL;
@@ -921,6 +925,9 @@
 	case MADULTRASOUND:
 		mad_type = MAD_HW_ULTRASOUND;
 		break;
+	case MADSWAUDIO:
+		mad_type = MAD_SW_AUDIO;
+		break;
 	default:
 		WARN(1, "Unknown\n");
 		return -EINVAL;
@@ -1337,7 +1344,7 @@
 		break;
 	case 1:
 		msm_route_ec_ref_rx = 1;
-		ec_ref_port_id = PRIMARY_I2S_RX;
+		ec_ref_port_id = AFE_PORT_ID_PRIMARY_MI2S_RX;
 		break;
 	default:
 		msm_route_ec_ref_rx = 3; /* NONE */
@@ -2427,7 +2434,7 @@
 			  msm_routing_lsm_mux_put);
 
 static const char * const lsm_func_text[] = {
-	"None", "AUDIO", "BEACON", "ULTRASOUND"
+	"None", "AUDIO", "BEACON", "ULTRASOUND", "SWAUDIO",
 };
 static const struct soc_enum lsm_func_enum =
 	SOC_ENUM_SINGLE_EXT(ARRAY_SIZE(lsm_func_text), lsm_func_text);
@@ -3725,12 +3732,11 @@
 	for_each_set_bit(i, &bedai->fe_sessions, MSM_FRONTEND_DAI_MM_SIZE) {
 		if (fe_dai_map[i][session_type] != INVALID_SESSION) {
 			adm_close(bedai->port_id,
-				test_bit(i, &(bedai->perf_mode)));
+				  fe_dai_perf_mode[i][session_type]);
 			srs_port_id = -1;
 			if ((DOLBY_ADM_COPP_TOPOLOGY_ID == topology) &&
-			    (!test_bit(i, &(bedai->perf_mode))))
+			    (fe_dai_perf_mode[i][session_type] == false))
 				dolby_dap_deinit(bedai->port_id);
-			clear_bit(i, &(bedai->perf_mode));
 		}
 	}
 
@@ -3751,7 +3757,6 @@
 	u32 channels;
 	bool playback, capture;
 	uint16_t bits_per_sample = 16;
-	bool perf_mode = false;
 
 	if (be_id >= MSM_BACKEND_DAI_MAX) {
 		pr_err("%s: unexpected be_id %d\n", __func__, be_id);
@@ -3794,13 +3799,12 @@
 				topology = DEFAULT_COPP_TOPOLOGY;
 
 			if ((playback) && (channels > 0)) {
-				perf_mode = test_bit(i, &(bedai->perf_mode));
 				adm_multi_ch_copp_open(bedai->port_id,
 					path_type,
 					bedai->sample_rate,
 					channels,
 					topology,
-					perf_mode,
+					fe_dai_perf_mode[i][session_type],
 					bits_per_sample);
 			} else if (capture) {
 				adm_open(bedai->port_id,
@@ -3813,11 +3817,11 @@
 
 			msm_pcm_routing_build_matrix(i,
 				fe_dai_map[i][session_type], path_type,
-				perf_mode);
+				fe_dai_perf_mode[i][session_type]);
 			port_id = srs_port_id = bedai->port_id;
 			srs_send_params(srs_port_id, 1, 0);
 			if ((DOLBY_ADM_COPP_TOPOLOGY_ID == topology) &&
-			    (!perf_mode))
+			    (fe_dai_perf_mode[i][session_type] == false))
 				if (dolby_dap_init(port_id, channels) < 0)
 					pr_err("%s: Err init dolby dap\n",
 						__func__);
diff --git a/sound/soc/msm/qdsp6v2/msm-pcm-voip-v2.c b/sound/soc/msm/qdsp6v2/msm-pcm-voip-v2.c
index 4a829fd..6cfc2ef 100644
--- a/sound/soc/msm/qdsp6v2/msm-pcm-voip-v2.c
+++ b/sound/soc/msm/qdsp6v2/msm-pcm-voip-v2.c
@@ -46,6 +46,7 @@
 #define MODE_AMR		0x5
 #define MODE_AMR_WB		0xD
 #define MODE_PCM		0xC
+#define MODE_4GV_NW		0xE
 
 enum format {
 	FORMAT_S16_LE = 2,
@@ -79,12 +80,16 @@
 	VOIP_STARTED,
 };
 
-struct voip_frame {
+struct voip_frame_hdr {
+	uint32_t timestamp;
 	union {
-	uint32_t frame_type;
-	uint32_t packet_rate;
-	} header;
-	uint32_t len;
+		uint32_t frame_type;
+		uint32_t packet_rate;
+	};
+};
+struct voip_frame {
+	struct voip_frame_hdr frm_hdr;
+	uint32_t pktlen;
 	uint8_t voc_pkt[VOIP_MAX_VOC_PKT_SIZE];
 };
 
@@ -136,6 +141,9 @@
 	unsigned int pcm_capture_count;
 	unsigned int pcm_capture_irq_pos;       /* IRQ position */
 	unsigned int pcm_capture_buf_pos;       /* position in buffer */
+
+	uint32_t evrc_min_rate;
+	uint32_t evrc_max_rate;
 };
 
 static int voip_get_media_type(uint32_t mode,
@@ -144,10 +152,15 @@
 static int voip_get_rate_type(uint32_t mode,
 				uint32_t rate,
 				uint32_t *rate_type);
+static int voip_config_vocoder(struct snd_pcm_substream *substream);
 static int msm_voip_mode_rate_config_put(struct snd_kcontrol *kcontrol,
 					struct snd_ctl_elem_value *ucontrol);
 static int msm_voip_mode_rate_config_get(struct snd_kcontrol *kcontrol,
 					struct snd_ctl_elem_value *ucontrol);
+static int msm_voip_evrc_min_max_rate_config_put(struct snd_kcontrol *kcontrol,
+					 struct snd_ctl_elem_value *ucontrol);
+static int msm_voip_evrc_min_max_rate_config_get(struct snd_kcontrol *kcontrol,
+					 struct snd_ctl_elem_value *ucontrol);
 
 static struct voip_drv_info voip_info;
 
@@ -257,6 +270,9 @@
 	SOC_SINGLE_MULTI_EXT("Voip Mode Rate Config", SND_SOC_NOPM, 0, 23850,
 			     0, 2, msm_voip_mode_rate_config_get,
 			     msm_voip_mode_rate_config_put),
+	SOC_SINGLE_MULTI_EXT("Voip Evrc Min Max Rate Config", SND_SOC_NOPM,
+			     0, 4, 0, 2, msm_voip_evrc_min_max_rate_config_get,
+			     msm_voip_evrc_min_max_rate_config_put),
 	SOC_SINGLE_EXT("Voip Dtx Mode", SND_SOC_NOPM, 0, 1, 0,
 		       msm_voip_dtx_mode_get, msm_voip_dtx_mode_put),
 };
@@ -275,6 +291,7 @@
 /* capture path */
 static void voip_process_ul_pkt(uint8_t *voc_pkt,
 				uint32_t pkt_len,
+				uint32_t timestamp,
 				void *private_data)
 {
 	struct voip_buf_node *buf_node = NULL;
@@ -299,44 +316,50 @@
 			 * Bits 0-3: Frame rate
 			 * Bits 4-7: Frame type
 			 */
-			buf_node->frame.header.frame_type =
+			buf_node->frame.frm_hdr.timestamp = timestamp;
+			buf_node->frame.frm_hdr.frame_type =
 						((*voc_pkt) & 0xF0) >> 4;
 			voc_pkt = voc_pkt + DSP_FRAME_HDR_LEN;
-			buf_node->frame.len = pkt_len - DSP_FRAME_HDR_LEN;
+			buf_node->frame.pktlen = pkt_len - DSP_FRAME_HDR_LEN;
 			memcpy(&buf_node->frame.voc_pkt[0],
 				voc_pkt,
-				buf_node->frame.len);
+				buf_node->frame.pktlen);
+
 			list_add_tail(&buf_node->list, &prtd->out_queue);
 			break;
 		}
 		case MODE_IS127:
 		case MODE_4GV_NB:
-		case MODE_4GV_WB: {
+		case MODE_4GV_WB:
+		case MODE_4GV_NW: {
 			/* Remove the DSP frame info header.
 			 * Header format:
 			 * Bits 0-3: frame rate
 			 */
-			buf_node->frame.header.packet_rate = (*voc_pkt) & 0x0F;
+			buf_node->frame.frm_hdr.timestamp = timestamp;
+			buf_node->frame.frm_hdr.packet_rate = (*voc_pkt) & 0x0F;
 			voc_pkt = voc_pkt + DSP_FRAME_HDR_LEN;
-			buf_node->frame.len = pkt_len - DSP_FRAME_HDR_LEN;
+			buf_node->frame.pktlen = pkt_len - DSP_FRAME_HDR_LEN;
 
 			memcpy(&buf_node->frame.voc_pkt[0],
 				voc_pkt,
-				buf_node->frame.len);
+				buf_node->frame.pktlen);
 
 			list_add_tail(&buf_node->list, &prtd->out_queue);
 			break;
 		}
 		default: {
-			buf_node->frame.len = pkt_len;
+			buf_node->frame.frm_hdr.timestamp = timestamp;
+			buf_node->frame.pktlen = pkt_len;
 			memcpy(&buf_node->frame.voc_pkt[0],
 			       voc_pkt,
-			       buf_node->frame.len);
+			       buf_node->frame.pktlen);
 			list_add_tail(&buf_node->list, &prtd->out_queue);
 		}
 		}
-		pr_debug("ul_pkt: pkt_len =%d, frame.len=%d\n", pkt_len,
-			buf_node->frame.len);
+		pr_debug("%s: pkt_len =%d, frame.pktlen=%d, timestamp=%d\n",
+			 __func__, pkt_len, buf_node->frame.pktlen, timestamp);
+
 		prtd->pcm_capture_irq_pos += prtd->pcm_capture_count;
 		spin_unlock_irqrestore(&prtd->dsp_ul_lock, dsp_flags);
 		snd_pcm_period_elapsed(prtd->capture_substream);
@@ -367,7 +390,7 @@
 		switch (prtd->mode) {
 		case MODE_AMR:
 		case MODE_AMR_WB: {
-			*((uint32_t *)voc_pkt) = buf_node->frame.len +
+			*((uint32_t *)voc_pkt) = buf_node->frame.pktlen +
 							DSP_FRAME_HDR_LEN;
 			/* Advance to the header of voip packet */
 			voc_pkt = voc_pkt + sizeof(uint32_t);
@@ -376,19 +399,20 @@
 			 * Bits 0-3: Frame rate
 			 * Bits 4-7: Frame type
 			 */
-			*voc_pkt = ((buf_node->frame.header.frame_type &
+			*voc_pkt = ((buf_node->frame.frm_hdr.frame_type &
 					0x0F) << 4) | (prtd->rate_type & 0x0F);
 			voc_pkt = voc_pkt + DSP_FRAME_HDR_LEN;
 			memcpy(voc_pkt,
 				&buf_node->frame.voc_pkt[0],
-				buf_node->frame.len);
+				buf_node->frame.pktlen);
 			list_add_tail(&buf_node->list, &prtd->free_in_queue);
 			break;
 		}
 		case MODE_IS127:
 		case MODE_4GV_NB:
-		case MODE_4GV_WB: {
-			*((uint32_t *)voc_pkt) = buf_node->frame.len +
+		case MODE_4GV_WB:
+		case MODE_4GV_NW: {
+			*((uint32_t *)voc_pkt) = buf_node->frame.pktlen +
 							 DSP_FRAME_HDR_LEN;
 			/* Advance to the header of voip packet */
 			voc_pkt = voc_pkt + sizeof(uint32_t);
@@ -396,22 +420,22 @@
 			 * Add the DSP frame info header. Header format:
 			 * Bits 0-3 : Frame rate
 			 */
-			*voc_pkt = buf_node->frame.header.packet_rate & 0x0F;
+			*voc_pkt = buf_node->frame.frm_hdr.packet_rate & 0x0F;
 			voc_pkt = voc_pkt + DSP_FRAME_HDR_LEN;
 
 			memcpy(voc_pkt,
 				&buf_node->frame.voc_pkt[0],
-				buf_node->frame.len);
+				buf_node->frame.pktlen);
 
 			list_add_tail(&buf_node->list, &prtd->free_in_queue);
 			break;
 		}
 		default: {
-			*((uint32_t *)voc_pkt) = buf_node->frame.len;
+			*((uint32_t *)voc_pkt) = buf_node->frame.pktlen;
 			voc_pkt = voc_pkt + sizeof(uint32_t);
 			memcpy(voc_pkt,
 			       &buf_node->frame.voc_pkt[0],
-			       buf_node->frame.len);
+			       buf_node->frame.pktlen);
 			list_add_tail(&buf_node->list, &prtd->free_in_queue);
 		}
 		}
@@ -559,7 +583,7 @@
 			if (prtd->mode == MODE_PCM) {
 				ret = copy_from_user(&buf_node->frame.voc_pkt,
 							buf, count);
-				buf_node->frame.len = count;
+				buf_node->frame.pktlen = count;
 			} else
 				ret = copy_from_user(&buf_node->frame,
 							buf, count);
@@ -759,13 +783,137 @@
 
 	return ret;
 }
-static int msm_pcm_prepare(struct snd_pcm_substream *substream)
+
+static int voip_config_vocoder(struct snd_pcm_substream *substream)
 {
 	int ret = 0;
 	struct snd_pcm_runtime *runtime = substream->runtime;
 	struct voip_drv_info *prtd = runtime->private_data;
 	uint32_t media_type = 0;
 	uint32_t rate_type = 0;
+	uint32_t evrc_min_rate_type = 0;
+	uint32_t evrc_max_rate_type = 0;
+
+	if ((runtime->format != FORMAT_SPECIAL) &&
+	    ((prtd->mode == MODE_AMR) || (prtd->mode == MODE_AMR_WB) ||
+	    (prtd->mode == MODE_IS127) || (prtd->mode == MODE_4GV_NB) ||
+	    (prtd->mode == MODE_4GV_WB) || (prtd->mode == MODE_4GV_NW))) {
+		pr_err("%s(): mode:%d and format:%u are not mached\n",
+			__func__, prtd->mode, (uint32_t)runtime->format);
+
+		ret =  -EINVAL;
+		goto done;
+	}
+
+	if ((runtime->format != FORMAT_S16_LE) &&
+	    (prtd->mode == MODE_PCM)) {
+		pr_err("%s(): mode:%d and format:%u are not mached\n",
+			__func__, prtd->mode, (uint32_t)runtime->format);
+
+		ret = -EINVAL;
+		goto done;
+	}
+
+	ret = voip_get_media_type(prtd->mode,
+				  prtd->play_samp_rate,
+				  &media_type);
+	if (ret < 0) {
+		pr_err("%s(): fail at getting media_type, ret=%d\n",
+			__func__, ret);
+
+		ret = -EINVAL;
+		goto done;
+	}
+	pr_debug("%s(): media_type=%d\n", __func__, media_type);
+
+	if ((prtd->mode == MODE_PCM) ||
+	    (prtd->mode == MODE_AMR) ||
+	    (prtd->mode == MODE_AMR_WB)) {
+		ret = voip_get_rate_type(prtd->mode,
+					 prtd->rate,
+					 &rate_type);
+		if (ret < 0) {
+			pr_err("%s(): fail at getting rate_type, ret=%d\n",
+				__func__, ret);
+
+			ret = -EINVAL;
+			goto done;
+		}
+		prtd->rate_type = rate_type;
+		pr_debug("rate_type=%d\n", rate_type);
+
+	} else if ((prtd->mode == MODE_IS127) ||
+		   (prtd->mode == MODE_4GV_NB) ||
+		   (prtd->mode == MODE_4GV_WB) ||
+		   (prtd->mode == MODE_4GV_NW)) {
+		ret = voip_get_rate_type(prtd->mode,
+					 prtd->evrc_min_rate,
+					 &evrc_min_rate_type);
+		if (ret < 0) {
+			pr_err("%s(): fail at getting min rate, ret=%d\n",
+				__func__, ret);
+
+			ret = -EINVAL;
+			goto done;
+		}
+		if (evrc_min_rate_type == VOC_0_RATE)
+			evrc_min_rate_type = VOC_8_RATE;
+
+		ret = voip_get_rate_type(prtd->mode,
+					 prtd->evrc_max_rate,
+					 &evrc_max_rate_type);
+		if (ret < 0) {
+			pr_err("%s(): fail at getting max rate, ret=%d\n",
+				__func__, ret);
+
+			ret = -EINVAL;
+			goto done;
+		}
+		if (evrc_max_rate_type == VOC_0_RATE)
+			evrc_max_rate_type = VOC_1_RATE;
+
+		if (evrc_max_rate_type < evrc_min_rate_type) {
+			pr_err("%s(): Invalid EVRC min max rates: %d, %d\n",
+				__func__, evrc_min_rate_type,
+				evrc_max_rate_type);
+
+			ret = -EINVAL;
+			goto done;
+		}
+		pr_debug("%s(): min rate=%d, max rate=%d\n",
+			  __func__, evrc_min_rate_type, evrc_max_rate_type);
+	}
+	if ((prtd->play_samp_rate == 8000) &&
+	    (prtd->cap_samp_rate == 8000))
+		voc_config_vocoder(media_type, rate_type,
+				   VSS_NETWORK_ID_VOIP_NB,
+				   voip_info.dtx_mode,
+				   evrc_min_rate_type,
+				   evrc_max_rate_type);
+	else if ((prtd->play_samp_rate == 16000) &&
+		 (prtd->cap_samp_rate == 16000))
+		voc_config_vocoder(media_type, rate_type,
+				   VSS_NETWORK_ID_VOIP_WB,
+				   voip_info.dtx_mode,
+				   evrc_min_rate_type,
+				   evrc_max_rate_type);
+	else {
+		pr_debug("%s: Invalid rate playback %d, capture %d\n",
+			 __func__, prtd->play_samp_rate,
+			 prtd->cap_samp_rate);
+
+		ret = -EINVAL;
+	}
+done:
+
+	return ret;
+}
+
+static int msm_pcm_prepare(struct snd_pcm_substream *substream)
+{
+	int ret = 0;
+	struct snd_pcm_runtime *runtime = substream->runtime;
+	struct voip_drv_info *prtd = runtime->private_data;
 
 	mutex_lock(&prtd->lock);
 
@@ -774,63 +922,19 @@
 	else if (substream->stream == SNDRV_PCM_STREAM_CAPTURE)
 		ret = msm_pcm_capture_prepare(substream);
 
-	if ((runtime->format != FORMAT_SPECIAL) &&
-		 ((prtd->mode == MODE_AMR) || (prtd->mode == MODE_AMR_WB) ||
-		 (prtd->mode == MODE_IS127) || (prtd->mode == MODE_4GV_NB) ||
-		 (prtd->mode == MODE_4GV_WB))) {
-		pr_err("mode:%d and format:%u are not mached\n",
-			prtd->mode, (uint32_t)runtime->format);
-		ret =  -EINVAL;
-		goto done;
-	}
-
-	if ((runtime->format != FORMAT_S16_LE) &&
-		(prtd->mode == MODE_PCM)) {
-		pr_err("mode:%d and format:%u are not mached\n",
-			prtd->mode, (uint32_t)runtime->format);
-		ret = -EINVAL;
-		goto done;
-	}
-
 	if (prtd->playback_instance && prtd->capture_instance
-				&& (prtd->state != VOIP_STARTED)) {
+	    && (prtd->state != VOIP_STARTED)) {
+		ret = voip_config_vocoder(substream);
+		if (ret < 0) {
+			pr_err("%s(): fail at configuring vocoder for voip, ret=%d\n",
+				__func__, ret);
 
-		ret = voip_get_rate_type(prtd->mode,
-					prtd->rate,
-					&rate_type);
-		if (ret < 0) {
-			pr_err("fail at getting rate_type\n");
-			ret = -EINVAL;
 			goto done;
 		}
-		prtd->rate_type = rate_type;
-		ret = voip_get_media_type(prtd->mode,
-						prtd->play_samp_rate,
-						&media_type);
-		if (ret < 0) {
-			pr_err("fail at getting media_type\n");
-			goto done;
-		}
-		pr_debug(" media_type=%d, rate_type=%d\n", media_type,
-			rate_type);
-		if ((prtd->play_samp_rate == 8000) &&
-					(prtd->cap_samp_rate == 8000))
-			voc_config_vocoder(media_type, rate_type,
-					VSS_NETWORK_ID_VOIP_NB,
-					voip_info.dtx_mode);
-		else if ((prtd->play_samp_rate == 16000) &&
-					(prtd->cap_samp_rate == 16000))
-			voc_config_vocoder(media_type, rate_type,
-					VSS_NETWORK_ID_VOIP_WB,
-					voip_info.dtx_mode);
-		else {
-			pr_debug("%s: Invalid rate playback %d, capture %d\n",
-				 __func__, prtd->play_samp_rate,
-				 prtd->cap_samp_rate);
-			goto done;
-		}
+
 		voc_register_mvs_cb(voip_process_ul_pkt,
-					voip_process_dl_pkt, prtd);
+				    voip_process_dl_pkt, prtd);
+
 		ret = voc_start_voice_call(
 				voc_get_session_id(VOIP_SESSION_NAME));
 
@@ -976,6 +1080,35 @@
 	return 0;
 }
 
+static int msm_voip_evrc_min_max_rate_config_get(struct snd_kcontrol *kcontrol,
+					 struct snd_ctl_elem_value *ucontrol)
+{
+	mutex_lock(&voip_info.lock);
+
+	ucontrol->value.integer.value[0] = voip_info.evrc_min_rate;
+	ucontrol->value.integer.value[1] = voip_info.evrc_max_rate;
+
+	mutex_unlock(&voip_info.lock);
+
+	return 0;
+}
+
+static int msm_voip_evrc_min_max_rate_config_put(struct snd_kcontrol *kcontrol,
+					 struct snd_ctl_elem_value *ucontrol)
+{
+	mutex_lock(&voip_info.lock);
+
+	voip_info.evrc_min_rate = ucontrol->value.integer.value[0];
+	voip_info.evrc_max_rate = ucontrol->value.integer.value[1];
+
+	pr_debug("%s(): evrc_min_rate=%d,evrc_max_rate=%d\n", __func__,
+		  voip_info.evrc_min_rate, voip_info.evrc_max_rate);
+
+	mutex_unlock(&voip_info.lock);
+
+	return 0;
+}
+
 static int voip_get_rate_type(uint32_t mode, uint32_t rate,
 				 uint32_t *rate_type)
 {
@@ -1073,6 +1206,23 @@
 		}
 		break;
 	}
+	case MODE_4GV_NW: {
+		switch (rate) {
+		case VOC_0_RATE:
+		case VOC_8_RATE:
+		case VOC_4_RATE:
+		case VOC_2_RATE:
+		case VOC_1_RATE:
+		case VOC_8_RATE_NC:
+			*rate_type = rate;
+			break;
+		default:
+			pr_err("wrong rate for 4GV_NW.\n");
+			ret = -EINVAL;
+			break;
+		}
+		break;
+	}
 	default:
 		pr_err("wrong mode type.\n");
 		ret = -EINVAL;
@@ -1112,6 +1262,9 @@
 	case MODE_4GV_WB: /* EVRC-WB */
 		*media_type = VSS_MEDIA_ID_4GV_WB_MODEM;
 		break;
+	case MODE_4GV_NW: /* EVRC-NW */
+		*media_type = VSS_MEDIA_ID_4GV_NW_MODEM;
+		break;
 	default:
 		pr_debug(" input mode is not supported\n");
 		ret = -EINVAL;
diff --git a/sound/soc/msm/qdsp6v2/q6adm.c b/sound/soc/msm/qdsp6v2/q6adm.c
index df0fa6a..bba4c14 100644
--- a/sound/soc/msm/qdsp6v2/q6adm.c
+++ b/sound/soc/msm/qdsp6v2/q6adm.c
@@ -18,8 +18,6 @@
 #include <linux/atomic.h>
 #include <linux/wait.h>
 
-#include <mach/qdsp6v2/rtac.h>
-
 #include <sound/apr_audio-v2.h>
 #include <mach/qdsp6v2/apr.h>
 #include <sound/q6adm-v2.h>
@@ -33,7 +31,21 @@
 
 #define RESET_COPP_ID 99
 #define INVALID_COPP_ID 0xFF
-#define ADM_GET_PARAMETER_LENGTH 350
+/* Used for inband payload copy, max size is 4k */
+/* 2 is to account for module & param ID in payload */
+#define ADM_GET_PARAMETER_LENGTH  (4096 - APR_HDR_SIZE - 2 * sizeof(uint32_t))
+
+#define ULL_SUPPORTED_SAMPLE_RATE 48000
+
+enum {
+	ADM_RX_AUDPROC_CAL,
+	ADM_TX_AUDPROC_CAL,
+	ADM_RX_AUDVOL_CAL,
+	ADM_TX_AUDVOL_CAL,
+	ADM_CUSTOM_TOP_CAL,
+	ADM_RTAC,
+	ADM_MAX_CAL_TYPES
+};
 
 struct adm_ctl {
 	void *apr;
@@ -48,10 +60,7 @@
 	struct acdb_cal_block mem_addr_audproc[MAX_AUDPROC_TYPES];
 	struct acdb_cal_block mem_addr_audvol[MAX_AUDPROC_TYPES];
 
-/* 0 - (MAX_AUDPROC_TYPES -1):				audproc handles */
-/* (MAX_AUDPROC_TYPES -1) - (2 * MAX_AUDPROC_TYPES -1):	audvol handles */
-/* + 1 for custom ADM topology */
-	atomic_t mem_map_cal_handles[(2 * MAX_AUDPROC_TYPES) + 1];
+	atomic_t mem_map_cal_handles[ADM_MAX_CAL_TYPES];
 	atomic_t mem_map_cal_index;
 
 	int set_custom_topology;
@@ -462,6 +471,10 @@
 			this_adm.apr = NULL;
 			reset_custom_topology_flags();
 			this_adm.set_custom_topology = 1;
+			for (i = 0; i < ADM_MAX_CAL_TYPES; i++)
+				atomic_set(&this_adm.mem_map_cal_handles[i],
+					0);
+			rtac_clear_mapping(ADM_RTAC_CAL);
 		}
 		pr_debug("Resetting calibration blocks");
 		for (i = 0; i < MAX_AUDPROC_TYPES; i++) {
@@ -515,11 +528,11 @@
 				/* Should only come here if there is an APR */
 				/* error or malformed APR packet. Otherwise */
 				/* response will be returned as */
-				/* ADM_CMDRSP_SHARED_MEM_MAP_REGIONS */
 				if (payload[1] != 0) {
 					pr_err("%s: ADM map error, resuming\n",
 						__func__);
-					atomic_set(&this_adm.copp_stat[0], 1);
+					atomic_set(&this_adm.copp_stat[index],
+							1);
 					wake_up(&this_adm.wait[index]);
 				}
 				break;
@@ -574,13 +587,18 @@
 			if (payload[0] != 0)
 				pr_err("%s: ADM_CMDRSP_GET_PP_PARAMS_V5 returned error = 0x%x\n",
 					__func__, payload[0]);
-			rtac_make_adm_callback(payload,
-				data->payload_size);
-			adm_get_parameters[0] = payload[3];
-			pr_debug("GET_PP PARAM:received parameter length: %x\n",
-					adm_get_parameters[0]);
-			for (i = 0; i < payload[3]; i++)
-				adm_get_parameters[1+i] = payload[4+i];
+			if (rtac_make_adm_callback(payload,
+					data->payload_size))
+				break;
+
+			if (data->payload_size > (4 * sizeof(uint32_t))) {
+				adm_get_parameters[0] = payload[3];
+				pr_debug("GET_PP PARAM:received parameter length: %x\n",
+						adm_get_parameters[0]);
+				/* storing param size then params */
+				for (i = 0; i < payload[3]; i++)
+					adm_get_parameters[1+i] = payload[4+i];
+			}
 			atomic_set(&this_adm.copp_stat[index], 1);
 			wake_up(&this_adm.wait[index]);
 			break;
@@ -590,7 +608,7 @@
 			atomic_set(&this_adm.mem_map_cal_handles[
 				atomic_read(&this_adm.mem_map_cal_index)],
 				*payload);
-			atomic_set(&this_adm.copp_stat[0], 1);
+			atomic_set(&this_adm.copp_stat[index], 1);
 			wake_up(&this_adm.wait[index]);
 			break;
 		default:
@@ -626,13 +644,13 @@
 
 	if (this_adm.set_custom_topology) {
 		/* specific index 4 for adm topology memory */
-		atomic_set(&this_adm.mem_map_cal_index, 4);
+		atomic_set(&this_adm.mem_map_cal_index, ADM_CUSTOM_TOP_CAL);
 
 		/* Only call this once */
 		this_adm.set_custom_topology = 0;
 
-		result = adm_memory_map_regions(port_id, &cal_block.cal_paddr,
-					0, &size, 1);
+		result = adm_memory_map_regions(port_id,
+				&cal_block.cal_paddr, 0, &size, 1);
 		if (result < 0) {
 			pr_err("%s: mmap did not work! addr = 0x%x, size = %d\n",
 				__func__, cal_block.cal_paddr,
@@ -656,7 +674,8 @@
 	adm_top.hdr.opcode = ADM_CMD_ADD_TOPOLOGIES;
 	adm_top.payload_addr_lsw = cal_block.cal_paddr;
 	adm_top.payload_addr_msw = 0;
-	adm_top.mem_map_handle = atomic_read(&this_adm.mem_map_cal_handles[4]);
+	adm_top.mem_map_handle =
+		atomic_read(&this_adm.mem_map_cal_handles[ADM_CUSTOM_TOP_CAL]);
 	adm_top.payload_size = cal_block.cal_size;
 
 	atomic_set(&this_adm.copp_stat[index], 0);
@@ -753,11 +772,15 @@
 	int			result = 0;
 	s32			acdb_path;
 	struct acdb_cal_block	aud_cal;
-	int			size = 4096;
+	int			size;
 	pr_debug("%s\n", __func__);
 
 	/* Maps audio_dev_ctrl path definition to ACDB definition */
 	acdb_path = path - 1;
+	if (acdb_path == TX_CAL)
+		size = 4096 * 4;
+	else
+		size = 4096;
 
 	pr_debug("%s: Sending audproc cal\n", __func__);
 	get_audproc_cal(acdb_path, &aud_cal);
@@ -770,9 +793,7 @@
 		this_adm.mem_addr_audproc[acdb_path].cal_size)) {
 
 		if (this_adm.mem_addr_audproc[acdb_path].cal_paddr != 0)
-			adm_memory_unmap_regions(port_id,
-				&this_adm.mem_addr_audproc[acdb_path].
-				cal_paddr, &size, 1);
+			adm_memory_unmap_regions(port_id);
 
 		result = adm_memory_map_regions(port_id, &aud_cal.cal_paddr,
 						0, &size, 1);
@@ -806,9 +827,7 @@
 		this_adm.mem_addr_audvol[acdb_path].cal_size)) {
 
 		if (this_adm.mem_addr_audvol[acdb_path].cal_paddr != 0)
-			adm_memory_unmap_regions(port_id,
-				&this_adm.mem_addr_audvol[acdb_path].cal_paddr,
-				&size, 1);
+			adm_memory_unmap_regions(port_id);
 
 		result = adm_memory_map_regions(port_id, &aud_cal.cal_paddr,
 						0, &size, 1);
@@ -831,6 +850,133 @@
 			__func__, port_id, acdb_path);
 }
 
+int adm_map_rtac_block(struct rtac_cal_block_data *cal_block)
+{
+	int	result = 0;
+	pr_debug("%s\n", __func__);
+
+	if (cal_block == NULL) {
+		pr_err("%s: cal_block is NULL!\n",
+			__func__);
+		result = -EINVAL;
+		goto done;
+	}
+
+	if (cal_block->cal_data.paddr == 0) {
+		pr_debug("%s: No address to map!\n",
+			__func__);
+		result = -EINVAL;
+		goto done;
+	}
+
+	if (cal_block->map_data.map_size == 0) {
+		pr_debug("%s: map size is 0!\n",
+			__func__);
+		result = -EINVAL;
+		goto done;
+	}
+
+	/* valid port ID needed for callback use primary I2S */
+	atomic_set(&this_adm.mem_map_cal_index, ADM_RTAC);
+	result = adm_memory_map_regions(PRIMARY_I2S_RX,
+			&cal_block->cal_data.paddr, 0,
+			&cal_block->map_data.map_size, 1);
+	if (result < 0) {
+		pr_err("%s: RTAC mmap did not work! addr = 0x%x, size = %d\n",
+			__func__, cal_block->cal_data.paddr,
+			cal_block->map_data.map_size);
+		goto done;
+	}
+
+	cal_block->map_data.map_handle = atomic_read(
+		&this_adm.mem_map_cal_handles[ADM_RTAC]);
+done:
+	return result;
+}
+
+int adm_unmap_rtac_block(uint32_t *mem_map_handle)
+{
+	int	result = 0;
+	pr_debug("%s\n", __func__);
+
+	if (mem_map_handle == NULL) {
+		pr_debug("%s: Map handle is NULL, nothing to unmap\n",
+			__func__);
+		goto done;
+	}
+
+	if (*mem_map_handle == 0) {
+		pr_debug("%s: Map handle is 0, nothing to unmap\n",
+			__func__);
+		goto done;
+	}
+
+	if (*mem_map_handle != atomic_read(
+			&this_adm.mem_map_cal_handles[ADM_RTAC])) {
+		pr_err("%s: Map handles do not match! Unmapping RTAC, RTAC map 0x%x, ADM map 0x%x\n",
+			__func__, *mem_map_handle, atomic_read(
+			&this_adm.mem_map_cal_handles[ADM_RTAC]));
+
+		/* if mismatch use handle passed in to unmap */
+		atomic_set(&this_adm.mem_map_cal_handles[ADM_RTAC],
+			   *mem_map_handle);
+	}
+
+	/* valid port ID needed for callback use primary I2S */
+	atomic_set(&this_adm.mem_map_cal_index, ADM_RTAC);
+	result = adm_memory_unmap_regions(PRIMARY_I2S_RX);
+	if (result < 0) {
+		pr_debug("%s: adm_memory_unmap_regions failed, error %d\n",
+			__func__, result);
+	} else {
+		atomic_set(&this_adm.mem_map_cal_handles[ADM_RTAC], 0);
+		*mem_map_handle = 0;
+	}
+done:
+	return result;
+}
+
+int adm_unmap_cal_blocks(void)
+{
+	int	i;
+	int	result = 0;
+	int	result2 = 0;
+
+	for (i = 0; i < ADM_MAX_CAL_TYPES; i++) {
+		if (atomic_read(&this_adm.mem_map_cal_handles[i]) != 0) {
+
+			if (i <= ADM_TX_AUDPROC_CAL) {
+				this_adm.mem_addr_audproc[i].cal_paddr = 0;
+				this_adm.mem_addr_audproc[i].cal_size = 0;
+			} else if (i <= ADM_TX_AUDVOL_CAL) {
+				this_adm.mem_addr_audvol
+					[(i - ADM_RX_AUDVOL_CAL)].cal_paddr
+					= 0;
+				this_adm.mem_addr_audvol
+					[(i - ADM_RX_AUDVOL_CAL)].cal_size
+					= 0;
+			} else if (i == ADM_CUSTOM_TOP_CAL) {
+				this_adm.set_custom_topology = 1;
+			} else {
+				continue;
+			}
+
+			/* valid port ID needed for callback use primary I2S */
+			atomic_set(&this_adm.mem_map_cal_index, i);
+			result2 = adm_memory_unmap_regions(PRIMARY_I2S_RX);
+			if (result2 < 0) {
+				pr_err("%s: adm_memory_unmap_regions failed, err %d\n",
+						__func__, result2);
+				result = result2;
+			} else {
+				atomic_set(&this_adm.mem_map_cal_handles[i],
+					0);
+			}
+		}
+	}
+	return result;
+}
+
 int adm_connect_afe_port(int mode, int session_id, int port_id)
 {
 	struct adm_cmd_connect_afe_port_v5	cmd;
@@ -959,11 +1105,9 @@
 		open.hdr.opcode = ADM_CMD_DEVICE_OPEN_V5;
 		open.flags = 0x00;
 		if (perf_mode) {
-			open.flags |= ADM_LOW_LATENCY_DEVICE_SESSION <<
-				ADM_BIT_SHIFT_DEVICE_PERF_MODE_FLAG;
+			open.flags |= ADM_ULTRA_LOW_LATENCY_DEVICE_SESSION;
 		} else {
-			open.flags |= ADM_LEGACY_DEVICE_SESSION <<
-				ADM_BIT_SHIFT_DEVICE_PERF_MODE_FLAG;
+			open.flags |= ADM_LEGACY_DEVICE_SESSION;
 		}
 
 		open.mode_of_operation = path;
@@ -981,11 +1125,14 @@
 			(open.topology_id == VPM_TX_DM_FLUENCE_COPP_TOPOLOGY))
 				rate = 16000;
 
-		if (perf_mode)
+		if (perf_mode) {
 			open.topology_id = NULL_COPP_TOPOLOGY;
+			rate = ULL_SUPPORTED_SAMPLE_RATE;
+		}
 
 		open.dev_num_channel = channel_mode & 0x00FF;
 		open.bit_width = bits_per_sample;
+		WARN_ON(perf_mode && (rate != 48000));
 		open.sample_rate  = rate;
 		memset(open.dev_channel_mapping, 0, 8);
 
@@ -1289,7 +1436,7 @@
 		++mregions;
 	}
 
-	atomic_set(&this_adm.copp_stat[0], 0);
+	atomic_set(&this_adm.copp_stat[index], 0);
 	ret = apr_send_pkt(this_adm.apr, (uint32_t *) mmap_region_cmd);
 	if (ret < 0) {
 		pr_err("%s: mmap_regions op[0x%x]rc[%d]\n", __func__,
@@ -1299,7 +1446,7 @@
 	}
 
 	ret = wait_event_timeout(this_adm.wait[index],
-			atomic_read(&this_adm.copp_stat[0]), 5 * HZ);
+			atomic_read(&this_adm.copp_stat[index]), 5 * HZ);
 	if (!ret) {
 		pr_err("%s: timeout. waited for memory_map\n", __func__);
 		ret = -EINVAL;
@@ -1310,8 +1457,7 @@
 	return ret;
 }
 
-int adm_memory_unmap_regions(int32_t port_id, uint32_t *buf_add,
-			uint32_t *bufsz, uint32_t bufcnt)
+int adm_memory_unmap_regions(int32_t port_id)
 {
 	struct  avs_cmd_shared_mem_unmap_regions unmap_regions;
 	int     ret = 0;
diff --git a/sound/soc/msm/qdsp6v2/q6afe.c b/sound/soc/msm/qdsp6v2/q6afe.c
index 1810770..59113fe 100644
--- a/sound/soc/msm/qdsp6v2/q6afe.c
+++ b/sound/soc/msm/qdsp6v2/q6afe.c
@@ -25,6 +25,14 @@
 
 #include "audio_acdb.h"
 
+enum {
+	AFE_RX_CAL,
+	AFE_TX_CAL,
+	AFE_AANC_TX_CAL,
+	MAX_AFE_CAL_TYPES
+};
+
+
 struct afe_ctl {
 	void *apr;
 	atomic_t state;
@@ -39,8 +47,8 @@
 	void *rx_private_data;
 	uint32_t mmap_handle;
 
-	struct acdb_cal_block afe_cal_addr[MAX_AUDPROC_TYPES];
-	atomic_t mem_map_cal_handles[MAX_AUDPROC_TYPES];
+	struct acdb_cal_block afe_cal_addr[MAX_AFE_CAL_TYPES];
+	atomic_t mem_map_cal_handles[MAX_AFE_CAL_TYPES];
 	atomic_t mem_map_cal_index;
 	u16 dtmf_gen_rx_portid;
 	struct afe_spkr_prot_calib_get_resp calib_data;
@@ -94,7 +102,7 @@
 		pr_debug("q6afe: reset event = %d %d apr[%p]\n",
 			data->reset_event, data->reset_proc, this_afe.apr);
 
-		for (i = 0; i < MAX_AUDPROC_TYPES; i++) {
+		for (i = 0; i < MAX_AFE_CAL_TYPES; i++) {
 			this_afe.afe_cal_addr[i].cal_paddr = 0;
 			this_afe.afe_cal_addr[i].cal_size = 0;
 		}
@@ -349,7 +357,8 @@
 {
 	int ret;
 
-	atomic_set(&this_afe.state, 1);
+	if (wait)
+		atomic_set(&this_afe.state, 1);
 	atomic_set(&this_afe.status, 0);
 	ret = apr_send_pkt(this_afe.apr, data);
 	if (ret > 0) {
@@ -384,7 +393,7 @@
 	u32 handle;
 
 	pr_debug("%s: path %d\n", __func__, path);
-	if (path == AANC_TX_CAL) {
+	if (path == AFE_AANC_TX_CAL) {
 		get_aanc_cal(&cal_block);
 	} else {
 		get_afe_cal(path, &cal_block);
@@ -461,6 +470,35 @@
 	return;
 }
 
+int afe_unmap_cal_blocks(void)
+{
+	int	i;
+	int	result = 0;
+	int	result2 = 0;
+
+	for (i = 0; i < MAX_AFE_CAL_TYPES; i++) {
+		if (atomic_read(&this_afe.mem_map_cal_handles[i]) != 0) {
+
+			atomic_set(&this_afe.mem_map_cal_index, i);
+			result2 = afe_cmd_memory_unmap(atomic_read(
+				&this_afe.mem_map_cal_handles[i]));
+			if (result2 < 0) {
+				pr_err("%s: unmap failed, err %d\n",
+					__func__, result2);
+				result = result2;
+			} else {
+				atomic_set(&this_afe.mem_map_cal_handles[i],
+					0);
+			}
+			atomic_set(&this_afe.mem_map_cal_index, -1);
+
+			this_afe.afe_cal_addr[i].cal_paddr = 0;
+			this_afe.afe_cal_addr[i].cal_size = 0;
+		}
+	}
+	return result;
+}
+
 static int afe_spk_prot_prepare(int port, int param_id,
 		union afe_spkr_prot_config *prot_config)
 {
@@ -594,16 +632,81 @@
 	}
 }
 
+static int afe_send_hw_delay(u16 port_id, u32 rate)
+{
+	struct hw_delay_entry delay_entry;
+	struct afe_audioif_config_command config;
+	int index = 0;
+	int ret = -EINVAL;
+
+	pr_debug("%s\n", __func__);
+
+	delay_entry.sample_rate = rate;
+	if (afe_get_port_type(port_id) == MSM_AFE_PORT_TYPE_TX)
+		ret = get_hw_delay(TX_CAL, &delay_entry);
+	else if (afe_get_port_type(port_id) == MSM_AFE_PORT_TYPE_RX)
+		ret = get_hw_delay(RX_CAL, &delay_entry);
+
+	if (ret != 0) {
+		pr_warn("%s: Failed to get hw delay info\n", __func__);
+		goto fail_cmd;
+	}
+	index = q6audio_get_port_index(port_id);
+	if (index < 0) {
+		pr_debug("%s: AFE port index invalid!\n", __func__);
+		goto fail_cmd;
+	}
+
+	config.hdr.hdr_field = APR_HDR_FIELD(APR_MSG_TYPE_SEQ_CMD,
+				APR_HDR_LEN(APR_HDR_SIZE), APR_PKT_VER);
+	config.hdr.pkt_size = sizeof(config);
+	config.hdr.src_port = 0;
+	config.hdr.dest_port = 0;
+	config.hdr.token = index;
+
+	config.hdr.opcode = AFE_PORT_CMD_SET_PARAM_V2;
+	config.param.port_id = q6audio_get_port_id(port_id);
+	config.param.payload_size = sizeof(config) - sizeof(struct apr_hdr) -
+				    sizeof(config.param);
+	config.param.payload_address_lsw = 0x00;
+	config.param.payload_address_msw = 0x00;
+	config.param.mem_map_handle = 0x00;
+	config.pdata.module_id = AFE_MODULE_AUDIO_DEV_INTERFACE;
+	config.pdata.param_id = AFE_PARAM_ID_DEVICE_HW_DELAY;
+	config.pdata.param_size = sizeof(config.port);
+
+	config.port.hw_delay.delay_in_us = delay_entry.delay_usec;
+	config.port.hw_delay.device_hw_delay_minor_version =
+				AFE_API_VERSION_DEVICE_HW_DELAY;
+
+	ret = afe_apr_send_pkt(&config, &this_afe.wait[index]);
+	if (ret) {
+		pr_err("%s: AFE hw delay for port %#x failed\n",
+		       __func__, port_id);
+		goto fail_cmd;
+	} else if (atomic_read(&this_afe.status) != 0) {
+		pr_err("%s: config cmd failed\n", __func__);
+		ret = -EINVAL;
+		goto fail_cmd;
+	}
+
+fail_cmd:
+	pr_debug("%s port_id %u rate %u delay_usec %d status %d\n",
+	__func__, port_id, rate, delay_entry.delay_usec, ret);
+	return ret;
+
+}
+
 void afe_send_cal(u16 port_id)
 {
 	pr_debug("%s\n", __func__);
 
 	if (afe_get_port_type(port_id) == MSM_AFE_PORT_TYPE_TX) {
 		afe_send_cal_spkr_prot_tx(port_id);
-		afe_send_cal_block(TX_CAL, port_id);
+		afe_send_cal_block(AFE_TX_CAL, port_id);
 	} else if (afe_get_port_type(port_id) == MSM_AFE_PORT_TYPE_RX) {
 		afe_send_cal_spkr_prot_rx(port_id);
-		afe_send_cal_block(RX_CAL, port_id);
+		afe_send_cal_block(AFE_RX_CAL, port_id);
 	}
 }
 
@@ -1149,7 +1252,7 @@
 			__func__, ret);
 		goto fail_cmd;
 	}
-	afe_send_cal_block(AANC_TX_CAL, tx_port_id);
+	afe_send_cal_block(AFE_AANC_TX_CAL, tx_port_id);
 
 fail_cmd:
 	return ret;
@@ -1210,12 +1313,19 @@
 		return ret;
 
 	afe_send_cal(port_id);
+	afe_send_hw_delay(port_id, rate);
 
 	/* Start SW MAD module */
 	mad_type = afe_port_get_mad_type(port_id);
 	pr_debug("%s: port_id 0x%x, mad_type %d\n", __func__, port_id,
 		 mad_type);
-	if (mad_type != MAD_HW_NONE) {
+	if (mad_type != MAD_HW_NONE && mad_type != MAD_SW_AUDIO) {
+		if (!afe_has_config(AFE_CDC_REGISTERS_CONFIG) ||
+		    !afe_has_config(AFE_SLIMBUS_SLAVE_CONFIG)) {
+			pr_err("%s: AFE isn't configured yet for HW MAD\n",
+			       __func__);
+			return -EINVAL;
+		}
 		ret = afe_turn_onoff_hw_mad(mad_type, true);
 		if (ret) {
 			pr_err("%s: afe_turn_onoff_hw_mad failed %d\n",
@@ -1998,7 +2108,6 @@
 		goto fail_cmd;
 	}
 
-	pr_debug("%s: mmap handle 0x%x\n", __func__, this_afe.mmap_handle);
 	kfree(mmap_region_cmd);
 	return 0;
 fail_cmd:
@@ -2082,7 +2191,6 @@
 	cnt = port->max_buf_cnt - 1;
 
 	if (port->buf[0].data) {
-		msm_audio_ion_free(port->buf[0].client, port->buf[0].handle);
 		pr_debug("%s:data[%p]phys[%p][%p] , client[%p] handle[%p]\n",
 			__func__,
 			(void *)port->buf[0].data,
@@ -2090,6 +2198,9 @@
 			(void *)&port->buf[0].phys,
 			(void *)port->buf[0].client,
 			(void *)port->buf[0].handle);
+		msm_audio_ion_free(port->buf[0].client, port->buf[0].handle);
+		port->buf[0].client = NULL;
+		port->buf[0].handle = NULL;
 	}
 
 	while (cnt >= 0) {
@@ -2809,7 +2920,7 @@
 	mad_type = afe_port_get_mad_type(port_id);
 	pr_debug("%s: port_id 0x%x, mad_type %d\n", __func__, port_id,
 		 mad_type);
-	if (mad_type != MAD_HW_NONE) {
+	if (mad_type != MAD_HW_NONE && mad_type != MAD_SW_AUDIO) {
 		pr_debug("%s: Turn off MAD\n", __func__);
 		ret = afe_turn_onoff_hw_mad(mad_type, false);
 		if (ret) {
diff --git a/sound/soc/msm/qdsp6v2/q6asm.c b/sound/soc/msm/qdsp6v2/q6asm.c
index 6a34470..9c0c362 100644
--- a/sound/soc/msm/qdsp6v2/q6asm.c
+++ b/sound/soc/msm/qdsp6v2/q6asm.c
@@ -36,7 +36,6 @@
 
 #include <mach/memory.h>
 #include <mach/debug_mm.h>
-#include <mach/qdsp6v2/rtac.h>
 
 #include <sound/apr_audio-v2.h>
 #include <sound/q6asm-v2.h>
@@ -72,11 +71,11 @@
 static int q6asm_memory_map_regions(struct audio_client *ac, int dir,
 				uint32_t bufsz, uint32_t bufcnt,
 				bool is_contiguous);
-static int q6asm_memory_unmap_regions(struct audio_client *ac, int dir,
-				uint32_t bufsz, uint32_t bufcnt);
+static int q6asm_memory_unmap_regions(struct audio_client *ac, int dir);
 static void q6asm_reset_buf_state(struct audio_client *ac);
 
 static int q6asm_map_channels(u8 *channel_mapping, uint32_t channels);
+void *q6asm_mmap_apr_reg(void);
 
 
 #ifdef CONFIG_DEBUG_FS
@@ -96,9 +95,28 @@
 static int out_cold_index;
 static char *out_buffer;
 static char *in_buffer;
+static struct audio_buffer common_buf[2];
+static struct audio_client common_client;
 static int set_custom_topology;
 static int topology_map_handle;
 
+
+int q6asm_mmap_apr_dereg(void)
+{
+	int c;
+
+	c = atomic_sub_return(1, &this_mmap.ref_cnt);
+	if (c == 0) {
+		apr_deregister(this_mmap.apr);
+		pr_debug("%s: APR De-Register common port\n", __func__);
+	} else if (c < 0) {
+		pr_err("%s: APR Common Port Already Closed\n", __func__);
+		atomic_set(&this_mmap.ref_cnt, 0);
+	}
+
+	return 0;
+}
+
 static int audio_output_latency_dbgfs_open(struct inode *inode,
 							struct file *file)
 {
@@ -340,7 +358,6 @@
 {
 	struct acdb_cal_block		cal_block;
 	struct cmd_set_topologies	asm_top;
-	struct audio_buffer		*buf;
 	struct asm_buffer_node		*buf_node = NULL;
 	struct list_head		*ptr, *next;
 	int				result;
@@ -354,20 +371,29 @@
 	}
 
 	if (set_custom_topology) {
+		if (common_client.mmap_apr == NULL) {
+			common_client.mmap_apr = q6asm_mmap_apr_reg();
+			common_client.apr = common_client.mmap_apr;
+			if (common_client.mmap_apr == NULL) {
+				pr_err("%s: q6asm_mmap_apr_reg failed\n",
+					__func__);
+				result = -EPERM;
+				goto done;
+			}
+		}
 		/* Only call this once */
 		set_custom_topology = 0;
 
 		/* Use first asm buf to map memory */
-		buf = kzalloc(sizeof(struct audio_buffer), GFP_KERNEL);
-		if (!buf) {
-			pr_debug("%s: could not allocate temp memory\n",
+		if (common_client.port[IN].buf == NULL) {
+			pr_err("%s: common buf is NULL\n",
 				__func__);
 			goto done;
 		}
-		buf[0].phys = cal_block.cal_paddr;
-		ac->port[0].buf = buf;
+		common_client.port[IN].buf->phys = cal_block.cal_paddr;
 
-		result = q6asm_memory_map_regions(ac, 0, size, 1, 1);
+		result = q6asm_memory_map_regions(&common_client,
+							IN, size, 1, 1);
 		if (result < 0) {
 			pr_err("%s: mmap did not work! addr = 0x%x, size = %d\n",
 				__func__, cal_block.cal_paddr,
@@ -375,7 +401,8 @@
 			goto done;
 		}
 
-		list_for_each_safe(ptr, next, &ac->port[IN].mem_map_handle) {
+		list_for_each_safe(ptr, next,
+				&common_client.port[IN].mem_map_handle) {
 			buf_node = list_entry(ptr, struct asm_buffer_node,
 						list);
 			if (buf_node->buf_addr_lsw == cal_block.cal_paddr) {
@@ -384,7 +411,13 @@
 			}
 		}
 
-		kfree(buf);
+		result = q6asm_mmap_apr_dereg();
+		if (result < 0) {
+			pr_err("%s: q6asm_mmap_apr_dereg failed, err %d\n",
+				__func__, result);
+		} else {
+			common_client.mmap_apr = NULL;
+		}
 	}
 
 	q6asm_add_hdr(ac, &asm_top.hdr, APR_PKT_SIZE(APR_HDR_SIZE,
@@ -415,11 +448,181 @@
 		goto done;
 	}
 
-
 done:
 	return;
 }
 
+int q6asm_map_rtac_block(struct rtac_cal_block_data *cal_block)
+{
+	int			result = 0;
+	struct asm_buffer_node	*buf_node = NULL;
+	struct list_head	*ptr, *next;
+	pr_debug("%s\n", __func__);
+
+	if (cal_block == NULL) {
+		pr_err("%s: cal_block is NULL!\n",
+			__func__);
+		result = -EINVAL;
+		goto done;
+	}
+
+	if (cal_block->cal_data.paddr == 0) {
+		pr_debug("%s: No address to map!\n",
+			__func__);
+		result = -EINVAL;
+		goto done;
+	}
+
+	if (common_client.mmap_apr == NULL) {
+		common_client.mmap_apr = q6asm_mmap_apr_reg();
+		if (common_client.mmap_apr == NULL) {
+			pr_err("%s: q6asm_mmap_apr_reg failed\n",
+				__func__);
+			result = -EPERM;
+			goto done;
+		}
+	}
+
+	if (cal_block->map_data.map_size == 0) {
+		pr_debug("%s: map size is 0!\n",
+			__func__);
+		result = -EINVAL;
+		goto done;
+	}
+
+	/* Use second asm buf to map memory */
+	if (common_client.port[OUT].buf == NULL) {
+		pr_err("%s: common buf is NULL\n",
+			__func__);
+		result = -EINVAL;
+		goto done;
+	}
+
+	common_client.port[OUT].buf->phys = cal_block->cal_data.paddr;
+
+	result = q6asm_memory_map_regions(&common_client,
+			OUT, cal_block->map_data.map_size, 1, 1);
+	if (result < 0) {
+		pr_err("%s: mmap did not work! addr = 0x%x, size = %d\n",
+			__func__, cal_block->cal_data.paddr,
+			cal_block->map_data.map_size);
+		goto done;
+	}
+
+	list_for_each_safe(ptr, next,
+		&common_client.port[OUT].mem_map_handle) {
+		buf_node = list_entry(ptr, struct asm_buffer_node,
+					list);
+		if (buf_node->buf_addr_lsw == cal_block->cal_data.paddr) {
+			cal_block->map_data.map_handle =  buf_node->mmap_hdl;
+			break;
+		}
+	}
+
+	result = q6asm_mmap_apr_dereg();
+	if (result < 0) {
+		pr_err("%s: q6asm_mmap_apr_dereg failed, err %d\n",
+			__func__, result);
+	} else {
+		common_client.mmap_apr = NULL;
+	}
+done:
+	return result;
+}
+
+int q6asm_unmap_rtac_block(uint32_t *mem_map_handle)
+{
+	int	result = 0;
+	int	result2 = 0;
+	pr_debug("%s\n", __func__);
+
+	if (mem_map_handle == NULL) {
+		pr_debug("%s: Map handle is NULL, nothing to unmap\n",
+			__func__);
+		goto done;
+	}
+
+	if (*mem_map_handle == 0) {
+		pr_debug("%s: Map handle is 0, nothing to unmap\n",
+			__func__);
+		goto done;
+	}
+
+	if (common_client.mmap_apr == NULL) {
+		common_client.mmap_apr = q6asm_mmap_apr_reg();
+		if (common_client.mmap_apr == NULL) {
+			pr_err("%s: q6asm_mmap_apr_reg failed\n",
+				__func__);
+			result = -EPERM;
+			goto done;
+		}
+	}
+
+
+	result2 = q6asm_memory_unmap_regions(&common_client, OUT);
+	if (result2 < 0) {
+		pr_err("%s: unmap failed, err %d\n",
+			__func__, result2);
+		result = result2;
+	} else {
+		mem_map_handle = 0;
+	}
+
+	result2 = q6asm_mmap_apr_dereg();
+	if (result2 < 0) {
+		pr_err("%s: q6asm_mmap_apr_dereg failed, err %d\n",
+			__func__, result2);
+		result = result2;
+	} else {
+		common_client.mmap_apr = NULL;
+	}
+done:
+	return result;
+}
+
+int q6asm_unmap_cal_blocks(void)
+{
+	int	result = 0;
+	int	result2 = 0;
+	pr_debug("%s\n", __func__);
+
+	if (topology_map_handle == 0)
+		goto done;
+
+	if (common_client.mmap_apr == NULL) {
+		common_client.mmap_apr = q6asm_mmap_apr_reg();
+		if (common_client.mmap_apr == NULL) {
+			pr_err("%s: q6asm_mmap_apr_reg failed\n",
+				__func__);
+			result = -EPERM;
+			goto done;
+		}
+	}
+
+	result2 = q6asm_memory_unmap_regions(&common_client, IN);
+	if (result2 < 0) {
+		pr_err("%s: unmap failed, err %d\n",
+			__func__, result2);
+		result = result2;
+	} else {
+		topology_map_handle = 0;
+	}
+
+	result2 = q6asm_mmap_apr_dereg();
+	if (result2 < 0) {
+		pr_err("%s: q6asm_mmap_apr_dereg failed, err %d\n",
+			__func__, result2);
+		result = result2;
+	} else {
+		common_client.mmap_apr = NULL;
+	}
+
+	set_custom_topology = 0;
+
+done:
+	return result;
+}
+
 int q6asm_audio_client_buf_free(unsigned int dir,
 			struct audio_client *ac)
 {
@@ -437,9 +640,7 @@
 		cnt = port->max_buf_cnt - 1;
 
 		if (cnt >= 0) {
-			rc = q6asm_memory_unmap_regions(ac, dir,
-							port->buf[0].size,
-							port->max_buf_cnt);
+			rc = q6asm_memory_unmap_regions(ac, dir);
 			if (rc < 0)
 				pr_err("%s CMD Memory_unmap_regions failed\n",
 								__func__);
@@ -449,6 +650,8 @@
 			if (port->buf[cnt].data) {
 				msm_audio_ion_free(port->buf[cnt].client,
 						   port->buf[cnt].handle);
+				port->buf[cnt].client = NULL;
+				port->buf[cnt].handle = NULL;
 				port->buf[cnt].data = NULL;
 				port->buf[cnt].phys = 0;
 				--(port->max_buf_cnt);
@@ -485,7 +688,6 @@
 	}
 
 	if (port->buf[0].data) {
-		msm_audio_ion_free(port->buf[0].client, port->buf[0].handle);
 		pr_debug("%s:data[%p]phys[%p][%p] , client[%p] handle[%p]\n",
 			__func__,
 			(void *)port->buf[0].data,
@@ -493,6 +695,9 @@
 			(void *)&port->buf[0].phys,
 			(void *)port->buf[0].client,
 			(void *)port->buf[0].handle);
+		msm_audio_ion_free(port->buf[0].client, port->buf[0].handle);
+		port->buf[0].client = NULL;
+		port->buf[0].handle = NULL;
 	}
 
 	while (cnt >= 0) {
@@ -507,23 +712,6 @@
 	return 0;
 }
 
-int q6asm_mmap_apr_dereg(void)
-{
-	int c;
-
-	c = atomic_sub_return(1, &this_mmap.ref_cnt);
-	if (c == 0) {
-		apr_deregister(this_mmap.apr);
-		pr_debug("%s: APR De-Register common port\n", __func__);
-	} else if (c < 0) {
-		pr_err("%s: APR Common Port Already Closed\n", __func__);
-		atomic_set(&this_mmap.ref_cnt, 0);
-	}
-
-	return 0;
-}
-
-
 void q6asm_audio_client_free(struct audio_client *ac)
 {
 	int loopcnt;
@@ -662,6 +850,10 @@
 
 struct audio_client *q6asm_get_audio_client(int session_id)
 {
+	if (session_id == ASM_CONTROL_SESSION) {
+		return &common_client;
+	}
+
 	if ((session_id <= 0) || (session_id > SESSION_MAX)) {
 		pr_err("%s: invalid session: %d\n", __func__, session_id);
 		goto err;
@@ -871,6 +1063,8 @@
 		this_mmap.apr = NULL;
 		reset_custom_topology_flags();
 		set_custom_topology = 1;
+		topology_map_handle = 0;
+		rtac_clear_mapping(ASM_RTAC_CAL);
 		return 0;
 	}
 	sid = (data->token >> 8) & 0x0F;
@@ -891,7 +1085,7 @@
 		case ASM_CMD_SHARED_MEM_UNMAP_REGIONS:
 			if (payload[1] != 0) {
 				pr_err("%s: cmd = 0x%x returned error = 0x%x sid:%d\n",
-				__func__, payload[0], payload[1], sid);
+					__func__, payload[0], payload[1], sid);
 			}
 
 			if (atomic_read(&ac->cmd_state)) {
@@ -1005,8 +1199,6 @@
 					(uint32_t *)data->payload, ac->priv);
 		apr_reset(ac->apr);
 		ac->apr = NULL;
-		reset_custom_topology_flags();
-		set_custom_topology = 1;
 		return 0;
 	}
 
@@ -1415,7 +1607,7 @@
 
 	open.preprocopo_id = get_asm_topology();
 	if (open.preprocopo_id == 0)
-		open.preprocopo_id = ASM_STREAM_POSTPROC_TOPO_ID_DEFAULT;
+		open.preprocopo_id = ASM_STREAM_POSTPROC_TOPO_ID_NONE;
 	open.bits_per_sample = bits_per_sample;
 	open.mode_flags = 0x0;
 
@@ -1504,11 +1696,9 @@
 	open.hdr.opcode = ASM_STREAM_CMD_OPEN_WRITE_V3;
 	open.mode_flags = 0x00;
 	if (ac->perf_mode)
-		open.mode_flags |= (ASM_LOW_LATENCY_STREAM_SESSION <<
-				ASM_SHIFT_STREAM_PERF_MODE_FLAG_IN_OPEN_WRITE);
+		open.mode_flags |= ASM_ULTRA_LOW_LATENCY_STREAM_SESSION;
 	else
-		open.mode_flags |= (ASM_LEGACY_STREAM_SESSION <<
-				ASM_SHIFT_STREAM_PERF_MODE_FLAG_IN_OPEN_WRITE);
+		open.mode_flags |= ASM_LEGACY_STREAM_SESSION;
 
 	/* source endpoint : matrix */
 	open.sink_endpointype = ASM_END_POINT_DEVICE_MATRIX;
@@ -1516,7 +1706,7 @@
 
 	open.postprocopo_id = get_asm_topology();
 	if (open.postprocopo_id == 0)
-		open.postprocopo_id = ASM_STREAM_POSTPROC_TOPO_ID_DEFAULT;
+		open.postprocopo_id = ASM_STREAM_POSTPROC_TOPO_ID_NONE;
 
 	switch (format) {
 	case FORMAT_LINEAR_PCM:
@@ -1600,7 +1790,7 @@
 	/* source endpoint : matrix */
 	open.postprocopo_id = get_asm_topology();
 	if (open.postprocopo_id == 0)
-		open.postprocopo_id = ASM_STREAM_POSTPROC_TOPO_ID_DEFAULT;
+		open.postprocopo_id = ASM_STREAM_POSTPROC_TOPO_ID_NONE;
 
 	switch (wr_format) {
 	case FORMAT_LINEAR_PCM:
@@ -2047,7 +2237,6 @@
 			uint16_t sce_left, uint16_t sce_right)
 {
 	struct asm_aac_dual_mono_mapping_param dual_mono;
-	u32 frames_per_buf = 0;
 
 	int rc = 0;
 
@@ -2058,11 +2247,8 @@
 
 	dual_mono.hdr.opcode = ASM_STREAM_CMD_SET_ENCDEC_PARAM;
 	dual_mono.encdec.param_id = ASM_PARAM_ID_AAC_DUAL_MONO_MAPPING;
-	dual_mono.encdec.param_size = sizeof(struct asm_aac_enc_cfg_v2) -
-				sizeof(struct asm_stream_cmd_set_encdec_param);
-	dual_mono.encblk.frames_per_buf = frames_per_buf;
-	dual_mono.encblk.enc_cfg_blk_size  = dual_mono.encdec.param_size -
-				sizeof(struct asm_enc_cfg_blk_param_v2);
+	dual_mono.encdec.param_size = sizeof(dual_mono.left_channel_sce) +
+				sizeof(dual_mono.right_channel_sce);
 	dual_mono.left_channel_sce = sce_left;
 	dual_mono.right_channel_sce = sce_right;
 
@@ -2604,7 +2790,7 @@
 	int	rc = 0;
 	int	cmd_size = 0;
 
-	if (!ac || ac->apr == NULL || ac->mmap_apr == NULL) {
+	if (!ac || ac->mmap_apr == NULL) {
 		pr_err("APR handle NULL\n");
 		return -EINVAL;
 	}
@@ -2681,7 +2867,7 @@
 
 	int rc = 0;
 
-	if (!ac || ac->apr == NULL || this_mmap.apr == NULL) {
+	if (!ac || this_mmap.apr == NULL) {
 		pr_err("APR handle NULL\n");
 		return -EINVAL;
 	}
@@ -2751,7 +2937,7 @@
 	uint32_t bufcnt_t;
 	uint32_t bufsz_t;
 
-	if (!ac || ac->apr == NULL || ac->mmap_apr == NULL) {
+	if (!ac || ac->mmap_apr == NULL) {
 		pr_err("APR handle NULL\n");
 		return -EINVAL;
 	}
@@ -2850,8 +3036,7 @@
 	return rc;
 }
 
-static int q6asm_memory_unmap_regions(struct audio_client *ac, int dir,
-				uint32_t bufsz, uint32_t bufcnt)
+static int q6asm_memory_unmap_regions(struct audio_client *ac, int dir)
 {
 	struct avs_cmd_shared_mem_unmap_regions mem_unmap;
 	struct audio_port_data *port = NULL;
@@ -2861,7 +3046,7 @@
 	int	rc = 0;
 	int	cmd_size = 0;
 
-	if (!ac || ac->apr == NULL || ac->mmap_apr == NULL) {
+	if (!ac || ac->mmap_apr == NULL) {
 		pr_err("APR handle NULL\n");
 		return -EINVAL;
 	}
@@ -3851,7 +4036,7 @@
 {
 	pr_debug("%s\n", __func__);
 
-	if (session_id < 0 || session_id > SESSION_MAX) {
+	if (session_id <= 0 || session_id > SESSION_MAX) {
 		pr_err("%s: invalid session_id = %d\n", __func__, session_id);
 		return -EINVAL;
 	}
@@ -3862,10 +4047,29 @@
 
 static int __init q6asm_init(void)
 {
+	int lcnt;
 	pr_debug("%s\n", __func__);
+
 	memset(session, 0, sizeof(session));
 	set_custom_topology = 1;
 
+	/*setup common client used for cal mem map */
+	common_client.session = ASM_CONTROL_SESSION;
+	common_client.port[0].buf = &common_buf[0];
+	common_client.port[1].buf = &common_buf[1];
+	init_waitqueue_head(&common_client.cmd_wait);
+	init_waitqueue_head(&common_client.time_wait);
+	atomic_set(&common_client.time_flag, 1);
+	INIT_LIST_HEAD(&common_client.port[0].mem_map_handle);
+	INIT_LIST_HEAD(&common_client.port[1].mem_map_handle);
+	mutex_init(&common_client.cmd_lock);
+	for (lcnt = 0; lcnt <= OUT; lcnt++) {
+		mutex_init(&common_client.port[lcnt].lock);
+		spin_lock_init(&common_client.port[lcnt].dsp_lock);
+	}
+	atomic_set(&common_client.cmd_state, 0);
+	atomic_set(&common_client.nowait_cmd_cnt, 0);
+
 	config_debug_fs_init();
 
 	return 0;
diff --git a/sound/soc/msm/qdsp6v2/q6lsm.c b/sound/soc/msm/qdsp6v2/q6lsm.c
index c5483ee..9227b23 100644
--- a/sound/soc/msm/qdsp6v2/q6lsm.c
+++ b/sound/soc/msm/qdsp6v2/q6lsm.c
@@ -45,6 +45,7 @@
 	LSM_INVALID_SESSION_ID = 0,
 	LSM_MIN_SESSION_ID = 1,
 	LSM_MAX_SESSION_ID = 8,
+	LSM_CONTROL_SESSION = 0x0F,
 };
 
 struct lsm_common {
@@ -53,6 +54,7 @@
 	uint32_t lsm_cal_addr;
 	uint32_t lsm_cal_size;
 	uint32_t mmap_handle_for_cal;
+	struct lsm_client	common_client;
 	struct mutex apr_lock;
 };
 
@@ -191,7 +193,7 @@
 	return 0;
 }
 
-struct lsm_client *q6lsm_client_alloc(app_cb cb, void *priv)
+struct lsm_client *q6lsm_client_alloc(lsm_app_cb cb, void *priv)
 {
 	struct lsm_client *client;
 	int n;
@@ -269,7 +271,7 @@
 		mmap_handle_p = mmap_p;
 	}
 	atomic_set(&client->cmd_state, CMD_STATE_WAIT_RESP);
-	ret = apr_send_pkt(client->apr, data);
+	ret = apr_send_pkt(handle, data);
 	if (mmap_p)
 		spin_unlock_irqrestore(&mmap_lock, flags);
 
@@ -318,13 +320,6 @@
 	int rc;
 	struct lsm_stream_cmd_open_tx open;
 
-	if (!afe_has_config(AFE_CDC_REGISTERS_CONFIG) ||
-	    !afe_has_config(AFE_SLIMBUS_SLAVE_CONFIG)) {
-		pr_err("%s: AFE isn't configured yet\n", __func__);
-		rc = -EAGAIN;
-		goto exit;
-	}
-
 	memset(&open, 0, sizeof(open));
 	q6lsm_add_hdr(client, &open.hdr, sizeof(open), true);
 
@@ -337,8 +332,6 @@
 		pr_err("%s: Open failed opcode 0x%x, rc %d\n",
 		       __func__, open.hdr.opcode, rc);
 
-exit:
-	pr_debug("%s: leave %d\n", __func__, rc);
 	return rc;
 }
 
@@ -607,6 +600,7 @@
 		}
 		lsm_common.lsm_cal_addr = lsm_cal.cal_paddr;
 		lsm_common.lsm_cal_size = LSM_CAL_SIZE;
+		lsm_common.common_client.session = client->session;
 	}
 
 	q6lsm_add_hdr(client, &params.hdr, sizeof(params), true);
@@ -626,6 +620,51 @@
 	return rc;
 }
 
+int q6lsm_unmap_cal_blocks(void)
+{
+	int	result = 0;
+	int	result2 = 0;
+
+	if (lsm_common.mmap_handle_for_cal == 0)
+		goto done;
+
+	if (lsm_common.common_client.mmap_apr == NULL) {
+		lsm_common.common_client.mmap_apr = q6lsm_mmap_apr_reg();
+		if (lsm_common.common_client.mmap_apr == NULL) {
+			pr_err("%s: q6lsm_mmap_apr_reg failed\n",
+				__func__);
+			result = -EPERM;
+			goto done;
+		}
+	}
+
+	result2 = q6lsm_memory_unmap_regions(
+		&lsm_common.common_client,
+		lsm_common.mmap_handle_for_cal);
+	if (result2 < 0) {
+		pr_err("%s: unmap failed, err %d\n",
+			__func__, result2);
+		result = result2;
+	} else {
+		lsm_common.mmap_handle_for_cal = 0;
+	}
+
+	result2 = q6lsm_mmap_apr_dereg();
+	if (result2 < 0) {
+		pr_err("%s: q6lsm_mmap_apr_dereg failed, err %d\n",
+			__func__, result2);
+		result = result2;
+	} else {
+		lsm_common.common_client.mmap_apr = NULL;
+	}
+
+	lsm_common.lsm_cal_addr = 0;
+	lsm_common.lsm_cal_size = 0;
+
+done:
+	return result;
+}
+
 int q6lsm_snd_model_buf_free(struct lsm_client *client)
 {
 	int rc;
@@ -655,6 +694,11 @@
 	unsigned long flags;
 	struct lsm_client *client = NULL;
 
+	if (session_id == LSM_CONTROL_SESSION) {
+		client = &lsm_common.common_client;
+		goto done;
+	}
+
 	spin_lock_irqsave(&lsm_session_lock, flags);
 	if (session_id < LSM_MIN_SESSION_ID || session_id > LSM_MAX_SESSION_ID)
 		pr_err("%s: Invalid session %d\n", __func__, session_id);
@@ -663,7 +707,7 @@
 	else
 		client = lsm_session[session_id];
 	spin_unlock_irqrestore(&lsm_session_lock, flags);
-
+done:
 	return client;
 }
 
@@ -735,7 +779,7 @@
 	int rc = -EINVAL;
 
 	if (!client)
-		goto fail;
+		return rc;
 
 	mutex_lock(&client->cmd_lock);
 	if (!client->sound_model.data) {
@@ -744,7 +788,6 @@
 		if (IS_ERR_OR_NULL(client->sound_model.client)) {
 			pr_err("%s: ION create client for AUDIO failed\n",
 			       __func__);
-			mutex_unlock(&client->cmd_lock);
 			goto fail;
 		}
 		client->sound_model.handle =
@@ -753,7 +796,6 @@
 		if (IS_ERR_OR_NULL(client->sound_model.handle)) {
 			pr_err("%s: ION memory allocation for AUDIO failed\n",
 			       __func__);
-			mutex_unlock(&client->cmd_lock);
 			goto fail;
 		}
 
@@ -764,7 +806,6 @@
 		if (rc) {
 			pr_err("%s: ION get physical mem failed, rc%d\n",
 			       __func__, rc);
-			mutex_unlock(&client->cmd_lock);
 			goto fail;
 		}
 
@@ -773,7 +814,6 @@
 				   client->sound_model.handle);
 		if (IS_ERR_OR_NULL(client->sound_model.data)) {
 			pr_err("%s: ION memory mapping failed\n", __func__);
-			mutex_unlock(&client->cmd_lock);
 			goto fail;
 		}
 		memset(client->sound_model.data, 0, len);
@@ -789,11 +829,13 @@
 				      &client->sound_model.mem_map_handle);
 	if (rc < 0) {
 		pr_err("%s:CMD Memory_map_regions failed\n", __func__);
-		goto fail;
+		goto exit;
 	}
 
 	return 0;
 fail:
+	mutex_unlock(&client->cmd_lock);
+exit:
 	q6lsm_snd_model_buf_free(client);
 	return rc;
 }
@@ -844,6 +886,12 @@
 	spin_lock_init(&lsm_session_lock);
 	spin_lock_init(&mmap_lock);
 	mutex_init(&lsm_common.apr_lock);
+
+	lsm_common.common_client.session = LSM_CONTROL_SESSION;
+	init_waitqueue_head(&lsm_common.common_client.cmd_wait);
+	mutex_init(&lsm_common.common_client.cmd_lock);
+	atomic_set(&lsm_common.common_client.cmd_state, CMD_STATE_CLEARED);
+
 	return 0;
 }
 
diff --git a/sound/soc/msm/qdsp6v2/q6voice.c b/sound/soc/msm/qdsp6v2/q6voice.c
index 60dd522..c16b14c 100644
--- a/sound/soc/msm/qdsp6v2/q6voice.c
+++ b/sound/soc/msm/qdsp6v2/q6voice.c
@@ -19,7 +19,6 @@
 #include <linux/msm_audio_ion.h>
 
 #include <asm/mach-types.h>
-#include <mach/qdsp6v2/rtac.h>
 #include <mach/socinfo.h>
 #include <mach/qdsp6v2/apr_tal.h>
 
@@ -45,6 +44,7 @@
 	VOC_TOKEN_NONE,
 	VOIP_MEM_MAP_TOKEN,
 	VOC_CAL_MEM_MAP_TOKEN,
+	VOC_RTAC_MEM_MAP_TOKEN
 };
 
 static struct common_data common;
@@ -88,6 +88,7 @@
 static int is_cal_memory_allocated(void);
 static int is_voip_memory_allocated(void);
 static int voice_alloc_cal_mem_map_table(void);
+static int voice_alloc_rtac_mem_map_table(void);
 static int voice_alloc_oob_shared_mem(void);
 static int voice_free_oob_shared_mem(void);
 static int voice_alloc_oob_mem_table(void);
@@ -1404,6 +1405,63 @@
 	return ret;
 }
 
+
+static int free_cal_map_table(void)
+{
+	int ret = 0;
+
+	if ((common.cal_mem_map_table.client == NULL) ||
+		(common.cal_mem_map_table.handle == NULL))
+		goto done;
+
+	ret = msm_audio_ion_free(common.cal_mem_map_table.client,
+		common.cal_mem_map_table.handle);
+	if (ret < 0) {
+		pr_err("%s: msm_audio_ion_free failed:\n", __func__);
+		ret = -EPERM;
+	}
+
+done:
+	common.cal_mem_map_table.client = NULL;
+	common.cal_mem_map_table.handle = NULL;
+	return ret;
+}
+
+static int is_rtac_memory_allocated(void)
+{
+	bool ret;
+
+	if (common.rtac_mem_map_table.client != NULL &&
+	    common.rtac_mem_map_table.handle != NULL)
+		ret = true;
+	else
+		ret = false;
+
+	return ret;
+}
+
+static int free_rtac_map_table(void)
+{
+	int ret = 0;
+
+	if ((common.rtac_mem_map_table.client == NULL) ||
+		(common.rtac_mem_map_table.handle == NULL))
+		goto done;
+
+	ret = msm_audio_ion_free(common.rtac_mem_map_table.client,
+		common.rtac_mem_map_table.handle);
+	if (ret < 0) {
+		pr_err("%s: msm_audio_ion_free failed:\n", __func__);
+		ret = -EPERM;
+	}
+
+done:
+	common.rtac_mem_map_table.client = NULL;
+	common.rtac_mem_map_table.handle = NULL;
+	return ret;
+}
+
+
 static int is_voip_memory_allocated(void)
 {
 	bool ret;
@@ -1486,7 +1544,8 @@
 	switch (common.mvs_info.media_type) {
 	case VSS_MEDIA_ID_EVRC_MODEM:
 	case VSS_MEDIA_ID_4GV_NB_MODEM:
-	case VSS_MEDIA_ID_4GV_WB_MODEM: {
+	case VSS_MEDIA_ID_4GV_WB_MODEM:
+	case VSS_MEDIA_ID_4GV_NW_MODEM: {
 		struct cvs_set_cdma_enc_minmax_rate_cmd cvs_set_cdma_rate;
 
 		pr_debug("Setting EVRC min-max rate\n");
@@ -1503,8 +1562,10 @@
 		cvs_set_cdma_rate.hdr.token = 0;
 		cvs_set_cdma_rate.hdr.opcode =
 				VSS_ISTREAM_CMD_CDMA_SET_ENC_MINMAX_RATE;
-		cvs_set_cdma_rate.cdma_rate.min_rate = common.mvs_info.rate;
-		cvs_set_cdma_rate.cdma_rate.max_rate = common.mvs_info.rate;
+		cvs_set_cdma_rate.cdma_rate.min_rate =
+				common.mvs_info.evrc_min_rate;
+		cvs_set_cdma_rate.cdma_rate.max_rate =
+				common.mvs_info.evrc_max_rate;
 
 		v->cvs_state = CMD_STATUS_FAIL;
 
@@ -1522,6 +1583,13 @@
 
 			goto fail;
 		}
+
+		if (common.mvs_info.media_type != VSS_MEDIA_ID_EVRC_MODEM) {
+			ret = voice_set_dtx(v);
+			if (ret < 0)
+				goto fail;
+		}
+
 		break;
 	}
 	case VSS_MEDIA_ID_AMR_NB_MODEM: {
@@ -1890,20 +1958,20 @@
 	if (!common.apr_q6_cvs) {
 		pr_err("%s: apr_cvs is NULL\n", __func__);
 
-		ret = -EINVAL;
+		ret = -EPERM;
 		goto done;
 	}
 
 	if (!common.cal_mem_handle) {
-		pr_debug("%s: Cal mem handle is NULL\n", __func__);
-
+		pr_err("%s: Cal mem handle is NULL\n", __func__);
+		ret = -EPERM;
 		goto done;
 	}
 
 	get_vocstrm_cal(&cal_block);
 	if (cal_block.cal_size == 0) {
 		pr_err("%s: CVS cal size is 0\n", __func__);
-
+		ret = -EPERM;
 		goto done;
 	}
 
@@ -1932,7 +2000,7 @@
 	ret = apr_send_pkt(common.apr_q6_cvs, (uint32_t *) &cvs_reg_cal_cmd);
 	if (ret < 0) {
 		pr_err("%s: Error %d registering CVS cal\n", __func__, ret);
-
+		ret = -EINVAL;
 		goto done;
 	}
 	ret = wait_event_timeout(v->cvs_wait,
@@ -1940,7 +2008,7 @@
 				 msecs_to_jiffies(TIMEOUT_MS));
 	if (!ret) {
 		pr_err("%s: Command timeout\n", __func__);
-
+		ret = -EINVAL;
 		goto done;
 	}
 
@@ -1965,19 +2033,22 @@
 	if (!common.apr_q6_cvs) {
 		pr_err("%s: apr_cvs is NULL\n", __func__);
 
-		ret = -EINVAL;
+		ret = -EPERM;
 		goto done;
 	}
 
 	if (!common.cal_mem_handle) {
-		pr_debug("%s: Cal mem handle is NULL\n", __func__);
-
+		pr_err("%s: Cal mem handle is NULL\n", __func__);
+		ret = -EPERM;
 		goto done;
 	}
 
 	get_vocstrm_cal(&cal_block);
-	if (cal_block.cal_size == 0)
+	if (cal_block.cal_size == 0) {
+		pr_err("%s: CVS cal size is 0\n", __func__);
+		ret = -EPERM;
 		goto done;
+	}
 
 	cvs_dereg_cal_cmd.hdr.hdr_field = APR_HDR_FIELD(APR_MSG_TYPE_SEQ_CMD,
 				APR_HDR_LEN(APR_HDR_SIZE), APR_PKT_VER);
@@ -1994,7 +2065,7 @@
 	ret = apr_send_pkt(common.apr_q6_cvs, (uint32_t *) &cvs_dereg_cal_cmd);
 	if (ret < 0) {
 		pr_err("%s: Error %d de-registering CVS cal\n", __func__, ret);
-
+		ret = -EINVAL;
 		goto done;
 	}
 	ret = wait_event_timeout(v->cvs_wait,
@@ -2002,7 +2073,7 @@
 				 msecs_to_jiffies(TIMEOUT_MS));
 	if (!ret) {
 		pr_err("%s: Command  timeout\n", __func__);
-
+		ret = -EINVAL;
 		goto done;
 	}
 
@@ -2028,20 +2099,20 @@
 	if (!common.apr_q6_cvp) {
 		pr_err("%s: apr_cvp is NULL\n", __func__);
 
-		ret = -EINVAL;
+		ret = -EPERM;
 		goto done;
 	}
 
 	if (!common.cal_mem_handle) {
-		pr_debug("%s: Cal mem handle is NULL\n", __func__);
-
+		pr_err("%s: Cal mem handle is NULL\n", __func__);
+		ret = -EPERM;
 		goto done;
 	}
 
 	get_vocproc_dev_cfg_cal(&cal_block);
 	if (cal_block.cal_size == 0) {
 		pr_err("%s: CVP cal size is 0\n", __func__);
-
+		ret = -EPERM;
 		goto done;
 	}
 
@@ -2066,7 +2137,7 @@
 	if (ret < 0) {
 		pr_err("%s: Error %d registering CVP dev cfg cal\n",
 		       __func__, ret);
-
+		ret = -EINVAL;
 		goto done;
 	}
 	ret = wait_event_timeout(v->cvp_wait,
@@ -2074,7 +2145,7 @@
 				 msecs_to_jiffies(TIMEOUT_MS));
 	if (!ret) {
 		pr_err("%s: Command timeout\n", __func__);
-
+		ret = -EINVAL;
 		goto done;
 	}
 
@@ -2099,19 +2170,22 @@
 	if (!common.apr_q6_cvp) {
 		pr_err("%s: apr_cvp is NULL\n", __func__);
 
-		ret = -EINVAL;
+		ret = -EPERM;
 		goto done;
 	}
 
 	if (!common.cal_mem_handle) {
-		pr_debug("%s: Cal mem handle is NULL\n", __func__);
-
+		pr_err("%s: Cal mem handle is NULL\n", __func__);
+		ret = -EPERM;
 		goto done;
 	}
 
 	get_vocproc_dev_cfg_cal(&cal_block);
-	if (cal_block.cal_size == 0)
+	if (cal_block.cal_size == 0) {
+		pr_err("%s: CVP cal size is 0\n", __func__);
+		ret = -EPERM;
 		goto done;
+	}
 
 	cvp_dereg_dev_cfg_cmd.hdr.hdr_field =
 				APR_HDR_FIELD(APR_MSG_TYPE_SEQ_CMD,
@@ -2131,7 +2205,7 @@
 	if (ret < 0) {
 		pr_err("%s: Error %d de-registering CVP dev cfg cal\n",
 		       __func__, ret);
-
+		ret = -EINVAL;
 		goto done;
 	}
 	ret = wait_event_timeout(v->cvp_wait,
@@ -2139,7 +2213,7 @@
 				 msecs_to_jiffies(TIMEOUT_MS));
 	if (!ret) {
 		pr_err("%s: Command timeout\n", __func__);
-
+		ret = -EINVAL;
 		goto done;
 	}
 
@@ -2164,20 +2238,20 @@
 	if (!common.apr_q6_cvp) {
 		pr_err("%s: apr_cvp is NULL\n", __func__);
 
-		ret = -EINVAL;
+		ret = -EPERM;
 		goto done;
 	}
 
 	if (!common.cal_mem_handle) {
-		pr_debug("%s: Cal mem handle is NULL\n", __func__);
-
+		pr_err("%s: Cal mem handle is NULL\n", __func__);
+		ret = -EPERM;
 		goto done;
 	}
 
 	get_vocproc_cal(&cal_block);
 	if (cal_block.cal_size == 0) {
 		pr_err("%s: CVP cal size is 0\n", __func__);
-
+		ret = -EPERM;
 		goto done;
 	}
 
@@ -2206,7 +2280,7 @@
 	ret = apr_send_pkt(common.apr_q6_cvp, (uint32_t *) &cvp_reg_cal_cmd);
 	if (ret < 0) {
 		pr_err("%s: Error %d registering CVP cal\n", __func__, ret);
-
+		ret = -EINVAL;
 		goto done;
 	}
 	ret = wait_event_timeout(v->cvp_wait,
@@ -2214,7 +2288,7 @@
 				 msecs_to_jiffies(TIMEOUT_MS));
 	if (!ret) {
 		pr_err("%s: Command timeout\n", __func__);
-
+		ret = -EINVAL;
 		goto done;
 	}
 
@@ -2239,19 +2313,22 @@
 	if (!common.apr_q6_cvp) {
 		pr_err("%s: apr_cvp is NULL.\n", __func__);
 
-		ret = -EINVAL;
+		ret = -EPERM;
 		goto done;
 	}
 
 	if (!common.cal_mem_handle) {
-		pr_debug("%s: Cal mem handle is NULL\n", __func__);
-
+		pr_err("%s: Cal mem handle is NULL\n", __func__);
+		ret = -EPERM;
 		goto done;
 	}
 
 	get_vocproc_cal(&cal_block);
-	if (cal_block.cal_size == 0)
+	if (cal_block.cal_size == 0) {
+		pr_err("%s: CVP vol cal size is 0\n", __func__);
+		ret = -EPERM;
 		goto done;
+	}
 
 	cvp_dereg_cal_cmd.hdr.hdr_field = APR_HDR_FIELD(APR_MSG_TYPE_SEQ_CMD,
 				APR_HDR_LEN(APR_HDR_SIZE), APR_PKT_VER);
@@ -2268,7 +2345,7 @@
 	ret = apr_send_pkt(common.apr_q6_cvp, (uint32_t *) &cvp_dereg_cal_cmd);
 	if (ret < 0) {
 		pr_err("%s: Error %d de-registering CVP cal\n", __func__, ret);
-
+		ret = -EINVAL;
 		goto done;
 	}
 	ret = wait_event_timeout(v->cvp_wait,
@@ -2276,7 +2353,7 @@
 				 msecs_to_jiffies(TIMEOUT_MS));
 	if (!ret) {
 		pr_err("%s: Command timeout\n", __func__);
-
+		ret = -EINVAL;
 		goto done;
 	}
 
@@ -2301,20 +2378,20 @@
 	if (!common.apr_q6_cvp) {
 		pr_err("%s: apr_cvp is NULL\n", __func__);
 
-		ret = -EINVAL;
+		ret = -EPERM;
 		goto done;
 	}
 
 	if (!common.cal_mem_handle) {
-		pr_debug("%s: Cal mem handle is NULL\n", __func__);
-
+		pr_err("%s: Cal mem handle is NULL\n", __func__);
+		ret = -EPERM;
 		goto done;
 	}
 
 	get_vocvol_cal(&cal_block);
 	if (cal_block.cal_size == 0) {
 		pr_err("%s: CVP vol cal size is 0\n", __func__);
-
+		ret = -EPERM;
 		goto done;
 	}
 
@@ -2346,7 +2423,7 @@
 			   (uint32_t *) &cvp_reg_vol_cal_cmd);
 	if (ret < 0) {
 		pr_err("%s: Error %d registering CVP vol cal\n", __func__, ret);
-
+		ret = -EINVAL;
 		goto done;
 	}
 	ret = wait_event_timeout(v->cvp_wait,
@@ -2354,7 +2431,7 @@
 				 msecs_to_jiffies(TIMEOUT_MS));
 	if (!ret) {
 		pr_err("%s: Command timeout\n", __func__);
-
+		ret = -EINVAL;
 		goto done;
 	}
 
@@ -2379,19 +2456,22 @@
 	if (!common.apr_q6_cvp) {
 		pr_err("%s: apr_cvp is NULL\n", __func__);
 
-		ret = -EINVAL;
+		ret = -EPERM;
 		goto done;
 	}
 
 	if (!common.cal_mem_handle) {
-		pr_debug("%s: Cal mem handle is NULL\n", __func__);
-
+		pr_err("%s: Cal mem handle is NULL\n", __func__);
+		ret = -EPERM;
 		goto done;
 	}
 
 	get_vocvol_cal(&cal_block);
-	if (cal_block.cal_size == 0)
+	if (cal_block.cal_size == 0) {
+		pr_err("%s: CVP vol cal size is 0\n", __func__);
+		ret = -EPERM;
 		goto done;
+	}
 
 	cvp_dereg_vol_cal_cmd.hdr.hdr_field =
 			APR_HDR_FIELD(APR_MSG_TYPE_SEQ_CMD,
@@ -2411,7 +2491,7 @@
 	if (ret < 0) {
 		pr_err("%s: Error %d de-registering CVP vol cal\n",
 		       __func__, ret);
-
+		ret = -EINVAL;
 		goto done;
 	}
 	ret = wait_event_timeout(v->cvp_wait,
@@ -2419,7 +2499,7 @@
 				 msecs_to_jiffies(TIMEOUT_MS));
 	if (!ret) {
 		pr_err("%s: Command timeout\n", __func__);
-
+		ret = -EINVAL;
 		goto done;
 	}
 
@@ -2427,62 +2507,6 @@
 	return ret;
 }
 
-int voc_register_vocproc_vol_table(void)
-{
-	int			result = 0;
-	int			i;
-	struct voice_data	*v = NULL;
-	pr_debug("%s\n", __func__);
-
-	mutex_lock(&common.common_lock);
-	for (i = 0; i < MAX_VOC_SESSIONS; i++) {
-		v = &common.voice[i];
-
-		mutex_lock(&v->lock);
-		if (is_voc_state_active(v->voc_state)) {
-			result = voice_send_cvp_register_vol_cal_cmd(v);
-			if (result) {
-				pr_err("%s: Failed to register vocvol table for session 0x%x!\n",
-					__func__, v->session_id);
-				mutex_unlock(&v->lock);
-				goto done;
-			}
-		}
-		mutex_unlock(&v->lock);
-	}
-done:
-	mutex_unlock(&common.common_lock);
-	return result;
-}
-
-int voc_deregister_vocproc_vol_table(void)
-{
-	int			result = 0;
-	int			i;
-	struct voice_data	*v = NULL;
-	pr_debug("%s\n", __func__);
-
-	mutex_lock(&common.common_lock);
-	for (i = 0; i < MAX_VOC_SESSIONS; i++) {
-		v = &common.voice[i];
-
-		mutex_lock(&v->lock);
-		if (is_voc_state_active(v->voc_state)) {
-			result = voice_send_cvp_deregister_vol_cal_cmd(v);
-			if (result) {
-				pr_err("%s: Failed to deregister vocvol table for session 0x%x!\n",
-					__func__, v->session_id);
-				mutex_unlock(&v->lock);
-				goto done;
-			}
-		}
-		mutex_unlock(&v->lock);
-	}
-done:
-	mutex_unlock(&common.common_lock);
-	return result;
-}
-
 static int voice_map_memory_physical_cmd(struct voice_data *v,
 					 struct mem_map_table *table_info,
 					 dma_addr_t phys,
@@ -2620,6 +2644,313 @@
 	return ret;
 }
 
+static int voice_pause_voice_call(struct voice_data *v)
+{
+	struct apr_hdr	mvm_pause_voice_cmd;
+	void		*apr_mvm;
+	int		ret = 0;
+
+	pr_debug("%s\n", __func__);
+
+	if (v == NULL) {
+		pr_err("%s: Voice data is NULL\n", __func__);
+
+		ret = -EINVAL;
+		goto done;
+	}
+
+	apr_mvm = common.apr_q6_mvm;
+	if (!apr_mvm) {
+		pr_err("%s: apr_mvm is NULL.\n", __func__);
+
+		ret = -EINVAL;
+		goto done;
+	}
+
+	mvm_pause_voice_cmd.hdr_field =
+		APR_HDR_FIELD(APR_MSG_TYPE_SEQ_CMD,
+		APR_HDR_LEN(APR_HDR_SIZE), APR_PKT_VER);
+	mvm_pause_voice_cmd.pkt_size =
+		APR_PKT_SIZE(APR_HDR_SIZE,
+		sizeof(mvm_pause_voice_cmd) - APR_HDR_SIZE);
+	mvm_pause_voice_cmd.src_port =
+			voice_get_idx_for_session(v->session_id);
+	mvm_pause_voice_cmd.dest_port = voice_get_mvm_handle(v);
+	mvm_pause_voice_cmd.token = 0;
+	mvm_pause_voice_cmd.opcode = VSS_IMVM_CMD_PAUSE_VOICE;
+	v->mvm_state = CMD_STATUS_FAIL;
+
+	pr_debug("%s: send mvm_pause_voice_cmd pkt size = %d\n",
+		__func__, mvm_pause_voice_cmd.pkt_size);
+
+	ret = apr_send_pkt(apr_mvm,
+		(uint32_t *)&mvm_pause_voice_cmd);
+	if (ret < 0) {
+		pr_err("Fail in sending VSS_IMVM_CMD_PAUSE_VOICE\n");
+
+		ret = -EINVAL;
+		goto done;
+	}
+
+	ret = wait_event_timeout(v->mvm_wait,
+		(v->mvm_state == CMD_STATUS_SUCCESS),
+		msecs_to_jiffies(TIMEOUT_MS));
+	if (!ret) {
+		pr_err("%s: Command timeout\n", __func__);
+
+		ret = -EINVAL;
+		goto done;
+	}
+
+done:
+	return ret;
+}
+
+int voc_register_vocproc_vol_table(void)
+{
+	int			result = 0;
+	int			result2 = 0;
+	int			i;
+	struct voice_data	*v = NULL;
+
+	pr_debug("%s\n", __func__);
+
+	mutex_lock(&common.common_lock);
+	for (i = 0; i < MAX_VOC_SESSIONS; i++) {
+		v = &common.voice[i];
+
+		mutex_lock(&v->lock);
+		if (is_voc_state_active(v->voc_state)) {
+			result2 = voice_send_cvp_register_vol_cal_cmd(v);
+			if (result2 < 0) {
+				pr_err("%s: Failed to register vocvol table for session 0x%x!\n",
+					__func__, v->session_id);
+
+				result = result2;
+				/* Still try to register other sessions */
+			}
+		}
+		mutex_unlock(&v->lock);
+	}
+
+	mutex_unlock(&common.common_lock);
+	return result;
+}
+
+int voc_deregister_vocproc_vol_table(void)
+{
+	int			result = 0;
+	int			success = 0;
+	int			i;
+	struct voice_data	*v = NULL;
+
+	pr_debug("%s\n", __func__);
+
+	mutex_lock(&common.common_lock);
+	for (i = 0; i < MAX_VOC_SESSIONS; i++) {
+		v = &common.voice[i];
+
+		mutex_lock(&v->lock);
+		if (is_voc_state_active(v->voc_state)) {
+			result = voice_send_cvp_deregister_vol_cal_cmd(v);
+			if (result < 0) {
+				pr_err("%s: Failed to deregister vocvol table for session 0x%x!\n",
+					__func__, v->session_id);
+
+				mutex_unlock(&v->lock);
+				mutex_unlock(&common.common_lock);
+				if (success) {
+					pr_err("%s: Try to re-register all deregistered sessions!\n",
+						__func__);
+
+					voc_register_vocproc_vol_table();
+				}
+				goto done;
+			} else {
+				success = 1;
+			}
+		}
+		mutex_unlock(&v->lock);
+	}
+	mutex_unlock(&common.common_lock);
+done:
+	return result;
+}
+
+int voc_map_rtac_block(struct rtac_cal_block_data *cal_block)
+{
+	int			result = 0;
+	struct voice_data	*v = NULL;
+
+	pr_debug("%s\n", __func__);
+
+	if (cal_block == NULL) {
+		pr_err("%s: cal_block is NULL!\n",
+			__func__);
+
+		result = -EINVAL;
+		goto done;
+	}
+
+	if (cal_block->cal_data.paddr == 0) {
+		pr_debug("%s: No address to map!\n",
+			__func__);
+
+		result = -EINVAL;
+		goto done;
+	}
+
+	if (cal_block->map_data.map_size == 0) {
+		pr_debug("%s: map size is 0!\n",
+			__func__);
+
+		result = -EINVAL;
+		goto done;
+	}
+
+	mutex_lock(&common.common_lock);
+	/* use first session */
+	v = &common.voice[0];
+	mutex_lock(&v->lock);
+
+	if (!is_rtac_memory_allocated()) {
+		result = voice_alloc_rtac_mem_map_table();
+		if (result < 0) {
+			pr_err("%s: RTAC alloc mem map table did not work! addr = 0x%x, size = %d\n",
+				__func__, cal_block->cal_data.paddr,
+				cal_block->map_data.map_size);
+
+			goto err;
+		}
+	}
+
+	result = voice_map_memory_physical_cmd(v,
+		&common.rtac_mem_map_table,
+		(dma_addr_t)cal_block->cal_data.paddr,
+		cal_block->map_data.map_size,
+		VOC_RTAC_MEM_MAP_TOKEN);
+	if (result < 0) {
+		pr_err("%s: RTAC mmap did not work! addr = 0x%x, size = %d\n",
+			__func__, cal_block->cal_data.paddr,
+			cal_block->map_data.map_size);
+
+		free_rtac_map_table();
+		goto err;
+	}
+
+	cal_block->map_data.map_handle = common.rtac_mem_handle;
+err:
+	mutex_unlock(&v->lock);
+	mutex_unlock(&common.common_lock);
+done:
+	return result;
+}
+
+int voc_unmap_rtac_block(uint32_t *mem_map_handle)
+{
+	int			result = 0;
+	struct voice_data	*v = NULL;
+
+	pr_debug("%s\n", __func__);
+
+	if (mem_map_handle == NULL) {
+		pr_debug("%s: Map handle is NULL, nothing to unmap\n",
+			__func__);
+
+		goto done;
+	}
+
+	if (*mem_map_handle == 0) {
+		pr_debug("%s: Map handle is 0, nothing to unmap\n",
+			__func__);
+
+		goto done;
+	}
+
+	mutex_lock(&common.common_lock);
+	/* use first session */
+	v = &common.voice[0];
+	mutex_lock(&v->lock);
+
+	result = voice_send_mvm_unmap_memory_physical_cmd(
+			v, *mem_map_handle);
+	if (result) {
+		pr_err("%s: voice_send_mvm_unmap_memory_physical_cmd Failed for session 0x%x!\n",
+			__func__, v->session_id);
+	} else {
+		*mem_map_handle = 0;
+		common.rtac_mem_handle = 0;
+		free_rtac_map_table();
+	}
+	mutex_unlock(&v->lock);
+	mutex_unlock(&common.common_lock);
+done:
+	return result;
+}
+
+int voc_unmap_cal_blocks(void)
+{
+	int			result = 0;
+	int			result2 = 0;
+	int			i;
+	struct voice_data	*v = NULL;
+
+	pr_debug("%s\n", __func__);
+
+	mutex_lock(&common.common_lock);
+
+	if (common.cal_mem_handle == 0)
+		goto done;
+
+	for (i = 0; i < MAX_VOC_SESSIONS; i++) {
+		v = &common.voice[i];
+
+		mutex_lock(&v->lock);
+		if (is_voc_state_active(v->voc_state)) {
+			result2 = voice_pause_voice_call(v);
+			if (result2 < 0) {
+				pr_err("%s: voice_pause_voice_call failed for session 0x%x, err %d!\n",
+					__func__, v->session_id, result2);
+
+				result = result2;
+			}
+
+			voice_send_cvp_deregister_vol_cal_cmd(v);
+			voice_send_cvp_deregister_cal_cmd(v);
+			voice_send_cvp_deregister_dev_cfg_cmd(v);
+			voice_send_cvs_deregister_cal_cmd(v);
+
+			result2 = voice_send_start_voice_cmd(v);
+			if (result2) {
+				pr_err("%s: voice_send_start_voice_cmd failed for session 0x%x, err %d!\n",
+					__func__, v->session_id, result2);
+
+				result = result2;
+			}
+		}
+
+		if ((common.cal_mem_handle != 0) &&
+			(!is_other_session_active(v->session_id))) {
+
+			result2 = voice_send_mvm_unmap_memory_physical_cmd(
+				v, common.cal_mem_handle);
+			if (result2) {
+				pr_err("%s: voice_send_mvm_unmap_memory_physical_cmd failed for session 0x%x, err %d!\n",
+					__func__, v->session_id, result2);
+
+				result = result2;
+			} else {
+				common.cal_mem_handle = 0;
+				free_cal_map_table();
+			}
+		}
+		mutex_unlock(&v->lock);
+	}
+done:
+	mutex_unlock(&common.common_lock);
+	return result;
+}
+
 static int voice_setup_vocproc(struct voice_data *v)
 {
 	struct cvp_create_full_ctl_session_cmd cvp_session_cmd;
@@ -3090,7 +3421,6 @@
 	voice_send_cvp_deregister_vol_cal_cmd(v);
 	voice_send_cvp_deregister_cal_cmd(v);
 	voice_send_cvp_deregister_dev_cfg_cmd(v);
-
 	voice_send_cvs_deregister_cal_cmd(v);
 
 	/* destrop cvp session */
@@ -3302,7 +3632,8 @@
 	return -EINVAL;
 }
 
-static int voice_send_stream_mute_cmd(struct voice_data *v)
+static int voice_send_stream_mute_cmd(struct voice_data *v, uint16_t direction,
+				     uint16_t mute_flag, uint32_t ramp_duration)
 {
 	struct cvs_set_mute_cmd cvs_mute_cmd;
 	int ret = 0;
@@ -3330,10 +3661,9 @@
 	cvs_mute_cmd.hdr.dest_port = voice_get_cvs_handle(v);
 	cvs_mute_cmd.hdr.token = 0;
 	cvs_mute_cmd.hdr.opcode = VSS_IVOLUME_CMD_MUTE_V2;
-	cvs_mute_cmd.cvs_set_mute.direction = VSS_IVOLUME_DIRECTION_TX;
-	cvs_mute_cmd.cvs_set_mute.mute_flag = v->stream_tx.stream_mute;
-	cvs_mute_cmd.cvs_set_mute.ramp_duration_ms =
-				v->stream_tx.stream_mute_ramp_duration_ms;
+	cvs_mute_cmd.cvs_set_mute.direction = direction;
+	cvs_mute_cmd.cvs_set_mute.mute_flag = mute_flag;
+	cvs_mute_cmd.cvs_set_mute.ramp_duration_ms = ramp_duration;
 
 	v->cvs_state = CMD_STATUS_FAIL;
 	ret = apr_send_pkt(common.apr_q6_cvs, (uint32_t *) &cvs_mute_cmd);
@@ -3989,6 +4319,13 @@
 						VSS_IVOLUME_DIRECTION_RX,
 						VSS_IVOLUME_MUTE_ON,
 						DEFAULT_MUTE_RAMP_DURATION);
+			/* Send unmute cmd as the TX stream
+			 * might be muted previously
+			 */
+			voice_send_stream_mute_cmd(v,
+						VSS_IVOLUME_DIRECTION_TX,
+						VSS_IVOLUME_MUTE_OFF,
+						DEFAULT_MUTE_RAMP_DURATION);
 		} else if (v->lch_mode == VOICE_LCH_STOP) {
 			pr_debug("%s: TX and RX mute OFF\n", __func__);
 
@@ -4003,7 +4340,10 @@
 			/* Reset lch mode when VOICE_LCH_STOP is recieved */
 			v->lch_mode = 0;
 			/* Apply cached mute setting */
-			voice_send_stream_mute_cmd(v);
+			voice_send_stream_mute_cmd(v,
+				VSS_IVOLUME_DIRECTION_TX,
+				v->stream_tx.stream_mute,
+				v->stream_tx.stream_mute_ramp_duration_ms);
 		} else {
 			pr_debug("%s: Mute commands not sent for lch_mode=%d\n",
 				 __func__, v->lch_mode);
@@ -4083,7 +4423,10 @@
 								ramp_duration;
 			if (is_voc_state_active(v->voc_state) &&
 				(v->lch_mode == 0))
-				ret = voice_send_stream_mute_cmd(v);
+				ret = voice_send_stream_mute_cmd(v,
+				VSS_IVOLUME_DIRECTION_TX,
+				v->stream_tx.stream_mute,
+				v->stream_tx.stream_mute_ramp_duration_ms);
 			mutex_unlock(&v->lock);
 		} else {
 			pr_err("%s: invalid session_id 0x%x\n", __func__,
@@ -4569,7 +4912,10 @@
 		if (ret < 0)
 			pr_err("voice volume failed\n");
 
-		ret = voice_send_stream_mute_cmd(v);
+		ret = voice_send_stream_mute_cmd(v,
+				VSS_IVOLUME_DIRECTION_TX,
+				v->stream_tx.stream_mute,
+				v->stream_tx.stream_mute_ramp_duration_ms);
 		if (ret < 0)
 			pr_err("voice mute failed\n");
 
@@ -4609,14 +4955,18 @@
 }
 
 void voc_config_vocoder(uint32_t media_type,
-			  uint32_t rate,
-			  uint32_t network_type,
-			  uint32_t dtx_mode)
+			uint32_t rate,
+			uint32_t network_type,
+			uint32_t dtx_mode,
+			uint32_t evrc_min_rate,
+			uint32_t evrc_max_rate)
 {
 	common.mvs_info.media_type = media_type;
 	common.mvs_info.rate = rate;
 	common.mvs_info.network_type = network_type;
 	common.mvs_info.dtx_mode = dtx_mode;
+	common.mvs_info.evrc_min_rate = evrc_min_rate;
+	common.mvs_info.evrc_max_rate = evrc_max_rate;
 }
 
 static int32_t qdsp_mvm_callback(struct apr_client_data *data, void *priv)
@@ -4649,6 +4999,8 @@
 
 			/* clean up memory handle */
 			c->cal_mem_handle = 0;
+			c->rtac_mem_handle = 0;
+			rtac_clear_mapping(VOICE_RTAC_CAL);
 
 			/* Sub-system restart is applicable to all sessions. */
 			for (i = 0; i < MAX_VOC_SESSIONS; i++) {
@@ -4707,6 +5059,7 @@
 			case VSS_IMVM_CMD_SET_CAL_MEDIA_TYPE:
 			case VSS_IMEMORY_CMD_MAP_PHYSICAL:
 			case VSS_IMEMORY_CMD_UNMAP:
+			case VSS_IMVM_CMD_PAUSE_VOICE:
 			case VSS_IMVM_CMD_STANDBY_VOICE:
 				pr_debug("%s: cmd = 0x%x\n", __func__, ptr[0]);
 				v->mvm_state = CMD_STATUS_SUCCESS;
@@ -4742,6 +5095,18 @@
 				v->mvm_state = CMD_STATUS_SUCCESS;
 				wake_up(&v->mvm_wait);
 			}
+		} else if (data->payload_size &&
+				data->token == VOC_RTAC_MEM_MAP_TOKEN) {
+			ptr = data->payload;
+			if (ptr[0]) {
+				c->rtac_mem_handle = ptr[0];
+
+				pr_debug("%s: cal mem handle 0x%x\n",
+					 __func__, c->rtac_mem_handle);
+
+				v->mvm_state = CMD_STATUS_SUCCESS;
+				wake_up(&v->mvm_wait);
+			}
 		} else {
 			pr_err("%s: Unknown mem map token %d\n",
 			       __func__, data->token);
@@ -4899,8 +5264,10 @@
 
 		cvs_voc_pkt = v->shmem_info.sh_buf.buf[1].data;
 		if (cvs_voc_pkt != NULL &&  common.mvs_info.ul_cb != NULL) {
+			/* cvs_voc_pkt[0] contains tx timestamp */
 			common.mvs_info.ul_cb((uint8_t *)&cvs_voc_pkt[3],
 					      cvs_voc_pkt[2],
+					      cvs_voc_pkt[0],
 					      common.mvs_info.private_data);
 		} else
 			pr_err("%s: cvs_voc_pkt or ul_cb is NULL\n", __func__);
@@ -5150,6 +5517,8 @@
 
 	rc = msm_audio_ion_free(v->shmem_info.sh_buf.client,
 				v->shmem_info.sh_buf.handle);
+	v->shmem_info.sh_buf.client = NULL;
+	v->shmem_info.sh_buf.handle = NULL;
 	if (rc < 0) {
 		pr_err("%s: Error:%d freeing memory\n", __func__, rc);
 
@@ -5294,6 +5663,33 @@
 	return ret;
 }
 
+static int voice_alloc_rtac_mem_map_table(void)
+{
+	int ret = 0;
+	int len;
+
+	ret = msm_audio_ion_alloc("voc_rtac_cal",
+			&(common.rtac_mem_map_table.client),
+			&(common.rtac_mem_map_table.handle),
+			sizeof(struct vss_imemory_table_t),
+			(ion_phys_addr_t *)&common.rtac_mem_map_table.phys,
+			(size_t *) &len,
+			&(common.rtac_mem_map_table.data));
+	if (ret < 0) {
+		pr_err("%s: audio ION alloc failed, rc = %d\n",
+			__func__, ret);
+		goto done;
+	}
+
+	common.rtac_mem_map_table.size = sizeof(struct vss_imemory_table_t);
+	pr_debug("%s: data 0x%x phys 0x%x\n", __func__,
+		 (unsigned int) common.rtac_mem_map_table.data,
+		 common.rtac_mem_map_table.phys);
+
+done:
+	return ret;
+}
+
 static int voice_alloc_and_map_cal_mem(struct voice_data *v)
 {
 	int ret = 0;
diff --git a/sound/soc/msm/qdsp6v2/q6voice.h b/sound/soc/msm/qdsp6v2/q6voice.h
index 20f2857..39f0986 100644
--- a/sound/soc/msm/qdsp6v2/q6voice.h
+++ b/sound/soc/msm/qdsp6v2/q6voice.h
@@ -13,6 +13,7 @@
 #define __QDSP6VOICE_H__
 
 #include <mach/qdsp6v2/apr.h>
+#include <mach/qdsp6v2/rtac.h>
 #include <linux/msm_ion.h>
 #include <sound/voice_params.h>
 
@@ -186,6 +187,9 @@
 #define VSS_IMVM_CMD_STOP_VOICE				0x00011192
 /**< No payload. Wait for APRV2_IBASIC_RSP_RESULT response. */
 
+#define VSS_IMVM_CMD_PAUSE_VOICE			0x0001137D
+/* No payload. Wait for APRV2_IBASIC_RSP_RESULT response. */
+
 #define VSS_ISTREAM_CMD_ATTACH_VOCPROC			0x000110F8
 /**< Wait for APRV2_IBASIC_RSP_RESULT response. */
 
@@ -213,7 +217,8 @@
 		VOC_8_RATE, /* 1/8 rate    */
 		VOC_4_RATE, /* 1/4 rate    */
 		VOC_2_RATE, /* 1/2 rate    */
-		VOC_1_RATE  /* Full rate   */
+		VOC_1_RATE,  /* Full rate   */
+		VOC_8_RATE_NC  /* Noncritical 1/8 rate   */
 };
 
 struct vss_istream_cmd_set_tty_mode_t {
@@ -977,6 +982,8 @@
 /*CDMA EVRC-B vocoder modem format */
 #define VSS_MEDIA_ID_4GV_WB_MODEM	0x00010FC4
 /*CDMA EVRC-WB vocoder modem format */
+#define VSS_MEDIA_ID_4GV_NW_MODEM	0x00010FC5
+/*CDMA EVRC-NW vocoder modem format */
 
 #define VSS_IVOCPROC_CMD_CREATE_FULL_CONTROL_SESSION_V2	0x000112BF
 
@@ -1207,6 +1214,7 @@
 /* CB for up-link packets. */
 typedef void (*ul_cb_fn)(uint8_t *voc_pkt,
 			 uint32_t pkt_len,
+			 uint32_t timestamp,
 			 void *private_data);
 
 /* CB for down-link packets. */
@@ -1226,6 +1234,8 @@
 	ul_cb_fn ul_cb;
 	dl_cb_fn dl_cb;
 	void *private_data;
+	uint32_t evrc_min_rate;
+	uint32_t evrc_max_rate;
 };
 
 struct dtmf_driver_info {
@@ -1328,6 +1338,10 @@
 
 	struct mem_map_table cal_mem_map_table;
 	uint32_t cal_mem_handle;
+
+	struct mem_map_table rtac_mem_map_table;
+	uint32_t rtac_mem_handle;
+
 	struct cal_mem cvp_cal;
 	struct cal_mem cvs_cal;
 
@@ -1357,7 +1371,9 @@
 void voc_config_vocoder(uint32_t media_type,
 			uint32_t rate,
 			uint32_t network_type,
-			uint32_t dtx_mode);
+			uint32_t dtx_mode,
+			uint32_t evrc_min_rate,
+			uint32_t evrc_max_rate);
 
 enum {
 	DEV_RX = 0,
@@ -1437,6 +1453,10 @@
 int voc_register_vocproc_vol_table(void);
 int voc_deregister_vocproc_vol_table(void);
 
+int voc_unmap_cal_blocks(void);
+int voc_map_rtac_block(struct rtac_cal_block_data *cal_block);
+int voc_unmap_rtac_block(uint32_t *mem_map_handle);
+
 uint32_t voc_get_session_id(char *name);
 
 int voc_start_playback(uint32_t set, uint16_t port_id);
diff --git a/sound/soc/msm/qdsp6v2/rtac.c b/sound/soc/msm/qdsp6v2/rtac.c
index a4983d3..ee21112 100644
--- a/sound/soc/msm/qdsp6v2/rtac.c
+++ b/sound/soc/msm/qdsp6v2/rtac.c
@@ -20,6 +20,7 @@
 #include <linux/sched.h>
 #include <linux/msm_audio_acdb.h>
 #include <linux/atomic.h>
+#include <linux/msm_audio_ion.h>
 #include <mach/qdsp6v2/rtac.h>
 #include <sound/q6asm-v2.h>
 #include <sound/q6afe-v2.h>
@@ -53,10 +54,26 @@
 #define RTAC_MAX_ACTIVE_DEVICES		4
 #define RTAC_MAX_ACTIVE_VOICE_COMBOS	2
 #define RTAC_MAX_ACTIVE_POPP		8
-#define RTAC_BUF_SIZE			4096
+#define RTAC_BUF_SIZE			8192
 
 #define TIMEOUT_MS	1000
 
+struct rtac_cal_block_data	rtac_cal[MAX_RTAC_BLOCKS] = {
+/* ADM_RTAC_CAL */
+	{{RTAC_BUF_SIZE, 0, 0, 0}, {0, 0, 0} },
+/* ASM_RTAC_CAL */
+	{{RTAC_BUF_SIZE, 0, 0, 0}, {0, 0, 0} },
+/* VOICE_RTAC_CAL */
+	{{RTAC_BUF_SIZE, 0, 0, 0}, {0, 0, 0} }
+};
+
+struct rtac_common_data {
+	atomic_t			usage_count;
+	atomic_t			apr_err_code;
+};
+
+static struct rtac_common_data		rtac_common;
+
 /* APR data */
 struct rtac_apr_data {
 	void			*apr_handle;
@@ -83,15 +100,11 @@
 	struct rtac_adm_data	device[RTAC_MAX_ACTIVE_DEVICES];
 };
 static struct rtac_adm		rtac_adm_data;
-static u32			rtac_adm_payload_size;
-static u32			rtac_adm_user_buf_size;
-static u8			*rtac_adm_buffer;
+static u32			*rtac_adm_buffer;
 
 
 /* ASM APR */
-static u32			rtac_asm_payload_size;
-static u32			rtac_asm_user_buf_size;
-static u8			*rtac_asm_buffer;
+static u32			*rtac_asm_buffer;
 
 
 /* Voice info & APR */
@@ -110,9 +123,7 @@
 };
 
 static struct rtac_voice	rtac_voice_data;
-static u32			rtac_voice_payload_size;
-static u32			rtac_voice_user_buf_size;
-static u8			*rtac_voice_buffer;
+static u32			*rtac_voice_buffer;
 static u32			voice_session_id[RTAC_MAX_ACTIVE_VOICE_COMBOS];
 
 
@@ -122,16 +133,227 @@
 struct mutex			rtac_voice_mutex;
 struct mutex			rtac_voice_apr_mutex;
 
+int rtac_clear_mapping(uint32_t cal_type)
+{
+	int result = 0;
+	pr_debug("%s\n", __func__);
+
+	if (cal_type >= MAX_RTAC_BLOCKS) {
+		pr_debug("%s: invalid cal type %d\n", __func__, cal_type);
+		result = -EINVAL;
+		goto done;
+	}
+
+	rtac_cal[cal_type].map_data.map_handle = 0;
+done:
+	return result;
+}
+
+int rtac_allocate_cal_buffer(uint32_t cal_type)
+{
+	int result = 0;
+	int len;
+	pr_debug("%s\n", __func__);
+
+	if (cal_type >= MAX_RTAC_BLOCKS) {
+		pr_err("%s: cal_type %d is invalid!\n",
+		       __func__, cal_type);
+		result =  -EINVAL;
+		goto done;
+	}
+
+	if (rtac_cal[cal_type].cal_data.paddr != 0) {
+		pr_err("%s: memory already allocated! cal_type %d, paddr 0x%x\n",
+		       __func__, cal_type, rtac_cal[cal_type].cal_data.paddr);
+		result = -EPERM;
+		goto done;
+	}
+
+	result = msm_audio_ion_alloc("rtac_client",
+		&rtac_cal[cal_type].map_data.ion_client,
+		&rtac_cal[cal_type].map_data.ion_handle,
+		rtac_cal[cal_type].map_data.map_size,
+		(ion_phys_addr_t *)&rtac_cal[cal_type].cal_data.paddr,
+		(size_t *)&len,
+		(void **)&rtac_cal[cal_type].cal_data.kvaddr);
+	if (result < 0) {
+		pr_err("%s: ION create client for RTAC failed\n",
+		       __func__);
+		goto done;
+	}
+
+	pr_debug("%s: cal_type %d, paddr 0x%x, kvaddr 0x%x, map_size 0x%x\n",
+		__func__, cal_type,
+		rtac_cal[cal_type].cal_data.paddr,
+		rtac_cal[cal_type].cal_data.kvaddr,
+		rtac_cal[cal_type].map_data.map_size);
+done:
+	return result;
+}
+
+int rtac_free_cal_buffer(uint32_t cal_type)
+{
+	int result = 0;
+	pr_debug("%s\n", __func__);
+
+	if (cal_type >= MAX_RTAC_BLOCKS) {
+		pr_err("%s: cal_type %d is invalid!\n",
+		       __func__, cal_type);
+		result =  -EINVAL;
+		goto done;
+	}
+
+	if (rtac_cal[cal_type].map_data.ion_client == NULL) {
+		pr_debug("%s: cal_type %d not allocated!\n",
+		       __func__, cal_type);
+		goto done;
+	}
+
+	result = msm_audio_ion_free(rtac_cal[cal_type].map_data.ion_client,
+				rtac_cal[cal_type].map_data.ion_handle);
+	if (result < 0) {
+		pr_err("%s: ION free for RTAC failed! cal_type %d, paddr 0x%x\n",
+		       __func__, cal_type, rtac_cal[cal_type].cal_data.paddr);
+		goto done;
+	}
+
+	rtac_cal[cal_type].map_data.map_handle = 0;
+	rtac_cal[cal_type].map_data.ion_client = NULL;
+	rtac_cal[cal_type].map_data.ion_handle = NULL;
+	rtac_cal[cal_type].cal_data.size = 0;
+	rtac_cal[cal_type].cal_data.kvaddr = 0;
+	rtac_cal[cal_type].cal_data.paddr = 0;
+done:
+	return result;
+}
+
+int rtac_map_cal_buffer(uint32_t cal_type)
+{
+	int result = 0;
+	pr_debug("%s\n", __func__);
+
+	if (cal_type >= MAX_RTAC_BLOCKS) {
+		pr_err("%s: cal_type %d is invalid!\n",
+		       __func__, cal_type);
+		result =  -EINVAL;
+		goto done;
+	}
+
+	if (rtac_cal[cal_type].map_data.map_handle != 0) {
+		pr_err("%s: already mapped cal_type %d\n",
+			__func__, cal_type);
+		result =  -EPERM;
+		goto done;
+	}
+
+	if (rtac_cal[cal_type].cal_data.paddr == 0) {
+		pr_err("%s: physical address is NULL cal_type %d\n",
+			__func__, cal_type);
+		result =  -EPERM;
+		goto done;
+	}
+
+	switch (cal_type) {
+	case ADM_RTAC_CAL:
+		result = adm_map_rtac_block(&rtac_cal[cal_type]);
+		break;
+	case ASM_RTAC_CAL:
+		result = q6asm_map_rtac_block(&rtac_cal[cal_type]);
+		break;
+	case VOICE_RTAC_CAL:
+		result = voc_map_rtac_block(&rtac_cal[cal_type]);
+		break;
+	}
+	if (result < 0) {
+		pr_err("%s: map RTAC failed! cal_type %d\n",
+		       __func__, cal_type);
+		goto done;
+	}
+done:
+	return result;
+}
+
+int rtac_unmap_cal_buffer(uint32_t cal_type)
+{
+	int result = 0;
+	pr_debug("%s\n", __func__);
+
+	if (cal_type >= MAX_RTAC_BLOCKS) {
+		pr_err("%s: cal_type %d is invalid!\n",
+		       __func__, cal_type);
+		result =  -EINVAL;
+		goto done;
+	}
+
+	if (rtac_cal[cal_type].map_data.map_handle == 0) {
+		pr_debug("%s: nothing to unmap cal_type %d\n",
+			__func__, cal_type);
+		goto done;
+	}
+
+	switch (cal_type) {
+	case ADM_RTAC_CAL:
+		result = adm_unmap_rtac_block(
+			&rtac_cal[cal_type].map_data.map_handle);
+		break;
+	case ASM_RTAC_CAL:
+		result = q6asm_unmap_rtac_block(
+			&rtac_cal[cal_type].map_data.map_handle);
+		break;
+	case VOICE_RTAC_CAL:
+		result = voc_unmap_rtac_block(
+			&rtac_cal[cal_type].map_data.map_handle);
+		break;
+	}
+	if (result < 0) {
+		pr_err("%s: unmap RTAC failed! cal_type %d\n",
+		       __func__, cal_type);
+		goto done;
+	}
+done:
+	return result;
+}
+
 static int rtac_open(struct inode *inode, struct file *f)
 {
+	int	result = 0;
 	pr_debug("%s\n", __func__);
-	return 0;
+
+	atomic_inc(&rtac_common.usage_count);
+	return result;
 }
 
 static int rtac_release(struct inode *inode, struct file *f)
 {
+	int	result = 0;
+	int	result2 = 0;
+	int	i;
 	pr_debug("%s\n", __func__);
-	return 0;
+
+	atomic_dec(&rtac_common.usage_count);
+	pr_debug("%s: ref count %d!\n", __func__,
+		atomic_read(&rtac_common.usage_count));
+
+	if (atomic_read(&rtac_common.usage_count) > 0)
+		goto done;
+
+	for (i = 0; i < MAX_RTAC_BLOCKS; i++) {
+		result2 = rtac_unmap_cal_buffer(i);
+		if (result2 < 0) {
+			pr_err("%s: unmap buffer failed! error %d!\n",
+				__func__, result2);
+			result = result2;
+		}
+
+		result2 = rtac_free_cal_buffer(i);
+		if (result2 < 0) {
+			pr_err("%s: free buffer failed! error %d!\n",
+				__func__, result2);
+			result = result2;
+		}
+	}
+done:
+	return result;
 }
 
 /* ADM Info */
@@ -412,52 +634,56 @@
 	if (atomic_read(&rtac_adm_apr_data.cmd_state) != 1)
 		return false;
 
-	/* Offset data for in-band payload */
-	rtac_copy_adm_payload_to_user(payload, payload_size);
+	pr_debug("%s\n", __func__);
+	if (payload_size == sizeof(uint32_t))
+		atomic_set(&rtac_common.apr_err_code, payload[0]);
+	else if (payload_size == (2*sizeof(uint32_t)))
+		atomic_set(&rtac_common.apr_err_code, payload[1]);
+
 	atomic_set(&rtac_adm_apr_data.cmd_state, 0);
 	wake_up(&rtac_adm_apr_data.cmd_wait);
 	return true;
 }
 
-void rtac_copy_adm_payload_to_user(void *payload, u32 payload_size)
-{
-	pr_debug("%s\n", __func__);
-	rtac_adm_payload_size = payload_size;
-
-	memcpy(rtac_adm_buffer, &payload_size, sizeof(u32));
-	if (payload_size != 0) {
-		if (payload_size > rtac_adm_user_buf_size) {
-			pr_err("%s: Buffer set not big enough for returned data, buf size = %d, ret data = %d\n",
-			 __func__, rtac_adm_user_buf_size, payload_size);
-			rtac_adm_payload_size = 0;
-			goto done;
-		}
-		memcpy(rtac_adm_buffer + sizeof(u32), payload, payload_size);
-	}
-done:
-	return;
-}
-
 u32 send_adm_apr(void *buf, u32 opcode)
 {
 	s32	result;
-	u32	count = 0;
+	u32	user_buf_size = 0;
 	u32	bytes_returned = 0;
 	u32	port_index = 0;
 	u32	copp_id;
 	u32	payload_size;
+	u32	data_size = 0;
 	struct apr_hdr	adm_params;
 	pr_debug("%s\n", __func__);
 
-	if (copy_from_user(&count, (void *)buf, sizeof(count))) {
-		pr_err("%s: Copy to user failed! buf = 0x%x\n",
-		       __func__, (unsigned int)buf);
-		result = -EFAULT;
-		goto done;
+	if (rtac_cal[ADM_RTAC_CAL].map_data.ion_handle == NULL) {
+		result = rtac_allocate_cal_buffer(ADM_RTAC_CAL);
+		if (result < 0) {
+			pr_err("%s: allocate buffer failed!",
+				__func__);
+			goto done;
+		}
 	}
 
-	if (count <= 0) {
-		pr_err("%s: Invalid buffer size = %d\n", __func__, count);
+	if (rtac_cal[ADM_RTAC_CAL].map_data.map_handle == 0) {
+		result = rtac_map_cal_buffer(ADM_RTAC_CAL);
+		if (result < 0) {
+			pr_err("%s: map buffer failed!",
+				__func__);
+			goto done;
+		}
+	}
+
+	if (copy_from_user(&user_buf_size, (void *)buf,
+						sizeof(user_buf_size))) {
+		pr_err("%s: Copy from user failed! buf = 0x%x\n",
+		       __func__, (unsigned int)buf);
+		goto done;
+	}
+	if (user_buf_size <= 0) {
+		pr_err("%s: Invalid buffer size = %d\n",
+			__func__, user_buf_size);
 		goto done;
 	}
 
@@ -467,13 +693,6 @@
 		goto done;
 	}
 
-
-	if (payload_size > MAX_PAYLOAD_SIZE) {
-		pr_err("%s: Invalid payload size = %d\n",
-			__func__, payload_size);
-		goto done;
-	}
-
 	if (copy_from_user(&copp_id, buf + 2 * sizeof(u32), sizeof(u32))) {
 		pr_err("%s: Could not copy port id from user buffer\n",
 			__func__);
@@ -496,15 +715,42 @@
 		goto err;
 	}
 
-	/* Set globals for copy of returned payload */
-	rtac_adm_user_buf_size = count;
+	if (opcode == ADM_CMD_SET_PP_PARAMS_V5) {
+		/* set payload size to in-band payload */
+		/* set data size to actual out of band payload size */
+		data_size = payload_size - 4 * sizeof(u32);
+		if (data_size > rtac_cal[ADM_RTAC_CAL].map_data.map_size) {
+			pr_err("%s: Invalid data size = %d\n",
+				__func__, data_size);
+			goto done;
+		}
+		payload_size = 4 * sizeof(u32);
 
-	/* Copy buffer to in-band payload */
-	if (copy_from_user(rtac_adm_buffer + sizeof(adm_params),
-			buf + 3 * sizeof(u32), payload_size)) {
-		pr_err("%s: Could not copy payload from user buffer\n",
-			__func__);
-		goto err;
+		/* Copy buffer to out-of-band payload */
+		if (copy_from_user((void *)
+				rtac_cal[ADM_RTAC_CAL].cal_data.kvaddr,
+				buf + 7 * sizeof(u32), data_size)) {
+			pr_err("%s: Could not copy payload from user buffer\n",
+				__func__);
+			goto err;
+		}
+		/* set payload size in packet */
+		rtac_adm_buffer[8] = data_size;
+	} else {
+		if (payload_size > MAX_PAYLOAD_SIZE) {
+			pr_err("%s: Invalid payload size = %d\n",
+				__func__, payload_size);
+			goto done;
+		}
+
+		/* Copy buffer to in-band payload */
+		if (copy_from_user(rtac_adm_buffer +
+				sizeof(adm_params)/sizeof(u32),
+				buf + 3 * sizeof(u32), payload_size)) {
+			pr_err("%s: Could not copy payload from user buffer\n",
+				__func__);
+			goto err;
+		}
 	}
 
 	/* Pack header */
@@ -521,14 +767,20 @@
 	adm_params.token = copp_id;
 	adm_params.opcode = opcode;
 
+	/* fill for out-of-band */
+	rtac_adm_buffer[5] = rtac_cal[ADM_RTAC_CAL].cal_data.paddr;
+	rtac_adm_buffer[6] = 0;
+	rtac_adm_buffer[7] = rtac_cal[ADM_RTAC_CAL].map_data.map_handle;
+
 	memcpy(rtac_adm_buffer, &adm_params, sizeof(adm_params));
 	atomic_set(&rtac_adm_apr_data.cmd_state, 1);
 
-	pr_debug("%s: Sending RTAC command size = %d\n",
-		__func__, adm_params.pkt_size);
+	pr_debug("%s: Sending RTAC command ioctl 0x%x, paddr 0x%x\n",
+		__func__, opcode,
+		rtac_cal[ADM_RTAC_CAL].cal_data.paddr);
 
 	result = apr_send_pkt(rtac_adm_apr_data.apr_handle,
-		(uint32_t *)rtac_adm_buffer);
+					(uint32_t *)rtac_adm_buffer);
 	if (result < 0) {
 		pr_err("%s: Set params failed port = %d, copp = %d\n",
 			__func__, port_index, copp_id);
@@ -544,21 +796,34 @@
 			__func__, port_index, copp_id);
 		goto done;
 	}
-
-	if (rtac_adm_payload_size != 0) {
-		if (copy_to_user(buf, rtac_adm_buffer,
-			rtac_adm_payload_size + sizeof(u32))) {
-			pr_err("%s: Could not copy buffer to user,size = %d\n",
-				__func__, payload_size);
-			goto done;
-		}
+	if (atomic_read(&rtac_common.apr_err_code)) {
+		pr_err("%s: DSP returned error code = %d, opcode = 0x%x\n",
+			__func__, atomic_read(&rtac_common.apr_err_code),
+			opcode);
+		goto done;
 	}
 
-	/* Return data written for SET & data read for GET */
-	if (opcode == ADM_CMD_GET_PP_PARAMS_V5)
-		bytes_returned = rtac_adm_payload_size;
-	else
-		bytes_returned = payload_size;
+	if (opcode == ADM_CMD_GET_PP_PARAMS_V5) {
+		bytes_returned = ((u32 *)rtac_cal[ADM_RTAC_CAL].cal_data.
+			kvaddr)[2] + 3 * sizeof(u32);
+
+		if (bytes_returned > user_buf_size) {
+			pr_err("%s: User buf not big enough, size = 0x%x, returned size = 0x%x\n",
+				__func__, user_buf_size, bytes_returned);
+			goto done;
+		}
+
+		if (copy_to_user(buf, (void *)
+				rtac_cal[ADM_RTAC_CAL].cal_data.kvaddr,
+				bytes_returned)) {
+			pr_err("%s: Could not copy buffer to user,size = %d\n",
+				__func__, bytes_returned);
+			goto done;
+		}
+	} else {
+		bytes_returned = data_size;
+	}
+
 done:
 	return bytes_returned;
 err:
@@ -584,51 +849,54 @@
 		return false;
 
 	pr_debug("%s\n", __func__);
-	/* Offset data for in-band payload */
-	rtac_copy_asm_payload_to_user(payload, payload_size);
+	if (payload_size == sizeof(uint32_t))
+		atomic_set(&rtac_common.apr_err_code, payload[0]);
+	else if (payload_size == (2*sizeof(uint32_t)))
+		atomic_set(&rtac_common.apr_err_code, payload[1]);
+
 	atomic_set(&rtac_asm_apr_data[session_id].cmd_state, 0);
 	wake_up(&rtac_asm_apr_data[session_id].cmd_wait);
 	return true;
 }
 
-void rtac_copy_asm_payload_to_user(void *payload, u32 payload_size)
-{
-	pr_debug("%s\n", __func__);
-	rtac_asm_payload_size = payload_size;
-
-	memcpy(rtac_asm_buffer, &payload_size, sizeof(u32));
-	if (payload_size) {
-		if (payload_size > rtac_asm_user_buf_size) {
-			pr_err("%s: Buffer set not big enough for returned data, buf size = %d, ret data = %d\n",
-			 __func__, rtac_asm_user_buf_size, payload_size);
-			rtac_asm_payload_size = 0;
-			goto done;
-		}
-		memcpy(rtac_asm_buffer + sizeof(u32), payload, payload_size);
-	}
-done:
-	return;
-}
-
 u32 send_rtac_asm_apr(void *buf, u32 opcode)
 {
 	s32	result;
-	u32	count = 0;
+	u32	user_buf_size = 0;
 	u32	bytes_returned = 0;
 	u32	session_id = 0;
 	u32	payload_size;
+	u32	data_size = 0;
 	struct apr_hdr		asm_params;
 	pr_debug("%s\n", __func__);
 
-	if (copy_from_user(&count, (void *)buf, sizeof(count))) {
-		pr_err("%s: Copy to user failed! buf = 0x%x\n",
-		       __func__, (unsigned int)buf);
-		result = -EFAULT;
-		goto done;
+	if (rtac_cal[ASM_RTAC_CAL].map_data.ion_handle == NULL) {
+		result = rtac_allocate_cal_buffer(ASM_RTAC_CAL);
+		if (result < 0) {
+			pr_err("%s: allocate buffer failed!",
+				__func__);
+			goto done;
+		}
 	}
 
-	if (count <= 0) {
-		pr_err("%s: Invalid buffer size = %d\n", __func__, count);
+	if (rtac_cal[ASM_RTAC_CAL].map_data.map_handle == 0) {
+		result = rtac_map_cal_buffer(ASM_RTAC_CAL);
+		if (result < 0) {
+			pr_err("%s: map buffer failed!",
+				__func__);
+			goto done;
+		}
+	}
+
+	if (copy_from_user(&user_buf_size, (void *)buf,
+						sizeof(user_buf_size))) {
+		pr_err("%s: Copy from user failed! buf = 0x%x\n",
+		       __func__, (unsigned int)buf);
+		goto done;
+	}
+	if (user_buf_size <= 0) {
+		pr_err("%s: Invalid buffer size = %d\n",
+			__func__, user_buf_size);
 		goto done;
 	}
 
@@ -638,40 +906,59 @@
 		goto done;
 	}
 
-	if (payload_size > MAX_PAYLOAD_SIZE) {
-		pr_err("%s: Invalid payload size = %d\n",
-			__func__, payload_size);
-		goto done;
-	}
-
 	if (copy_from_user(&session_id, buf + 2 * sizeof(u32), sizeof(u32))) {
 		pr_err("%s: Could not copy session id from user buffer\n",
 			__func__);
 		goto done;
 	}
-
-	if (session_id > (SESSION_MAX + 1)) {
+	if (session_id >= (SESSION_MAX + 1)) {
 		pr_err("%s: Invalid Session = %d\n", __func__, session_id);
 		goto done;
 	}
 
 	mutex_lock(&rtac_asm_apr_mutex);
-	if (session_id < SESSION_MAX+1) {
-		if (rtac_asm_apr_data[session_id].apr_handle == NULL) {
-			pr_err("%s: APR not initialized\n", __func__);
-			goto err;
-		}
+	if (rtac_asm_apr_data[session_id].apr_handle == NULL) {
+		pr_err("%s: APR not initialized\n", __func__);
+		goto err;
 	}
 
-	/* Set globals for copy of returned payload */
-	rtac_asm_user_buf_size = count;
+	if (opcode == ASM_STREAM_CMD_SET_PP_PARAMS_V2) {
+		/* set payload size to in-band payload */
+		/* set data size to actual out of band payload size */
+		data_size = payload_size - 4 * sizeof(u32);
+		if (data_size > rtac_cal[ASM_RTAC_CAL].map_data.map_size) {
+			pr_err("%s: Invalid data size = %d\n",
+				__func__, data_size);
+			goto done;
+		}
+		payload_size = 4 * sizeof(u32);
 
-	/* Copy buffer to in-band payload */
-	if (copy_from_user(rtac_asm_buffer + sizeof(asm_params),
-			buf + 3 * sizeof(u32), payload_size)) {
-		pr_err("%s: Could not copy payload from user buffer\n",
-			__func__);
-		goto err;
+		/* Copy buffer to out-of-band payload */
+		if (copy_from_user((void *)
+				rtac_cal[ASM_RTAC_CAL].cal_data.kvaddr,
+				buf + 7 * sizeof(u32), data_size)) {
+			pr_err("%s: Could not copy payload from user buffer\n",
+				__func__);
+			goto err;
+		}
+		/* set payload size in packet */
+		rtac_asm_buffer[8] = data_size;
+
+	} else {
+		if (payload_size > MAX_PAYLOAD_SIZE) {
+			pr_err("%s: Invalid payload size = %d\n",
+				__func__, payload_size);
+			goto done;
+		}
+
+		/* Copy buffer to in-band payload */
+		if (copy_from_user(rtac_asm_buffer +
+				sizeof(asm_params)/sizeof(u32),
+				buf + 3 * sizeof(u32), payload_size)) {
+			pr_err("%s: Could not copy payload from user buffer\n",
+				__func__);
+			goto err;
+		}
 	}
 
 	/* Pack header */
@@ -688,12 +975,17 @@
 	asm_params.token = session_id;
 	asm_params.opcode = opcode;
 
-	memcpy(rtac_asm_buffer, &asm_params, sizeof(asm_params));
-	if (session_id < SESSION_MAX+1)
-		atomic_set(&rtac_asm_apr_data[session_id].cmd_state, 1);
+	/* fill for out-of-band */
+	rtac_asm_buffer[5] = rtac_cal[ASM_RTAC_CAL].cal_data.paddr;
+	rtac_asm_buffer[6] = 0;
+	rtac_asm_buffer[7] = rtac_cal[ASM_RTAC_CAL].map_data.map_handle;
 
-	pr_debug("%s: Sending RTAC command size = %d, session_id=%d\n",
-		__func__, asm_params.pkt_size, session_id);
+	memcpy(rtac_asm_buffer, &asm_params, sizeof(asm_params));
+	atomic_set(&rtac_asm_apr_data[session_id].cmd_state, 1);
+
+	pr_debug("%s: Sending RTAC command ioctl 0x%x, paddr 0x%x\n",
+		__func__, opcode,
+		rtac_cal[ASM_RTAC_CAL].cal_data.paddr);
 
 	result = apr_send_pkt(rtac_asm_apr_data[session_id].apr_handle,
 				(uint32_t *)rtac_asm_buffer);
@@ -713,21 +1005,33 @@
 			__func__, session_id);
 		goto done;
 	}
-
-	if (rtac_asm_payload_size != 0) {
-		if (copy_to_user(buf, rtac_asm_buffer,
-			rtac_asm_payload_size + sizeof(u32))) {
-			pr_err("%s: Could not copy buffer to user,size = %d\n",
-				 __func__, payload_size);
-			goto done;
-		}
+	if (atomic_read(&rtac_common.apr_err_code)) {
+		pr_err("%s: DSP returned error code = %d, opcode = 0x%x\n",
+			__func__, atomic_read(&rtac_common.apr_err_code),
+			opcode);
+		goto done;
 	}
 
-	/* Return data written for SET & data read for GET */
-	if (opcode == ASM_STREAM_CMD_GET_PP_PARAMS_V2)
-		bytes_returned = rtac_asm_payload_size;
-	else
-		bytes_returned = payload_size;
+	if (opcode == ASM_STREAM_CMD_GET_PP_PARAMS_V2) {
+		bytes_returned = ((u32 *)rtac_cal[ASM_RTAC_CAL].cal_data.
+			kvaddr)[2] + 3 * sizeof(u32);
+
+		if (bytes_returned > user_buf_size) {
+			pr_err("%s: User buf not big enough, size = 0x%x, returned size = 0x%x\n",
+				__func__, user_buf_size, bytes_returned);
+			goto done;
+		}
+
+		if (copy_to_user(buf, (void *)
+				rtac_cal[ASM_RTAC_CAL].cal_data.kvaddr,
+				bytes_returned)) {
+			pr_err("%s: Could not copy buffer to user,size = %d\n",
+				 __func__, bytes_returned);
+			goto done;
+		}
+	} else {
+		bytes_returned = data_size;
+	}
 done:
 	return bytes_returned;
 err:
@@ -753,51 +1057,54 @@
 		return false;
 
 	pr_debug("%s\n", __func__);
-	/* Offset data for in-band payload */
-	rtac_copy_voice_payload_to_user(payload, payload_size);
+	if (payload_size == sizeof(uint32_t))
+		atomic_set(&rtac_common.apr_err_code, payload[0]);
+	else if (payload_size == (2*sizeof(uint32_t)))
+		atomic_set(&rtac_common.apr_err_code, payload[1]);
+
 	atomic_set(&rtac_voice_apr_data[mode].cmd_state, 0);
 	wake_up(&rtac_voice_apr_data[mode].cmd_wait);
 	return true;
 }
 
-void rtac_copy_voice_payload_to_user(void *payload, u32 payload_size)
-{
-	pr_debug("%s\n", __func__);
-	rtac_voice_payload_size = payload_size;
-
-	memcpy(rtac_voice_buffer, &payload_size, sizeof(u32));
-	if (payload_size) {
-		if (payload_size > rtac_voice_user_buf_size) {
-			pr_err("%s: Buffer set not big enough for returned data, buf size = %d, ret data = %d\n",
-			 __func__, rtac_voice_user_buf_size, payload_size);
-			rtac_voice_payload_size = 0;
-			goto done;
-		}
-		memcpy(rtac_voice_buffer + sizeof(u32), payload, payload_size);
-	}
-done:
-	return;
-}
-
 u32 send_voice_apr(u32 mode, void *buf, u32 opcode)
 {
 	s32	result;
-	u32	count = 0;
+	u32	user_buf_size = 0;
 	u32	bytes_returned = 0;
 	u32	payload_size;
 	u32	dest_port;
+	u32	data_size = 0;
 	struct apr_hdr		voice_params;
 	pr_debug("%s\n", __func__);
 
-	if (copy_from_user(&count, (void *)buf, sizeof(count))) {
-		pr_err("%s: Copy to user failed! buf = 0x%x\n",
-		       __func__, (unsigned int)buf);
-		result = -EFAULT;
-		goto done;
+	if (rtac_cal[VOICE_RTAC_CAL].map_data.ion_handle == NULL) {
+		result = rtac_allocate_cal_buffer(VOICE_RTAC_CAL);
+		if (result < 0) {
+			pr_err("%s: allocate buffer failed!",
+				__func__);
+			goto done;
+		}
 	}
 
-	if (count <= 0) {
-		pr_err("%s: Invalid buffer size = %d\n", __func__, count);
+	if (rtac_cal[VOICE_RTAC_CAL].map_data.map_handle == 0) {
+		result = rtac_map_cal_buffer(VOICE_RTAC_CAL);
+		if (result < 0) {
+			pr_err("%s: map buffer failed!",
+				__func__);
+			goto done;
+		}
+	}
+
+	if (copy_from_user(&user_buf_size, (void *)buf,
+						sizeof(user_buf_size))) {
+		pr_err("%s: Copy from user failed! buf = 0x%x\n",
+		       __func__, (unsigned int)buf);
+		goto done;
+	}
+	if (user_buf_size <= 0) {
+		pr_err("%s: Invalid buffer size = %d\n",
+			__func__, user_buf_size);
 		goto done;
 	}
 
@@ -807,12 +1114,6 @@
 		goto done;
 	}
 
-	if (payload_size > MAX_PAYLOAD_SIZE) {
-		pr_err("%s: Invalid payload size = %d\n",
-				__func__, payload_size);
-		goto done;
-	}
-
 	if (copy_from_user(&dest_port, buf + 2 * sizeof(u32), sizeof(u32))) {
 		pr_err("%s: Could not copy port id from user buffer\n",
 			__func__);
@@ -831,15 +1132,42 @@
 		goto err;
 	}
 
-	/* Set globals for copy of returned payload */
-	rtac_voice_user_buf_size = count;
+	if (opcode == VOICE_CMD_SET_PARAM) {
+		/* set payload size to in-band payload */
+		/* set data size to actual out of band payload size */
+		data_size = payload_size - 4 * sizeof(u32);
+		if (data_size > rtac_cal[VOICE_RTAC_CAL].map_data.map_size) {
+			pr_err("%s: Invalid data size = %d\n",
+				__func__, data_size);
+			goto done;
+		}
+		payload_size = 4 * sizeof(u32);
 
-	/* Copy buffer to in-band payload */
-	if (copy_from_user(rtac_voice_buffer + sizeof(voice_params),
-			buf + 3 * sizeof(u32), payload_size)) {
-		pr_err("%s: Could not copy payload from user buffer\n",
-			__func__);
-		goto err;
+		/* Copy buffer to out-of-band payload */
+		if (copy_from_user((void *)
+				rtac_cal[VOICE_RTAC_CAL].cal_data.kvaddr,
+				buf + 7 * sizeof(u32), data_size)) {
+			pr_err("%s: Could not copy payload from user buffer\n",
+				__func__);
+			goto err;
+		}
+		/* set payload size in packet */
+		rtac_voice_buffer[8] = data_size;
+	} else {
+		if (payload_size > MAX_PAYLOAD_SIZE) {
+			pr_err("%s: Invalid payload size = %d\n",
+					__func__, payload_size);
+			goto done;
+		}
+
+		/* Copy buffer to in-band payload */
+		if (copy_from_user(rtac_voice_buffer +
+				sizeof(voice_params)/sizeof(u32),
+				buf + 3 * sizeof(u32), payload_size)) {
+			pr_err("%s: Could not copy payload from user buffer\n",
+				__func__);
+			goto err;
+		}
 	}
 
 	/* Pack header */
@@ -856,11 +1184,17 @@
 	voice_params.token = 0;
 	voice_params.opcode = opcode;
 
+	/* fill for out-of-band */
+	rtac_voice_buffer[5] = rtac_cal[VOICE_RTAC_CAL].map_data.map_handle;
+	rtac_voice_buffer[6] = rtac_cal[VOICE_RTAC_CAL].cal_data.paddr;
+	rtac_voice_buffer[7] = 0;
+
 	memcpy(rtac_voice_buffer, &voice_params, sizeof(voice_params));
 	atomic_set(&rtac_voice_apr_data[mode].cmd_state, 1);
 
-	pr_debug("%s: Sending RTAC command size = %d, opcode = %x\n",
-		__func__, voice_params.pkt_size, opcode);
+	pr_debug("%s: Sending RTAC command ioctl 0x%x, paddr 0x%x\n",
+		__func__, opcode,
+		rtac_cal[VOICE_RTAC_CAL].cal_data.paddr);
 
 	result = apr_send_pkt(rtac_voice_apr_data[mode].apr_handle,
 					(uint32_t *)rtac_voice_buffer);
@@ -879,21 +1213,33 @@
 			__func__, opcode);
 		goto done;
 	}
-
-	if (rtac_voice_payload_size != 0) {
-		if (copy_to_user(buf, rtac_voice_buffer,
-			rtac_voice_payload_size + sizeof(u32))) {
-			pr_err("%s: Could not copy buffer to user, size = %d\n",
-				 __func__, payload_size);
-			goto done;
-		}
+	if (atomic_read(&rtac_common.apr_err_code)) {
+		pr_err("%s: DSP returned error code = %d, opcode = 0x%x\n",
+			__func__, atomic_read(&rtac_common.apr_err_code),
+			opcode);
+		goto done;
 	}
 
-	/* Return data written for SET & data read for GET */
-	if (opcode == VOICE_CMD_GET_PARAM)
-		bytes_returned = rtac_voice_payload_size;
-	else
-		bytes_returned = payload_size;
+	if (opcode == VOICE_CMD_GET_PARAM) {
+		bytes_returned = ((u32 *)rtac_cal[VOICE_RTAC_CAL].cal_data.
+			kvaddr)[2] + 3 * sizeof(u32);
+
+		if (bytes_returned > user_buf_size) {
+			pr_err("%s: User buf not big enough, size = 0x%x, returned size = 0x%x\n",
+				__func__, user_buf_size, bytes_returned);
+			goto done;
+		}
+
+		if (copy_to_user(buf, (void *)
+				rtac_cal[VOICE_RTAC_CAL].cal_data.kvaddr,
+				bytes_returned)) {
+			pr_err("%s: Could not copy buffer to user, size = %d\n",
+				 __func__, bytes_returned);
+			goto done;
+		}
+	} else {
+		bytes_returned = data_size;
+	}
 done:
 	return bytes_returned;
 err:
@@ -987,6 +1333,10 @@
 	int i = 0;
 	pr_debug("%s\n", __func__);
 
+	/* Driver */
+	atomic_set(&rtac_common.usage_count, 0);
+	atomic_set(&rtac_common.apr_err_code, 0);
+
 	/* ADM */
 	memset(&rtac_adm_data, 0, sizeof(rtac_adm_data));
 	rtac_adm_apr_data.apr_handle = NULL;
@@ -995,10 +1345,11 @@
 	mutex_init(&rtac_adm_mutex);
 	mutex_init(&rtac_adm_apr_mutex);
 
-	rtac_adm_buffer = kzalloc(RTAC_BUF_SIZE, GFP_KERNEL);
+	rtac_adm_buffer = kzalloc(
+		rtac_cal[ADM_RTAC_CAL].map_data.map_size, GFP_KERNEL);
 	if (rtac_adm_buffer == NULL) {
 		pr_err("%s: Could not allocate payload of size = %d\n",
-			__func__, RTAC_BUF_SIZE);
+			__func__, rtac_cal[ADM_RTAC_CAL].map_data.map_size);
 		goto nomem;
 	}
 
@@ -1010,10 +1361,11 @@
 	}
 	mutex_init(&rtac_asm_apr_mutex);
 
-	rtac_asm_buffer = kzalloc(RTAC_BUF_SIZE, GFP_KERNEL);
+	rtac_asm_buffer = kzalloc(
+		rtac_cal[ASM_RTAC_CAL].map_data.map_size, GFP_KERNEL);
 	if (rtac_asm_buffer == NULL) {
 		pr_err("%s: Could not allocate payload of size = %d\n",
-			__func__, RTAC_BUF_SIZE);
+			__func__, rtac_cal[ASM_RTAC_CAL].map_data.map_size);
 		kzfree(rtac_adm_buffer);
 		goto nomem;
 	}
@@ -1028,10 +1380,11 @@
 	mutex_init(&rtac_voice_mutex);
 	mutex_init(&rtac_voice_apr_mutex);
 
-	rtac_voice_buffer = kzalloc(RTAC_BUF_SIZE, GFP_KERNEL);
+	rtac_voice_buffer = kzalloc(
+		rtac_cal[VOICE_RTAC_CAL].map_data.map_size, GFP_KERNEL);
 	if (rtac_voice_buffer == NULL) {
 		pr_err("%s: Could not allocate payload of size = %d\n",
-			__func__, RTAC_BUF_SIZE);
+			__func__, rtac_cal[VOICE_RTAC_CAL].map_data.map_size);
 		kzfree(rtac_adm_buffer);
 		kzfree(rtac_asm_buffer);
 		goto nomem;
diff --git a/sound/soc/soc-core.c b/sound/soc/soc-core.c
index 79016b5..55f8dc8 100644
--- a/sound/soc/soc-core.c
+++ b/sound/soc/soc-core.c
@@ -55,7 +55,6 @@
 #endif
 
 static DEFINE_MUTEX(client_mutex);
-static LIST_HEAD(card_list);
 static LIST_HEAD(dai_list);
 static LIST_HEAD(platform_list);
 static LIST_HEAD(codec_list);
@@ -850,15 +849,9 @@
 	struct snd_soc_dai *codec_dai, *cpu_dai;
 	const char *platform_name;
 
-	if (rtd->complete)
-		return 1;
 	dev_dbg(card->dev, "binding %s at idx %d\n", dai_link->name, num);
 
-	/* do we already have the CPU DAI for this link ? */
-	if (rtd->cpu_dai) {
-		goto find_codec;
-	}
-	/* no, then find CPU DAI from registered DAIs*/
+	/* Find CPU DAI from registered DAIs*/
 	list_for_each_entry(cpu_dai, &dai_list, list) {
 		if (dai_link->cpu_dai_of_node) {
 			if (cpu_dai->dev->of_node != dai_link->cpu_dai_of_node)
@@ -869,15 +862,13 @@
 		}
 
 		rtd->cpu_dai = cpu_dai;
-		goto find_codec;
 	}
-	dev_dbg(card->dev, "CPU DAI %s not registered\n",
-			dai_link->cpu_dai_name);
 
-find_codec:
-	/* do we already have the CODEC for this link ? */
-	if (rtd->codec) {
-		goto find_platform;
+	if (!rtd->cpu_dai) {
+		dev_dbg(card->dev, "CPU DAI %s not registered\n",
+			dai_link->cpu_dai_name);
+		return -EPROBE_DEFER;
+
 	}
 
 	/* no, then find CODEC from registered CODECs*/
@@ -902,21 +893,21 @@
 					dai_link->codec_dai_name)) {
 
 				rtd->codec_dai = codec_dai;
-				goto find_platform;
 			}
 		}
-		dev_dbg(card->dev, "CODEC DAI %s not registered\n",
+		if (!rtd->codec_dai) {
+			dev_dbg(card->dev, "CODEC DAI %s not registered\n",
 				dai_link->codec_dai_name);
+			return -EPROBE_DEFER;
+		}
 
-		goto find_platform;
 	}
-	dev_dbg(card->dev, "CODEC %s not registered\n",
-			dai_link->codec_name);
 
-find_platform:
-	/* do we need a platform? */
-	if (rtd->platform)
-		goto out;
+	if (!rtd->codec) {
+		dev_dbg(card->dev, "CODEC %s not registered\n",
+			dai_link->codec_name);
+		return -EPROBE_DEFER;
+	}
 
 	/* if there's no platform we match on the empty platform */
 	platform_name = dai_link->platform_name;
@@ -935,20 +926,17 @@
 		}
 
 		rtd->platform = platform;
-		goto out;
 	}
-
-	dev_dbg(card->dev, "platform %s not registered\n",
+	if (!rtd->platform) {
+		dev_dbg(card->dev, "platform %s not registered\n",
 			dai_link->platform_name);
+
+		return -EPROBE_DEFER;
+	}
+	card->num_rtd++;
+
 	return 0;
 
-out:
-	/* mark rtd as complete if we found all 4 of our client devices */
-	if (rtd->codec && rtd->codec_dai && rtd->platform && rtd->cpu_dai) {
-		rtd->complete = 1;
-		card->num_rtd++;
-	}
-	return 1;
 }
 
 static void soc_remove_codec(struct snd_soc_codec *codec)
@@ -1399,6 +1387,20 @@
 }
 #endif
 
+static int soc_check_aux_dev(struct snd_soc_card *card, int num)
+{
+	struct snd_soc_aux_dev *aux_dev = &card->aux_dev[num];
+	struct snd_soc_codec *codec;
+
+	/* find CODEC from registered CODECs*/
+	list_for_each_entry(codec, &codec_list, list) {
+		if (!strcmp(codec->name, aux_dev->codec_name))
+			return 0;
+	}
+
+	return -EPROBE_DEFER;
+}
+
 static int soc_probe_aux_dev(struct snd_soc_card *card, int num)
 {
 	struct snd_soc_aux_dev *aux_dev = &card->aux_dev[num];
@@ -1419,7 +1421,7 @@
 	}
 	/* codec not found */
 	dev_err(card->dev, "asoc: codec %s not found", aux_dev->codec_name);
-	goto out;
+	return -EPROBE_DEFER;
 
 found:
 	ret = soc_probe_codec(card, codec);
@@ -1559,7 +1561,7 @@
 }
 
 
-static void snd_soc_instantiate_card(struct snd_soc_card *card)
+static int snd_soc_instantiate_card(struct snd_soc_card *card)
 {
 	struct snd_soc_codec *codec;
 	struct snd_soc_codec_conf *codec_conf;
@@ -1569,19 +1571,19 @@
 
 	mutex_lock(&card->mutex);
 
-	if (card->instantiated) {
-		mutex_unlock(&card->mutex);
-		return;
-	}
 
 	/* bind DAIs */
-	for (i = 0; i < card->num_links; i++)
-		soc_bind_dai_link(card, i);
+	for (i = 0; i < card->num_links; i++) {
+		ret = soc_bind_dai_link(card, i);
+		if (ret != 0)
+			goto base_error;
+	}
 
-	/* bind completed ? */
-	if (card->num_rtd != card->num_links) {
-		mutex_unlock(&card->mutex);
-		return;
+	/* check aux_devs too */
+	for (i = 0; i < card->num_aux_devs; i++) {
+		ret = soc_check_aux_dev(card, i);
+		if (ret != 0)
+			goto base_error;
 	}
 
 	/* initialize the register cache for each available codec */
@@ -1601,10 +1603,8 @@
 			}
 		}
 		ret = snd_soc_init_codec_cache(codec, compress_type);
-		if (ret < 0) {
-			mutex_unlock(&card->mutex);
-			return;
-		}
+		if (ret < 0)
+			goto base_error;
 	}
 
 	/* card bind complete so register a sound card */
@@ -1613,8 +1613,7 @@
 	if (ret < 0) {
 		printk(KERN_ERR "asoc: can't create sound card for card %s\n",
 			card->name);
-		mutex_unlock(&card->mutex);
-		return;
+		goto base_error;
 	}
 	card->snd_card->dev = card->dev;
 
@@ -1751,7 +1750,7 @@
 	card->instantiated = 1;
 	snd_soc_dapm_sync(&card->dapm);
 	mutex_unlock(&card->mutex);
-	return;
+	return 0;
 
 probe_aux_dev_err:
 	for (i = 0; i < card->num_aux_devs; i++)
@@ -1765,19 +1764,9 @@
 		card->remove(card);
 
 	snd_card_free(card->snd_card);
-
+base_error:
 	mutex_unlock(&card->mutex);
-}
-
-/*
- * Attempt to initialise any uninitialised cards.  Must be called with
- * client_mutex.
- */
-static void snd_soc_instantiate_cards(void)
-{
-	struct snd_soc_card *card;
-	list_for_each_entry(card, &card_list, list)
-		snd_soc_instantiate_card(card);
+	return ret;
 }
 
 /* probes a new socdev */
@@ -2035,6 +2024,10 @@
 {
 	unsigned int ret;
 
+	if (unlikely(!snd_card_is_online_state(codec->card->snd_card))) {
+		dev_err(codec->dev, "read 0x%02x while offline\n", reg);
+		return -ENODEV;
+	}
 	ret = codec->read(codec, reg);
 	dev_dbg(codec->dev, "read %x => %x\n", reg, ret);
 	trace_snd_soc_reg_read(codec, reg, ret);
@@ -2046,6 +2039,10 @@
 unsigned int snd_soc_write(struct snd_soc_codec *codec,
 			   unsigned int reg, unsigned int val)
 {
+	if (unlikely(!snd_card_is_online_state(codec->card->snd_card))) {
+		dev_err(codec->dev, "write 0x%02x while offline\n", reg);
+		return -ENODEV;
+	}
 	dev_dbg(codec->dev, "write %x = %x\n", reg, val);
 	trace_snd_soc_reg_write(codec, reg, val);
 	return codec->write(codec, reg, val);
@@ -3233,12 +3230,13 @@
 	mutex_init(&card->dpcm_mutex);
 	mutex_init(&card->dapm_power_mutex);
 
-	mutex_lock(&client_mutex);
-	list_add(&card->list, &card_list);
-	snd_soc_instantiate_cards();
-	mutex_unlock(&client_mutex);
+	ret = snd_soc_instantiate_card(card);
+	if (ret != 0) {
+		soc_cleanup_card_debugfs(card);
+		if (card->rtd)
+			kfree(card->rtd);
+	}
 
-	dev_dbg(card->dev, "Registered card '%s'\n", card->name);
 
 	return ret;
 }
@@ -3254,9 +3252,6 @@
 {
 	if (card->instantiated)
 		soc_cleanup_card_resources(card);
-	mutex_lock(&client_mutex);
-	list_del(&card->list);
-	mutex_unlock(&client_mutex);
 	dev_dbg(card->dev, "Unregistered card '%s'\n", card->name);
 
 	return 0;
@@ -3352,7 +3347,6 @@
 
 	mutex_lock(&client_mutex);
 	list_add(&dai->list, &dai_list);
-	snd_soc_instantiate_cards();
 	mutex_unlock(&client_mutex);
 
 	pr_debug("Registered DAI '%s'\n", dai->name);
@@ -3434,9 +3428,6 @@
 		pr_debug("Registered DAI '%s'\n", dai->name);
 	}
 
-	mutex_lock(&client_mutex);
-	snd_soc_instantiate_cards();
-	mutex_unlock(&client_mutex);
 	return 0;
 
 err:
@@ -3493,7 +3484,6 @@
 
 	mutex_lock(&client_mutex);
 	list_add(&platform->list, &platform_list);
-	snd_soc_instantiate_cards();
 	mutex_unlock(&client_mutex);
 
 	pr_debug("Registered platform '%s'\n", platform->name);
@@ -3562,6 +3552,17 @@
 }
 
 /**
+ * snd_soc_card_change_online_state - Mark if soc card is online/offline
+ *
+ * @soc_card : soc_card to mark
+ */
+void snd_soc_card_change_online_state(struct snd_soc_card *soc_card, int online)
+{
+	snd_card_change_online_state(soc_card->snd_card, online);
+}
+EXPORT_SYMBOL(snd_soc_card_change_online_state);
+
+/**
  * snd_soc_register_codec - Register a codec with the ASoC core
  *
  * @codec: codec to register
@@ -3651,7 +3652,6 @@
 
 	mutex_lock(&client_mutex);
 	list_add(&codec->list, &codec_list);
-	snd_soc_instantiate_cards();
 	mutex_unlock(&client_mutex);
 
 	pr_debug("Registered codec '%s'\n", codec->name);