Merge "mdss: support for solid fill with color specified by HAL"
diff --git a/Documentation/devicetree/bindings/arm/msm/clock-krait-8974.txt b/Documentation/devicetree/bindings/arm/msm/clock-krait-8974.txt
new file mode 100644
index 0000000..ee9a286
--- /dev/null
+++ b/Documentation/devicetree/bindings/arm/msm/clock-krait-8974.txt
@@ -0,0 +1,98 @@
+Qualcomm MSM8974 Krait clock tree
+
+clock-krait-8974 is a device that represents the MSM8974 Krait subsystem
+clock tree. It lists the various power supplies that need to be scaled when
+the clocks are scaled and also other HW specific parameters like fmax tables,
+avs settings table, etc.
+
+Required properties:
+- compatible:		Must be "qcom,clock-krait-8974"
+- reg:			Pairs of physical base addresses and region sizes of
+			memory mapped registers.
+- reg-names:		Names of the bases for the above registers. Expected
+			bases are:
+			"hfpll_l2_clk", "hfpll0_clk", ... "hfpllN_clk", "efuse"
+- cpuX-supply:		The regulator powering the CPUX.
+- l2-dig-supply:	The regulator powering the L2 digital logic.
+- hfpll-dig-supply:	The regulator powering the HFPLL digital domains.
+- hfpll-analog-supply:	The regulator powering the HFPLL analog domains.
+- qcom,l2-fmax:		A table of L2 frequency to voltage mappings that
+			represents the max frequency (Hz) possible for each
+			supported voltage level (uV).
+- qcom,speedX-pvsY-bin-vZ:
+			A table of CPU frequency (Hz) to voltage (uV) and
+			current (uA) mapping that represents the max
+			frequency possible for each supported voltage level
+			for a CPU that's binned as speed bin X, PVS bin Y
+			based on characterization version Z. Speed and PVS
+			bin values can be between [0-7] and the version can
+			be between [0-3]
+
+Optional properties:
+- qcom,avs-tbl:		A table of frequencies (Hz) and their corresponding
+			AVS DSCR register settings (32 bit value) to program
+			into the AVS HW. Frequencies with no AVS support do
+			not need to be listed in the table. If there is no
+			AVS support at all, then the whole property can be
+			omitted.
+- qcom,hfpll-config-val:
+			A 32 bit value to be programmed into the HFPLL
+			configuration control register.
+- qcom,hfpll-user-vco-mask:
+			The mask to be used when programming the VCO selection
+			bits in the user control register.
+
+Example:
+	qcom,clock-krait@f9016000 {
+		compatible = "qcom,clock-krait-8974";
+		reg = <0xf9016000 0x20>,
+			<0xf908a000 0x20>,
+			<0xf909a000 0x20>,
+			<0xf90aa000 0x20>,
+			<0xf90ba000 0x20>,
+			<0xfc4b80b0 0x08>;
+		reg-names = "hfpll_l2_clk", "hfpll0_clk",
+				"hfpll1_clk", "hfpll2_clk",
+				"hfpll3_clk", "efuse";
+		cpu0-supply = <&krait0_vreg>;
+		cpu1-supply = <&krait1_vreg>;
+		cpu2-supply = <&krait2_vreg>;
+		cpu3-supply = <&krait3_vreg>;
+		l2-dig-supply = <&pm8841_s2_corner_ao>;
+		hfpll-dig-supply = <&pm8841_s2_corner_ao>;
+		hfpll-analog-supply = <&pm8941_l12_ao>;
+
+		qcom,l2-fmax =
+			<  576000000 4 /* svs_soc */	>,
+			< 1036800000 5 /* normal */	>,
+			< 1728000000 7 /* super_turbo */>;
+
+		qcom,avs-tbl =
+			<  300000000 0xfa70054 >,
+			< 1574400000 0xfa70100 >;
+
+		qcom,speed0-pvs0-bin-v0 =
+			<          0       0   0 >,
+			<  300000000  815000  73 >,
+				.....
+				.....
+			< 1958400000 1100000 598 >;
+
+		qcom,speed0-pvs1-bin-v0 =
+			<          0       0   0 >,
+			<  300000000  800000  73 >,
+				.....
+				.....
+			< 1958400000 1075000 598 >;
+
+				.....
+				.....
+
+		qcom,speed2-pvs6-bin-v0 =
+			<          0       0   0 >,
+			<  300000000  750000  72 >,
+				.....
+				.....
+			< 2265600000  950000 691 >;
+
+	};
diff --git a/Documentation/devicetree/bindings/arm/msm/msm-cpufreq.txt b/Documentation/devicetree/bindings/arm/msm/msm-cpufreq.txt
new file mode 100644
index 0000000..02514d4
--- /dev/null
+++ b/Documentation/devicetree/bindings/arm/msm/msm-cpufreq.txt
@@ -0,0 +1,44 @@
+Qualcomm MSM CPUfreq device
+
+msm-cpufreq is a device that represents the list of useable CPU frequencies
+and the cache frequency and/or memory bandwidth required for each of them. It
+also captures the bus master/slave ports towards which the bus bandwidth
+requests need to be made to ensure the required memory bandwidth.
+
+Required properties:
+- compatible:		Must be "qcom,msm-cpufreq"
+- qcom,cpufreq-table:	A list of tuples where each tuple consists of a
+			usable CPU frequency (KHz), an optional cache
+			frequency (KHz) and an optional memory bandwidth
+			value (MBPS) listed in that order.  The cache
+			frequencies shall not be listed if the device cannot
+			run the cache asynchronous to one or more CPUs. The
+			memory bandwidth values shall not be listed if the
+			optional cpu-mem-ports property is not supplied.
+
+Optional properties:
+- qcom,cpu-mem-ports:	A list of tuples where each tuple consists of a bus
+			master (CPU) port number and a bus slave (memory)
+			port number.
+
+Example:
+	qcom,msm-cpufreq@0 {
+		regs = <0 4>
+		compatible = "qcom,msm-cpufreq";
+		qcom,cpu-mem-ports = <1 512>, <2 513>;
+		qcom,cpufreq-table =
+			<  300000  300000  600 >,
+			<  422400  422400 1200 >,
+			<  652800  499200 1600 >,
+			<  729600  576000 2456 >,
+			<  883200  576000 2456 >,
+			<  960000  960000 3680 >,
+			< 1036800 1036800 3680 >,
+			< 1190400 1036800 3680 >,
+			< 1267200 1267200 6400 >,
+			< 1497600 1497600 6400 >,
+			< 1574400 1574400 6400 >,
+			< 1728000 1651200 6400 >,
+			< 1958400 1728000 7448 >,
+			< 2265600 1728000 7448 >;
+	};
diff --git a/Documentation/devicetree/bindings/arm/msm/pm-8x60.txt b/Documentation/devicetree/bindings/arm/msm/pm-8x60.txt
index 82e7e2a..795af3b 100644
--- a/Documentation/devicetree/bindings/arm/msm/pm-8x60.txt
+++ b/Documentation/devicetree/bindings/arm/msm/pm-8x60.txt
@@ -25,6 +25,11 @@
 - qcom,saw-turns-off-pll: Version of SAW2.1 or can turn off the HFPLL, when
 	doing power collapse and so the core need to switch to Global PLL before
 	PC.
+- qcom,synced-clocks: Indicates that all cpus running off a single clock source and to
+	instantiate the necessary clock source.
+- qcom,cpus-as-clocks: Indicates that the CPU clocks are implemented using clock APIs and should
+	switch to using generic clock APIs to enable/disable power collapse.
+	If set, the pm driver would ignore clock API errors and continue to call acpuclock API directly.
 - qcom,pc-resets-timer: Indicates that the timer gets reset during power collapse.
 
 Example:
diff --git a/Documentation/devicetree/bindings/arm/msm/spm-v2.txt b/Documentation/devicetree/bindings/arm/msm/spm-v2.txt
index d9a0d59..f969e2f 100644
--- a/Documentation/devicetree/bindings/arm/msm/spm-v2.txt
+++ b/Documentation/devicetree/bindings/arm/msm/spm-v2.txt
@@ -40,6 +40,8 @@
 - qcom,saw2-spm-cmd-wfi: The WFI command sequence
 - qcom,saw2-spm-cmd-ret: The Retention command sequence
 - qcom,saw2-spm-cmd-spc: The Standalone PC command sequence
+- qcom,saw2-spm-cmd-pc-no-rpm: The Power Collapse command sequence where APPS
+	proc won't inform the RPM.
 - 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
diff --git a/Documentation/devicetree/bindings/input/touchscreen/gt9xx/gt9xx.txt b/Documentation/devicetree/bindings/input/touchscreen/gt9xx/gt9xx.txt
index fdba7c2..f2ca95b 100644
--- a/Documentation/devicetree/bindings/input/touchscreen/gt9xx/gt9xx.txt
+++ b/Documentation/devicetree/bindings/input/touchscreen/gt9xx/gt9xx.txt
@@ -30,6 +30,7 @@
 				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,enable-power-off	: Power off touchscreen during suspend.
  - goodix,button-map	: Button map of key codes. The number of key codes
 				depend on panel.
  - goodix,cfg-data0	: Touch screen controller config data group 0. Ask vendor
@@ -50,6 +51,7 @@
 				to provide that.
  - goodix,cfg-data5	: Touch screen controller config data group 5. Ask vendor
 				to provide that.
+ - goodix,fw-name	: Touch screen controller firmware file name.
 Example:
 i2c@f9927000 {
 		goodix@5d {
@@ -84,5 +86,6 @@
 				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];
+			goodix,fw_name = "gtp_fw.bin";
 		};
 };
diff --git a/Documentation/devicetree/bindings/leds/leds-qpnp.txt b/Documentation/devicetree/bindings/leds/leds-qpnp.txt
index af6a0b5..749c594 100644
--- a/Documentation/devicetree/bindings/leds/leds-qpnp.txt
+++ b/Documentation/devicetree/bindings/leds/leds-qpnp.txt
@@ -10,13 +10,13 @@
 node will further contain the type of LED supported and its
 properties.  At least one child node is required for each LED
 module.  Each must have the required properties below, in addition
-to the properties for the LED type, WLED, Flash or RGB.
+to the properties for the LED type, WLED, Flash, RGB and MPP.
 
 Required properties for each child node, WLED, Flash and RGB:
 - compatible		: should be "qcom,leds-qpnp"
 - qcom,id		: must be one of values supported in enum qpnp_led
 - label			: type of led that will be used, ie "wled"
-- qcom,max-current	: maximum current that the LED can sustain
+- qcom,max-current	: maximum current that the LED can sustain in mA
 - linux,name		: name of the led that is used in led framework
 
 WLED is primarily used as display backlight. Display subsystem uses
@@ -85,6 +85,7 @@
 - qcom,vin-ctrl: select input source, supported values are 0 to 3
 - qcom,use-blink: Use blink sysfs entry for switching into lpg mode.  For optimal use, set default mode to pwm.  All required lpg parameters must be supplied.
 - qcom,min-brightness - Lowest possible brightness supported on this LED other than 0.
+- qcom,current-setting: default current value for wled used as button backlight in mA
 
 Required properties for PWM mode only:
 - qcom,pwm-channel: pwm channel the led will operate on
@@ -131,6 +132,22 @@
 
 Example:
 
+	qcom,leds@a100 {
+		status = "okay";
+		qcom,led_mpp_2 {
+			label = "mpp";
+			linux,name = "button-backlight";
+			linux,default-trigger = "hr-trigger";
+			qcom,default-state = "off";
+			qcom,current-setting = <20>;
+			qcom,max-current = <40>;
+			qcom,id = <6>;
+			qcom,source-sel = <1>;
+			qcom,mode-ctrl = <0x61>;
+			qcom,mode = "manual";
+		};
+	};
+
 	qcom,leds@a200 {
 		status = "okay";
 		qcom,led_mpp_3 {
diff --git a/Documentation/devicetree/bindings/power/qpnp-charger.txt b/Documentation/devicetree/bindings/power/qpnp-charger.txt
index 5425c92..584a76d 100644
--- a/Documentation/devicetree/bindings/power/qpnp-charger.txt
+++ b/Documentation/devicetree/bindings/power/qpnp-charger.txt
@@ -93,6 +93,10 @@
 					set, the charger ovp status is monitored in software.
 - qcom,ext-ovp-present			Indicates if an external OVP exists which reduces the
 					overall input resistance of the charge path.
+- qcom,power-stage-reduced		Indicates if power stage workaround is enabled. This work
+					around reduces the power stage segments while charging
+					under high load during low battery voltages. It's for
+					improving IADC accuracy while board has a bad layout.
 
 Sub node required structure:
 - A qcom,chg node must be a child of an SPMI node that has specified
diff --git a/Documentation/devicetree/bindings/regulator/krait-regulator.txt b/Documentation/devicetree/bindings/regulator/krait-regulator.txt
index a8195df..7c661fe 100644
--- a/Documentation/devicetree/bindings/regulator/krait-regulator.txt
+++ b/Documentation/devicetree/bindings/regulator/krait-regulator.txt
@@ -55,6 +55,9 @@
 				to LDO mode. Acceptable values are from 1000uV to 100000uV
 - qcom,cpu-num:			Indicates what cpu this regulator controls
 
+Optional properties:
+- qcom,ldo-disable:		Indicates whether to disable using LDO mode
+
 Any property defined as part of the core regulator
 binding, defined in regulator.txt, can also be used.
 
diff --git a/Documentation/devicetree/bindings/sound/qcom-audio-dev.txt b/Documentation/devicetree/bindings/sound/qcom-audio-dev.txt
index 5e686a4f..56bdc59 100644
--- a/Documentation/devicetree/bindings/sound/qcom-audio-dev.txt
+++ b/Documentation/devicetree/bindings/sound/qcom-audio-dev.txt
@@ -407,6 +407,17 @@
 Required properties:
 - compatible : "qcom,msm8974-audio-taiko"
 - qcom,model : The user-visible name of this sound card.
+- reg : Offset and length of the register region(s) for MI2S/PCM MUX
+- reg-names : Register region name(s) referenced in reg above
+	 Required register resource entries are:
+	 "lpaif_pri_mode_muxsel": Physical address of MUX to select between
+				  Primary PCM and Primary MI2S
+	 "lpaif_sec_mode_muxsel": Physical address of MUX to select between
+				  Secondary PCM and Secondary MI2S
+	 "lpaif_tert_mode_muxsel": Physical address of MUX to select between
+				   Primary PCM and Tertiary MI2S
+	 "lpaif_quat_mode_muxsel": Physical address of MUX to select between
+				   Secondary PCM and Quarternary MI2S
 - qcom,audio-routing : A list of the connections between audio components.
   Each entry is a pair of strings, the first being the connection's sink,
   the second being the connection's source.
diff --git a/Documentation/devicetree/bindings/usb/msm-hsusb.txt b/Documentation/devicetree/bindings/usb/msm-hsusb.txt
index e7eae76..714311e 100644
--- a/Documentation/devicetree/bindings/usb/msm-hsusb.txt
+++ b/Documentation/devicetree/bindings/usb/msm-hsusb.txt
@@ -86,6 +86,11 @@
 	for detection of dp line transition during VDD minimization.
 - qcom,hsusb-otg-dmsehv-int: If present, indicates mpm interrupt to be configured
 	for detection of dm line transition during VDD minimization.
+- qcom,ahb-async-bridge-bypass: If present, indicates that enable AHB2AHB By Pass
+	mode with device controller for better throughput. With this mode, USB Core
+	runs using PNOC clock and synchronous to it. Hence it is must to have proper
+	"qcom,msm_bus,vectors" to have high bus frequency. User shouldn't try to
+	enable this feature without proper bus voting.
 
 Example HSUSB OTG controller device node :
 	usb@f9690000 {
@@ -176,12 +181,19 @@
 - 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
+  creates a new LUN as internal usb mass storage.
+- qcom,streaming-func : add list of usb function name. If mention usb function
+  is being enable as part of USB composition, streaming mode is enable with
+  usb device controller to get better throughput. NOTE: Inverted CRC and
+  turnaround timeout is observed on enabling streaming. Hence it is required
+  to see these errors and number of erros on enabling this at USB level to make
+  final decision to enable this feature or not.
 Example Android USB device node :
 	android_usb@fc42b0c8 {
 		compatible = "qcom,android-usb";
 		reg = <0xfc42b0c8 0xc8>;
 		qcom,android-usb-swfi-latency = <1>;
+		qcom,streaming-func = "rndis","mtp";
 	};
 
 
diff --git a/arch/arm/boot/dts/apq8026-v1-cdp.dts b/arch/arm/boot/dts/apq8026-v1-cdp.dts
index d7e283b..b9ec6f9 100644
--- a/arch/arm/boot/dts/apq8026-v1-cdp.dts
+++ b/arch/arm/boot/dts/apq8026-v1-cdp.dts
@@ -13,7 +13,7 @@
 
 /dts-v1/;
 /include/ "apq8026-v1.dtsi"
-/include/ "msm8226-cdp.dtsi"
+/include/ "msm8226-720p-cdp.dtsi"
 
 / {
 	model = "Qualcomm APQ 8026 CDP";
diff --git a/arch/arm/boot/dts/apq8026-v1-mtp.dts b/arch/arm/boot/dts/apq8026-v1-mtp.dts
index d24875c..c2fc72c 100644
--- a/arch/arm/boot/dts/apq8026-v1-mtp.dts
+++ b/arch/arm/boot/dts/apq8026-v1-mtp.dts
@@ -13,7 +13,7 @@
 
 /dts-v1/;
 /include/ "apq8026-v1.dtsi"
-/include/ "msm8226-mtp.dtsi"
+/include/ "msm8226-720p-mtp.dtsi"
 
 / {
 	model = "Qualcomm APQ 8026 MTP";
diff --git a/arch/arm/boot/dts/apq8026-v1-xpm.dts b/arch/arm/boot/dts/apq8026-v1-xpm.dts
index f69511b..b435018 100644
--- a/arch/arm/boot/dts/apq8026-v1-xpm.dts
+++ b/arch/arm/boot/dts/apq8026-v1-xpm.dts
@@ -13,7 +13,7 @@
 
 /dts-v1/;
 /include/ "apq8026-v1.dtsi"
-/include/ "msm8226-cdp.dtsi"
+/include/ "msm8226-720p-cdp.dtsi"
 
 / {
 	model = "Qualcomm APQ 8026 XPM";
diff --git a/arch/arm/boot/dts/apq8026-v2-cdp.dts b/arch/arm/boot/dts/apq8026-v2-1080p-cdp.dts
similarity index 91%
copy from arch/arm/boot/dts/apq8026-v2-cdp.dts
copy to arch/arm/boot/dts/apq8026-v2-1080p-cdp.dts
index cb68779..5294628 100644
--- a/arch/arm/boot/dts/apq8026-v2-cdp.dts
+++ b/arch/arm/boot/dts/apq8026-v2-1080p-cdp.dts
@@ -13,10 +13,10 @@
 
 /dts-v1/;
 /include/ "apq8026-v2.dtsi"
-/include/ "msm8226-cdp.dtsi"
+/include/ "msm8226-1080p-cdp.dtsi"
 
 / {
 	model = "Qualcomm APQ 8026v2 CDP";
 	compatible = "qcom,apq8026-cdp", "qcom,apq8026", "qcom,cdp";
-	qcom,board-id = <1 0>;
+	qcom,board-id = <1 2>;
 };
diff --git a/arch/arm/boot/dts/apq8026-v2-mtp.dts b/arch/arm/boot/dts/apq8026-v2-1080p-mtp.dts
similarity index 91%
copy from arch/arm/boot/dts/apq8026-v2-mtp.dts
copy to arch/arm/boot/dts/apq8026-v2-1080p-mtp.dts
index 40856c8..0ea98f5 100644
--- a/arch/arm/boot/dts/apq8026-v2-mtp.dts
+++ b/arch/arm/boot/dts/apq8026-v2-1080p-mtp.dts
@@ -13,10 +13,10 @@
 
 /dts-v1/;
 /include/ "apq8026-v2.dtsi"
-/include/ "msm8226-mtp.dtsi"
+/include/ "msm8226-1080p-mtp.dtsi"
 
 / {
 	model = "Qualcomm APQ 8026v2 MTP";
 	compatible = "qcom,apq8026-mtp", "qcom,apq8026", "qcom,mtp";
-	qcom,board-id = <8 0>;
+	qcom,board-id = <8 2>;
 };
diff --git a/arch/arm/boot/dts/apq8026-v2-cdp.dts b/arch/arm/boot/dts/apq8026-v2-720p-cdp.dts
similarity index 95%
rename from arch/arm/boot/dts/apq8026-v2-cdp.dts
rename to arch/arm/boot/dts/apq8026-v2-720p-cdp.dts
index cb68779..cb2226a 100644
--- a/arch/arm/boot/dts/apq8026-v2-cdp.dts
+++ b/arch/arm/boot/dts/apq8026-v2-720p-cdp.dts
@@ -13,7 +13,7 @@
 
 /dts-v1/;
 /include/ "apq8026-v2.dtsi"
-/include/ "msm8226-cdp.dtsi"
+/include/ "msm8226-720p-cdp.dtsi"
 
 / {
 	model = "Qualcomm APQ 8026v2 CDP";
diff --git a/arch/arm/boot/dts/apq8026-v2-mtp.dts b/arch/arm/boot/dts/apq8026-v2-720p-mtp.dts
similarity index 95%
rename from arch/arm/boot/dts/apq8026-v2-mtp.dts
rename to arch/arm/boot/dts/apq8026-v2-720p-mtp.dts
index 40856c8..439b3d7 100644
--- a/arch/arm/boot/dts/apq8026-v2-mtp.dts
+++ b/arch/arm/boot/dts/apq8026-v2-720p-mtp.dts
@@ -13,7 +13,7 @@
 
 /dts-v1/;
 /include/ "apq8026-v2.dtsi"
-/include/ "msm8226-mtp.dtsi"
+/include/ "msm8226-720p-mtp.dtsi"
 
 / {
 	model = "Qualcomm APQ 8026v2 MTP";
diff --git a/arch/arm/boot/dts/apq8026-v2-xpm.dts b/arch/arm/boot/dts/apq8026-v2-xpm.dts
index 324516d..3133424 100644
--- a/arch/arm/boot/dts/apq8026-v2-xpm.dts
+++ b/arch/arm/boot/dts/apq8026-v2-xpm.dts
@@ -13,7 +13,7 @@
 
 /dts-v1/;
 /include/ "apq8026-v2.dtsi"
-/include/ "msm8226-cdp.dtsi"
+/include/ "msm8226-720p-cdp.dtsi"
 
 / {
 	model = "Qualcomm APQ 8026v2 XPM";
diff --git a/arch/arm/boot/dts/dsi-panel-hx8379a-wvga-video.dtsi b/arch/arm/boot/dts/dsi-panel-hx8379a-wvga-video.dtsi
index 23b65f3..92e6fc1 100644
--- a/arch/arm/boot/dts/dsi-panel-hx8379a-wvga-video.dtsi
+++ b/arch/arm/boot/dts/dsi-panel-hx8379a-wvga-video.dtsi
@@ -81,14 +81,47 @@
 				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
+				14 23 24 3F
+				30 46 06 10
+				13 16 17 16
+				16 13 18 05
+				0F 14 23 24
+				3F 30 46 06
+				10 13 16 17
+				16 16 13 18
+			39 01 00 00 00 00 80
+				C1 01 00 07
+				10 17 1D 2A
+				33 3A 43 4A
+				52 5B 64 6D
+				78 7F 88 90
+				98 A0 A9 B2
+				B9 C1 C9 D1
+				D7 DF E6 ED
+				F4 FA FD 00
+				00 00 00 00
+				00 00 00 00
+				00 08 10 18
+				20 28 30 38
+				40 47 4F 58
+				60 68 70 78
+				80 88 90 98
+				A0 A9 B1 B9
+				C1 C9 D1 D8
+				E0 E8 F0 F9
+				FE 00 00 00
+				00 00 00 00
+				00 00 00 08
+				10 18 1E 26
+				2E 34 3A 41
+				49 4F 58 5E
+				67 6F 77 80
+				88 8F 97 9F
+				A7 AF B8 BF
+				C7 D1 D8 E3
+				EA F6 FF 00
+				00 00 00 00
+				00 00 00 00
 			23 01 00 00 00 00 02
 				cc 02
 			39 01 00 00 00 00 05
diff --git a/arch/arm/boot/dts/dsi-panel-hx8389b-qhd-video.dtsi b/arch/arm/boot/dts/dsi-panel-hx8389b-qhd-video.dtsi
index 7e63014..8f94502 100755
--- a/arch/arm/boot/dts/dsi-panel-hx8389b-qhd-video.dtsi
+++ b/arch/arm/boot/dts/dsi-panel-hx8389b-qhd-video.dtsi
@@ -124,7 +124,7 @@
 		qcom,mdss-dsi-panel-timings = [97 23 17 00 4B 53 1C 27 27 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-min-level = <26>;
 		qcom,mdss-dsi-bl-max-level = <255>;
 		qcom,mdss-dsi-dma-trigger = <4>;
 		qcom,mdss-dsi-mdp-trigger = <0>;
diff --git a/arch/arm/boot/dts/dsi-panel-otm8018b-fwvga-video.dtsi b/arch/arm/boot/dts/dsi-panel-otm8018b-fwvga-video.dtsi
index 9477c56..393419b 100644
--- a/arch/arm/boot/dts/dsi-panel-otm8018b-fwvga-video.dtsi
+++ b/arch/arm/boot/dts/dsi-panel-otm8018b-fwvga-video.dtsi
@@ -256,7 +256,7 @@
 		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-min-level = <26>;
 		qcom,mdss-dsi-bl-max-level = <255>;
 		qcom,mdss-dsi-dma-trigger = <4>;
 		qcom,mdss-dsi-mdp-trigger = <0>;
diff --git a/arch/arm/boot/dts/dsi-panel-ssd2080m-720p-video.dtsi b/arch/arm/boot/dts/dsi-panel-ssd2080m-720p-video.dtsi
index bb8389f..b510e6b 100644
--- a/arch/arm/boot/dts/dsi-panel-ssd2080m-720p-video.dtsi
+++ b/arch/arm/boot/dts/dsi-panel-ssd2080m-720p-video.dtsi
@@ -30,9 +30,9 @@
 		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-v-back-porch = <14>;
+		qcom,mdss-dsi-v-front-porch = <11>;
+		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>;
diff --git a/arch/arm/boot/dts/msm8226-1080p-cdp.dtsi b/arch/arm/boot/dts/msm8226-1080p-cdp.dtsi
new file mode 100644
index 0000000..bb66538
--- /dev/null
+++ b/arch/arm/boot/dts/msm8226-1080p-cdp.dtsi
@@ -0,0 +1,502 @@
+/* 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/ "msm8226-camera-sensor-cdp.dtsi"
+
+&soc {
+	serial@f991f000 {
+		status = "ok";
+	};
+
+	i2c@f9927000 { /* BLSP1 QUP5 */
+		synaptics@20 {
+			compatible = "synaptics,rmi4";
+			reg = <0x20>;
+			interrupt-parent = <&msmgpio>;
+			interrupts = <17 0x2008>;
+			vdd-supply = <&pm8226_l19>;
+			vcc_i2c-supply = <&pm8226_lvs1>;
+			synaptics,reset-gpio = <&msmgpio 16 0x00>;
+			synaptics,irq-gpio = <&msmgpio 17 0x2008>;
+			synaptics,display-coords = <0 0 1079 1919>;
+			synaptics,i2c-pull-up;
+			synaptics,power-down;
+			synaptics,disable-gpios;
+		};
+	};
+
+	gen-vkeys {
+		compatible = "qcom,gen-vkeys";
+		label = "synaptics_rmi4_i2c";
+		qcom,disp-maxx = <1079>;
+		qcom,disp-maxy = <1919>;
+		qcom,panel-maxx = <1079>;
+		qcom,panel-maxy = <2084>;
+		qcom,key-codes = <158 139 102 217>;
+	};
+
+	i2c@f9925000 { /* BLSP1 QUP3 */
+		nfc-nci@0e {
+			compatible = "qcom,nfc-nci";
+			reg = <0x0e>;
+			qcom,irq-gpio = <&msmgpio 21 0x00>;
+			qcom,dis-gpio = <&msmgpio 20 0x00>;
+			qcom,clk-src = "BBCLK2";
+			qcom,clk-en-gpio = <&msmgpio 0 0x00>;
+			interrupt-parent = <&msmgpio>;
+			interrupts = <21 0>;
+			qcom,clk-gpio = <&pm8226_gpios 3 0>;
+		};
+	};
+
+	gpio_keys {
+		compatible = "gpio-keys";
+		input-name = "gpio-keys";
+
+		camera_focus {
+			label = "camera_focus";
+			gpios = <&msmgpio 108 0x1>;
+			linux,input-type = <1>;
+			linux,code = <0x210>;
+			gpio-key,wakeup;
+			debounce-interval = <15>;
+		};
+
+		camera_snapshot {
+			label = "camera_snapshot";
+			gpios = <&msmgpio 107 0x1>;
+			linux,input-type = <1>;
+			linux,code = <0x2fe>;
+			gpio-key,wakeup;
+			debounce-interval = <15>;
+		};
+
+		vol_up {
+			label = "volume_up";
+			gpios = <&msmgpio 106 0x1>;
+			linux,input-type = <1>;
+			linux,code = <115>;
+			gpio-key,wakeup;
+			debounce-interval = <15>;
+		};
+	};
+
+	spi@f9923000 {
+		ethernet-switch@3 {
+			compatible = "micrel,ks8851";
+			reg = <3>;
+			interrupt-parent = <&msmgpio>;
+			interrupts = <115 0x8>;
+			spi-max-frequency = <4800000>;
+			rst-gpio = <&msmgpio 114 0>;
+			vdd-io-supply = <&pm8226_lvs1>;
+			vdd-phy-supply = <&pm8226_lvs1>;
+		};
+	};
+
+	sound {
+		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",
+			"AMIC4", "MIC BIAS2 External",
+			"MIC BIAS2 External", "ANCRight Headset Mic",
+			"AMIC5", "MIC BIAS2 External",
+			"MIC BIAS2 External", "ANCLeft Headset Mic",
+			"DMIC1", "MIC BIAS1 External",
+			"MIC BIAS1 External", "Digital Mic1",
+			"DMIC2", "MIC BIAS1 External",
+			"MIC BIAS1 External", "Digital Mic2",
+			"DMIC3", "MIC BIAS3 External",
+			"MIC BIAS3 External", "Digital Mic3",
+			"DMIC4", "MIC BIAS3 External",
+			"MIC BIAS3 External", "Digital Mic4";
+
+		qcom,cdc-mclk-gpios = <&pm8226_gpios 1 0>;
+		qcom,cdc-vdd-spkr-gpios = <&pm8226_gpios 2 0>;
+		qcom,headset-jack-type-NC;
+	};
+
+	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-NC;
+	};
+};
+
+&sdcc1 {
+	vdd-supply = <&pm8226_l17>;
+	qcom,vdd-voltage-level = <2950000 2950000>;
+	qcom,vdd-current-level = <800 500000>;
+
+	vdd-io-supply = <&pm8226_l6>;
+	qcom,vdd-io-always-on;
+	qcom,vdd-io-voltage-level = <1800000 1800000>;
+	qcom,vdd-io-current-level = <250 154000>;
+
+	qcom,pad-pull-on = <0x0 0x3 0x3>; /* no-pull, pull-up, pull-up */
+	qcom,pad-pull-off = <0x0 0x3 0x3>; /* no-pull, pull-up, pull-up */
+	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,sup-voltages = <2950 2950>;
+
+	qcom,bus-speed-mode = "HS200_1p8v", "DDR_1p8v";
+	qcom,nonremovable;
+
+	status = "disabled";
+};
+
+&sdhc_1 {
+	vdd-supply = <&pm8226_l17>;
+	qcom,vdd-voltage-level = <2950000 2950000>;
+	qcom,vdd-current-level = <800 500000>;
+
+	vdd-io-supply = <&pm8226_l6>;
+	qcom,vdd-io-always-on;
+	qcom,vdd-io-voltage-level = <1800000 1800000>;
+	qcom,vdd-io-current-level = <250 154000>;
+
+	qcom,pad-pull-on = <0x0 0x3 0x3>; /* no-pull, pull-up, pull-up */
+	qcom,pad-pull-off = <0x0 0x3 0x3>; /* no-pull, pull-up, pull-up */
+	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,bus-speed-mode = "HS200_1p8v", "DDR_1p8v";
+	qcom,nonremovable;
+
+	status = "ok";
+};
+
+&sdcc2 {
+	vdd-supply = <&pm8226_l18>;
+	qcom,vdd-voltage-level = <2950000 2950000>;
+	qcom,vdd-current-level = <9000 800000>;
+
+	vdd-io-supply = <&pm8226_l21>;
+	qcom,vdd-io-voltage-level = <1800000 2950000>;
+	qcom,vdd-io-current-level = <6 22000>;
+
+	qcom,pad-pull-on = <0x0 0x3 0x3>; /* no-pull, pull-up, pull-up */
+	qcom,pad-pull-off = <0x0 0x3 0x3>; /* no-pull, pull-up, pull-up */
+	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,sup-voltages = <2950 2950>;
+
+	qcom,xpc;
+	qcom,bus-speed-mode = "SDR12", "SDR25", "SDR50", "DDR50", "SDR104";
+	qcom,current-limit = <600>;
+
+	#address-cells = <0>;
+	interrupt-parent = <&sdcc2>;
+	interrupts = <0 1 2>;
+	#interrupt-cells = <1>;
+	interrupt-map-mask = <0xffffffff>;
+	interrupt-map = <0 &intc 0 125 0
+			1 &intc 0 220 0
+			2 &msmgpio 38 0x3>;
+	interrupt-names = "core_irq", "bam_irq", "status_irq";
+	cd-gpios = <&msmgpio 38 0x1>;
+
+	status = "disabled";
+};
+
+&sdhc_2 {
+	vdd-supply = <&pm8226_l18>;
+	qcom,vdd-voltage-level = <2950000 2950000>;
+	qcom,vdd-current-level = <9000 800000>;
+
+	vdd-io-supply = <&pm8226_l21>;
+	qcom,vdd-io-voltage-level = <1800000 2950000>;
+	qcom,vdd-io-current-level = <6 22000>;
+
+	qcom,pad-pull-on = <0x0 0x3 0x3>; /* no-pull, pull-up, pull-up */
+	qcom,pad-pull-off = <0x0 0x3 0x3>; /* no-pull, pull-up, pull-up */
+	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>;
+
+	#address-cells = <0>;
+	interrupt-parent = <&sdhc_2>;
+	interrupts = <0 1 2>;
+	#interrupt-cells = <1>;
+	interrupt-map-mask = <0xffffffff>;
+	interrupt-map = <0 &intc 0 125 0
+			1 &intc 0 221 0
+			2 &msmgpio 38 0x3>;
+	interrupt-names = "hc_irq", "pwr_irq", "status_irq";
+	cd-gpios = <&msmgpio 38 0x1>;
+
+	status = "ok";
+};
+
+&sdcc3 {
+	qcom,sup-voltages = <1800 1800>;
+	status = "disabled";
+};
+
+&sdhc_3 {
+	qcom,sup-voltages = <1800 1800>;
+	status = "disabled";
+};
+
+&spmi_bus {
+	qcom,pm8226@0 {
+		qcom,leds@a100 {
+			status = "okay";
+			qcom,led_mpp_2 {
+				label = "mpp";
+				linux,name = "button-backlight";
+				linux,default-trigger = "none";
+				qcom,default-state = "off";
+				qcom,max-current = <40>;
+				qcom,current-setting = <5>;
+				qcom,id = <6>;
+				qcom,mode = "manual";
+				qcom,source-sel = <1>;
+				qcom,mode-ctrl = <0x60>;
+			};
+		};
+
+		qcom,leds@a300 {
+			status = "okay";
+			qcom,led_mpp_4 {
+				label = "mpp";
+				linux,name = "green";
+				linux,default-trigger = "battery-full";
+				qcom,default-state = "off";
+				qcom,max-current = <40>;
+				qcom,current-setting = <5>;
+				qcom,id = <6>;
+				qcom,mode = "pwm";
+				qcom,pwm-us = <1000>;
+				qcom,source-sel = <8>;
+				qcom,mode-ctrl = <0x60>;
+				qcom,pwm-channel = <0>;
+				qcom,start-idx = <1>;
+				qcom,ramp-step-ms = <120>;
+				qcom,duty-pcts = [00 00 00 00 00
+						  00 00 00 00 00
+						  50 00 00 00 00
+						  00 00 00 00 00
+						  00];
+				qcom,use-blink;
+			};
+		};
+
+		qcom,leds@a500 {
+			status = "okay";
+			qcom,led_mpp_6 {
+				label = "mpp";
+				linux,name = "red";
+				linux,default-trigger = "battery-charging";
+				qcom,default-state = "off";
+				qcom,max-current = <40>;
+				qcom,current-setting = <5>;
+				qcom,id = <6>;
+				qcom,mode = "pwm";
+				qcom,pwm-us = <1000>;
+				qcom,mode-ctrl = <0x60>;
+				qcom,source-sel = <10>;
+				qcom,pwm-channel = <5>;
+				qcom,start-idx = <1>;
+				qcom,ramp-step-ms = <120>;
+				qcom,duty-pcts = [00 00 00 00 00
+						  00 00 00 00 00
+						  50 00 00 00 00
+						  00 00 00 00 00
+						  00];
+				qcom,use-blink;
+			};
+		};
+	};
+
+	qcom,pm8226@1 {
+		qcom,leds@d800 {
+			status = "okay";
+			qcom,wled_0 {
+				label = "wled";
+				linux,name = "wled:backlight";
+				linux,default-trigger = "bkl-trigger";
+				qcom,cs-out-en;
+				qcom,op-fdbck = <1>;
+				qcom,default-state = "on";
+				qcom,max-current = <20>;
+				qcom,ctrl-delay-us = <0>;
+				qcom,boost-curr-lim = <3>;
+				qcom,cp-sel = <0>;
+				qcom,switch-freq = <11>;
+				qcom,ovp-val = <0>;
+				qcom,num-strings = <1>;
+				qcom,id = <0>;
+			};
+		};
+
+		qcom,vibrator@c000 {
+			status = "okay";
+			qcom,vib-timeout-ms = <15000>;
+			qcom,vib-vtg-level-mV = <3100>;
+		};
+	};
+};
+
+&pm8226_gpios {
+	gpio@c000 { /* GPIO 1 */
+		/* XO_PMIC_CDC_MCLK enable for tapan codec */
+		qcom,mode = <1>;		/* Digital output */
+		qcom,output-type = <0>;	/* CMOS logic */
+		qcom,pull = <5>;		/* QPNP_PIN_PULL_NO*/
+		qcom,vin-sel = <3>;		/* QPNP_PIN_VIN3 */
+		qcom,out-strength = <3>;/* QPNP_PIN_OUT_STRENGTH_HIGH */
+		qcom,src-sel = <2>;		/* QPNP_PIN_SEL_FUNC_1 */
+		qcom,master-en = <1>;	/* Enable GPIO */
+	};
+
+	gpio@c100 { /* GPIO 2 */
+		qcom,mode = <1>;
+		qcom,output-type = <0>;
+		qcom,pull = <5>;
+		qcom,vin-sel = <3>;
+		qcom,out-strength = <3>;
+		qcom,src-sel = <2>;
+		qcom,master-en = <1>;
+	};
+
+	gpio@c200 { /* GPIO 3 */
+		qcom,mode = <0>;		/* QPNP_PIN_MODE_DIG_IN */
+		qcom,pull = <5>;		/* QPNP_PIN_PULL_NO */
+		qcom,vin-sel = <2>;		/* QPNP_PIN_VIN2 */
+		qcom,src-sel = <2>;		/* QPNP_PIN_SEL_FUNC_1 */
+		qcom,master-en = <1>;
+	};
+
+	gpio@c300 { /* GPIO 4 */
+	};
+
+	gpio@c400 { /* GPIO 5 */
+	};
+
+	gpio@c500 { /* GPIO 6 */
+	};
+
+	gpio@c600 { /* GPIO 7 */
+	};
+
+	gpio@c700 { /* GPIO 8 */
+	};
+};
+
+&pm8226_mpps {
+	mpp@a000 { /* MPP 1 */
+	};
+
+	mpp@a100 { /* MPP 2 */
+	};
+
+	mpp@a200 { /* MPP 3 */
+	};
+
+	mpp@a300 { /* MPP 4 */
+	};
+
+	mpp@a400 { /* MPP 5 */
+		/* PA_THERM0 config */
+		qcom,mode = <4>; /* AIN input */
+		qcom,invert = <1>; /* Enable MPP */
+		qcom,ain-route = <0>; /* AMUX 5 */
+		qcom,master-en = <1>;
+		qcom,src-sel = <0>; /* Function constant */
+	};
+
+	mpp@a500 { /* MPP 6 */
+	};
+
+	mpp@a600 { /* MPP 7 */
+	};
+
+	mpp@a700 { /* MPP 8 */
+		/* PA_THERM1 config */
+		qcom,mode = <4>; /* AIN input */
+		qcom,invert = <1>; /* Enable MPP */
+		qcom,ain-route = <3>; /* AMUX 8 */
+		qcom,master-en = <1>;
+		qcom,src-sel = <0>; /* Function constant */
+	};
+};
+
+&pm8226_chg {
+	qcom,charging-disabled;
+	qcom,use-default-batt-values;
+
+	qcom,bat-if@1200 {
+		status = "disabled";
+	};
+};
+
+&pm8226_vadc {
+	chan@14 {
+		label = "pa_therm0";
+		reg = <0x14>;
+		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@17 {
+		label = "pa_therm1";
+		reg = <0x17>;
+		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>;
+	};
+};
+
+&mdss_mdp {
+	qcom,mdss-pref-prim-intf = "dsi";
+};
+
+&mdss_dsi0 {
+	qcom,dsi-pref-prim-pan = <&dsi_jdi_1080_vid>;
+	qcom,platform-enable-gpio = <&msmgpio 109 0>;
+};
+
+&dsi_jdi_1080_vid {
+	qcom,cont-splash-enabled;
+};
diff --git a/arch/arm/boot/dts/msm8226-1080p-mtp.dtsi b/arch/arm/boot/dts/msm8226-1080p-mtp.dtsi
new file mode 100644
index 0000000..31624de
--- /dev/null
+++ b/arch/arm/boot/dts/msm8226-1080p-mtp.dtsi
@@ -0,0 +1,519 @@
+/* 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/ "msm8226-camera-sensor-mtp.dtsi"
+
+&soc {
+	serial@f991f000 {
+		status = "ok";
+	};
+
+	i2c@f9927000 { /* BLSP1 QUP5 */
+		synaptics@20 {
+			compatible = "synaptics,rmi4";
+			reg = <0x20>;
+			interrupt-parent = <&msmgpio>;
+			interrupts = <17 0x2008>;
+			vdd-supply = <&pm8226_l19>;
+			vcc_i2c-supply = <&pm8226_lvs1>;
+			synaptics,reset-gpio = <&msmgpio 16 0x00>;
+			synaptics,irq-gpio = <&msmgpio 17 0x2008>;
+			synaptics,display-coords = <0 0 1079 1919>;
+			synaptics,i2c-pull-up;
+			synaptics,power-down;
+			synaptics,disable-gpios;
+		};
+	};
+
+	gen-vkeys {
+		compatible = "qcom,gen-vkeys";
+		label = "synaptics_rmi4_i2c";
+		qcom,disp-maxx = <1079>;
+		qcom,disp-maxy = <1919>;
+		qcom,panel-maxx = <1079>;
+		qcom,panel-maxy = <2084>;
+		qcom,key-codes = <158 139 102 217>;
+	};
+
+	i2c@f9925000 { /* BLSP1 QUP3 */
+		nfc-nci@0e {
+			compatible = "qcom,nfc-nci";
+			reg = <0x0e>;
+			qcom,irq-gpio = <&msmgpio 21 0x00>;
+			qcom,dis-gpio = <&msmgpio 20 0x00>;
+			qcom,clk-src = "BBCLK2";
+			qcom,clk-en-gpio = <&msmgpio 0 0x00>;
+			interrupt-parent = <&msmgpio>;
+			interrupts = <21 0>;
+			qcom,clk-gpio = <&pm8226_gpios 3 0>;
+		};
+	};
+	gpio_keys {
+		compatible = "gpio-keys";
+		input-name = "gpio-keys";
+
+		camera_focus {
+			label = "camera_focus";
+			gpios = <&msmgpio 108 0x1>;
+			linux,input-type = <1>;
+			linux,code = <0x210>;
+			gpio-key,wakeup;
+			debounce-interval = <15>;
+		};
+
+		camera_snapshot {
+			label = "camera_snapshot";
+			gpios = <&msmgpio 107 0x1>;
+			linux,input-type = <1>;
+			linux,code = <0x2fe>;
+			gpio-key,wakeup;
+			debounce-interval = <15>;
+		};
+
+		vol_up {
+			label = "volume_up";
+			gpios = <&msmgpio 106 0x1>;
+			linux,input-type = <1>;
+			linux,code = <115>;
+			gpio-key,wakeup;
+			debounce-interval = <15>;
+		};
+	};
+
+	spi@f9923000 {
+		ethernet-switch@3 {
+			compatible = "micrel,ks8851";
+			reg = <3>;
+			interrupt-parent = <&msmgpio>;
+			interrupts = <115 0x8>;
+			spi-max-frequency = <4800000>;
+			rst-gpio = <&msmgpio 114 0>;
+			vdd-io-supply = <&pm8226_lvs1>;
+			vdd-phy-supply = <&pm8226_lvs1>;
+		};
+	};
+
+	sound {
+		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",
+			"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 {
+	#address-cells = <0>;
+	interrupt-parent = <&usb_otg>;
+	interrupts = <0 1 2>;
+	#interrupt-cells = <1>;
+	interrupt-map-mask = <0xffffffff>;
+	interrupt-map = <0 &intc 0 134 0
+			1 &intc 0 140 0
+			2 &spmi_bus 0x0 0x0 0x9 0x0>;
+	interrupt-names = "core_irq", "async_irq", "pmic_id_irq";
+
+	qcom,hsusb-otg-mode = <3>;
+	vbus_otg-supply = <&pm8226_chg_otg>;
+};
+
+&sdcc1 {
+	vdd-supply = <&pm8226_l17>;
+	qcom,vdd-voltage-level = <2950000 2950000>;
+	qcom,vdd-current-level = <800 500000>;
+
+	vdd-io-supply = <&pm8226_l6>;
+	qcom,vdd-io-always-on;
+	qcom,vdd-io-voltage-level = <1800000 1800000>;
+	qcom,vdd-io-current-level = <250 154000>;
+
+	qcom,pad-pull-on = <0x0 0x3 0x3>; /* no-pull, pull-up, pull-up */
+	qcom,pad-pull-off = <0x0 0x3 0x3>; /* no-pull, pull-up, pull-up */
+	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,sup-voltages = <2950 2950>;
+
+	qcom,bus-speed-mode = "HS200_1p8v", "DDR_1p8v";
+	qcom,nonremovable;
+
+	status = "disabled";
+};
+
+&sdhc_1 {
+	vdd-supply = <&pm8226_l17>;
+	qcom,vdd-voltage-level = <2950000 2950000>;
+	qcom,vdd-current-level = <800 500000>;
+
+	vdd-io-supply = <&pm8226_l6>;
+	qcom,vdd-io-always-on;
+	qcom,vdd-io-voltage-level = <1800000 1800000>;
+	qcom,vdd-io-current-level = <250 154000>;
+
+	qcom,pad-pull-on = <0x0 0x3 0x3>; /* no-pull, pull-up, pull-up */
+	qcom,pad-pull-off = <0x0 0x3 0x3>; /* no-pull, pull-up, pull-up */
+	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,bus-speed-mode = "HS200_1p8v", "DDR_1p8v";
+	qcom,nonremovable;
+
+	status = "ok";
+};
+
+&sdcc2 {
+	vdd-supply = <&pm8226_l18>;
+	qcom,vdd-voltage-level = <2950000 2950000>;
+	qcom,vdd-current-level = <9000 800000>;
+
+	vdd-io-supply = <&pm8226_l21>;
+	qcom,vdd-io-voltage-level = <1800000 2950000>;
+	qcom,vdd-io-current-level = <6 22000>;
+
+	qcom,pad-pull-on = <0x0 0x3 0x3>; /* no-pull, pull-up, pull-up */
+	qcom,pad-pull-off = <0x0 0x3 0x3>; /* no-pull, pull-up, pull-up */
+	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,sup-voltages = <2950 2950>;
+
+	qcom,xpc;
+	qcom,bus-speed-mode = "SDR12", "SDR25", "SDR50", "DDR50", "SDR104";
+	qcom,current-limit = <600>; #address-cells = <0>; interrupt-parent = <&sdcc2>;
+	interrupts = <0 1 2>;
+	#interrupt-cells = <1>;
+	interrupt-map-mask = <0xffffffff>;
+	interrupt-map = <0 &intc 0 125 0
+			1 &intc 0 220 0
+			2 &msmgpio 38 0x3>;
+	interrupt-names = "core_irq", "bam_irq", "status_irq";
+	cd-gpios = <&msmgpio 38 0x1>;
+
+	status = "disabled";
+};
+
+&sdhc_2 {
+	vdd-supply = <&pm8226_l18>;
+	qcom,vdd-voltage-level = <2950000 2950000>;
+	qcom,vdd-current-level = <9000 800000>;
+
+	vdd-io-supply = <&pm8226_l21>;
+	qcom,vdd-io-voltage-level = <1800000 2950000>;
+	qcom,vdd-io-current-level = <6 22000>;
+
+	qcom,pad-pull-on = <0x0 0x3 0x3>; /* no-pull, pull-up, pull-up */
+	qcom,pad-pull-off = <0x0 0x3 0x3>; /* no-pull, pull-up, pull-up */
+	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>;
+
+	#address-cells = <0>;
+	interrupt-parent = <&sdhc_2>;
+	interrupts = <0 1 2>;
+	#interrupt-cells = <1>;
+	interrupt-map-mask = <0xffffffff>;
+	interrupt-map = <0 &intc 0 125 0
+			1 &intc 0 221 0
+			2 &msmgpio 38 0x3>;
+	interrupt-names = "hc_irq", "pwr_irq", "status_irq";
+	cd-gpios = <&msmgpio 38 0x1>;
+
+	status = "ok";
+};
+
+&spmi_bus {
+	qcom,pm8226@0 {
+		qcom,leds@a100 {
+			status = "okay";
+			qcom,led_mpp_2 {
+				label = "mpp";
+				linux,name = "button-backlight";
+				linux,default-trigger = "none";
+				qcom,default-state = "off";
+				qcom,max-current = <40>;
+				qcom,current-setting = <5>;
+				qcom,id = <6>;
+				qcom,mode = "manual";
+				qcom,source-sel = <1>;
+				qcom,mode-ctrl = <0x60>;
+			};
+		};
+
+		qcom,leds@a300 {
+			status = "okay";
+			qcom,led_mpp_4 {
+				label = "mpp";
+				linux,name = "green";
+				linux,default-trigger = "battery-full";
+				qcom,default-state = "off";
+				qcom,max-current = <40>;
+				qcom,current-setting = <5>;
+				qcom,id = <6>;
+				qcom,mode = "pwm";
+				qcom,pwm-us = <1000>;
+				qcom,source-sel = <8>;
+				qcom,mode-ctrl = <0x60>;
+				qcom,pwm-channel = <0>;
+				qcom,start-idx = <1>;
+				qcom,ramp-step-ms = <120>;
+				qcom,duty-pcts = [00 00 00 00 00
+						  00 00 00 00 00
+						  50 00 00 00 00
+						  00 00 00 00 00
+						  00];
+				qcom,use-blink;
+			};
+		};
+
+		qcom,leds@a500 {
+			status = "okay";
+			qcom,led_mpp_6 {
+				label = "mpp";
+				linux,name = "red";
+				linux,default-trigger = "battery-charging";
+				qcom,default-state = "off";
+				qcom,max-current = <40>;
+				qcom,current-setting = <5>;
+				qcom,id = <6>;
+				qcom,mode = "pwm";
+				qcom,pwm-us = <1000>;
+				qcom,mode-ctrl = <0x60>;
+				qcom,source-sel = <10>;
+				qcom,pwm-channel = <5>;
+				qcom,start-idx = <1>;
+				qcom,ramp-step-ms = <120>;
+				qcom,duty-pcts = [00 00 00 00 00
+						  00 00 00 00 00
+						  50 00 00 00 00
+						  00 00 00 00 00
+						  00];
+				qcom,use-blink;
+			};
+		};
+	};
+
+	qcom,pm8226@1 {
+                qcom,leds@d300 {
+                        status = "okay";
+                };
+
+		qcom,leds@d800 {
+			status = "okay";
+			qcom,wled_0 {
+				label = "wled";
+				linux,name = "wled:backlight";
+				linux,default-trigger = "bkl-trigger";
+				qcom,cs-out-en;
+				qcom,op-fdbck = <1>;
+				qcom,default-state = "on";
+				qcom,max-current = <20>;
+				qcom,ctrl-delay-us = <0>;
+				qcom,boost-curr-lim = <3>;
+				qcom,cp-sel = <0>;
+				qcom,switch-freq = <11>;
+				qcom,ovp-val = <0>;
+				qcom,num-strings = <1>;
+				qcom,id = <0>;
+			};
+		};
+
+		qcom,vibrator@c000 {
+			status = "okay";
+			qcom,vib-timeout-ms = <15000>;
+			qcom,vib-vtg-level-mV = <3100>;
+		};
+	};
+};
+
+&pm8226_gpios {
+	gpio@c000 { /* GPIO 1 */
+		/* XO_PMIC_CDC_MCLK enable for tapan codec */
+		qcom,mode = <1>;		/* Digital output */
+		qcom,output-type = <0>;	/* CMOS logic */
+		qcom,pull = <5>;		/* QPNP_PIN_PULL_NO*/
+		qcom,vin-sel = <3>;		/* QPNP_PIN_VIN3 */
+		qcom,out-strength = <3>;/* QPNP_PIN_OUT_STRENGTH_HIGH */
+		qcom,src-sel = <2>;		/* QPNP_PIN_SEL_FUNC_1 */
+		qcom,master-en = <1>;	/* Enable GPIO */
+	};
+
+	gpio@c100 { /* GPIO 2 */
+		qcom,mode = <1>;
+		qcom,output-type = <0>;
+		qcom,pull = <5>;
+		qcom,vin-sel = <3>;
+		qcom,out-strength = <3>;
+		qcom,src-sel = <2>;
+		qcom,master-en = <1>;
+	};
+
+	gpio@c200 { /* GPIO 3 */
+		qcom,mode = <0>;		/* QPNP_PIN_MODE_DIG_IN */
+		qcom,pull = <5>;		/* QPNP_PIN_PULL_NO */
+		qcom,vin-sel = <2>;		/* QPNP_PIN_VIN2 */
+		qcom,src-sel = <2>;		/* QPNP_PIN_SEL_FUNC_1 */
+		qcom,master-en = <1>;
+	};
+
+	gpio@c300 { /* GPIO 4 */
+	};
+
+	gpio@c400 { /* GPIO 5 */
+	};
+
+	gpio@c500 { /* GPIO 6 */
+	};
+
+	gpio@c600 { /* GPIO 7 */
+	};
+
+	gpio@c700 { /* GPIO 8 */
+	};
+};
+
+&pm8226_mpps {
+	mpp@a000 { /* MPP 1 */
+	};
+
+	mpp@a100 { /* MPP 2 */
+	};
+
+	mpp@a200 { /* MPP 3 */
+	};
+
+	mpp@a300 { /* MPP 4 */
+	};
+
+	mpp@a400 { /* MPP 5 */
+		/* PA_THERM0 config */
+		qcom,mode = <4>; /* AIN input */
+		qcom,invert = <1>; /* Enable MPP */
+		qcom,ain-route = <0>; /* AMUX 5 */
+		qcom,master-en = <1>;
+		qcom,src-sel = <0>; /* Function constant */
+	};
+
+	mpp@a500 { /* MPP 6 */
+	};
+
+	mpp@a600 { /* MPP 7 */
+	};
+
+	mpp@a700 { /* MPP 8 */
+		/* PA_THERM1 config */
+		qcom,mode = <4>; /* AIN input */
+		qcom,invert = <1>; /* Enable MPP */
+		qcom,ain-route = <3>; /* AMUX 8 */
+		qcom,master-en = <1>;
+		qcom,src-sel = <0>; /* Function constant */
+	};
+};
+
+&pm8226_vadc {
+	chan@14 {
+		label = "pa_therm0";
+		reg = <0x14>;
+		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@17 {
+		label = "pa_therm1";
+		reg = <0x17>;
+		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>;
+	};
+};
+
+/ {
+	mtp_batterydata: qcom,battery-data {
+		qcom,rpull-up-kohm = <100>;
+		qcom,vref-batt-therm = <1800000>;
+
+		/include/ "batterydata-palladium.dtsi"
+		/include/ "batterydata-mtp-3000mah.dtsi"
+	};
+};
+
+&pm8226_bms {
+	status = "ok";
+	qcom,battery-data = <&mtp_batterydata>;
+	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 {
+	qcom,charging-disabled;
+	qcom,battery-data = <&mtp_batterydata>;
+};
+
+&slim_msm {
+	tapan_codec {
+		qcom,cdc-micbias1-ext-cap;
+	};
+};
+
+&mdss_mdp {
+	qcom,mdss-pref-prim-intf = "dsi";
+};
+
+&mdss_dsi0 {
+	qcom,dsi-pref-prim-pan = <&dsi_jdi_1080_vid>;
+	qcom,platform-enable-gpio = <&msmgpio 109 0>;
+};
+
+&dsi_jdi_1080_vid {
+	qcom,cont-splash-enabled;
+};
diff --git a/arch/arm/boot/dts/msm8226-cdp.dtsi b/arch/arm/boot/dts/msm8226-720p-cdp.dtsi
similarity index 100%
rename from arch/arm/boot/dts/msm8226-cdp.dtsi
rename to arch/arm/boot/dts/msm8226-720p-cdp.dtsi
diff --git a/arch/arm/boot/dts/msm8226-mtp.dtsi b/arch/arm/boot/dts/msm8226-720p-mtp.dtsi
similarity index 100%
rename from arch/arm/boot/dts/msm8226-mtp.dtsi
rename to arch/arm/boot/dts/msm8226-720p-mtp.dtsi
diff --git a/arch/arm/boot/dts/msm8226-mdss-panels.dtsi b/arch/arm/boot/dts/msm8226-mdss-panels.dtsi
index eeec175..0731a9a 100644
--- a/arch/arm/boot/dts/msm8226-mdss-panels.dtsi
+++ b/arch/arm/boot/dts/msm8226-mdss-panels.dtsi
@@ -16,3 +16,4 @@
 /include/ "dsi-panel-nt35596-1080p-video.dtsi"
 /include/ "dsi-panel-nt35590-720p-cmd.dtsi"
 /include/ "dsi-panel-ssd2080m-720p-video.dtsi"
+/include/ "dsi-panel-jdi-1080p-video.dtsi"
diff --git a/arch/arm/boot/dts/msm8226-mdss.dtsi b/arch/arm/boot/dts/msm8226-mdss.dtsi
index 3e2507ff..e2891d1 100644
--- a/arch/arm/boot/dts/msm8226-mdss.dtsi
+++ b/arch/arm/boot/dts/msm8226-mdss.dtsi
@@ -36,7 +36,7 @@
 		qcom,mdss-wb-off = <0x00011100 0x00013100>;
 		qcom,mdss-intf-off = <0x00000000 0x00021300>;
 		qcom,mdss-rot-block-size = <64>;
-		qcom,mdss-smp-mb-per-pipe = <2>;
+		qcom,mdss-smp-mb-per-pipe = <4>;
 		vdd-cx-supply = <&pm8226_s1_corner>;
 
 		qcom,vbif-settings = <0x004 0x00000001>,
diff --git a/arch/arm/boot/dts/msm8226-qrd-skuf.dtsi b/arch/arm/boot/dts/msm8226-qrd-skuf.dtsi
index 66f5095..76bd262 100755
--- a/arch/arm/boot/dts/msm8226-qrd-skuf.dtsi
+++ b/arch/arm/boot/dts/msm8226-qrd-skuf.dtsi
@@ -124,6 +124,7 @@
 				20 21 22 24 26 28 29 2A FF FF
 				FF FF FF FF FF FF FF FF FF FF
 				FF FF FF FF 3E 01];
+			goodix,fw_name = "gtp_fw.bin";
 		};
 	};
 };
diff --git a/arch/arm/boot/dts/msm8226-regulator.dtsi b/arch/arm/boot/dts/msm8226-regulator.dtsi
index 23a2158..9764982 100644
--- a/arch/arm/boot/dts/msm8226-regulator.dtsi
+++ b/arch/arm/boot/dts/msm8226-regulator.dtsi
@@ -336,7 +336,7 @@
 		pm8226_l16: regulator-l16 {
 			regulator-name = "8226_l16";
 			regulator-min-microvolt = <3000000>;
-			regulator-max-microvolt = <3300000>;
+			regulator-max-microvolt = <3350000>;
 			qcom,init-voltage = <3300000>;
 			status = "okay";
 		};
@@ -423,7 +423,7 @@
 		pm8226_l24: regulator-l24 {
 			regulator-name = "8226_l24";
 			regulator-min-microvolt = <1300000>;
-			regulator-max-microvolt = <1300000>;
+			regulator-max-microvolt = <1350000>;
 			qcom,init-voltage = <1300000>;
 			status = "okay";
 		};
diff --git a/arch/arm/boot/dts/msm8226-v1-cdp.dts b/arch/arm/boot/dts/msm8226-v1-cdp.dts
index e426a97..4b8cafd 100644
--- a/arch/arm/boot/dts/msm8226-v1-cdp.dts
+++ b/arch/arm/boot/dts/msm8226-v1-cdp.dts
@@ -12,7 +12,7 @@
 
 /dts-v1/;
 /include/ "msm8226-v1.dtsi"
-/include/ "msm8226-cdp.dtsi"
+/include/ "msm8226-720p-cdp.dtsi"
 
 / {
 	model = "Qualcomm MSM 8226 CDP";
diff --git a/arch/arm/boot/dts/msm8226-v1-mtp.dts b/arch/arm/boot/dts/msm8226-v1-mtp.dts
index 08d7cec..a1e78b7 100644
--- a/arch/arm/boot/dts/msm8226-v1-mtp.dts
+++ b/arch/arm/boot/dts/msm8226-v1-mtp.dts
@@ -12,7 +12,7 @@
 
 /dts-v1/;
 /include/ "msm8226-v1.dtsi"
-/include/ "msm8226-mtp.dtsi"
+/include/ "msm8226-720p-mtp.dtsi"
 
 / {
 	model = "Qualcomm MSM 8226 MTP";
diff --git a/arch/arm/boot/dts/msm8226-v2-cdp.dts b/arch/arm/boot/dts/msm8226-v2-1080p-cdp.dts
similarity index 92%
copy from arch/arm/boot/dts/msm8226-v2-cdp.dts
copy to arch/arm/boot/dts/msm8226-v2-1080p-cdp.dts
index 3302d26..77cc08c 100644
--- a/arch/arm/boot/dts/msm8226-v2-cdp.dts
+++ b/arch/arm/boot/dts/msm8226-v2-1080p-cdp.dts
@@ -12,13 +12,13 @@
 
 /dts-v1/;
 /include/ "msm8226-v2.dtsi"
-/include/ "msm8226-cdp.dtsi"
+/include/ "msm8226-1080p-cdp.dtsi"
 /include/ "msm8226-camera-sensor-cdp.dtsi"
 
 / {
 	model = "Qualcomm MSM 8226v2 CDP";
 	compatible = "qcom,msm8226-cdp", "qcom,msm8226", "qcom,cdp";
-	qcom,board-id = <1 0>;
+	qcom,board-id = <1 2>;
 };
 
 &hsic_host {
diff --git a/arch/arm/boot/dts/msm8226-v2-mtp.dts b/arch/arm/boot/dts/msm8226-v2-1080p-mtp.dts
similarity index 92%
copy from arch/arm/boot/dts/msm8226-v2-mtp.dts
copy to arch/arm/boot/dts/msm8226-v2-1080p-mtp.dts
index 6034107..b12a77d 100644
--- a/arch/arm/boot/dts/msm8226-v2-mtp.dts
+++ b/arch/arm/boot/dts/msm8226-v2-1080p-mtp.dts
@@ -12,11 +12,11 @@
 
 /dts-v1/;
 /include/ "msm8226-v2.dtsi"
-/include/ "msm8226-mtp.dtsi"
+/include/ "msm8226-1080p-mtp.dtsi"
 /include/ "msm8226-camera-sensor-mtp.dtsi"
 
 / {
 	model = "Qualcomm MSM 8226v2 MTP";
 	compatible = "qcom,msm8226-mtp", "qcom,msm8226", "qcom,mtp";
-	qcom,board-id = <8 0>;
+	qcom,board-id = <8 2>;
 };
diff --git a/arch/arm/boot/dts/msm8226-v2-cdp.dts b/arch/arm/boot/dts/msm8226-v2-720p-cdp.dts
similarity index 95%
rename from arch/arm/boot/dts/msm8226-v2-cdp.dts
rename to arch/arm/boot/dts/msm8226-v2-720p-cdp.dts
index 3302d26..966ae2b 100644
--- a/arch/arm/boot/dts/msm8226-v2-cdp.dts
+++ b/arch/arm/boot/dts/msm8226-v2-720p-cdp.dts
@@ -12,7 +12,7 @@
 
 /dts-v1/;
 /include/ "msm8226-v2.dtsi"
-/include/ "msm8226-cdp.dtsi"
+/include/ "msm8226-720p-cdp.dtsi"
 /include/ "msm8226-camera-sensor-cdp.dtsi"
 
 / {
diff --git a/arch/arm/boot/dts/msm8226-v2-mtp.dts b/arch/arm/boot/dts/msm8226-v2-720p-mtp.dts
similarity index 95%
rename from arch/arm/boot/dts/msm8226-v2-mtp.dts
rename to arch/arm/boot/dts/msm8226-v2-720p-mtp.dts
index 6034107..0768b75 100644
--- a/arch/arm/boot/dts/msm8226-v2-mtp.dts
+++ b/arch/arm/boot/dts/msm8226-v2-720p-mtp.dts
@@ -12,7 +12,7 @@
 
 /dts-v1/;
 /include/ "msm8226-v2.dtsi"
-/include/ "msm8226-mtp.dtsi"
+/include/ "msm8226-720p-mtp.dtsi"
 /include/ "msm8226-camera-sensor-mtp.dtsi"
 
 / {
diff --git a/arch/arm/boot/dts/msm8226.dtsi b/arch/arm/boot/dts/msm8226.dtsi
index 51a0795..3ef0d6d 100644
--- a/arch/arm/boot/dts/msm8226.dtsi
+++ b/arch/arm/boot/dts/msm8226.dtsi
@@ -39,7 +39,7 @@
 
 		qsecom_mem: qsecom_region {
 			linux,contiguous-region;
-			reg = <0 0x780000>;
+			reg = <0 0xd00000>;
 			label = "qsecom_mem";
 		};
 	};
@@ -283,6 +283,7 @@
 		qcom,hsusb-otg-otg-control = <2>;
 		qcom,hsusb-otg-disable-reset;
 		qcom,dp-manual-pullup;
+		qcom,ahb-async-bridge-bypass;
 
 		qcom,msm-bus,name = "usb";
 		qcom,msm-bus,num-cases = <3>;
@@ -297,6 +298,7 @@
 		compatible = "qcom,android-usb";
 		reg = <0xfe8050c8 0xc8>;
 		qcom,android-usb-swfi-latency = <1>;
+		qcom,streaming-func = "rndis";
 	};
 
 	hsic_host: hsic@f9a00000 {
diff --git a/arch/arm/boot/dts/msm8610-cdp.dtsi b/arch/arm/boot/dts/msm8610-cdp.dtsi
index 9920f77..d63c6e5 100644
--- a/arch/arm/boot/dts/msm8610-cdp.dtsi
+++ b/arch/arm/boot/dts/msm8610-cdp.dtsi
@@ -20,7 +20,7 @@
 		compatible = "atmel,mxt-ts";
 		reg = <0x4a>;
 		interrupt-parent = <&msmgpio>;
-		interrupts = <1 0x2>;
+		interrupts = <1 0x2002>;
 		vdd_ana-supply = <&pm8110_l19>;
 		vcc_i2c-supply = <&pm8110_l14>;
 		atmel,reset-gpio = <&msmgpio 0 0x00>;
@@ -76,6 +76,21 @@
 				];
 			};
 		};
+
+		synaptics@20 {
+			compatible = "synaptics,rmi4";
+			reg = <0x20>;
+			interrupt-parent = <&msmgpio>;
+			interrupts = <1 0x2002>;
+			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 {
diff --git a/arch/arm/boot/dts/msm8610-mtp.dtsi b/arch/arm/boot/dts/msm8610-mtp.dtsi
index 0244b89..6ce0109 100644
--- a/arch/arm/boot/dts/msm8610-mtp.dtsi
+++ b/arch/arm/boot/dts/msm8610-mtp.dtsi
@@ -20,7 +20,7 @@
 		compatible = "atmel,mxt-ts";
 		reg = <0x4a>;
 		interrupt-parent = <&msmgpio>;
-		interrupts = <1 0x2>;
+		interrupts = <1 0x2002>;
 		vdd_ana-supply = <&pm8110_l19>;
 		vcc_i2c-supply = <&pm8110_l14>;
 		atmel,reset-gpio = <&msmgpio 0 0x00>;
@@ -76,6 +76,21 @@
 				];
 			};
 		};
+
+		synaptics@20 {
+			compatible = "synaptics,rmi4";
+			reg = <0x20>;
+			interrupt-parent = <&msmgpio>;
+			interrupts = <1 0x2002>;
+			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 {
diff --git a/arch/arm/boot/dts/msm8610-qrd-skuab.dtsi b/arch/arm/boot/dts/msm8610-qrd-skuab.dtsi
index 08e9be5..a22958a 100644
--- a/arch/arm/boot/dts/msm8610-qrd-skuab.dtsi
+++ b/arch/arm/boot/dts/msm8610-qrd-skuab.dtsi
@@ -67,6 +67,7 @@
 			goodix,display-coords = <0 0 540 960>;
 			goodix,button-map= <139 102 158>;
 			goodix,product-id = "915";
+			goodix,enable-power-off;
 			goodix,cfg-data0 = [
 				46 1C 02 C0 03 0A 05 11 01 08
 				14 3B 46 32 03 05 00 00 00 00
diff --git a/arch/arm/boot/dts/msm8610-qrd.dtsi b/arch/arm/boot/dts/msm8610-qrd.dtsi
index d578ef6..85bd746 100644
--- a/arch/arm/boot/dts/msm8610-qrd.dtsi
+++ b/arch/arm/boot/dts/msm8610-qrd.dtsi
@@ -210,8 +210,9 @@
 			status = "okay";
 			qcom,led_mpp_2 {
 				label = "mpp";
-				linux,name = "wled-homerow";
-				linux-default-trigger = "hr-trigger";
+				linux,name = "button-backlight";
+				linux,default-trigger = "hr-trigger";
+				qcom,current-setting = <20>;
 				qcom,default-state = "off";
 				qcom,max-current = <40>;
 				qcom,id = <6>;
@@ -287,7 +288,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>;
@@ -308,6 +309,7 @@
 
 	qcom,chgr@1000 {
 		status = "ok";
+		qcom,tchg-mins = <250>;
 	};
 
 	qcom,buck@1100 {
diff --git a/arch/arm/boot/dts/msm8610-regulator.dtsi b/arch/arm/boot/dts/msm8610-regulator.dtsi
index f97d991..7eb6a22 100644
--- a/arch/arm/boot/dts/msm8610-regulator.dtsi
+++ b/arch/arm/boot/dts/msm8610-regulator.dtsi
@@ -215,7 +215,7 @@
 		status = "okay";
 		pm8110_l5: regulator-l5 {
 			regulator-min-microvolt = <1300000>;
-			regulator-max-microvolt = <1300000>;
+			regulator-max-microvolt = <1350000>;
 			qcom,init-voltage = <1300000>;
 			status = "okay";
 		};
@@ -325,7 +325,7 @@
 		status = "okay";
 		pm8110_l16: regulator-l16 {
 			regulator-min-microvolt = <3000000>;
-			regulator-max-microvolt = <3000000>;
+			regulator-max-microvolt = <3350000>;
 			qcom,init-voltage = <3000000>;
 			status = "okay";
 		};
diff --git a/arch/arm/boot/dts/msm8610-v1-pm.dtsi b/arch/arm/boot/dts/msm8610-v1-pm.dtsi
index 6296692..62aa0f4 100644
--- a/arch/arm/boot/dts/msm8610-v1-pm.dtsi
+++ b/arch/arm/boot/dts/msm8610-v1-pm.dtsi
@@ -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 03 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 {
@@ -99,6 +99,9 @@
 		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,saw2-spm-cmd-pc-no-rpm = [00 32 b0 10 e0 d0 6b c0 42 f0
+				11 03 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;
 	};
 
@@ -125,28 +128,29 @@
 			qcom,latency-us = <500>;
 			qcom,ss-power = <410>;
 			qcom,energy-overhead = <603400>;
-			qcom,time-overhead = <1200>;
+			qcom,time-overhead = <1410>;
 		};
 
 		qcom,lpm-level@2 {
 			reg = <0x2>;
 			qcom,mode = "pc";
-			qcom,l2 = "l2_cache_retention";
-			qcom,latency-us = <520>;
-			qcom,ss-power = <460>;
-			qcom,energy-overhead = <704900>;
-			qcom,time-overhead = <1300>;
+			qcom,l2 = "l2_cache_pc_no_rpm";
+			qcom,latency-us = <1000>;
+			qcom,ss-power = <315>;
+			qcom,energy-overhead = <1027150>;
+			qcom,time-overhead = <2400>;
 		};
 
 		qcom,lpm-level@3 {
 			reg = <0x3>;
 			qcom,mode = "pc";
 			qcom,l2 = "l2_cache_pc";
-			qcom,latency-us = <11700>;
+			qcom,latency-us = <12700>;
 			qcom,ss-power = <315>;
 			qcom,energy-overhead = <1027150>;
 			qcom,time-overhead = <2400>;
 		};
+
 	};
 
 	qcom,pm-boot {
diff --git a/arch/arm/boot/dts/msm8610-v1-qrd-skuab-dvt2.dts b/arch/arm/boot/dts/msm8610-v1-qrd-skuab-dvt2.dts
index 4a08f3f..de48f1f 100644
--- a/arch/arm/boot/dts/msm8610-v1-qrd-skuab-dvt2.dts
+++ b/arch/arm/boot/dts/msm8610-v1-qrd-skuab-dvt2.dts
@@ -33,3 +33,10 @@
 &dsi_hx8389b_qhd_vid {
 	qcom,cont-splash-enabled;
 };
+&soc {
+	i2c@f9925000 {
+		fsl@1c {
+			fsl,sensors-position = <7>;
+		};
+	};
+};
\ No newline at end of file
diff --git a/arch/arm/boot/dts/msm8610-v2-pm.dtsi b/arch/arm/boot/dts/msm8610-v2-pm.dtsi
index 6c7f2f6..e401f7a 100644
--- a/arch/arm/boot/dts/msm8610-v2-pm.dtsi
+++ b/arch/arm/boot/dts/msm8610-v2-pm.dtsi
@@ -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 03 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 {
@@ -101,6 +101,9 @@
 		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,saw2-spm-cmd-pc-no-rpm = [00 32 b0 10 e0 d0 6b c0 42 f0
+				11 03 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;
 	};
 
@@ -134,17 +137,27 @@
 			reg = <0x2>;
 			qcom,mode = "pc";
 			qcom,l2 = "l2_cache_gdhs";
-			qcom,latency-us = <10700>;
-			qcom,ss-power = <325>;
-			qcom,energy-overhead = <441250>;
-			qcom,time-overhead = <1020>;
+			qcom,latency-us = <11700>;
+			qcom,ss-power = <372>;
+			qcom,energy-overhead = <738750>;
+			qcom,time-overhead = <1410>;
 		};
 
 		qcom,lpm-level@3 {
 			reg = <0x3>;
 			qcom,mode = "pc";
+			qcom,l2 = "l2_cache_pc_no_rpm";
+			qcom,latency-us = <1000>;
+			qcom,ss-power = <315>;
+			qcom,energy-overhead = <1027150>;
+			qcom,time-overhead = <2400>;
+		};
+
+		qcom,lpm-level@4 {
+			reg = <0x4>;
+			qcom,mode = "pc";
 			qcom,l2 = "l2_cache_pc";
-			qcom,latency-us = <11700>;
+			qcom,latency-us = <12700>;
 			qcom,ss-power = <315>;
 			qcom,energy-overhead = <1027150>;
 			qcom,time-overhead = <2400>;
diff --git a/arch/arm/boot/dts/msm8610-v2-qrd-skuab-dvt2.dts b/arch/arm/boot/dts/msm8610-v2-qrd-skuab-dvt2.dts
index 4735554..95a5da5 100644
--- a/arch/arm/boot/dts/msm8610-v2-qrd-skuab-dvt2.dts
+++ b/arch/arm/boot/dts/msm8610-v2-qrd-skuab-dvt2.dts
@@ -56,3 +56,10 @@
 &dsi_hx8389b_qhd_vid {
 	qcom,cont-splash-enabled;
 };
+&soc {
+	i2c@f9925000 {
+		fsl@1c {
+			fsl,sensors-position = <7>;
+		};
+	};
+};
\ No newline at end of file
diff --git a/arch/arm/boot/dts/msm8610.dtsi b/arch/arm/boot/dts/msm8610.dtsi
index 9406b75..42b7887 100644
--- a/arch/arm/boot/dts/msm8610.dtsi
+++ b/arch/arm/boot/dts/msm8610.dtsi
@@ -239,6 +239,7 @@
 		qcom,hsusb-otg-otg-control = <2>;
 		qcom,hsusb-otg-disable-reset;
 		qcom,dp-manual-pullup;
+		qcom,ahb-async-bridge-bypass;
 
 		qcom,msm-bus,name = "usb2";
 		qcom,msm-bus,num-cases = <2>;
@@ -253,6 +254,7 @@
 		compatible = "qcom,android-usb";
 		reg = <0xfe8050c8 0xc8>;
 		qcom,android-usb-swfi-latency = <1>;
+		qcom,streaming-func = "rndis";
 	};
 
 	sdcc1: qcom,sdcc@f9824000 {
@@ -422,7 +424,6 @@
 		compatible = "qcom,rpm-smd";
 		rpm-channel-name = "rpm_requests";
 		rpm-channel-type = <15>; /* SMD_APPS_RPM */
-		rpm-standalone;
 	};
 
 	qcom,bcl {
diff --git a/arch/arm/boot/dts/msm8926-cdp.dts b/arch/arm/boot/dts/msm8926-1080p-cdp.dts
similarity index 93%
copy from arch/arm/boot/dts/msm8926-cdp.dts
copy to arch/arm/boot/dts/msm8926-1080p-cdp.dts
index d6e70e6..33e484a 100644
--- a/arch/arm/boot/dts/msm8926-cdp.dts
+++ b/arch/arm/boot/dts/msm8926-1080p-cdp.dts
@@ -13,13 +13,13 @@
 
 /dts-v1/;
 /include/ "msm8926.dtsi"
-/include/ "msm8226-cdp.dtsi"
+/include/ "msm8226-1080p-cdp.dtsi"
 /include/ "msm8226-camera-sensor-cdp.dtsi"
 
 / {
 	model = "Qualcomm MSM 8926 CDP";
 	compatible = "qcom,msm8926-cdp", "qcom,msm8926", "qcom,cdp";
-	qcom,board-id = <1 0>;
+	qcom,board-id = <1 2>;
 };
 
 &pm8226_chg {
diff --git a/arch/arm/boot/dts/msm8926-mtp.dts b/arch/arm/boot/dts/msm8926-1080p-mtp.dts
similarity index 92%
copy from arch/arm/boot/dts/msm8926-mtp.dts
copy to arch/arm/boot/dts/msm8926-1080p-mtp.dts
index 624781b..c1217a2 100644
--- a/arch/arm/boot/dts/msm8926-mtp.dts
+++ b/arch/arm/boot/dts/msm8926-1080p-mtp.dts
@@ -13,11 +13,11 @@
 
 /dts-v1/;
 /include/ "msm8926.dtsi"
-/include/ "msm8226-mtp.dtsi"
+/include/ "msm8226-1080p-mtp.dtsi"
 /include/ "msm8226-camera-sensor-mtp.dtsi"
 
 / {
 	model = "Qualcomm MSM 8926 MTP";
 	compatible = "qcom,msm8926-mtp", "qcom,msm8926", "qcom,mtp";
-	qcom,board-id = <8 0>;
+	qcom,board-id = <8 2>;
 };
diff --git a/arch/arm/boot/dts/msm8926-cdp.dts b/arch/arm/boot/dts/msm8926-720p-cdp.dts
similarity index 96%
rename from arch/arm/boot/dts/msm8926-cdp.dts
rename to arch/arm/boot/dts/msm8926-720p-cdp.dts
index d6e70e6..80bb5e6 100644
--- a/arch/arm/boot/dts/msm8926-cdp.dts
+++ b/arch/arm/boot/dts/msm8926-720p-cdp.dts
@@ -13,7 +13,7 @@
 
 /dts-v1/;
 /include/ "msm8926.dtsi"
-/include/ "msm8226-cdp.dtsi"
+/include/ "msm8226-720p-cdp.dtsi"
 /include/ "msm8226-camera-sensor-cdp.dtsi"
 
 / {
diff --git a/arch/arm/boot/dts/msm8926-mtp.dts b/arch/arm/boot/dts/msm8926-720p-mtp.dts
similarity index 95%
rename from arch/arm/boot/dts/msm8926-mtp.dts
rename to arch/arm/boot/dts/msm8926-720p-mtp.dts
index 624781b..32301fd 100644
--- a/arch/arm/boot/dts/msm8926-mtp.dts
+++ b/arch/arm/boot/dts/msm8926-720p-mtp.dts
@@ -13,7 +13,7 @@
 
 /dts-v1/;
 /include/ "msm8926.dtsi"
-/include/ "msm8226-mtp.dtsi"
+/include/ "msm8226-720p-mtp.dtsi"
 /include/ "msm8226-camera-sensor-mtp.dtsi"
 
 / {
diff --git a/arch/arm/boot/dts/msm8926-qrd-skug.dts b/arch/arm/boot/dts/msm8926-qrd-skug.dts
index 6d907ef..15a2d58 100644
--- a/arch/arm/boot/dts/msm8926-qrd-skug.dts
+++ b/arch/arm/boot/dts/msm8926-qrd-skug.dts
@@ -61,8 +61,8 @@
 			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-upgrade-id1 = <0x11>;
+			focaltech,fw-upgrade-id2 = <0x11>;
 			focaltech,fw-delay-readid-ms = <10>;
 			focaltech,fw-delay-era-flsh-ms = <2000>;
 			focaltech,fw-auto-cal;
diff --git a/arch/arm/boot/dts/msm8974-regulator.dtsi b/arch/arm/boot/dts/msm8974-regulator.dtsi
index 344c26f..9b9202e 100644
--- a/arch/arm/boot/dts/msm8974-regulator.dtsi
+++ b/arch/arm/boot/dts/msm8974-regulator.dtsi
@@ -289,7 +289,7 @@
 		status = "okay";
 		pm8941_l11: regulator-l11 {
 			regulator-min-microvolt = <1300000>;
-			regulator-max-microvolt = <1300000>;
+			regulator-max-microvolt = <1350000>;
 			qcom,init-voltage = <1300000>;
 			status = "okay";
 		};
@@ -376,7 +376,7 @@
 		status = "okay";
 		pm8941_l19: regulator-l19 {
 			regulator-min-microvolt = <2900000>;
-			regulator-max-microvolt = <3300000>;
+			regulator-max-microvolt = <3350000>;
 			qcom,init-voltage = <2900000>;
 			status = "okay";
 		};
diff --git a/arch/arm/boot/dts/msm8974-v1-pm.dtsi b/arch/arm/boot/dts/msm8974-v1-pm.dtsi
index 0115d89..179edac 100644
--- a/arch/arm/boot/dts/msm8974-v1-pm.dtsi
+++ b/arch/arm/boot/dts/msm8974-v1-pm.dtsi
@@ -208,10 +208,26 @@
 			<50 172>, /* usb1_hs_async_wakeup_irq */
 			<53 104>, /* mdss_irq */
 			<62 222>, /* ee0_krait_hlos_spmi_periph_irq */
+			<0xff 34>,  /* APCC_qgicL2ErrorIrptReq */
+			<0xff 35>,  /* WDT_barkInt */
+			<0xff 40>,  /* qtimer_phy_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 74>,  /* osmmu_CIrpt[1] */
+			<0xff 75>,  /* osmmu_CIrpt[0] */
+			<0xff 77>,  /* osmmu_CIrpt[0] */
+			<0xff 78>,  /* osmmu_CIrpt[0] */
+			<0xff 79>,  /* osmmu_CIrpt[0] */
+			<0xff 94>,  /* osmmu_CIrpt[0] */
+			<0xff 99>,  /* msm_iommu_pmon_nonsecure_irq */
+			<0xff 102>,  /* osmmu_CIrpt[1] */
+			<0xff 109>,  /* ocmem_dm_nonsec_irq */
+			<0xff 126>,  /* bam_irq[0] */
+			<0xff 155>,  /* sdcc_irq[0] */
+			<0xff 163>,  /* usb30_ee1_irq */
+			<0xff 170>,  /* sdcc_pwr_cmd_irq */
 			<0xff 173>, /* o_wcss_apss_smd_hi */
 			<0xff 174>, /* o_wcss_apss_smd_med */
 			<0xff 175>, /* o_wcss_apss_smd_low */
@@ -230,6 +246,7 @@
 			<0xff 195>, /* lpass_irq_out_apcs(7) */
 			<0xff 196>, /* lpass_irq_out_apcs(8) */
 			<0xff 197>, /* lpass_irq_out_apcs(9) */
+			<0xff 198>, /* coresight-tmc-etr interrupt */
 			<0xff 200>, /* rpm_ipc(4) */
 			<0xff 201>, /* rpm_ipc(5) */
 			<0xff 202>, /* rpm_ipc(6) */
@@ -238,7 +255,10 @@
 			<0xff 205>, /* rpm_ipc(25) */
 			<0xff 206>, /* rpm_ipc(26) */
 			<0xff 207>, /* rpm_ipc(27) */
-			<0xff 240>; /* summary_irq_kpss */
+			<0xff 240>, /* summary_irq_kpss */
+			<0xff 268>, /* bam_irq[1] */
+			<0xff 270>, /* bam_irq[0] */
+			<0xff 271>; /* bam_irq[0] */
 
 		qcom,gpio-parent = <&msmgpio>;
 		qcom,gpio-map = <3  102>,
@@ -290,6 +310,7 @@
 		reg = <0xfe805664 0x40>;
 		qcom,pc-mode = "tz_l2_int";
 		qcom,use-sync-timer;
+		qcom,cpus-as-clocks;
 	};
 
 	qcom,cpu-sleep-status@f9088008 {
diff --git a/arch/arm/boot/dts/msm8974-v2-pm.dtsi b/arch/arm/boot/dts/msm8974-v2-pm.dtsi
index 8836975..eba053f 100644
--- a/arch/arm/boot/dts/msm8974-v2-pm.dtsi
+++ b/arch/arm/boot/dts/msm8974-v2-pm.dtsi
@@ -215,6 +215,9 @@
 			<50 172>, /* usb1_hs_async_wakeup_irq */
 			<53 104>, /* mdss_irq */
 			<62 222>, /* ee0_krait_hlos_spmi_periph_irq */
+			<0xff 34>,  /* APCC_qgicL2ErrorIrptReq */
+			<0xff 35>,  /* WDT_barkInt */
+			<0xff 40>,  /* qtimer_phy_irq */
 			<0xff 56>,  /* modem_watchdog */
 			<0xff 57>,  /* mss_to_apps_irq(0) */
 			<0xff 58>,  /* mss_to_apps_irq(1) */
@@ -222,8 +225,21 @@
 			<0xff 60>,  /* mss_to_apps_irq(3) */
 			<0xff 61>,  /* mss_a2_bam_irq */
 			<0xff 70>,  /* iommu_pmon_nonsecure_irq */
+			<0xff 74>,  /* osmmu_CIrpt[1] */
+			<0xff 75>,  /* osmmu_CIrpt[0] */
+			<0xff 77>,  /* osmmu_CIrpt[0] */
+			<0xff 78>,  /* osmmu_CIrpt[0] */
+			<0xff 79>,  /* osmmu_CIrpt[0] */
+			<0xff 94>,  /* osmmu_CIrpt[0] */
 			<0xff 97>,  /* iommu_nonsecure_irq */
+			<0xff 99>,  /* msm_iommu_pmon_nonsecure_irq */
+			<0xff 102>,  /* osmmu_CIrpt[1] */
 			<0xff 105>, /* iommu_pmon_nonsecure_irq */
+			<0xff 109>,  /* ocmem_dm_nonsec_irq */
+			<0xff 126>,  /* bam_irq[0] */
+			<0xff 155>,  /* sdcc_irq[0] */
+			<0xff 163>,  /* usb30_ee1_irq */
+			<0xff 170>,  /* sdcc_pwr_cmd_irq */
 			<0xff 173>, /* o_wcss_apss_smd_hi */
 			<0xff 174>, /* o_wcss_apss_smd_med */
 			<0xff 175>, /* o_wcss_apss_smd_low */
@@ -231,7 +247,6 @@
 			<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) */
@@ -243,6 +258,7 @@
 			<0xff 195>, /* lpass_irq_out_apcs(7) */
 			<0xff 196>, /* lpass_irq_out_apcs(8) */
 			<0xff 197>, /* lpass_irq_out_apcs(9) */
+			<0xff 198>, /* coresight-tmc-etr interrupt */
 			<0xff 200>, /* rpm_ipc(4) */
 			<0xff 201>, /* rpm_ipc(5) */
 			<0xff 202>, /* rpm_ipc(6) */
@@ -252,7 +268,10 @@
 			<0xff 206>, /* rpm_ipc(26) */
 			<0xff 207>, /* rpm_ipc(27) */
 			<0xff 211>, /* usb_dwc3_otg */
-			<0xff 240>; /* summary_irq_kpss */
+			<0xff 240>, /* summary_irq_kpss */
+			<0xff 268>, /* bam_irq[1] */
+			<0xff 270>, /* bam_irq[0] */
+			<0xff 271>; /* bam_irq[0] */
 
 		qcom,gpio-parent = <&msmgpio>;
 		qcom,gpio-map = <3  102>,
@@ -304,6 +323,7 @@
 		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";
diff --git a/arch/arm/boot/dts/msm8974.dtsi b/arch/arm/boot/dts/msm8974.dtsi
index 39fb108..de49851 100644
--- a/arch/arm/boot/dts/msm8974.dtsi
+++ b/arch/arm/boot/dts/msm8974.dtsi
@@ -741,6 +741,14 @@
 	sound {
 		compatible = "qcom,msm8974-audio-taiko";
 		qcom,model = "msm8974-taiko-snd-card";
+		reg = <0xfe02b000 0x4>,
+		      <0xfe02c000 0x4>,
+		      <0xfe02d000 0x4>,
+		      <0xfe02e000 0x4>;
+		reg-names = "lpaif_pri_mode_muxsel",
+			    "lpaif_sec_mode_muxsel",
+			    "lpaif_tert_mode_muxsel",
+			    "lpaif_quat_mode_muxsel";
 
 		qcom,audio-routing =
 			"RX_BIAS", "MCLK",
@@ -865,25 +873,648 @@
 		qcom,master-id = <86>;
 	};
 
-	qcom,acpuclk@f9000000 {
-		compatible = "qcom,acpuclk-8974";
-		krait0-supply = <&krait0_vreg>;
-		krait1-supply = <&krait1_vreg>;
-		krait2-supply = <&krait2_vreg>;
-		krait3-supply = <&krait3_vreg>;
-		krait0_mem-supply = <&pm8841_s1_ao>;
-		krait1_mem-supply = <&pm8841_s1_ao>;
-		krait2_mem-supply = <&pm8841_s1_ao>;
-		krait3_mem-supply = <&pm8841_s1_ao>;
-		krait0_dig-supply = <&pm8841_s2_corner_ao>;
-		krait1_dig-supply = <&pm8841_s2_corner_ao>;
-		krait2_dig-supply = <&pm8841_s2_corner_ao>;
-		krait3_dig-supply = <&pm8841_s2_corner_ao>;
-		krait0_hfpll-supply = <&pm8941_l12_ao>;
-		krait1_hfpll-supply = <&pm8941_l12_ao>;
-		krait2_hfpll-supply = <&pm8941_l12_ao>;
-		krait3_hfpll-supply = <&pm8941_l12_ao>;
-		l2_hfpll-supply = <&pm8941_l12_ao>;
+	qcom,clock-krait@f9016000 {
+		compatible = "qcom,clock-krait-8974";
+		reg = <0xf9016000 0x20>,
+			<0xf908a000 0x20>,
+			<0xf909a000 0x20>,
+			<0xf90aa000 0x20>,
+			<0xf90ba000 0x20>,
+			<0xfc4b80b0 0x08>;
+		reg-names = "hfpll_l2_clk", "hfpll0_clk",
+				"hfpll1_clk", "hfpll2_clk",
+				"hfpll3_clk", "efuse";
+		cpu0-supply = <&krait0_vreg>;
+		cpu1-supply = <&krait1_vreg>;
+		cpu2-supply = <&krait2_vreg>;
+		cpu3-supply = <&krait3_vreg>;
+		l2-dig-supply = <&pm8841_s2_corner_ao>;
+		hfpll-dig-supply = <&pm8841_s2_corner_ao>;
+		hfpll-analog-supply = <&pm8941_l12_ao>;
+		qcom,hfpll-config-val = <0x04D0405D>;
+                qcom,hfpll-user-vco-mask = <0x00100000>;
+
+		qcom,l2-fmax =
+			<          0 0			 >,
+			<  576000000 4 /* SVS_SOC */	 >,
+			< 1036800000 5 /* NORMAL */	 >,
+			< 1728000000 7 /* SUPER_TURBO */ >;
+
+		qcom,speed0-pvs0-bin-v0 =
+			<          0       0   0 >,
+			<  300000000  815000  73 >,
+			<  345600000  825000  85 >,
+			<  422400000  835000 104 >,
+			<  499200000  845000 124 >,
+			<  576000000  855000 144 >,
+			<  652800000  865000 165 >,
+			<  729600000  875000 186 >,
+			<  806400000  890000 208 >,
+			<  883200000  900000 229 >,
+			<  960000000  915000 252 >,
+			< 1036800000  925000 275 >,
+			< 1113600000  940000 298 >,
+			< 1190400000  950000 321 >,
+			< 1267200000  965000 346 >,
+			< 1344000000  980000 371 >,
+			< 1420800000  995000 397 >,
+			< 1497600000 1010000 423 >,
+			< 1574400000 1025000 450 >,
+			< 1651200000 1040000 477 >,
+			< 1728000000 1055000 506 >,
+			< 1804800000 1070000 536 >,
+			< 1881600000 1085000 567 >,
+			< 1958400000 1100000 598 >;
+
+		qcom,speed0-pvs1-bin-v0 =
+			<          0       0   0 >,
+			<  300000000  800000  73 >,
+			<  345600000  810000  85 >,
+			<  422400000  820000 104 >,
+			<  499200000  830000 124 >,
+			<  576000000  840000 144 >,
+			<  652800000  850000 165 >,
+			<  729600000  860000 186 >,
+			<  806400000  875000 208 >,
+			<  883200000  885000 229 >,
+			<  960000000  895000 252 >,
+			< 1036800000  910000 275 >,
+			< 1113600000  920000 298 >,
+			< 1190400000  930000 321 >,
+			< 1267200000  945000 346 >,
+			< 1344000000  960000 371 >,
+			< 1420800000  975000 397 >,
+			< 1497600000  990000 423 >,
+			< 1574400000 1005000 450 >,
+			< 1651200000 1020000 477 >,
+			< 1728000000 1030000 506 >,
+			< 1804800000 1045000 536 >,
+			< 1881600000 1060000 567 >,
+			< 1958400000 1075000 598 >;
+
+		qcom,speed0-pvs2-bin-v0 =
+			<          0       0   0 >,
+			<  300000000  785000  73 >,
+			<  345600000  795000  85 >,
+			<  422400000  805000 104 >,
+			<  499200000  815000 124 >,
+			<  576000000  825000 144 >,
+			<  652800000  835000 165 >,
+			<  729600000  845000 186 >,
+			<  806400000  855000 208 >,
+			<  883200000  865000 229 >,
+			<  960000000  875000 252 >,
+			< 1036800000  890000 275 >,
+			< 1113600000  900000 298 >,
+			< 1190400000  910000 321 >,
+			< 1267200000  925000 346 >,
+			< 1344000000  940000 371 >,
+			< 1420800000  955000 397 >,
+			< 1497600000  970000 423 >,
+			< 1574400000  980000 450 >,
+			< 1651200000  995000 477 >,
+			< 1728000000 1005000 506 >,
+			< 1804800000 1020000 536 >,
+			< 1881600000 1035000 567 >,
+			< 1958400000 1050000 598 >;
+
+		qcom,speed0-pvs3-bin-v0 =
+			<          0       0   0 >,
+			<  300000000  775000  73 >,
+			<  345600000  780000  85 >,
+			<  422400000  790000 104 >,
+			<  499200000  800000 124 >,
+			<  576000000  810000 144 >,
+			<  652800000  820000 165 >,
+			<  729600000  830000 186 >,
+			<  806400000  840000 208 >,
+			<  883200000  850000 229 >,
+			<  960000000  860000 252 >,
+			< 1036800000  875000 275 >,
+			< 1113600000  885000 298 >,
+			< 1190400000  895000 321 >,
+			< 1267200000  910000 346 >,
+			< 1344000000  925000 371 >,
+			< 1420800000  935000 397 >,
+			< 1497600000  950000 423 >,
+			< 1574400000  960000 450 >,
+			< 1651200000  970000 477 >,
+			< 1728000000  985000 506 >,
+			< 1804800000  995000 536 >,
+			< 1881600000 1010000 567 >,
+			< 1958400000 1025000 598 >;
+
+		qcom,speed0-pvs4-bin-v0 =
+			<          0       0   0 >,
+			<  300000000  775000  73 >,
+			<  345600000  775000  85 >,
+			<  422400000  780000 104 >,
+			<  499200000  790000 124 >,
+			<  576000000  800000 144 >,
+			<  652800000  810000 165 >,
+			<  729600000  820000 186 >,
+			<  806400000  830000 208 >,
+			<  883200000  840000 229 >,
+			<  960000000  850000 252 >,
+			< 1036800000  860000 275 >,
+			< 1113600000  870000 298 >,
+			< 1190400000  880000 321 >,
+			< 1267200000  895000 346 >,
+			< 1344000000  910000 371 >,
+			< 1420800000  920000 397 >,
+			< 1497600000  930000 423 >,
+			< 1574400000  940000 450 >,
+			< 1651200000  950000 477 >,
+			< 1728000000  960000 506 >,
+			< 1804800000  975000 536 >,
+			< 1881600000  985000 567 >,
+			< 1958400000 1000000 598 >;
+
+		qcom,speed0-pvs5-bin-v0 =
+			<          0       0   0 >,
+			<  300000000  750000  73 >,
+			<  345600000  760000  85 >,
+			<  422400000  770000 104 >,
+			<  499200000  780000 124 >,
+			<  576000000  790000 144 >,
+			<  652800000  800000 165 >,
+			<  729600000  810000 186 >,
+			<  806400000  820000 208 >,
+			<  883200000  830000 229 >,
+			<  960000000  840000 252 >,
+			< 1036800000  850000 275 >,
+			< 1113600000  860000 298 >,
+			< 1190400000  870000 321 >,
+			< 1267200000  880000 346 >,
+			< 1344000000  890000 371 >,
+			< 1420800000  900000 397 >,
+			< 1497600000  910000 423 >,
+			< 1574400000  920000 450 >,
+			< 1651200000  930000 477 >,
+			< 1728000000  940000 506 >,
+			< 1804800000  955000 536 >,
+			< 1881600000  965000 567 >,
+			< 1958400000  975000 598 >;
+
+		qcom,speed0-pvs6-bin-v0 =
+			<          0       0   0 >,
+			<  300000000  750000  73 >,
+			<  345600000  750000  85 >,
+			<  422400000  760000 104 >,
+			<  499200000  770000 124 >,
+			<  576000000  780000 144 >,
+			<  652800000  790000 165 >,
+			<  729600000  800000 186 >,
+			<  806400000  810000 208 >,
+			<  883200000  820000 229 >,
+			<  960000000  830000 252 >,
+			< 1036800000  840000 275 >,
+			< 1113600000  850000 298 >,
+			< 1190400000  860000 321 >,
+			< 1267200000  870000 346 >,
+			< 1344000000  875000 371 >,
+			< 1420800000  885000 397 >,
+			< 1497600000  895000 423 >,
+			< 1574400000  905000 450 >,
+			< 1651200000  915000 477 >,
+			< 1728000000  920000 506 >,
+			< 1804800000  930000 536 >,
+			< 1881600000  940000 567 >,
+			< 1958400000  950000 598 >;
+
+		qcom,speed2-pvs0-bin-v0 =
+			<          0       0   0 >,
+			<  300000000  800000  72 >,
+			<  345600000  800000  83 >,
+			<  422400000  805000 102 >,
+			<  499200000  815000 121 >,
+			<  576000000  825000 141 >,
+			<  652800000  835000 161 >,
+			<  729600000  845000 181 >,
+			<  806400000  855000 202 >,
+			<  883200000  865000 223 >,
+			<  960000000  875000 245 >,
+			< 1036800000  890000 267 >,
+			< 1113600000  900000 289 >,
+			< 1190400000  915000 313 >,
+			< 1267200000  925000 336 >,
+			< 1344000000  940000 360 >,
+			< 1420800000  950000 383 >,
+			< 1497600000  965000 409 >,
+			< 1574400000  980000 435 >,
+			< 1651200000  995000 461 >,
+			< 1728000000 1010000 488 >,
+			< 1804800000 1025000 516 >,
+			< 1881600000 1040000 543 >,
+			< 1958400000 1055000 573 >,
+			< 2035200000 1070000 604 >,
+			< 2112000000 1085000 636 >,
+			< 2150400000 1100000 656 >;
+
+		qcom,speed2-pvs1-bin-v0 =
+			<          0       0   0 >,
+			<  300000000  800000  72 >,
+			<  345600000  800000  83 >,
+			<  422400000  800000 102 >,
+			<  499200000  800000 121 >,
+			<  576000000  810000 141 >,
+			<  652800000  820000 161 >,
+			<  729600000  830000 181 >,
+			<  806400000  840000 202 >,
+			<  883200000  850000 223 >,
+			<  960000000  860000 245 >,
+			< 1036800000  875000 267 >,
+			< 1113600000  885000 289 >,
+			< 1190400000  895000 313 >,
+			< 1267200000  910000 336 >,
+			< 1344000000  920000 360 >,
+			< 1420800000  930000 383 >,
+			< 1497600000  945000 409 >,
+			< 1574400000  960000 435 >,
+			< 1651200000  975000 461 >,
+			< 1728000000  990000 488 >,
+			< 1804800000 1005000 516 >,
+			< 1881600000 1020000 543 >,
+			< 1958400000 1030000 573 >,
+			< 2035200000 1045000 604 >,
+			< 2112000000 1060000 636 >,
+			< 2150400000 1075000 656 >;
+
+		qcom,speed2-pvs2-bin-v0 =
+			<          0       0   0 >,
+			<  300000000  775000  72 >,
+			<  345600000  775000  83 >,
+			<  422400000  775000 102 >,
+			<  499200000  785000 121 >,
+			<  576000000  795000 141 >,
+			<  652800000  805000 161 >,
+			<  729600000  815000 181 >,
+			<  806400000  825000 202 >,
+			<  883200000  835000 223 >,
+			<  960000000  845000 245 >,
+			< 1036800000  855000 267 >,
+			< 1113600000  865000 289 >,
+			< 1190400000  875000 313 >,
+			< 1267200000  890000 336 >,
+			< 1344000000  900000 360 >,
+			< 1420800000  910000 383 >,
+			< 1497600000  925000 409 >,
+			< 1574400000  940000 435 >,
+			< 1651200000  955000 461 >,
+			< 1728000000  970000 488 >,
+			< 1804800000  980000 516 >,
+			< 1881600000  995000 543 >,
+			< 1958400000 1005000 573 >,
+			< 2035200000 1020000 604 >,
+			< 2112000000 1035000 636 >,
+			< 2150400000 1050000 656 >;
+
+		qcom,speed2-pvs3-bin-v0 =
+			<          0       0   0 >,
+			<  300000000  775000  72 >,
+			<  345600000  775000  83 >,
+			<  422400000  775000 102 >,
+			<  499200000  775000 121 >,
+			<  576000000  780000 141 >,
+			<  652800000  790000 161 >,
+			<  729600000  800000 181 >,
+			<  806400000  810000 202 >,
+			<  883200000  820000 223 >,
+			<  960000000  830000 245 >,
+			< 1036800000  840000 267 >,
+			< 1113600000  850000 289 >,
+			< 1190400000  860000 313 >,
+			< 1267200000  875000 336 >,
+			< 1344000000  885000 360 >,
+			< 1420800000  895000 383 >,
+			< 1497600000  910000 409 >,
+			< 1574400000  925000 435 >,
+			< 1651200000  935000 461 >,
+			< 1728000000  950000 488 >,
+			< 1804800000  960000 516 >,
+			< 1881600000  970000 543 >,
+			< 1958400000  985000 573 >,
+			< 2035200000  995000 604 >,
+			< 2112000000 1010000 636 >,
+			< 2150400000 1025000 656 >;
+
+		qcom,speed2-pvs4-bin-v0 =
+			<          0       0   0 >,
+			<  300000000  775000  72 >,
+			<  345600000  775000  83 >,
+			<  422400000  775000 102 >,
+			<  499200000  775000 121 >,
+			<  576000000  775000 141 >,
+			<  652800000  780000 161 >,
+			<  729600000  790000 181 >,
+			<  806400000  800000 202 >,
+			<  883200000  810000 223 >,
+			<  960000000  820000 245 >,
+			< 1036800000  830000 267 >,
+			< 1113600000  840000 289 >,
+			< 1190400000  850000 313 >,
+			< 1267200000  860000 336 >,
+			< 1344000000  870000 360 >,
+			< 1420800000  880000 383 >,
+			< 1497600000  895000 409 >,
+			< 1574400000  910000 435 >,
+			< 1651200000  920000 461 >,
+			< 1728000000  930000 488 >,
+			< 1804800000  940000 516 >,
+			< 1881600000  950000 543 >,
+			< 1958400000  960000 573 >,
+			< 2035200000  975000 604 >,
+			< 2112000000  985000 636 >,
+			< 2150400000 1000000 656 >;
+
+		qcom,speed2-pvs5-bin-v0 =
+			<          0       0   0 >,
+			<  300000000  750000  72 >,
+			<  345600000  750000  83 >,
+			<  422400000  750000 102 >,
+			<  499200000  750000 121 >,
+			<  576000000  760000 141 >,
+			<  652800000  770000 161 >,
+			<  729600000  780000 181 >,
+			<  806400000  790000 202 >,
+			<  883200000  800000 223 >,
+			<  960000000  810000 245 >,
+			< 1036800000  820000 267 >,
+			< 1113600000  830000 289 >,
+			< 1190400000  840000 313 >,
+			< 1267200000  850000 336 >,
+			< 1344000000  860000 360 >,
+			< 1420800000  870000 383 >,
+			< 1497600000  880000 409 >,
+			< 1574400000  890000 435 >,
+			< 1651200000  900000 461 >,
+			< 1728000000  910000 488 >,
+			< 1804800000  920000 516 >,
+			< 1881600000  930000 543 >,
+			< 1958400000  940000 573 >,
+			< 2035200000  955000 604 >,
+			< 2112000000  965000 636 >,
+			< 2150400000  975000 656 >;
+
+		qcom,speed2-pvs6-bin-v0 =
+			<          0       0   0 >,
+			<  300000000  750000  72 >,
+			<  345600000  750000  83 >,
+			<  422400000  750000 102 >,
+			<  499200000  750000 121 >,
+			<  576000000  750000 141 >,
+			<  652800000  760000 161 >,
+			<  729600000  770000 181 >,
+			<  806400000  780000 202 >,
+			<  883200000  790000 223 >,
+			<  960000000  800000 245 >,
+			< 1036800000  810000 267 >,
+			< 1113600000  820000 289 >,
+			< 1190400000  830000 313 >,
+			< 1267200000  840000 336 >,
+			< 1344000000  850000 360 >,
+			< 1420800000  860000 383 >,
+			< 1497600000  870000 409 >,
+			< 1574400000  875000 435 >,
+			< 1651200000  885000 461 >,
+			< 1728000000  895000 488 >,
+			< 1804800000  905000 516 >,
+			< 1881600000  915000 543 >,
+			< 1958400000  920000 573 >,
+			< 2035200000  930000 604 >,
+			< 2112000000  940000 636 >,
+			< 2150400000  950000 656 >;
+
+		qcom,speed1-pvs0-bin-v0 =
+			<          0       0   0 >,
+			<  300000000  775000  72 >,
+			<  345600000  775000  83 >,
+			<  422400000  775000 101 >,
+			<  499200000  780000 120 >,
+			<  576000000  790000 139 >,
+			<  652800000  800000 159 >,
+			<  729600000  810000 180 >,
+			<  806400000  820000 200 >,
+			<  883200000  830000 221 >,
+			<  960000000  840000 242 >,
+			< 1036800000  850000 264 >,
+			< 1113600000  865000 287 >,
+			< 1190400000  875000 308 >,
+			< 1267200000  890000 333 >,
+			< 1344000000  900000 356 >,
+			< 1420800000  915000 380 >,
+			< 1497600000  925000 404 >,
+			< 1574400000  940000 430 >,
+			< 1651200000  955000 456 >,
+			< 1728000000  970000 482 >,
+			< 1804800000  985000 510 >,
+			< 1881600000 1000000 538 >,
+			< 1958400000 1015000 565 >,
+			< 2035200000 1030000 596 >,
+			< 2112000000 1045000 627 >,
+			< 2188800000 1060000 659 >,
+			< 2265600000 1075000 691 >;
+
+		qcom,speed1-pvs1-bin-v0 =
+			<          0       0   0 >,
+			<  300000000  775000  72 >,
+			<  345600000  775000  83 >,
+			<  422400000  775000 101 >,
+			<  499200000  775000 120 >,
+			<  576000000  775000 139 >,
+			<  652800000  785000 159 >,
+			<  729600000  795000 180 >,
+			<  806400000  805000 200 >,
+			<  883200000  815000 221 >,
+			<  960000000  825000 242 >,
+			< 1036800000  835000 264 >,
+			< 1113600000  850000 287 >,
+			< 1190400000  860000 308 >,
+			< 1267200000  870000 333 >,
+			< 1344000000  885000 356 >,
+			< 1420800000  895000 380 >,
+			< 1497600000  905000 404 >,
+			< 1574400000  920000 430 >,
+			< 1651200000  935000 456 >,
+			< 1728000000  950000 482 >,
+			< 1804800000  965000 510 >,
+			< 1881600000  980000 538 >,
+			< 1958400000  995000 565 >,
+			< 2035200000 1005000 596 >,
+			< 2112000000 1020000 627 >,
+			< 2188800000 1035000 659 >,
+			< 2265600000 1050000 691 >;
+
+		qcom,speed1-pvs2-bin-v0 =
+			<          0       0   0 >,
+			<  300000000  750000  72 >,
+			<  345600000  750000  83 >,
+			<  422400000  750000 101 >,
+			<  499200000  750000 120 >,
+			<  576000000  760000 139 >,
+			<  652800000  770000 159 >,
+			<  729600000  780000 180 >,
+			<  806400000  790000 200 >,
+			<  883200000  800000 221 >,
+			<  960000000  810000 242 >,
+			< 1036800000  820000 264 >,
+			< 1113600000  830000 287 >,
+			< 1190400000  840000 308 >,
+			< 1267200000  850000 333 >,
+			< 1344000000  865000 356 >,
+			< 1420800000  875000 380 >,
+			< 1497600000  885000 404 >,
+			< 1574400000  900000 430 >,
+			< 1651200000  915000 456 >,
+			< 1728000000  930000 482 >,
+			< 1804800000  945000 510 >,
+			< 1881600000  955000 538 >,
+			< 1958400000  970000 565 >,
+			< 2035200000  980000 596 >,
+			< 2112000000  995000 627 >,
+			< 2188800000 1010000 659 >,
+			< 2265600000 1025000 691 >;
+
+		qcom,speed1-pvs3-bin-v0 =
+			<          0       0   0 >,
+			<  300000000  750000  72 >,
+			<  345600000  750000  83 >,
+			<  422400000  750000 101 >,
+			<  499200000  750000 120 >,
+			<  576000000  750000 139 >,
+			<  652800000  755000 159 >,
+			<  729600000  765000 180 >,
+			<  806400000  775000 200 >,
+			<  883200000  785000 221 >,
+			<  960000000  795000 242 >,
+			< 1036800000  805000 264 >,
+			< 1113600000  815000 287 >,
+			< 1190400000  825000 308 >,
+			< 1267200000  835000 333 >,
+			< 1344000000  850000 356 >,
+			< 1420800000  860000 380 >,
+			< 1497600000  870000 404 >,
+			< 1574400000  885000 430 >,
+			< 1651200000  900000 456 >,
+			< 1728000000  910000 482 >,
+			< 1804800000  925000 510 >,
+			< 1881600000  935000 538 >,
+			< 1958400000  945000 565 >,
+			< 2035200000  960000 596 >,
+			< 2112000000  970000 627 >,
+			< 2188800000  985000 659 >,
+			< 2265600000 1000000 691 >;
+
+		qcom,speed1-pvs4-bin-v0 =
+			<          0       0   0 >,
+			<  300000000  750000  72 >,
+			<  345600000  750000  83 >,
+			<  422400000  750000 101 >,
+			<  499200000  750000 120 >,
+			<  576000000  750000 139 >,
+			<  652800000  750000 159 >,
+			<  729600000  755000 180 >,
+			<  806400000  765000 200 >,
+			<  883200000  775000 221 >,
+			<  960000000  785000 242 >,
+			< 1036800000  795000 264 >,
+			< 1113600000  805000 287 >,
+			< 1190400000  815000 308 >,
+			< 1267200000  825000 333 >,
+			< 1344000000  835000 356 >,
+			< 1420800000  845000 380 >,
+			< 1497600000  855000 404 >,
+			< 1574400000  870000 430 >,
+			< 1651200000  885000 456 >,
+			< 1728000000  895000 482 >,
+			< 1804800000  905000 510 >,
+			< 1881600000  915000 538 >,
+			< 1958400000  925000 565 >,
+			< 2035200000  935000 596 >,
+			< 2112000000  950000 627 >,
+			< 2188800000  960000 659 >,
+			< 2265600000  975000 691 >;
+
+		qcom,speed1-pvs5-bin-v0 =
+			<          0       0   0 >,
+			<  300000000  725000  72 >,
+			<  345600000  725000  83 >,
+			<  422400000  725000 101 >,
+			<  499200000  725000 120 >,
+			<  576000000  725000 139 >,
+			<  652800000  735000 159 >,
+			<  729600000  745000 180 >,
+			<  806400000  755000 200 >,
+			<  883200000  765000 221 >,
+			<  960000000  775000 242 >,
+			< 1036800000  785000 264 >,
+			< 1113600000  795000 287 >,
+			< 1190400000  805000 308 >,
+			< 1267200000  815000 333 >,
+			< 1344000000  825000 356 >,
+			< 1420800000  835000 380 >,
+			< 1497600000  845000 404 >,
+			< 1574400000  855000 430 >,
+			< 1651200000  865000 456 >,
+			< 1728000000  875000 482 >,
+			< 1804800000  885000 510 >,
+			< 1881600000  895000 538 >,
+			< 1958400000  905000 565 >,
+			< 2035200000  915000 596 >,
+			< 2112000000  930000 627 >,
+			< 2188800000  940000 659 >,
+			< 2265600000  950000 691 >;
+
+		qcom,speed1-pvs6-bin-v0 =
+			<          0       0   0 >,
+			<  300000000  725000  72 >,
+			<  345600000  725000  83 >,
+			<  422400000  725000 101 >,
+			<  499200000  725000 120 >,
+			<  576000000  725000 139 >,
+			<  652800000  725000 159 >,
+			<  729600000  735000 180 >,
+			<  806400000  745000 200 >,
+			<  883200000  755000 221 >,
+			<  960000000  765000 242 >,
+			< 1036800000  775000 264 >,
+			< 1113600000  785000 287 >,
+			< 1190400000  795000 308 >,
+			< 1267200000  805000 333 >,
+			< 1344000000  815000 356 >,
+			< 1420800000  825000 380 >,
+			< 1497600000  835000 404 >,
+			< 1574400000  845000 430 >,
+			< 1651200000  850000 456 >,
+			< 1728000000  860000 482 >,
+			< 1804800000  870000 510 >,
+			< 1881600000  880000 538 >,
+			< 1958400000  890000 565 >,
+			< 2035200000  895000 596 >,
+			< 2112000000  905000 627 >,
+			< 2188800000  915000 659 >,
+			< 2265600000  925000 691 >;
+	};
+
+	qcom,msm-cpufreq@0 {
+		reg = <0 4>;
+		compatible = "qcom,msm-cpufreq";
+		qcom,cpu-mem-ports = <1 512>, <2 512>;
+		qcom,cpufreq-table =
+			<  300000  300000  600 /*  75 MHz */ >,
+			<  422400  422400 1200 /* 150 MHz */ >,
+			<  652800  499200 1600 /* 200 MHz */ >,
+			<  729600  576000 2456 /* 307 MHz */ >,
+			<  883200  576000 2456 /* 307 MHz */ >,
+			<  960000  960000 3680 /* 460 MHz */ >,
+			< 1036800 1036800 3680 /* 460 MHz */ >,
+			< 1190400 1036800 3680 /* 460 MHz */ >,
+			< 1267200 1267200 4912 /* 614 MHz */ >,
+			< 1497600 1497600 4912 /* 614 MHz */ >,
+			< 1574400 1574400 6400 /* 800 MHz */ >,
+			< 1728000 1651200 6400 /* 800 MHz */ >,
+			< 1958400 1728000 7448 /* 931 MHz */ >,
+			< 2265600 1728000 7448 /* 931 MHz */ >;
 	};
 
 	usb3: qcom,ssusb@f9200000 {
diff --git a/arch/arm/boot/dts/msm8974pro-pm.dtsi b/arch/arm/boot/dts/msm8974pro-pm.dtsi
index 9e1f83f..5769446 100644
--- a/arch/arm/boot/dts/msm8974pro-pm.dtsi
+++ b/arch/arm/boot/dts/msm8974pro-pm.dtsi
@@ -205,6 +205,9 @@
 			<50 172>, /* usb1_hs_async_wakeup_irq */
 			<53 104>, /* mdss_irq */
 			<62 222>, /* ee0_krait_hlos_spmi_periph_irq */
+			<0xff 34>,  /* APCC_qgicL2ErrorIrptReq */
+			<0xff 35>,  /* WDT_barkInt */
+			<0xff 40>,  /* qtimer_phy_irq */
 			<0xff 56>,  /* modem_watchdog */
 			<0xff 57>,  /* mss_to_apps_irq(0) */
 			<0xff 58>,  /* mss_to_apps_irq(1) */
@@ -212,8 +215,21 @@
 			<0xff 60>,  /* mss_to_apps_irq(3) */
 			<0xff 61>,  /* mss_a2_bam_irq */
 			<0xff 70>,  /* iommu_pmon_nonsecure_irq */
+			<0xff 74>,  /* osmmu_CIrpt[1] */
+			<0xff 75>,  /* osmmu_CIrpt[0] */
+			<0xff 77>,  /* osmmu_CIrpt[0] */
+			<0xff 78>,  /* osmmu_CIrpt[0] */
+			<0xff 79>,  /* osmmu_CIrpt[0] */
+			<0xff 94>,  /* osmmu_CIrpt[0] */
 			<0xff 97>,  /* iommu_nonsecure_irq */
+			<0xff 99>,  /* msm_iommu_pmon_nonsecure_irq */
+			<0xff 102>,  /* osmmu_CIrpt[1] */
 			<0xff 105>, /* iommu_pmon_nonsecure_irq */
+			<0xff 109>,  /* ocmem_dm_nonsec_irq */
+			<0xff 126>,  /* bam_irq[0] */
+			<0xff 155>,  /* sdcc_irq[0] */
+			<0xff 163>,  /* usb30_ee1_irq */
+			<0xff 170>,  /* sdcc_pwr_cmd_irq */
 			<0xff 173>, /* o_wcss_apss_smd_hi */
 			<0xff 174>, /* o_wcss_apss_smd_med */
 			<0xff 175>, /* o_wcss_apss_smd_low */
@@ -233,6 +249,7 @@
 			<0xff 195>, /* lpass_irq_out_apcs(7) */
 			<0xff 196>, /* lpass_irq_out_apcs(8) */
 			<0xff 197>, /* lpass_irq_out_apcs(9) */
+			<0xff 198>, /* coresight-tmc-etr interrupt */
 			<0xff 200>, /* rpm_ipc(4) */
 			<0xff 201>, /* rpm_ipc(5) */
 			<0xff 202>, /* rpm_ipc(6) */
@@ -242,7 +259,10 @@
 			<0xff 206>, /* rpm_ipc(26) */
 			<0xff 207>, /* rpm_ipc(27) */
 			<0xff 211>, /* usb_dwc3_otg */
-			<0xff 240>; /* summary_irq_kpss */
+			<0xff 240>, /* summary_irq_kpss */
+			<0xff 268>, /* bam_irq[1] */
+			<0xff 270>, /* bam_irq[0] */
+			<0xff 271>; /* bam_irq[0] */
 
 		qcom,gpio-parent = <&msmgpio>;
 		qcom,gpio-map = <3  102>,
diff --git a/arch/arm/boot/dts/msm8974pro-pma8084.dtsi b/arch/arm/boot/dts/msm8974pro-pma8084.dtsi
index cd485c5..2693642 100644
--- a/arch/arm/boot/dts/msm8974pro-pma8084.dtsi
+++ b/arch/arm/boot/dts/msm8974pro-pma8084.dtsi
@@ -100,20 +100,10 @@
 		};
 	};
 
-	qcom,acpuclk@f9000000 {
-		krait0_mem-supply = <&pma8084_s1_ao>;
-		krait1_mem-supply = <&pma8084_s1_ao>;
-		krait2_mem-supply = <&pma8084_s1_ao>;
-		krait3_mem-supply = <&pma8084_s1_ao>;
-		krait0_dig-supply = <&pma8084_s2_corner_ao>;
-		krait1_dig-supply = <&pma8084_s2_corner_ao>;
-		krait2_dig-supply = <&pma8084_s2_corner_ao>;
-		krait3_dig-supply = <&pma8084_s2_corner_ao>;
-		krait0_hfpll-supply = <&pma8084_l12_ao>;
-		krait1_hfpll-supply = <&pma8084_l12_ao>;
-		krait2_hfpll-supply = <&pma8084_l12_ao>;
-		krait3_hfpll-supply = <&pma8084_l12_ao>;
-		l2_hfpll-supply = <&pma8084_l12_ao>;
+	qcom,clock-krait@f9016000 {
+		l2-dig-supply = <&pma8084_s2_corner_ao>;
+		hfpll-dig-supply = <&pma8084_s2_corner_ao>;
+		hfpll-analog-supply = <&pma8084_l12_ao>;
 	};
 
 	qcom,ssusb@f9200000 {
diff --git a/arch/arm/boot/dts/msm8974pro.dtsi b/arch/arm/boot/dts/msm8974pro.dtsi
index 6d5c862..85c2fe3 100644
--- a/arch/arm/boot/dts/msm8974pro.dtsi
+++ b/arch/arm/boot/dts/msm8974pro.dtsi
@@ -39,6 +39,1533 @@
 		/delete-property/ qcom,pmic-sw-mode-temp-hysteresis;
 		/delete-property/ qcom,pmic-sw-mode-regs;
 	};
+
+	sound {
+		reg = <0xfe02c000 0x4>,
+		      <0xfe02d000 0x4>,
+		      <0xfe02e000 0x4>,
+		      <0xfe02f000 0x4>;
+		reg-names = "lpaif_pri_mode_muxsel",
+			    "lpaif_sec_mode_muxsel",
+			    "lpaif_tert_mode_muxsel",
+			    "lpaif_quat_mode_muxsel";
+	};
+
+	qcom,clock-krait@f9016000 {
+		qcom,speed1-pvs0-bin-v0 =
+			<          0       0    0 >,
+			<  300000000  775000   74 >,
+			<  345600000  775000   85 >,
+			<  422400000  775000  104 >,
+			<  499200000  780000  124 >,
+			<  576000000  790000  144 >,
+			<  652800000  800000  164 >,
+			<  729600000  810000  184 >,
+			<  806400000  820000  206 >,
+			<  883200000  830000  227 >,
+			<  960000000  840000  249 >,
+			< 1036800000  850000  271 >,
+			< 1113600000  865000  295 >,
+			< 1190400000  875000  318 >,
+			< 1267200000  890000  342 >,
+			< 1344000000  900000  365 >,
+			< 1420800000  915000  392 >,
+			< 1497600000  925000  416 >,
+			< 1574400000  940000  442 >,
+			< 1651200000  955000  469 >,
+			< 1728000000  970000  497 >,
+			< 1804800000  985000  525 >,
+			< 1881600000 1000000  554 >,
+			< 1958400000 1015000  583 >,
+			< 2035200000 1030000  613 >,
+			< 2112000000 1045000  642 >,
+			< 2150400000 1060000  663 >,
+			< 2188800000 1060000  675 >,
+			< 2265600000 1075000  708 >;
+
+		qcom,speed1-pvs1-bin-v0 =
+			<          0       0    0 >,
+			<  300000000  775000   74 >,
+			<  345600000  775000   85 >,
+			<  422400000  775000  104 >,
+			<  499200000  775000  124 >,
+			<  576000000  775000  144 >,
+			<  652800000  785000  164 >,
+			<  729600000  795000  184 >,
+			<  806400000  805000  206 >,
+			<  883200000  815000  227 >,
+			<  960000000  825000  249 >,
+			< 1036800000  835000  271 >,
+			< 1113600000  850000  295 >,
+			< 1190400000  860000  318 >,
+			< 1267200000  870000  342 >,
+			< 1344000000  885000  365 >,
+			< 1420800000  895000  392 >,
+			< 1497600000  905000  416 >,
+			< 1574400000  920000  442 >,
+			< 1651200000  935000  469 >,
+			< 1728000000  950000  497 >,
+			< 1804800000  965000  525 >,
+			< 1881600000  980000  554 >,
+			< 1958400000  995000  583 >,
+			< 2035200000 1005000  613 >,
+			< 2112000000 1020000  642 >,
+			< 2150400000 1035000  663 >,
+			< 2188800000 1035000  675 >,
+			< 2265600000 1050000  708 >;
+
+		qcom,speed1-pvs2-bin-v0 =
+			<          0       0    0 >,
+			<  300000000  750000   74 >,
+			<  345600000  750000   85 >,
+			<  422400000  750000  104 >,
+			<  499200000  750000  124 >,
+			<  576000000  760000  144 >,
+			<  652800000  770000  164 >,
+			<  729600000  780000  184 >,
+			<  806400000  790000  206 >,
+			<  883200000  800000  227 >,
+			<  960000000  810000  249 >,
+			< 1036800000  820000  271 >,
+			< 1113600000  830000  295 >,
+			< 1190400000  840000  318 >,
+			< 1267200000  850000  342 >,
+			< 1344000000  865000  365 >,
+			< 1420800000  875000  392 >,
+			< 1497600000  885000  416 >,
+			< 1574400000  900000  442 >,
+			< 1651200000  915000  469 >,
+			< 1728000000  930000  497 >,
+			< 1804800000  945000  525 >,
+			< 1881600000  955000  554 >,
+			< 1958400000  970000  583 >,
+			< 2035200000  980000  613 >,
+			< 2112000000  995000  642 >,
+			< 2150400000 1010000  663 >,
+			< 2188800000 1010000  675 >,
+			< 2265600000 1025000  708 >;
+
+		qcom,speed1-pvs3-bin-v0 =
+			<          0       0    0 >,
+			<  300000000  750000   74 >,
+			<  345600000  750000   85 >,
+			<  422400000  750000  104 >,
+			<  499200000  750000  124 >,
+			<  576000000  750000  144 >,
+			<  652800000  755000  164 >,
+			<  729600000  765000  184 >,
+			<  806400000  775000  206 >,
+			<  883200000  785000  227 >,
+			<  960000000  795000  249 >,
+			< 1036800000  805000  271 >,
+			< 1113600000  815000  295 >,
+			< 1190400000  825000  318 >,
+			< 1267200000  835000  342 >,
+			< 1344000000  850000  365 >,
+			< 1420800000  860000  392 >,
+			< 1497600000  870000  416 >,
+			< 1574400000  885000  442 >,
+			< 1651200000  900000  469 >,
+			< 1728000000  910000  497 >,
+			< 1804800000  925000  525 >,
+			< 1881600000  935000  554 >,
+			< 1958400000  945000  583 >,
+			< 2035200000  960000  613 >,
+			< 2112000000  970000  642 >,
+			< 2150400000  985000  663 >,
+			< 2188800000  985000  675 >,
+			< 2265600000 1000000  708 >;
+
+		qcom,speed1-pvs4-bin-v0 =
+			<          0       0    0 >,
+			<  300000000  750000   74 >,
+			<  345600000  750000   85 >,
+			<  422400000  750000  104 >,
+			<  499200000  750000  124 >,
+			<  576000000  750000  144 >,
+			<  652800000  750000  164 >,
+			<  729600000  755000  184 >,
+			<  806400000  765000  206 >,
+			<  883200000  775000  227 >,
+			<  960000000  785000  249 >,
+			< 1036800000  795000  271 >,
+			< 1113600000  805000  295 >,
+			< 1190400000  815000  318 >,
+			< 1267200000  825000  342 >,
+			< 1344000000  835000  365 >,
+			< 1420800000  845000  392 >,
+			< 1497600000  855000  416 >,
+			< 1574400000  870000  442 >,
+			< 1651200000  885000  469 >,
+			< 1728000000  895000  497 >,
+			< 1804800000  905000  525 >,
+			< 1881600000  915000  554 >,
+			< 1958400000  925000  583 >,
+			< 2035200000  935000  613 >,
+			< 2112000000  950000  642 >,
+			< 2150400000  960000  663 >,
+			< 2188800000  960000  675 >,
+			< 2265600000  975000  708 >;
+
+		qcom,speed1-pvs5-bin-v0 =
+			<          0       0    0 >,
+			<  300000000  725000   74 >,
+			<  345600000  725000   85 >,
+			<  422400000  725000  104 >,
+			<  499200000  725000  124 >,
+			<  576000000  725000  144 >,
+			<  652800000  735000  164 >,
+			<  729600000  745000  184 >,
+			<  806400000  755000  206 >,
+			<  883200000  765000  227 >,
+			<  960000000  775000  249 >,
+			< 1036800000  785000  271 >,
+			< 1113600000  795000  295 >,
+			< 1190400000  805000  318 >,
+			< 1267200000  815000  342 >,
+			< 1344000000  825000  365 >,
+			< 1420800000  835000  392 >,
+			< 1497600000  845000  416 >,
+			< 1574400000  855000  442 >,
+			< 1651200000  865000  469 >,
+			< 1728000000  875000  497 >,
+			< 1804800000  885000  525 >,
+			< 1881600000  895000  554 >,
+			< 1958400000  905000  583 >,
+			< 2035200000  915000  613 >,
+			< 2112000000  930000  642 >,
+			< 2150400000  940000  663 >,
+			< 2188800000  940000  675 >,
+			< 2265600000  950000  708 >;
+
+		qcom,speed1-pvs6-bin-v0 =
+			<          0       0    0 >,
+			<  300000000  725000   74 >,
+			<  345600000  725000   85 >,
+			<  422400000  725000  104 >,
+			<  499200000  725000  124 >,
+			<  576000000  725000  144 >,
+			<  652800000  725000  164 >,
+			<  729600000  735000  184 >,
+			<  806400000  745000  206 >,
+			<  883200000  755000  227 >,
+			<  960000000  765000  249 >,
+			< 1036800000  775000  271 >,
+			< 1113600000  785000  295 >,
+			< 1190400000  795000  318 >,
+			< 1267200000  805000  342 >,
+			< 1344000000  815000  365 >,
+			< 1420800000  825000  392 >,
+			< 1497600000  835000  416 >,
+			< 1574400000  845000  442 >,
+			< 1651200000  850000  469 >,
+			< 1728000000  860000  497 >,
+			< 1804800000  870000  525 >,
+			< 1881600000  880000  554 >,
+			< 1958400000  890000  583 >,
+			< 2035200000  895000  613 >,
+			< 2112000000  905000  642 >,
+			< 2150400000  915000  663 >,
+			< 2188800000  915000  675 >,
+			< 2265600000  925000  708 >;
+
+		qcom,speed3-pvs0-bin-v0 =
+			<          0       0    0 >,
+			<  300000000  800000   76 >,
+			<  345600000  800000   87 >,
+			<  422400000  800000  106 >,
+			<  499200000  800000  125 >,
+			<  576000000  800000  145 >,
+			<  652800000  810000  165 >,
+			<  729600000  820000  186 >,
+			<  806400000  830000  208 >,
+			<  883200000  840000  229 >,
+			<  960000000  850000  251 >,
+			< 1036800000  860000  273 >,
+			< 1113600000  870000  296 >,
+			< 1190400000  880000  319 >,
+			< 1267200000  890000  342 >,
+			< 1344000000  900000  365 >,
+			< 1420800000  910000  390 >,
+			< 1497600000  920000  415 >,
+			< 1574400000  930000  439 >,
+			< 1651200000  945000  465 >,
+			< 1728000000  960000  493 >,
+			< 1804800000  975000  521 >,
+			< 1881600000  990000  549 >,
+			< 1958400000 1005000  579 >,
+			< 2035200000 1020000  608 >,
+			< 2112000000 1035000  638 >,
+			< 2150400000 1050000  667 >,
+			< 2188800000 1050000  667 >,
+			< 2265600000 1065000  700 >,
+			< 2342400000 1080000  734 >,
+			< 2419200000 1095000  769 >,
+			< 2457600000 1100000  785 >;
+
+		qcom,speed3-pvs1-bin-v0 =
+			<          0       0    0 >,
+			<  300000000  800000   76 >,
+			<  345600000  800000   87 >,
+			<  422400000  800000  106 >,
+			<  499200000  800000  125 >,
+			<  576000000  800000  145 >,
+			<  652800000  800000  165 >,
+			<  729600000  800000  186 >,
+			<  806400000  805000  208 >,
+			<  883200000  815000  229 >,
+			<  960000000  825000  251 >,
+			< 1036800000  835000  273 >,
+			< 1113600000  845000  296 >,
+			< 1190400000  855000  319 >,
+			< 1267200000  865000  342 >,
+			< 1344000000  875000  365 >,
+			< 1420800000  885000  390 >,
+			< 1497600000  895000  415 >,
+			< 1574400000  905000  439 >,
+			< 1651200000  920000  465 >,
+			< 1728000000  935000  493 >,
+			< 1804800000  950000  521 >,
+			< 1881600000  965000  549 >,
+			< 1958400000  980000  579 >,
+			< 2035200000  995000  608 >,
+			< 2112000000 1010000  638 >,
+			< 2150400000 1025000  667 >,
+			< 2188800000 1025000  667 >,
+			< 2265600000 1040000  700 >,
+			< 2342400000 1055000  734 >,
+			< 2419200000 1070000  769 >,
+			< 2457600000 1075000  785 >;
+
+		qcom,speed3-pvs2-bin-v0 =
+			<          0       0    0 >,
+			<  300000000  775000   76 >,
+			<  345600000  775000   87 >,
+			<  422400000  775000  106 >,
+			<  499200000  775000  125 >,
+			<  576000000  775000  145 >,
+			<  652800000  775000  165 >,
+			<  729600000  775000  186 >,
+			<  806400000  780000  208 >,
+			<  883200000  790000  229 >,
+			<  960000000  800000  251 >,
+			< 1036800000  810000  273 >,
+			< 1113600000  820000  296 >,
+			< 1190400000  830000  319 >,
+			< 1267200000  840000  342 >,
+			< 1344000000  850000  365 >,
+			< 1420800000  860000  390 >,
+			< 1497600000  870000  415 >,
+			< 1574400000  880000  439 >,
+			< 1651200000  895000  465 >,
+			< 1728000000  910000  493 >,
+			< 1804800000  925000  521 >,
+			< 1881600000  940000  549 >,
+			< 1958400000  955000  579 >,
+			< 2035200000  970000  608 >,
+			< 2112000000  985000  638 >,
+			< 2150400000 1000000  667 >,
+			< 2188800000 1000000  667 >,
+			< 2265600000 1015000  700 >,
+			< 2342400000 1030000  734 >,
+			< 2419200000 1045000  769 >,
+			< 2457600000 1050000  785 >;
+
+		qcom,speed3-pvs3-bin-v0 =
+			<          0       0    0 >,
+			<  300000000  775000   76 >,
+			<  345600000  775000   87 >,
+			<  422400000  775000  106 >,
+			<  499200000  775000  125 >,
+			<  576000000  775000  145 >,
+			<  652800000  775000  165 >,
+			<  729600000  775000  186 >,
+			<  806400000  775000  208 >,
+			<  883200000  775000  229 >,
+			<  960000000  780000  251 >,
+			< 1036800000  785000  273 >,
+			< 1113600000  795000  296 >,
+			< 1190400000  805000  319 >,
+			< 1267200000  815000  342 >,
+			< 1344000000  825000  365 >,
+			< 1420800000  835000  390 >,
+			< 1497600000  845000  415 >,
+			< 1574400000  855000  439 >,
+			< 1651200000  870000  465 >,
+			< 1728000000  885000  493 >,
+			< 1804800000  900000  521 >,
+			< 1881600000  915000  549 >,
+			< 1958400000  930000  579 >,
+			< 2035200000  945000  608 >,
+			< 2112000000  960000  638 >,
+			< 2150400000  975000  667 >,
+			< 2188800000  975000  667 >,
+			< 2265600000  990000  700 >,
+			< 2342400000 1005000  734 >,
+			< 2419200000 1020000  769 >,
+			< 2457600000 1025000  785 >;
+
+		qcom,speed3-pvs4-bin-v0 =
+			<          0       0    0 >,
+			<  300000000  775000   76 >,
+			<  345600000  775000   87 >,
+			<  422400000  775000  106 >,
+			<  499200000  775000  125 >,
+			<  576000000  775000  145 >,
+			<  652800000  775000  165 >,
+			<  729600000  775000  186 >,
+			<  806400000  775000  208 >,
+			<  883200000  775000  229 >,
+			<  960000000  775000  251 >,
+			< 1036800000  775000  273 >,
+			< 1113600000  775000  296 >,
+			< 1190400000  780000  319 >,
+			< 1267200000  790000  342 >,
+			< 1344000000  800000  365 >,
+			< 1420800000  810000  390 >,
+			< 1497600000  820000  415 >,
+			< 1574400000  830000  439 >,
+			< 1651200000  845000  465 >,
+			< 1728000000  860000  493 >,
+			< 1804800000  875000  521 >,
+			< 1881600000  890000  549 >,
+			< 1958400000  905000  579 >,
+			< 2035200000  920000  608 >,
+			< 2112000000  935000  638 >,
+			< 2150400000  950000  667 >,
+			< 2188800000  950000  667 >,
+			< 2265600000  965000  700 >,
+			< 2342400000  980000  734 >,
+			< 2419200000  995000  769 >,
+			< 2457600000 1000000  785 >;
+
+		qcom,speed3-pvs5-bin-v0 =
+			<          0       0    0 >,
+			<  300000000  750000   76 >,
+			<  345600000  750000   87 >,
+			<  422400000  750000  106 >,
+			<  499200000  750000  125 >,
+			<  576000000  750000  145 >,
+			<  652800000  750000  165 >,
+			<  729600000  750000  186 >,
+			<  806400000  750000  208 >,
+			<  883200000  750000  229 >,
+			<  960000000  750000  251 >,
+			< 1036800000  750000  273 >,
+			< 1113600000  750000  296 >,
+			< 1190400000  760000  319 >,
+			< 1267200000  770000  342 >,
+			< 1344000000  780000  365 >,
+			< 1420800000  790000  390 >,
+			< 1497600000  800000  415 >,
+			< 1574400000  810000  439 >,
+			< 1651200000  820000  465 >,
+			< 1728000000  835000  493 >,
+			< 1804800000  850000  521 >,
+			< 1881600000  865000  549 >,
+			< 1958400000  880000  579 >,
+			< 2035200000  895000  608 >,
+			< 2112000000  910000  638 >,
+			< 2150400000  925000  667 >,
+			< 2188800000  925000  667 >,
+			< 2265600000  940000  700 >,
+			< 2342400000  955000  734 >,
+			< 2419200000  970000  769 >,
+			< 2457600000  975000  785 >;
+
+		qcom,speed3-pvs6-bin-v0 =
+			<          0       0    0 >,
+			<  300000000  750000   76 >,
+			<  345600000  750000   87 >,
+			<  422400000  750000  106 >,
+			<  499200000  750000  125 >,
+			<  576000000  750000  145 >,
+			<  652800000  750000  165 >,
+			<  729600000  750000  186 >,
+			<  806400000  750000  208 >,
+			<  883200000  750000  229 >,
+			<  960000000  750000  251 >,
+			< 1036800000  750000  273 >,
+			< 1113600000  750000  296 >,
+			< 1190400000  750000  319 >,
+			< 1267200000  755000  342 >,
+			< 1344000000  765000  365 >,
+			< 1420800000  775000  390 >,
+			< 1497600000  785000  415 >,
+			< 1574400000  795000  439 >,
+			< 1651200000  805000  465 >,
+			< 1728000000  815000  493 >,
+			< 1804800000  825000  521 >,
+			< 1881600000  840000  549 >,
+			< 1958400000  855000  579 >,
+			< 2035200000  870000  608 >,
+			< 2112000000  885000  638 >,
+			< 2150400000  900000  667 >,
+			< 2188800000  900000  667 >,
+			< 2265600000  915000  700 >,
+			< 2342400000  930000  734 >,
+			< 2419200000  945000  769 >,
+			< 2457600000  950000  785 >;
+
+		qcom,speed1-pvs0-bin-v1 =
+			<          0       0    0 >,
+			<  300000000  800000   76 >,
+			<  345600000  810000   87 >,
+			<  422400000  820000  108 >,
+			<  499200000  830000  129 >,
+			<  576000000  840000  150 >,
+			<  652800000  850000  171 >,
+			<  729600000  860000  193 >,
+			<  806400000  870000  215 >,
+			<  883200000  880000  237 >,
+			<  960000000  890000  260 >,
+			< 1036800000  900000  282 >,
+			< 1113600000  910000  306 >,
+			< 1190400000  920000  330 >,
+			< 1267200000  930000  354 >,
+			< 1344000000  940000  378 >,
+			< 1420800000  955000  404 >,
+			< 1497600000  970000  431 >,
+			< 1574400000  985000  458 >,
+			< 1651200000 1000000  486 >,
+			< 1728000000 1015000  515 >,
+			< 1804800000 1030000  543 >,
+			< 1881600000 1045000  572 >,
+			< 1958400000 1060000  604 >,
+			< 2035200000 1075000  636 >,
+			< 2112000000 1090000  669 >,
+			< 2150400000 1105000  703 >,
+			< 2188800000 1105000  703 >,
+			< 2265600000 1120000  738 >;
+
+		qcom,speed1-pvs1-bin-v1 =
+			<          0       0    0 >,
+			<  300000000  800000   76 >,
+			<  345600000  800000   87 >,
+			<  422400000  810000  108 >,
+			<  499200000  820000  129 >,
+			<  576000000  830000  150 >,
+			<  652800000  840000  171 >,
+			<  729600000  850000  193 >,
+			<  806400000  860000  215 >,
+			<  883200000  870000  237 >,
+			<  960000000  880000  260 >,
+			< 1036800000  890000  282 >,
+			< 1113600000  900000  306 >,
+			< 1190400000  910000  330 >,
+			< 1267200000  920000  354 >,
+			< 1344000000  930000  378 >,
+			< 1420800000  945000  404 >,
+			< 1497600000  960000  431 >,
+			< 1574400000  975000  458 >,
+			< 1651200000  990000  486 >,
+			< 1728000000 1005000  515 >,
+			< 1804800000 1020000  543 >,
+			< 1881600000 1035000  572 >,
+			< 1958400000 1050000  604 >,
+			< 2035200000 1065000  636 >,
+			< 2112000000 1080000  669 >,
+			< 2150400000 1095000  703 >,
+			< 2188800000 1095000  703 >,
+			< 2265600000 1110000  738 >;
+
+		qcom,speed1-pvs2-bin-v1 =
+			<          0       0    0 >,
+			<  300000000  800000   76 >,
+			<  345600000  800000   87 >,
+			<  422400000  800000  108 >,
+			<  499200000  810000  129 >,
+			<  576000000  820000  150 >,
+			<  652800000  830000  171 >,
+			<  729600000  840000  193 >,
+			<  806400000  850000  215 >,
+			<  883200000  860000  237 >,
+			<  960000000  870000  260 >,
+			< 1036800000  880000  282 >,
+			< 1113600000  890000  306 >,
+			< 1190400000  900000  330 >,
+			< 1267200000  910000  354 >,
+			< 1344000000  920000  378 >,
+			< 1420800000  935000  404 >,
+			< 1497600000  950000  431 >,
+			< 1574400000  965000  458 >,
+			< 1651200000  980000  486 >,
+			< 1728000000  995000  515 >,
+			< 1804800000 1010000  543 >,
+			< 1881600000 1025000  572 >,
+			< 1958400000 1040000  604 >,
+			< 2035200000 1055000  636 >,
+			< 2112000000 1070000  669 >,
+			< 2150400000 1085000  703 >,
+			< 2188800000 1085000  703 >,
+			< 2265600000 1100000  738 >;
+
+		qcom,speed1-pvs3-bin-v1 =
+			<          0       0    0 >,
+			<  300000000  800000   76 >,
+			<  345600000  800000   87 >,
+			<  422400000  800000  108 >,
+			<  499200000  800000  129 >,
+			<  576000000  810000  150 >,
+			<  652800000  820000  171 >,
+			<  729600000  830000  193 >,
+			<  806400000  840000  215 >,
+			<  883200000  850000  237 >,
+			<  960000000  860000  260 >,
+			< 1036800000  870000  282 >,
+			< 1113600000  880000  306 >,
+			< 1190400000  890000  330 >,
+			< 1267200000  900000  354 >,
+			< 1344000000  910000  378 >,
+			< 1420800000  925000  404 >,
+			< 1497600000  940000  431 >,
+			< 1574400000  955000  458 >,
+			< 1651200000  970000  486 >,
+			< 1728000000  985000  515 >,
+			< 1804800000 1000000  543 >,
+			< 1881600000 1015000  572 >,
+			< 1958400000 1030000  604 >,
+			< 2035200000 1045000  636 >,
+			< 2112000000 1060000  669 >,
+			< 2150400000 1075000  703 >,
+			< 2188800000 1075000  703 >,
+			< 2265600000 1090000  738 >;
+
+		qcom,speed1-pvs4-bin-v1 =
+			<          0       0    0 >,
+			<  300000000  800000   76 >,
+			<  345600000  800000   87 >,
+			<  422400000  800000  108 >,
+			<  499200000  800000  129 >,
+			<  576000000  800000  150 >,
+			<  652800000  810000  171 >,
+			<  729600000  820000  193 >,
+			<  806400000  830000  215 >,
+			<  883200000  840000  237 >,
+			<  960000000  850000  260 >,
+			< 1036800000  860000  282 >,
+			< 1113600000  870000  306 >,
+			< 1190400000  880000  330 >,
+			< 1267200000  890000  354 >,
+			< 1344000000  900000  378 >,
+			< 1420800000  915000  404 >,
+			< 1497600000  930000  431 >,
+			< 1574400000  945000  458 >,
+			< 1651200000  960000  486 >,
+			< 1728000000  975000  515 >,
+			< 1804800000  990000  543 >,
+			< 1881600000 1005000  572 >,
+			< 1958400000 1020000  604 >,
+			< 2035200000 1035000  636 >,
+			< 2112000000 1050000  669 >,
+			< 2150400000 1065000  703 >,
+			< 2188800000 1065000  703 >,
+			< 2265600000 1080000  738 >;
+
+		qcom,speed1-pvs5-bin-v1 =
+			<          0       0    0 >,
+			<  300000000  800000   76 >,
+			<  345600000  800000   87 >,
+			<  422400000  800000  108 >,
+			<  499200000  800000  129 >,
+			<  576000000  800000  150 >,
+			<  652800000  800000  171 >,
+			<  729600000  810000  193 >,
+			<  806400000  820000  215 >,
+			<  883200000  830000  237 >,
+			<  960000000  840000  260 >,
+			< 1036800000  850000  282 >,
+			< 1113600000  860000  306 >,
+			< 1190400000  870000  330 >,
+			< 1267200000  880000  354 >,
+			< 1344000000  890000  378 >,
+			< 1420800000  905000  404 >,
+			< 1497600000  920000  431 >,
+			< 1574400000  935000  458 >,
+			< 1651200000  950000  486 >,
+			< 1728000000  965000  515 >,
+			< 1804800000  980000  543 >,
+			< 1881600000  995000  572 >,
+			< 1958400000 1010000  604 >,
+			< 2035200000 1025000  636 >,
+			< 2112000000 1040000  669 >,
+			< 2150400000 1055000  703 >,
+			< 2188800000 1055000  703 >,
+			< 2265600000 1070000  738 >;
+
+		qcom,speed1-pvs6-bin-v1 =
+			<          0       0    0 >,
+			<  300000000  775000   76 >,
+			<  345600000  775000   87 >,
+			<  422400000  775000  108 >,
+			<  499200000  775000  129 >,
+			<  576000000  780000  150 >,
+			<  652800000  790000  171 >,
+			<  729600000  800000  193 >,
+			<  806400000  810000  215 >,
+			<  883200000  820000  237 >,
+			<  960000000  830000  260 >,
+			< 1036800000  840000  282 >,
+			< 1113600000  850000  306 >,
+			< 1190400000  860000  330 >,
+			< 1267200000  870000  354 >,
+			< 1344000000  880000  378 >,
+			< 1420800000  895000  404 >,
+			< 1497600000  910000  431 >,
+			< 1574400000  925000  458 >,
+			< 1651200000  940000  486 >,
+			< 1728000000  955000  515 >,
+			< 1804800000  970000  543 >,
+			< 1881600000  985000  572 >,
+			< 1958400000 1000000  604 >,
+			< 2035200000 1015000  636 >,
+			< 2112000000 1030000  669 >,
+			< 2150400000 1045000  703 >,
+			< 2188800000 1045000  703 >,
+			< 2265600000 1060000  738 >;
+
+		qcom,speed1-pvs7-bin-v1 =
+			<          0       0    0 >,
+			<  300000000  775000   76 >,
+			<  345600000  775000   87 >,
+			<  422400000  775000  108 >,
+			<  499200000  775000  129 >,
+			<  576000000  775000  150 >,
+			<  652800000  780000  171 >,
+			<  729600000  790000  193 >,
+			<  806400000  800000  215 >,
+			<  883200000  810000  237 >,
+			<  960000000  820000  260 >,
+			< 1036800000  830000  282 >,
+			< 1113600000  840000  306 >,
+			< 1190400000  850000  330 >,
+			< 1267200000  860000  354 >,
+			< 1344000000  870000  378 >,
+			< 1420800000  885000  404 >,
+			< 1497600000  900000  431 >,
+			< 1574400000  915000  458 >,
+			< 1651200000  930000  486 >,
+			< 1728000000  945000  515 >,
+			< 1804800000  960000  543 >,
+			< 1881600000  975000  572 >,
+			< 1958400000  990000  604 >,
+			< 2035200000 1005000  636 >,
+			< 2112000000 1020000  669 >,
+			< 2150400000 1035000  703 >,
+			< 2188800000 1035000  703 >,
+			< 2265600000 1050000  738 >;
+
+		qcom,speed1-pvs8-bin-v1 =
+			<          0       0    0 >,
+			<  300000000  775000   76 >,
+			<  345600000  775000   87 >,
+			<  422400000  775000  108 >,
+			<  499200000  775000  129 >,
+			<  576000000  775000  150 >,
+			<  652800000  775000  171 >,
+			<  729600000  780000  193 >,
+			<  806400000  790000  215 >,
+			<  883200000  800000  237 >,
+			<  960000000  810000  260 >,
+			< 1036800000  820000  282 >,
+			< 1113600000  830000  306 >,
+			< 1190400000  840000  330 >,
+			< 1267200000  850000  354 >,
+			< 1344000000  860000  378 >,
+			< 1420800000  875000  404 >,
+			< 1497600000  890000  431 >,
+			< 1574400000  905000  458 >,
+			< 1651200000  920000  486 >,
+			< 1728000000  935000  515 >,
+			< 1804800000  950000  543 >,
+			< 1881600000  965000  572 >,
+			< 1958400000  980000  604 >,
+			< 2035200000  995000  636 >,
+			< 2112000000 1010000  669 >,
+			< 2150400000 1025000  703 >,
+			< 2188800000 1025000  703 >,
+			< 2265600000 1040000  738 >;
+
+		qcom,speed1-pvs9-bin-v1 =
+			<          0       0    0 >,
+			<  300000000  775000   76 >,
+			<  345600000  775000   87 >,
+			<  422400000  775000  108 >,
+			<  499200000  775000  129 >,
+			<  576000000  775000  150 >,
+			<  652800000  775000  171 >,
+			<  729600000  775000  193 >,
+			<  806400000  780000  215 >,
+			<  883200000  790000  237 >,
+			<  960000000  800000  260 >,
+			< 1036800000  810000  282 >,
+			< 1113600000  820000  306 >,
+			< 1190400000  830000  330 >,
+			< 1267200000  840000  354 >,
+			< 1344000000  850000  378 >,
+			< 1420800000  865000  404 >,
+			< 1497600000  880000  431 >,
+			< 1574400000  895000  458 >,
+			< 1651200000  910000  486 >,
+			< 1728000000  925000  515 >,
+			< 1804800000  940000  543 >,
+			< 1881600000  955000  572 >,
+			< 1958400000  970000  604 >,
+			< 2035200000  985000  636 >,
+			< 2112000000 1000000  669 >,
+			< 2150400000 1015000  703 >,
+			< 2188800000 1015000  703 >,
+			< 2265600000 1030000  738 >;
+
+		qcom,speed1-pvs10-bin-v1 =
+			<          0       0    0 >,
+			<  300000000  775000   76 >,
+			<  345600000  775000   87 >,
+			<  422400000  775000  108 >,
+			<  499200000  775000  129 >,
+			<  576000000  775000  150 >,
+			<  652800000  775000  171 >,
+			<  729600000  775000  193 >,
+			<  806400000  775000  215 >,
+			<  883200000  780000  237 >,
+			<  960000000  790000  260 >,
+			< 1036800000  800000  282 >,
+			< 1113600000  810000  306 >,
+			< 1190400000  820000  330 >,
+			< 1267200000  830000  354 >,
+			< 1344000000  840000  378 >,
+			< 1420800000  855000  404 >,
+			< 1497600000  870000  431 >,
+			< 1574400000  885000  458 >,
+			< 1651200000  900000  486 >,
+			< 1728000000  915000  515 >,
+			< 1804800000  930000  543 >,
+			< 1881600000  945000  572 >,
+			< 1958400000  960000  604 >,
+			< 2035200000  975000  636 >,
+			< 2112000000  990000  669 >,
+			< 2150400000 1005000  703 >,
+			< 2188800000 1005000  703 >,
+			< 2265600000 1020000  738 >;
+
+		qcom,speed1-pvs11-bin-v1 =
+			<          0       0    0 >,
+			<  300000000  775000   76 >,
+			<  345600000  775000   87 >,
+			<  422400000  775000  108 >,
+			<  499200000  775000  129 >,
+			<  576000000  775000  150 >,
+			<  652800000  775000  171 >,
+			<  729600000  775000  193 >,
+			<  806400000  775000  215 >,
+			<  883200000  775000  237 >,
+			<  960000000  780000  260 >,
+			< 1036800000  790000  282 >,
+			< 1113600000  800000  306 >,
+			< 1190400000  810000  330 >,
+			< 1267200000  820000  354 >,
+			< 1344000000  830000  378 >,
+			< 1420800000  845000  404 >,
+			< 1497600000  860000  431 >,
+			< 1574400000  875000  458 >,
+			< 1651200000  890000  486 >,
+			< 1728000000  905000  515 >,
+			< 1804800000  920000  543 >,
+			< 1881600000  935000  572 >,
+			< 1958400000  950000  604 >,
+			< 2035200000  965000  636 >,
+			< 2112000000  980000  669 >,
+			< 2150400000  995000  703 >,
+			< 2188800000  995000  703 >,
+			< 2265600000 1010000  738 >;
+
+		qcom,speed1-pvs12-bin-v1 =
+			<          0       0    0 >,
+			<  300000000  775000   76 >,
+			<  345600000  775000   87 >,
+			<  422400000  775000  108 >,
+			<  499200000  775000  129 >,
+			<  576000000  775000  150 >,
+			<  652800000  775000  171 >,
+			<  729600000  775000  193 >,
+			<  806400000  775000  215 >,
+			<  883200000  775000  237 >,
+			<  960000000  775000  260 >,
+			< 1036800000  780000  282 >,
+			< 1113600000  790000  306 >,
+			< 1190400000  800000  330 >,
+			< 1267200000  810000  354 >,
+			< 1344000000  820000  378 >,
+			< 1420800000  835000  404 >,
+			< 1497600000  850000  431 >,
+			< 1574400000  865000  458 >,
+			< 1651200000  880000  486 >,
+			< 1728000000  895000  515 >,
+			< 1804800000  910000  543 >,
+			< 1881600000  925000  572 >,
+			< 1958400000  940000  604 >,
+			< 2035200000  955000  636 >,
+			< 2112000000  970000  669 >,
+			< 2150400000  985000  703 >,
+			< 2188800000  985000  703 >,
+			< 2265600000 1000000  738 >;
+
+		qcom,speed1-pvs13-bin-v1 =
+			<          0       0    0 >,
+			<  300000000  775000   76 >,
+			<  345600000  775000   87 >,
+			<  422400000  775000  108 >,
+			<  499200000  775000  129 >,
+			<  576000000  775000  150 >,
+			<  652800000  775000  171 >,
+			<  729600000  775000  193 >,
+			<  806400000  775000  215 >,
+			<  883200000  775000  237 >,
+			<  960000000  775000  260 >,
+			< 1036800000  775000  282 >,
+			< 1113600000  780000  306 >,
+			< 1190400000  790000  330 >,
+			< 1267200000  800000  354 >,
+			< 1344000000  810000  378 >,
+			< 1420800000  825000  404 >,
+			< 1497600000  840000  431 >,
+			< 1574400000  855000  458 >,
+			< 1651200000  870000  486 >,
+			< 1728000000  885000  515 >,
+			< 1804800000  900000  543 >,
+			< 1881600000  915000  572 >,
+			< 1958400000  930000  604 >,
+			< 2035200000  945000  636 >,
+			< 2112000000  960000  669 >,
+			< 2150400000  975000  703 >,
+			< 2188800000  975000  703 >,
+			< 2265600000  990000  738 >;
+
+		qcom,speed1-pvs14-bin-v1 =
+			<          0       0    0 >,
+			<  300000000  750000   76 >,
+			<  345600000  750000   87 >,
+			<  422400000  750000  108 >,
+			<  499200000  750000  129 >,
+			<  576000000  750000  150 >,
+			<  652800000  750000  171 >,
+			<  729600000  750000  193 >,
+			<  806400000  750000  215 >,
+			<  883200000  750000  237 >,
+			<  960000000  750000  260 >,
+			< 1036800000  760000  282 >,
+			< 1113600000  770000  306 >,
+			< 1190400000  780000  330 >,
+			< 1267200000  790000  354 >,
+			< 1344000000  800000  378 >,
+			< 1420800000  815000  404 >,
+			< 1497600000  830000  431 >,
+			< 1574400000  845000  458 >,
+			< 1651200000  860000  486 >,
+			< 1728000000  875000  515 >,
+			< 1804800000  890000  543 >,
+			< 1881600000  905000  572 >,
+			< 1958400000  920000  604 >,
+			< 2035200000  935000  636 >,
+			< 2112000000  950000  669 >,
+			< 2150400000  965000  703 >,
+			< 2188800000  965000  703 >,
+			< 2265600000  980000  738 >;
+
+		qcom,speed1-pvs15-bin-v1 =
+			<          0       0    0 >,
+			<  300000000  750000   76 >,
+			<  345600000  750000   87 >,
+			<  422400000  750000  108 >,
+			<  499200000  750000  129 >,
+			<  576000000  750000  150 >,
+			<  652800000  750000  171 >,
+			<  729600000  750000  193 >,
+			<  806400000  750000  215 >,
+			<  883200000  750000  237 >,
+			<  960000000  750000  260 >,
+			< 1036800000  750000  282 >,
+			< 1113600000  760000  306 >,
+			< 1190400000  770000  330 >,
+			< 1267200000  780000  354 >,
+			< 1344000000  790000  378 >,
+			< 1420800000  805000  404 >,
+			< 1497600000  820000  431 >,
+			< 1574400000  835000  458 >,
+			< 1651200000  850000  486 >,
+			< 1728000000  865000  515 >,
+			< 1804800000  880000  543 >,
+			< 1881600000  895000  572 >,
+			< 1958400000  910000  604 >,
+			< 2035200000  925000  636 >,
+			< 2112000000  940000  669 >,
+			< 2150400000  955000  703 >,
+			< 2188800000  955000  703 >,
+			< 2265600000  970000  738 >;
+
+		qcom,speed3-pvs0-bin-v1 =
+			<          0       0    0 >,
+			<  300000000  800000   76 >,
+			<  345600000  800000   87 >,
+			<  422400000  800000  106 >,
+			<  499200000  810000  126 >,
+			<  576000000  820000  147 >,
+			<  652800000  830000  168 >,
+			<  729600000  840000  189 >,
+			<  806400000  850000  211 >,
+			<  883200000  860000  233 >,
+			<  960000000  870000  256 >,
+			< 1036800000  880000  278 >,
+			< 1113600000  890000  301 >,
+			< 1190400000  900000  324 >,
+			< 1267200000  910000  348 >,
+			< 1344000000  920000  372 >,
+			< 1420800000  930000  396 >,
+			< 1497600000  940000  421 >,
+			< 1574400000  950000  446 >,
+			< 1651200000  965000  473 >,
+			< 1728000000  980000  501 >,
+			< 1804800000  995000  529 >,
+			< 1881600000 1010000  558 >,
+			< 1958400000 1025000  588 >,
+			< 2035200000 1040000  617 >,
+			< 2112000000 1055000  649 >,
+			< 2150400000 1070000  682 >,
+			< 2188800000 1070000  682 >,
+			< 2265600000 1085000  716 >,
+			< 2342400000 1100000  751 >,
+			< 2419200000 1115000  786 >,
+			< 2457600000 1120000  802 >;
+
+		qcom,speed3-pvs1-bin-v1 =
+			<          0       0    0 >,
+			<  300000000  800000   76 >,
+			<  345600000  800000   87 >,
+			<  422400000  800000  106 >,
+			<  499200000  800000  126 >,
+			<  576000000  810000  147 >,
+			<  652800000  820000  168 >,
+			<  729600000  830000  189 >,
+			<  806400000  840000  211 >,
+			<  883200000  850000  233 >,
+			<  960000000  860000  256 >,
+			< 1036800000  870000  278 >,
+			< 1113600000  880000  301 >,
+			< 1190400000  890000  324 >,
+			< 1267200000  900000  348 >,
+			< 1344000000  910000  372 >,
+			< 1420800000  920000  396 >,
+			< 1497600000  930000  421 >,
+			< 1574400000  940000  446 >,
+			< 1651200000  955000  473 >,
+			< 1728000000  970000  501 >,
+			< 1804800000  985000  529 >,
+			< 1881600000 1000000  558 >,
+			< 1958400000 1015000  588 >,
+			< 2035200000 1030000  617 >,
+			< 2112000000 1045000  649 >,
+			< 2150400000 1060000  682 >,
+			< 2188800000 1060000  682 >,
+			< 2265600000 1075000  716 >,
+			< 2342400000 1090000  751 >,
+			< 2419200000 1105000  786 >,
+			< 2457600000 1110000  802 >;
+
+		qcom,speed3-pvs2-bin-v1 =
+			<          0       0    0 >,
+			<  300000000  800000   76 >,
+			<  345600000  800000   87 >,
+			<  422400000  800000  106 >,
+			<  499200000  800000  126 >,
+			<  576000000  800000  147 >,
+			<  652800000  810000  168 >,
+			<  729600000  820000  189 >,
+			<  806400000  830000  211 >,
+			<  883200000  840000  233 >,
+			<  960000000  850000  256 >,
+			< 1036800000  860000  278 >,
+			< 1113600000  870000  301 >,
+			< 1190400000  880000  324 >,
+			< 1267200000  890000  348 >,
+			< 1344000000  900000  372 >,
+			< 1420800000  910000  396 >,
+			< 1497600000  920000  421 >,
+			< 1574400000  930000  446 >,
+			< 1651200000  945000  473 >,
+			< 1728000000  960000  501 >,
+			< 1804800000  975000  529 >,
+			< 1881600000  990000  558 >,
+			< 1958400000 1005000  588 >,
+			< 2035200000 1020000  617 >,
+			< 2112000000 1035000  649 >,
+			< 2150400000 1050000  682 >,
+			< 2188800000 1050000  682 >,
+			< 2265600000 1065000  716 >,
+			< 2342400000 1080000  751 >,
+			< 2419200000 1095000  786 >,
+			< 2457600000 1100000  802 >;
+
+		qcom,speed3-pvs3-bin-v1 =
+			<          0       0    0 >,
+			<  300000000  800000   76 >,
+			<  345600000  800000   87 >,
+			<  422400000  800000  106 >,
+			<  499200000  800000  126 >,
+			<  576000000  800000  147 >,
+			<  652800000  800000  168 >,
+			<  729600000  810000  189 >,
+			<  806400000  820000  211 >,
+			<  883200000  830000  233 >,
+			<  960000000  840000  256 >,
+			< 1036800000  850000  278 >,
+			< 1113600000  860000  301 >,
+			< 1190400000  870000  324 >,
+			< 1267200000  880000  348 >,
+			< 1344000000  890000  372 >,
+			< 1420800000  900000  396 >,
+			< 1497600000  910000  421 >,
+			< 1574400000  920000  446 >,
+			< 1651200000  935000  473 >,
+			< 1728000000  950000  501 >,
+			< 1804800000  965000  529 >,
+			< 1881600000  980000  558 >,
+			< 1958400000  995000  588 >,
+			< 2035200000 1010000  617 >,
+			< 2112000000 1025000  649 >,
+			< 2150400000 1040000  682 >,
+			< 2188800000 1040000  682 >,
+			< 2265600000 1055000  716 >,
+			< 2342400000 1070000  751 >,
+			< 2419200000 1085000  786 >,
+			< 2457600000 1090000  802 >;
+
+		qcom,speed3-pvs4-bin-v1 =
+			<          0       0    0 >,
+			<  300000000  800000   76 >,
+			<  345600000  800000   87 >,
+			<  422400000  800000  106 >,
+			<  499200000  800000  126 >,
+			<  576000000  800000  147 >,
+			<  652800000  800000  168 >,
+			<  729600000  800000  189 >,
+			<  806400000  810000  211 >,
+			<  883200000  820000  233 >,
+			<  960000000  830000  256 >,
+			< 1036800000  840000  278 >,
+			< 1113600000  850000  301 >,
+			< 1190400000  860000  324 >,
+			< 1267200000  870000  348 >,
+			< 1344000000  880000  372 >,
+			< 1420800000  890000  396 >,
+			< 1497600000  900000  421 >,
+			< 1574400000  910000  446 >,
+			< 1651200000  925000  473 >,
+			< 1728000000  940000  501 >,
+			< 1804800000  955000  529 >,
+			< 1881600000  970000  558 >,
+			< 1958400000  985000  588 >,
+			< 2035200000 1000000  617 >,
+			< 2112000000 1015000  649 >,
+			< 2150400000 1030000  682 >,
+			< 2188800000 1030000  682 >,
+			< 2265600000 1045000  716 >,
+			< 2342400000 1060000  751 >,
+			< 2419200000 1075000  786 >,
+			< 2457600000 1080000  802 >;
+
+		qcom,speed3-pvs5-bin-v1 =
+			<          0       0    0 >,
+			<  300000000  800000   76 >,
+			<  345600000  800000   87 >,
+			<  422400000  800000  106 >,
+			<  499200000  800000  126 >,
+			<  576000000  800000  147 >,
+			<  652800000  800000  168 >,
+			<  729600000  800000  189 >,
+			<  806400000  800000  211 >,
+			<  883200000  810000  233 >,
+			<  960000000  820000  256 >,
+			< 1036800000  830000  278 >,
+			< 1113600000  840000  301 >,
+			< 1190400000  850000  324 >,
+			< 1267200000  860000  348 >,
+			< 1344000000  870000  372 >,
+			< 1420800000  880000  396 >,
+			< 1497600000  890000  421 >,
+			< 1574400000  900000  446 >,
+			< 1651200000  915000  473 >,
+			< 1728000000  930000  501 >,
+			< 1804800000  945000  529 >,
+			< 1881600000  960000  558 >,
+			< 1958400000  975000  588 >,
+			< 2035200000  990000  617 >,
+			< 2112000000 1005000  649 >,
+			< 2150400000 1020000  682 >,
+			< 2188800000 1020000  682 >,
+			< 2265600000 1035000  716 >,
+			< 2342400000 1050000  751 >,
+			< 2419200000 1065000  786 >,
+			< 2457600000 1070000  802 >;
+
+		qcom,speed3-pvs6-bin-v1 =
+			<          0       0    0 >,
+			<  300000000  775000   76 >,
+			<  345600000  775000   87 >,
+			<  422400000  775000  106 >,
+			<  499200000  775000  126 >,
+			<  576000000  775000  147 >,
+			<  652800000  775000  168 >,
+			<  729600000  780000  189 >,
+			<  806400000  790000  211 >,
+			<  883200000  800000  233 >,
+			<  960000000  810000  256 >,
+			< 1036800000  820000  278 >,
+			< 1113600000  830000  301 >,
+			< 1190400000  840000  324 >,
+			< 1267200000  850000  348 >,
+			< 1344000000  860000  372 >,
+			< 1420800000  870000  396 >,
+			< 1497600000  880000  421 >,
+			< 1574400000  890000  446 >,
+			< 1651200000  905000  473 >,
+			< 1728000000  920000  501 >,
+			< 1804800000  935000  529 >,
+			< 1881600000  950000  558 >,
+			< 1958400000  965000  588 >,
+			< 2035200000  980000  617 >,
+			< 2112000000  995000  649 >,
+			< 2150400000 1010000  682 >,
+			< 2188800000 1010000  682 >,
+			< 2265600000 1025000  716 >,
+			< 2342400000 1040000  751 >,
+			< 2419200000 1055000  786 >,
+			< 2457600000 1060000  802 >;
+
+		qcom,speed3-pvs7-bin-v1 =
+			<          0       0    0 >,
+			<  300000000  775000   76 >,
+			<  345600000  775000   87 >,
+			<  422400000  775000  106 >,
+			<  499200000  775000  126 >,
+			<  576000000  775000  147 >,
+			<  652800000  775000  168 >,
+			<  729600000  775000  189 >,
+			<  806400000  780000  211 >,
+			<  883200000  790000  233 >,
+			<  960000000  800000  256 >,
+			< 1036800000  810000  278 >,
+			< 1113600000  820000  301 >,
+			< 1190400000  830000  324 >,
+			< 1267200000  840000  348 >,
+			< 1344000000  850000  372 >,
+			< 1420800000  860000  396 >,
+			< 1497600000  870000  421 >,
+			< 1574400000  880000  446 >,
+			< 1651200000  895000  473 >,
+			< 1728000000  910000  501 >,
+			< 1804800000  925000  529 >,
+			< 1881600000  940000  558 >,
+			< 1958400000  955000  588 >,
+			< 2035200000  970000  617 >,
+			< 2112000000  985000  649 >,
+			< 2150400000 1000000  682 >,
+			< 2188800000 1000000  682 >,
+			< 2265600000 1015000  716 >,
+			< 2342400000 1030000  751 >,
+			< 2419200000 1045000  786 >,
+			< 2457600000 1050000  802 >;
+
+		qcom,speed3-pvs8-bin-v1 =
+			<          0       0    0 >,
+			<  300000000  775000   76 >,
+			<  345600000  775000   87 >,
+			<  422400000  775000  106 >,
+			<  499200000  775000  126 >,
+			<  576000000  775000  147 >,
+			<  652800000  775000  168 >,
+			<  729600000  775000  189 >,
+			<  806400000  775000  211 >,
+			<  883200000  780000  233 >,
+			<  960000000  790000  256 >,
+			< 1036800000  800000  278 >,
+			< 1113600000  810000  301 >,
+			< 1190400000  820000  324 >,
+			< 1267200000  830000  348 >,
+			< 1344000000  840000  372 >,
+			< 1420800000  850000  396 >,
+			< 1497600000  860000  421 >,
+			< 1574400000  870000  446 >,
+			< 1651200000  885000  473 >,
+			< 1728000000  900000  501 >,
+			< 1804800000  915000  529 >,
+			< 1881600000  930000  558 >,
+			< 1958400000  945000  588 >,
+			< 2035200000  960000  617 >,
+			< 2112000000  975000  649 >,
+			< 2150400000  990000  682 >,
+			< 2188800000  990000  682 >,
+			< 2265600000 1005000  716 >,
+			< 2342400000 1020000  751 >,
+			< 2419200000 1035000  786 >,
+			< 2457600000 1040000  802 >;
+
+		qcom,speed3-pvs9-bin-v1 =
+			<          0       0    0 >,
+			<  300000000  775000   76 >,
+			<  345600000  775000   87 >,
+			<  422400000  775000  106 >,
+			<  499200000  775000  126 >,
+			<  576000000  775000  147 >,
+			<  652800000  775000  168 >,
+			<  729600000  775000  189 >,
+			<  806400000  775000  211 >,
+			<  883200000  775000  233 >,
+			<  960000000  780000  256 >,
+			< 1036800000  790000  278 >,
+			< 1113600000  800000  301 >,
+			< 1190400000  810000  324 >,
+			< 1267200000  820000  348 >,
+			< 1344000000  830000  372 >,
+			< 1420800000  840000  396 >,
+			< 1497600000  850000  421 >,
+			< 1574400000  860000  446 >,
+			< 1651200000  875000  473 >,
+			< 1728000000  890000  501 >,
+			< 1804800000  905000  529 >,
+			< 1881600000  920000  558 >,
+			< 1958400000  935000  588 >,
+			< 2035200000  950000  617 >,
+			< 2112000000  965000  649 >,
+			< 2150400000  980000  682 >,
+			< 2188800000  980000  682 >,
+			< 2265600000  995000  716 >,
+			< 2342400000 1010000  751 >,
+			< 2419200000 1025000  786 >,
+			< 2457600000 1030000  802 >;
+
+		qcom,speed3-pvs10-bin-v1 =
+			<          0       0    0 >,
+			<  300000000  775000   76 >,
+			<  345600000  775000   87 >,
+			<  422400000  775000  106 >,
+			<  499200000  775000  126 >,
+			<  576000000  775000  147 >,
+			<  652800000  775000  168 >,
+			<  729600000  775000  189 >,
+			<  806400000  775000  211 >,
+			<  883200000  775000  233 >,
+			<  960000000  775000  256 >,
+			< 1036800000  780000  278 >,
+			< 1113600000  790000  301 >,
+			< 1190400000  800000  324 >,
+			< 1267200000  810000  348 >,
+			< 1344000000  820000  372 >,
+			< 1420800000  830000  396 >,
+			< 1497600000  840000  421 >,
+			< 1574400000  850000  446 >,
+			< 1651200000  865000  473 >,
+			< 1728000000  880000  501 >,
+			< 1804800000  895000  529 >,
+			< 1881600000  910000  558 >,
+			< 1958400000  925000  588 >,
+			< 2035200000  940000  617 >,
+			< 2112000000  955000  649 >,
+			< 2150400000  970000  682 >,
+			< 2188800000  970000  682 >,
+			< 2265600000  985000  716 >,
+			< 2342400000 1000000  751 >,
+			< 2419200000 1015000  786 >,
+			< 2457600000 1020000  802 >;
+
+		qcom,speed3-pvs11-bin-v1 =
+			<          0       0    0 >,
+			<  300000000  775000   76 >,
+			<  345600000  775000   87 >,
+			<  422400000  775000  106 >,
+			<  499200000  775000  126 >,
+			<  576000000  775000  147 >,
+			<  652800000  775000  168 >,
+			<  729600000  775000  189 >,
+			<  806400000  775000  211 >,
+			<  883200000  775000  233 >,
+			<  960000000  775000  256 >,
+			< 1036800000  775000  278 >,
+			< 1113600000  780000  301 >,
+			< 1190400000  790000  324 >,
+			< 1267200000  800000  348 >,
+			< 1344000000  810000  372 >,
+			< 1420800000  820000  396 >,
+			< 1497600000  830000  421 >,
+			< 1574400000  840000  446 >,
+			< 1651200000  855000  473 >,
+			< 1728000000  870000  501 >,
+			< 1804800000  885000  529 >,
+			< 1881600000  900000  558 >,
+			< 1958400000  915000  588 >,
+			< 2035200000  930000  617 >,
+			< 2112000000  945000  649 >,
+			< 2150400000  960000  682 >,
+			< 2188800000  960000  682 >,
+			< 2265600000  975000  716 >,
+			< 2342400000  990000  751 >,
+			< 2419200000 1005000  786 >,
+			< 2457600000 1010000  802 >;
+
+		qcom,speed3-pvs12-bin-v1 =
+			<          0       0    0 >,
+			<  300000000  775000   76 >,
+			<  345600000  775000   87 >,
+			<  422400000  775000  106 >,
+			<  499200000  775000  126 >,
+			<  576000000  775000  147 >,
+			<  652800000  775000  168 >,
+			<  729600000  775000  189 >,
+			<  806400000  775000  211 >,
+			<  883200000  775000  233 >,
+			<  960000000  775000  256 >,
+			< 1036800000  775000  278 >,
+			< 1113600000  775000  301 >,
+			< 1190400000  780000  324 >,
+			< 1267200000  790000  348 >,
+			< 1344000000  800000  372 >,
+			< 1420800000  810000  396 >,
+			< 1497600000  820000  421 >,
+			< 1574400000  830000  446 >,
+			< 1651200000  845000  473 >,
+			< 1728000000  860000  501 >,
+			< 1804800000  875000  529 >,
+			< 1881600000  890000  558 >,
+			< 1958400000  905000  588 >,
+			< 2035200000  920000  617 >,
+			< 2112000000  935000  649 >,
+			< 2150400000  950000  682 >,
+			< 2188800000  950000  682 >,
+			< 2265600000  965000  716 >,
+			< 2342400000  980000  751 >,
+			< 2419200000  995000  786 >,
+			< 2457600000 1000000  802 >;
+
+		qcom,speed3-pvs13-bin-v1 =
+			<          0       0    0 >,
+			<  300000000  775000   76 >,
+			<  345600000  775000   87 >,
+			<  422400000  775000  106 >,
+			<  499200000  775000  126 >,
+			<  576000000  775000  147 >,
+			<  652800000  775000  168 >,
+			<  729600000  775000  189 >,
+			<  806400000  775000  211 >,
+			<  883200000  775000  233 >,
+			<  960000000  775000  256 >,
+			< 1036800000  775000  278 >,
+			< 1113600000  775000  301 >,
+			< 1190400000  775000  324 >,
+			< 1267200000  780000  348 >,
+			< 1344000000  790000  372 >,
+			< 1420800000  800000  396 >,
+			< 1497600000  810000  421 >,
+			< 1574400000  820000  446 >,
+			< 1651200000  835000  473 >,
+			< 1728000000  850000  501 >,
+			< 1804800000  865000  529 >,
+			< 1881600000  880000  558 >,
+			< 1958400000  895000  588 >,
+			< 2035200000  910000  617 >,
+			< 2112000000  925000  649 >,
+			< 2150400000  940000  682 >,
+			< 2188800000  940000  682 >,
+			< 2265600000  955000  716 >,
+			< 2342400000  970000  751 >,
+			< 2419200000  985000  786 >,
+			< 2457600000  990000  802 >;
+
+		qcom,speed3-pvs14-bin-v1 =
+			<          0       0    0 >,
+			<  300000000  750000   76 >,
+			<  345600000  750000   87 >,
+			<  422400000  750000  106 >,
+			<  499200000  750000  126 >,
+			<  576000000  750000  147 >,
+			<  652800000  750000  168 >,
+			<  729600000  750000  189 >,
+			<  806400000  750000  211 >,
+			<  883200000  750000  233 >,
+			<  960000000  750000  256 >,
+			< 1036800000  750000  278 >,
+			< 1113600000  750000  301 >,
+			< 1190400000  760000  324 >,
+			< 1267200000  770000  348 >,
+			< 1344000000  780000  372 >,
+			< 1420800000  790000  396 >,
+			< 1497600000  800000  421 >,
+			< 1574400000  810000  446 >,
+			< 1651200000  825000  473 >,
+			< 1728000000  840000  501 >,
+			< 1804800000  855000  529 >,
+			< 1881600000  870000  558 >,
+			< 1958400000  885000  588 >,
+			< 2035200000  900000  617 >,
+			< 2112000000  915000  649 >,
+			< 2150400000  930000  682 >,
+			< 2188800000  930000  682 >,
+			< 2265600000  945000  716 >,
+			< 2342400000  960000  751 >,
+			< 2419200000  975000  786 >,
+			< 2457600000  980000  802 >;
+
+		qcom,speed3-pvs15-bin-v1 =
+			<          0       0    0 >,
+			<  300000000  750000   76 >,
+			<  345600000  750000   87 >,
+			<  422400000  750000  106 >,
+			<  499200000  750000  126 >,
+			<  576000000  750000  147 >,
+			<  652800000  750000  168 >,
+			<  729600000  750000  189 >,
+			<  806400000  750000  211 >,
+			<  883200000  750000  233 >,
+			<  960000000  750000  256 >,
+			< 1036800000  750000  278 >,
+			< 1113600000  750000  301 >,
+			< 1190400000  750000  324 >,
+			< 1267200000  760000  348 >,
+			< 1344000000  770000  372 >,
+			< 1420800000  780000  396 >,
+			< 1497600000  790000  421 >,
+			< 1574400000  800000  446 >,
+			< 1651200000  815000  473 >,
+			< 1728000000  830000  501 >,
+			< 1804800000  845000  529 >,
+			< 1881600000  860000  558 >,
+			< 1958400000  875000  588 >,
+			< 2035200000  890000  617 >,
+			< 2112000000  905000  649 >,
+			< 2150400000  920000  682 >,
+			< 2188800000  920000  682 >,
+			< 2265600000  935000  716 >,
+			< 2342400000  950000  751 >,
+			< 2419200000  965000  786 >,
+			< 2457600000  970000  802 >;
+	};
+
+	qcom,msm-cpufreq@0 {
+		qcom,cpufreq-table =
+			<  300000  300000  600 /*  75 MHz */ >,
+			<  422400  422400 1200 /* 150 MHz */ >,
+			<  652800  499200 1600 /* 200 MHz */ >,
+			<  729600  576000 2456 /* 307 MHz */ >,
+			<  883200  576000 2456 /* 307 MHz */ >,
+			<  960000  960000 3680 /* 460 MHz */ >,
+			< 1036800 1036800 3680 /* 460 MHz */ >,
+			< 1190400 1036800 3680 /* 460 MHz */ >,
+			< 1267200 1267200 4912 /* 614 MHz */ >,
+			< 1497600 1497600 4912 /* 614 MHz */ >,
+			< 1574400 1574400 6400 /* 800 MHz */ >,
+			< 1728000 1651200 6400 /* 800 MHz */ >,
+			< 1958400 1728000 7448 /* 931 MHz */ >,
+			< 2265600 1728000 7448 /* 931 MHz */ >,
+			< 2457600 1728000 7448 /* 931 MHz */ >;
+	};
 };
 
 /* GPU overrides */
@@ -48,20 +1575,29 @@
 
 	qcom,initial-pwrlevel = <6>;
 
+	qcom,msm-bus,num-cases = <10>;
 	/* Updated bus bandwidth requirements */
 	qcom,msm-bus,vectors-KBps =
 		/* Off */
 		<26 512 0 0>, <89 604 0 0>,
 		/* SVS */
-		<26 512 0 2400000>, <89 604 0 3000000>,
+		<26 512 0 2400000>, <89 604 0 3200000>,
 		/* Nominal / SVS */
-		<26 512 0 4656000>, <89 604 0 3000000>,
-		/* Nominal */
-		<26 512 0 4656000>, <89 604 0 5120000>,
-		/* Turbo / Nominal */
-		<26 512 0 7464000>, <89 604 0 5120000>,
+		<26 512 0 3680000>, <89 604 0 3200000>,
+		/* Nominal / Nominal */
+		<26 512 0 3680000>, <89 604 0 5280000>,
+		/* Nominal / Nominal */
+		<26 512 0 4912000>, <89 604 0 5280000>,
+		/* Nominal / Turbo */
+		<26 512 0 4912000>, <89 604 0 6224000>,
+		/* Turbo / Turbo */
+		<26 512 0 7464000>, <89 604 0 6224000>,
+		/* Nominal / Turbo */
+		<26 512 0 4912000>, <89 604 0 7400000>,
 		/* Turbo */
-		<26 512 0 7464000>, <89 604 0 6400000>;
+		<26 512 0 7464000>, <89 604 0 7400000>,
+		/* Turbo */
+		<26 512 0 7464000>, <89 604 0 9248000>;
 
        qcom,gpu-pwrlevels {
                #address-cells = <1>;
@@ -72,35 +1608,35 @@
                qcom,gpu-pwrlevel@0 {
                        reg = <0>;
                        qcom,gpu-freq = <578000000>;
-                       qcom,bus-freq = <5>;
+                       qcom,bus-freq = <9>;
                        qcom,io-fraction = <33>;
                };
 
 		qcom,gpu-pwrlevel@1 {
 			reg = <1>;
 			qcom,gpu-freq = <462400000>;
-			qcom,bus-freq = <4>;
+			qcom,bus-freq = <8>;
 			qcom,io-fraction = <33>;
 		};
 
 		qcom,gpu-pwrlevel@2 {
 			reg = <2>;
 			qcom,gpu-freq = <462400000>;
-			qcom,bus-freq = <3>;
+			qcom,bus-freq = <7>;
 			qcom,io-fraction = <66>;
 		};
 
 		qcom,gpu-pwrlevel@3 {
 			reg = <3>;
 			qcom,gpu-freq = <389000000>;
-			qcom,bus-freq = <4>;
+			qcom,bus-freq = <6>;
 			qcom,io-fraction = <66>;
 		};
 
 		qcom,gpu-pwrlevel@4 {
 			reg = <4>;
 			qcom,gpu-freq = <389000000>;
-			qcom,bus-freq = <3>;
+			qcom,bus-freq = <5>;
 			qcom,io-fraction = <66>;
 		};
 
diff --git a/arch/arm/configs/apq8084_defconfig b/arch/arm/configs/apq8084_defconfig
index 7c1af1a..cda1e59 100644
--- a/arch/arm/configs/apq8084_defconfig
+++ b/arch/arm/configs/apq8084_defconfig
@@ -90,6 +90,7 @@
 CONFIG_AEABI=y
 CONFIG_HIGHMEM=y
 CONFIG_COMPACTION=y
+CONFIG_ENABLE_VMALLOC_SAVING=y
 CONFIG_CC_STACKPROTECTOR=y
 CONFIG_CP_ACCESS=y
 CONFIG_USE_OF=y
diff --git a/arch/arm/configs/msm8226-perf_defconfig b/arch/arm/configs/msm8226-perf_defconfig
index 265234b..818e052 100644
--- a/arch/arm/configs/msm8226-perf_defconfig
+++ b/arch/arm/configs/msm8226-perf_defconfig
@@ -25,6 +25,7 @@
 CONFIG_PANIC_TIMEOUT=5
 CONFIG_KALLSYMS_ALL=y
 CONFIG_EMBEDDED=y
+# CONFIG_SLUB_DEBUG is not set
 CONFIG_PROFILING=y
 CONFIG_OPROFILE=m
 CONFIG_KPROBES=y
@@ -81,6 +82,7 @@
 CONFIG_AEABI=y
 CONFIG_HIGHMEM=y
 CONFIG_COMPACTION=y
+CONFIG_ENABLE_VMALLOC_SAVING=y
 CONFIG_CC_STACKPROTECTOR=y
 CONFIG_CP_ACCESS=y
 CONFIG_USE_OF=y
diff --git a/arch/arm/configs/msm8226_defconfig b/arch/arm/configs/msm8226_defconfig
index 55627a3..c1f2ca2 100644
--- a/arch/arm/configs/msm8226_defconfig
+++ b/arch/arm/configs/msm8226_defconfig
@@ -82,6 +82,7 @@
 CONFIG_AEABI=y
 CONFIG_HIGHMEM=y
 CONFIG_COMPACTION=y
+CONFIG_ENABLE_VMALLOC_SAVING=y
 CONFIG_CC_STACKPROTECTOR=y
 CONFIG_CP_ACCESS=y
 CONFIG_USE_OF=y
diff --git a/arch/arm/configs/msm8610-perf_defconfig b/arch/arm/configs/msm8610-perf_defconfig
index 7ea1bd5..efdd8de 100644
--- a/arch/arm/configs/msm8610-perf_defconfig
+++ b/arch/arm/configs/msm8610-perf_defconfig
@@ -82,6 +82,7 @@
 CONFIG_HIGHMEM=y
 CONFIG_COMPACTION=y
 CONFIG_CC_STACKPROTECTOR=y
+CONFIG_ENABLE_VMALLOC_SAVING=y
 CONFIG_CP_ACCESS=y
 CONFIG_USE_OF=y
 CONFIG_CPU_FREQ_GOV_POWERSAVE=y
@@ -313,7 +314,6 @@
 CONFIG_MSM_KGSL=y
 CONFIG_KGSL_PER_PROCESS_PAGE_TABLE=y
 CONFIG_FB=y
-CONFIG_FB_VIRTUAL=y
 CONFIG_FB_MSM=y
 # CONFIG_FB_MSM_BACKLIGHT is not set
 CONFIG_FB_MSM_MDSS=y
diff --git a/arch/arm/configs/msm8610_defconfig b/arch/arm/configs/msm8610_defconfig
index 8e6f5f9..c140a46 100644
--- a/arch/arm/configs/msm8610_defconfig
+++ b/arch/arm/configs/msm8610_defconfig
@@ -83,6 +83,7 @@
 CONFIG_HIGHMEM=y
 CONFIG_COMPACTION=y
 CONFIG_CC_STACKPROTECTOR=y
+CONFIG_ENABLE_VMALLOC_SAVING=y
 CONFIG_CP_ACCESS=y
 CONFIG_USE_OF=y
 CONFIG_CPU_FREQ_GOV_POWERSAVE=y
diff --git a/arch/arm/kernel/signal.c b/arch/arm/kernel/signal.c
index e000e5e..edb73b4 100644
--- a/arch/arm/kernel/signal.c
+++ b/arch/arm/kernel/signal.c
@@ -440,12 +440,18 @@
 		 */
 		thumb = handler & 1;
 
+#if __LINUX_ARM_ARCH__ >= 7
+		/*
+		 * Clear the If-Then Thumb-2 execution state
+		 * ARM spec requires this to be all 000s in ARM mode
+		 * Snapdragon S4/Krait misbehaves on a Thumb=>ARM
+		 * signal transition without this.
+		 */
+		cpsr &= ~PSR_IT_MASK;
+#endif
+
 		if (thumb) {
 			cpsr |= PSR_T_BIT;
-#if __LINUX_ARM_ARCH__ >= 7
-			/* clear the If-Then Thumb-2 execution state */
-			cpsr &= ~PSR_IT_MASK;
-#endif
 		} else
 			cpsr &= ~PSR_T_BIT;
 	}
diff --git a/arch/arm/lib/memset.S b/arch/arm/lib/memset.S
index 650d592..94b0650 100644
--- a/arch/arm/lib/memset.S
+++ b/arch/arm/lib/memset.S
@@ -14,27 +14,15 @@
 
 	.text
 	.align	5
-	.word	0
-
-1:	subs	r2, r2, #4		@ 1 do we have enough
-	blt	5f			@ 1 bytes to align with?
-	cmp	r3, #2			@ 1
-	strltb	r1, [r0], #1		@ 1
-	strleb	r1, [r0], #1		@ 1
-	strb	r1, [r0], #1		@ 1
-	add	r2, r2, r3		@ 1 (r2 = r2 - (4 - r3))
-/*
- * The pointer is now aligned and the length is adjusted.  Try doing the
- * memset again.
- */
 
 ENTRY(memset)
 	ands	r3, r0, #3		@ 1 unaligned?
-	bne	1b			@ 1
+	mov	ip, r0			@ preserve r0 as return value
+	bne	6f			@ 1
 /*
- * we know that the pointer in r0 is aligned to a word boundary.
+ * we know that the pointer in ip is aligned to a word boundary.
  */
-	orr	r1, r1, r1, lsl #8
+1:	orr	r1, r1, r1, lsl #8
 	orr	r1, r1, r1, lsl #16
 	mov	r3, r1
 	cmp	r2, #16
@@ -43,29 +31,28 @@
 #if ! CALGN(1)+0
 
 /*
- * We need an extra register for this loop - save the return address and
- * use the LR
+ * We need 2 extra registers for this loop - use r8 and the LR
  */
-	str	lr, [sp, #-4]!
-	mov	ip, r1
+	stmfd	sp!, {r8, lr}
+	mov	r8, r1
 	mov	lr, r1
 
 2:	subs	r2, r2, #64
-	stmgeia	r0!, {r1, r3, ip, lr}	@ 64 bytes at a time.
-	stmgeia	r0!, {r1, r3, ip, lr}
-	stmgeia	r0!, {r1, r3, ip, lr}
-	stmgeia	r0!, {r1, r3, ip, lr}
+	stmgeia	ip!, {r1, r3, r8, lr}	@ 64 bytes at a time.
+	stmgeia	ip!, {r1, r3, r8, lr}
+	stmgeia	ip!, {r1, r3, r8, lr}
+	stmgeia	ip!, {r1, r3, r8, lr}
 	bgt	2b
-	ldmeqfd	sp!, {pc}		@ Now <64 bytes to go.
+	ldmeqfd	sp!, {r8, pc}		@ Now <64 bytes to go.
 /*
  * No need to correct the count; we're only testing bits from now on
  */
 	tst	r2, #32
-	stmneia	r0!, {r1, r3, ip, lr}
-	stmneia	r0!, {r1, r3, ip, lr}
+	stmneia	ip!, {r1, r3, r8, lr}
+	stmneia	ip!, {r1, r3, r8, lr}
 	tst	r2, #16
-	stmneia	r0!, {r1, r3, ip, lr}
-	ldr	lr, [sp], #4
+	stmneia	ip!, {r1, r3, r8, lr}
+	ldmfd	sp!, {r8, lr}
 
 #else
 
@@ -74,54 +61,63 @@
  * whole cache lines at once.
  */
 
-	stmfd	sp!, {r4-r7, lr}
+	stmfd	sp!, {r4-r8, lr}
 	mov	r4, r1
 	mov	r5, r1
 	mov	r6, r1
 	mov	r7, r1
-	mov	ip, r1
+	mov	r8, r1
 	mov	lr, r1
 
 	cmp	r2, #96
-	tstgt	r0, #31
+	tstgt	ip, #31
 	ble	3f
 
-	and	ip, r0, #31
-	rsb	ip, ip, #32
-	sub	r2, r2, ip
-	movs	ip, ip, lsl #(32 - 4)
-	stmcsia	r0!, {r4, r5, r6, r7}
-	stmmiia	r0!, {r4, r5}
-	tst	ip, #(1 << 30)
-	mov	ip, r1
-	strne	r1, [r0], #4
+	and	r8, ip, #31
+	rsb	r8, r8, #32
+	sub	r2, r2, r8
+	movs	r8, r8, lsl #(32 - 4)
+	stmcsia	ip!, {r4, r5, r6, r7}
+	stmmiia	ip!, {r4, r5}
+	tst	r8, #(1 << 30)
+	mov	r8, r1
+	strne	r1, [ip], #4
 
 3:	subs	r2, r2, #64
-	stmgeia	r0!, {r1, r3-r7, ip, lr}
-	stmgeia	r0!, {r1, r3-r7, ip, lr}
+	stmgeia	ip!, {r1, r3-r8, lr}
+	stmgeia	ip!, {r1, r3-r8, lr}
 	bgt	3b
-	ldmeqfd	sp!, {r4-r7, pc}
+	ldmeqfd	sp!, {r4-r8, pc}
 
 	tst	r2, #32
-	stmneia	r0!, {r1, r3-r7, ip, lr}
+	stmneia	ip!, {r1, r3-r8, lr}
 	tst	r2, #16
-	stmneia	r0!, {r4-r7}
-	ldmfd	sp!, {r4-r7, lr}
+	stmneia	ip!, {r4-r7}
+	ldmfd	sp!, {r4-r8, lr}
 
 #endif
 
 4:	tst	r2, #8
-	stmneia	r0!, {r1, r3}
+	stmneia	ip!, {r1, r3}
 	tst	r2, #4
-	strne	r1, [r0], #4
+	strne	r1, [ip], #4
 /*
  * When we get here, we've got less than 4 bytes to zero.  We
  * may have an unaligned pointer as well.
  */
 5:	tst	r2, #2
-	strneb	r1, [r0], #1
-	strneb	r1, [r0], #1
+	strneb	r1, [ip], #1
+	strneb	r1, [ip], #1
 	tst	r2, #1
-	strneb	r1, [r0], #1
+	strneb	r1, [ip], #1
 	mov	pc, lr
+
+6:	subs	r2, r2, #4		@ 1 do we have enough
+	blt	5b			@ 1 bytes to align with?
+	cmp	r3, #2			@ 1
+	strltb	r1, [ip], #1		@ 1
+	strleb	r1, [ip], #1		@ 1
+	strb	r1, [ip], #1		@ 1
+	add	r2, r2, r3		@ 1 (r2 = r2 - (4 - r3))
+	b	1b
 ENDPROC(memset)
diff --git a/arch/arm/mach-msm/Kconfig b/arch/arm/mach-msm/Kconfig
index 87c2f8c..a341c23 100644
--- a/arch/arm/mach-msm/Kconfig
+++ b/arch/arm/mach-msm/Kconfig
@@ -280,11 +280,11 @@
 	select MEMORY_HOLE_CARVEOUT
 	select MSM_RPM_STATS_LOG
 	select QMI_ENCDEC
-	select DONT_MAP_HOLE_AFTER_MEMBANK0
 	select MSM_ULTRASOUND_B
 	select MSM_RPM_LOG
 	select ARCH_WANT_KMAP_ATOMIC_FLUSH
 	select KRAIT_REGULATOR
+	select ENABLE_VMALLOC_SAVINGS
 
 config ARCH_APQ8084
 	bool "APQ8084"
@@ -305,12 +305,12 @@
 	select ARCH_DMA_ADDR_T_64BIT if ARM_LPAE
 	select ARCH_WANT_KMAP_ATOMIC_FLUSH
 	select MEMORY_HOLE_CARVEOUT
-	select DONT_MAP_HOLE_AFTER_MEMBANK0
 	select QMI_ENCDEC
 	select MSM_SPM_V2
 	select MSM_L2_SPM
 	select MSM_PM8X60 if PM
 	select MSM_RPM_SMD
+	select ENABLE_VMALLOC_SAVINGS
 
 config ARCH_MPQ8092
 	bool "MPQ8092"
@@ -460,7 +460,6 @@
 	select MSM_L2_SPM
 	select MSM_PM8X60 if PM
 	select MEMORY_HOLE_CARVEOUT
-	select DONT_MAP_HOLE_AFTER_MEMBANK0
 	select MSM_BUS_SCALING
 	select CPU_FREQ_MSM
 	select CPU_FREQ
@@ -475,6 +474,7 @@
 	select MSM_RPM_LOG
 	select MSM_IOMMU_SYNC
 	select MSM_RPM_STATS_LOG
+	select ENABLE_VMALLOC_SAVINGS
 
 config ARCH_MSM8226
 	bool "MSM8226"
@@ -500,7 +500,6 @@
 	select MSM_L2_SPM
 	select MSM_PM8X60 if PM
 	select MEMORY_HOLE_CARVEOUT
-	select DONT_MAP_HOLE_AFTER_MEMBANK0
 	select MSM_BUS_SCALING
 	select CPU_FREQ_MSM
 	select CPU_FREQ
@@ -515,6 +514,7 @@
 	select MSM_RPM_LOG
 	select MSM_RPM_STATS_LOG
 	select ARCH_WANT_KMAP_ATOMIC_FLUSH
+	select ENABLE_VMALLOC_SAVINGS
 
 config ARCH_MSMSAMARIUM
 	bool "MSMSAMARIUM"
diff --git a/arch/arm/mach-msm/Makefile b/arch/arm/mach-msm/Makefile
index c44dbc7..eacdcdf 100644
--- a/arch/arm/mach-msm/Makefile
+++ b/arch/arm/mach-msm/Makefile
@@ -161,7 +161,6 @@
 obj-$(CONFIG_MSM_AUDIO_QDSP6V2) += qdsp6v2/
 obj-$(CONFIG_MSM_HW3D) += hw3d.o
 obj-$(CONFIG_PM) += pm-boot.o
-obj-$(CONFIG_MSM_PM8X60) += pm-8x60.o pm-data.o
 obj-$(CONFIG_MSM_IDLE_STATS) += pm-stats.o
 obj-$(CONFIG_MSM_PM2) += pm2.o
 obj-$(CONFIG_MSM_NOPM) += no-pm.o
@@ -286,7 +285,7 @@
 obj-$(CONFIG_ARCH_APQ8084) += board-8084.o board-8084-gpiomux.o
 obj-$(CONFIG_ARCH_APQ8084) += clock-8084.o
 obj-$(CONFIG_ARCH_MSM8974) += board-8974.o board-8974-gpiomux.o
-obj-$(CONFIG_ARCH_MSM8974) += acpuclock-8974.o
+obj-$(CONFIG_ARCH_MSM8974) += acpuclock-8974.o clock-krait-8974.o
 obj-$(CONFIG_ARCH_MSM8974) += clock-local2.o clock-pll.o clock-8974.o clock-rpm.o clock-voter.o clock-mdss-8974.o
 obj-$(CONFIG_ARCH_MSM8974) += gdsc.o
 obj-$(CONFIG_ARCH_MSM9625) += gdsc.o
@@ -311,6 +310,8 @@
 obj-$(CONFIG_ARCH_MSM8610) += clock-dsi-8610.o
 obj-$(CONFIG_ARCH_MSMKRYPTON) += clock-local2.o clock-pll.o clock-krypton.o clock-rpm.o clock-voter.o
 
+obj-$(CONFIG_MSM_PM8X60) += pm-8x60.o pm-data.o
+
 obj-$(CONFIG_MACH_SAPPHIRE) += board-sapphire.o board-sapphire-gpio.o
 obj-$(CONFIG_MACH_SAPPHIRE) += board-sapphire-keypad.o board-sapphire-panel.o
 obj-$(CONFIG_MACH_SAPPHIRE) += board-sapphire-mmc.o board-sapphire-wifi.o
diff --git a/arch/arm/mach-msm/Makefile.boot b/arch/arm/mach-msm/Makefile.boot
index 552ed16..83c1d4c 100644
--- a/arch/arm/mach-msm/Makefile.boot
+++ b/arch/arm/mach-msm/Makefile.boot
@@ -99,28 +99,34 @@
 
 # MSM8226
    zreladdr-$(CONFIG_ARCH_MSM8226)	:= 0x00008000
-        dtb-$(CONFIG_ARCH_MSM8226)	+= msm8226-sim.dtb
-        dtb-$(CONFIG_ARCH_MSM8226)	+= msm8226-fluid.dtb
-        dtb-$(CONFIG_ARCH_MSM8226)	+= msm8226-v1-cdp.dtb
-        dtb-$(CONFIG_ARCH_MSM8226)	+= msm8226-v1-mtp.dtb
-        dtb-$(CONFIG_ARCH_MSM8226)	+= msm8226-v1-qrd-evt.dtb
-        dtb-$(CONFIG_ARCH_MSM8226)	+= msm8226-v1-qrd-dvt.dtb
-        dtb-$(CONFIG_ARCH_MSM8226)	+= msm8226-v2-cdp.dtb
-        dtb-$(CONFIG_ARCH_MSM8226)	+= msm8226-v2-mtp.dtb
-        dtb-$(CONFIG_ARCH_MSM8226)	+= msm8226-v2-qrd-evt.dtb
-        dtb-$(CONFIG_ARCH_MSM8226)	+= msm8226-v2-qrd-dvt.dtb
-        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
-        dtb-$(CONFIG_ARCH_MSM8226)	+= apq8026-v1-cdp.dtb
-        dtb-$(CONFIG_ARCH_MSM8226)	+= apq8026-v1-mtp.dtb
-        dtb-$(CONFIG_ARCH_MSM8226)	+= apq8026-v2-xpm.dtb
-        dtb-$(CONFIG_ARCH_MSM8226)	+= apq8026-v2-cdp.dtb
-        dtb-$(CONFIG_ARCH_MSM8226)	+= apq8026-v2-mtp.dtb
+	dtb-$(CONFIG_ARCH_MSM8226)	+= msm8226-sim.dtb
+	dtb-$(CONFIG_ARCH_MSM8226)	+= msm8226-fluid.dtb
+	dtb-$(CONFIG_ARCH_MSM8226)	+= msm8226-v1-cdp.dtb
+	dtb-$(CONFIG_ARCH_MSM8226)	+= msm8226-v1-mtp.dtb
+	dtb-$(CONFIG_ARCH_MSM8226)	+= msm8226-v1-qrd-evt.dtb
+	dtb-$(CONFIG_ARCH_MSM8226)	+= msm8226-v1-qrd-dvt.dtb
+	dtb-$(CONFIG_ARCH_MSM8226)	+= msm8226-v2-720p-cdp.dtb
+	dtb-$(CONFIG_ARCH_MSM8226)	+= msm8226-v2-1080p-cdp.dtb
+	dtb-$(CONFIG_ARCH_MSM8226)	+= msm8226-v2-720p-mtp.dtb
+	dtb-$(CONFIG_ARCH_MSM8226)	+= msm8226-v2-1080p-mtp.dtb
+	dtb-$(CONFIG_ARCH_MSM8226)	+= msm8226-v2-qrd-evt.dtb
+	dtb-$(CONFIG_ARCH_MSM8226)	+= msm8226-v2-qrd-dvt.dtb
+	dtb-$(CONFIG_ARCH_MSM8226)	+= msm8926-720p-cdp.dtb
+	dtb-$(CONFIG_ARCH_MSM8226)	+= msm8926-1080p-cdp.dtb
+	dtb-$(CONFIG_ARCH_MSM8226)	+= msm8926-720p-mtp.dtb
+	dtb-$(CONFIG_ARCH_MSM8226)	+= msm8926-1080p-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
+	dtb-$(CONFIG_ARCH_MSM8226)	+= apq8026-v1-cdp.dtb
+	dtb-$(CONFIG_ARCH_MSM8226)	+= apq8026-v1-mtp.dtb
+	dtb-$(CONFIG_ARCH_MSM8226)	+= apq8026-v2-xpm.dtb
+	dtb-$(CONFIG_ARCH_MSM8226)	+= apq8026-v2-720p-cdp.dtb
+	dtb-$(CONFIG_ARCH_MSM8226)	+= apq8026-v2-1080p-cdp.dtb
+	dtb-$(CONFIG_ARCH_MSM8226)	+= apq8026-v2-720p-mtp.dtb
+	dtb-$(CONFIG_ARCH_MSM8226)	+= apq8026-v2-1080p-mtp.dtb
 
 # FSM9XXX
    zreladdr-$(CONFIG_ARCH_FSM9XXX)	:= 0x10008000
diff --git a/arch/arm/mach-msm/acpuclock-8974.c b/arch/arm/mach-msm/acpuclock-8974.c
index 60be20a..5117949 100644
--- a/arch/arm/mach-msm/acpuclock-8974.c
+++ b/arch/arm/mach-msm/acpuclock-8974.c
@@ -95,159 +95,7 @@
 	},
 };
 
-static struct msm_bus_paths bw_level_tbl_v1[] __initdata = {
-	[0] =  BW_MBPS(600), /* At least  75 MHz on bus. */
-	[1] =  BW_MBPS(800), /* At least 100 MHz on bus. */
-	[2] = BW_MBPS(1200), /* At least 150 MHz on bus. */
-	[3] = BW_MBPS(1600), /* At least 200 MHz on bus. */
-	[4] = BW_MBPS(2224), /* At least 278 MHz on bus. */
-	[5] = BW_MBPS(3200), /* At least 400 MHz on bus. */
-	[6] = BW_MBPS(4448), /* At least 556 MHz on bus. */
-	[7] = BW_MBPS(6400), /* At least 800 MHz on bus. */
-};
-
-static struct l2_level l2_freq_tbl_v1[] __initdata = {
-	[0]  = { {  300000, PLL_0, 0,   0 }, LVL_LOW,   950000, 0 },
-	[1]  = { {  345600, HFPLL, 2,  36 }, LVL_NOM,   950000, 1 },
-	[2]  = { {  422400, HFPLL, 2,  44 }, LVL_NOM,   950000, 1 },
-	[3]  = { {  499200, HFPLL, 2,  52 }, LVL_NOM,   950000, 2 },
-	[4]  = { {  576000, HFPLL, 1,  30 }, LVL_NOM,   950000, 3 },
-	[5]  = { {  652800, HFPLL, 1,  34 }, LVL_NOM,   950000, 3 },
-	[6]  = { {  729600, HFPLL, 1,  38 }, LVL_NOM,   950000, 3 },
-	[7]  = { {  806400, HFPLL, 1,  42 }, LVL_HIGH, 1050000, 4 },
-	[8]  = { {  883200, HFPLL, 1,  46 }, LVL_HIGH, 1050000, 4 },
-	[9]  = { {  960000, HFPLL, 1,  50 }, LVL_HIGH, 1050000, 4 },
-	[10] = { { 1036800, HFPLL, 1,  54 }, LVL_HIGH, 1050000, 5 },
-	[11] = { { 1113600, HFPLL, 1,  58 }, LVL_HIGH, 1050000, 5 },
-	[12] = { { 1190400, HFPLL, 1,  62 }, LVL_HIGH, 1050000, 6 },
-	[13] = { { 1267200, HFPLL, 1,  66 }, LVL_HIGH, 1050000, 6 },
-	[14] = { { 1344000, HFPLL, 1,  70 }, LVL_HIGH, 1050000, 7 },
-	[15] = { { 1420800, HFPLL, 1,  74 }, LVL_HIGH, 1050000, 7 },
-	[16] = { { 1497600, HFPLL, 1,  78 }, LVL_HIGH, 1050000, 7 },
-	{ }
-};
-
-static struct acpu_level acpu_freq_tbl_v1_pvs0[] __initdata = {
-	{ 1, {  300000, PLL_0, 0,   0 }, L2(0),   825000,  73 },
-	{ 0, {  345600, HFPLL, 2,  36 }, L2(3),   825000,  85 },
-	{ 1, {  422400, HFPLL, 2,  44 }, L2(3),   825000, 104 },
-	{ 0, {  499200, HFPLL, 2,  52 }, L2(6),   825000, 124 },
-	{ 1, {  576000, HFPLL, 1,  30 }, L2(6),   825000, 144 },
-	{ 1, {  652800, HFPLL, 1,  34 }, L2(7),   825000, 165 },
-	{ 1, {  729600, HFPLL, 1,  38 }, L2(7),   825000, 186 },
-	{ 0, {  806400, HFPLL, 1,  42 }, L2(10),  835000, 208 },
-	{ 1, {  883200, HFPLL, 1,  46 }, L2(10),  845000, 229 },
-	{ 0, {  960000, HFPLL, 1,  50 }, L2(10),  860000, 252 },
-	{ 1, { 1036800, HFPLL, 1,  54 }, L2(10),  880000, 275 },
-	{ 0, { 1113600, HFPLL, 1,  58 }, L2(12),  905000, 298 },
-	{ 0, { 1190400, HFPLL, 1,  62 }, L2(12),  920000, 321 },
-	{ 0, { 1267200, HFPLL, 1,  66 }, L2(12),  940000, 346 },
-	{ 1, { 1344000, HFPLL, 1,  70 }, L2(12),  960000, 371 },
-	{ 0, { 1420800, HFPLL, 1,  74 }, L2(16),  980000, 397 },
-	{ 0, { 1497600, HFPLL, 1,  78 }, L2(16),  995000, 423 },
-	{ 0, { 1574400, HFPLL, 1,  82 }, L2(16), 1015000, 450 },
-	{ 0, { 1651200, HFPLL, 1,  86 }, L2(16), 1030000, 477 },
-	{ 1, { 1728000, HFPLL, 1,  90 }, L2(16), 1050000, 506 },
-	{ 0, { 0 } }
-};
-
-static struct acpu_level acpu_freq_tbl_v1_pvs1[] __initdata = {
-	{ 1, {  300000, PLL_0, 0,   0 }, L2(0),   825000,  73 },
-	{ 0, {  345600, HFPLL, 2,  36 }, L2(3),   825000,  85 },
-	{ 1, {  422400, HFPLL, 2,  44 }, L2(3),   825000, 104 },
-	{ 0, {  499200, HFPLL, 2,  52 }, L2(6),   825000, 124 },
-	{ 1, {  576000, HFPLL, 1,  30 }, L2(6),   825000, 144 },
-	{ 1, {  652800, HFPLL, 1,  34 }, L2(7),   825000, 165 },
-	{ 1, {  729600, HFPLL, 1,  38 }, L2(7),   825000, 186 },
-	{ 0, {  806400, HFPLL, 1,  42 }, L2(10),  835000, 208 },
-	{ 1, {  883200, HFPLL, 1,  46 }, L2(10),  845000, 229 },
-	{ 0, {  960000, HFPLL, 1,  50 }, L2(10),  860000, 252 },
-	{ 1, { 1036800, HFPLL, 1,  54 }, L2(10),  880000, 275 },
-	{ 0, { 1113600, HFPLL, 1,  58 }, L2(12),  905000, 298 },
-	{ 0, { 1190400, HFPLL, 1,  62 }, L2(12),  920000, 321 },
-	{ 0, { 1267200, HFPLL, 1,  66 }, L2(12),  940000, 346 },
-	{ 1, { 1344000, HFPLL, 1,  70 }, L2(12),  960000, 371 },
-	{ 0, { 1420800, HFPLL, 1,  74 }, L2(16),  980000, 397 },
-	{ 0, { 1497600, HFPLL, 1,  78 }, L2(16),  995000, 423 },
-	{ 0, { 1574400, HFPLL, 1,  82 }, L2(16), 1015000, 450 },
-	{ 0, { 1651200, HFPLL, 1,  86 }, L2(16), 1030000, 477 },
-	{ 1, { 1728000, HFPLL, 1,  90 }, L2(16), 1050000, 506 },
-	{ 0, { 0 } }
-};
-
-static struct acpu_level acpu_freq_tbl_v1_pvs2[] __initdata = {
-	{ 1, {  300000, PLL_0, 0,   0 }, L2(0),   825000,  73 },
-	{ 0, {  345600, HFPLL, 2,  36 }, L2(3),   825000,  85 },
-	{ 1, {  422400, HFPLL, 2,  44 }, L2(3),   825000, 104 },
-	{ 0, {  499200, HFPLL, 2,  52 }, L2(6),   825000, 124 },
-	{ 1, {  576000, HFPLL, 1,  30 }, L2(6),   825000, 144 },
-	{ 1, {  652800, HFPLL, 1,  34 }, L2(7),   825000, 165 },
-	{ 1, {  729600, HFPLL, 1,  38 }, L2(7),   825000, 186 },
-	{ 0, {  806400, HFPLL, 1,  42 }, L2(10),  825000, 208 },
-	{ 1, {  883200, HFPLL, 1,  46 }, L2(10),  825000, 229 },
-	{ 0, {  960000, HFPLL, 1,  50 }, L2(10),  835000, 252 },
-	{ 1, { 1036800, HFPLL, 1,  54 }, L2(10),  855000, 275 },
-	{ 0, { 1113600, HFPLL, 1,  58 }, L2(12),  875000, 298 },
-	{ 0, { 1190400, HFPLL, 1,  62 }, L2(12),  895000, 321 },
-	{ 0, { 1267200, HFPLL, 1,  66 }, L2(12),  915000, 346 },
-	{ 1, { 1344000, HFPLL, 1,  70 }, L2(12),  930000, 371 },
-	{ 0, { 1420800, HFPLL, 1,  74 }, L2(16),  945000, 397 },
-	{ 0, { 1497600, HFPLL, 1,  78 }, L2(16),  960000, 423 },
-	{ 0, { 1574400, HFPLL, 1,  82 }, L2(16),  975000, 450 },
-	{ 0, { 1651200, HFPLL, 1,  86 }, L2(16),  990000, 477 },
-	{ 1, { 1728000, HFPLL, 1,  90 }, L2(16), 1000000, 506 },
-	{ 0, { 0 } }
-};
-
-static struct acpu_level acpu_freq_tbl_v1_pvs3[] __initdata = {
-	{ 1, {  300000, PLL_0, 0,   0 }, L2(0),   825000,  73 },
-	{ 0, {  345600, HFPLL, 2,  36 }, L2(3),   825000,  85 },
-	{ 1, {  422400, HFPLL, 2,  44 }, L2(3),   825000, 104 },
-	{ 0, {  499200, HFPLL, 2,  52 }, L2(6),   825000, 124 },
-	{ 1, {  576000, HFPLL, 1,  30 }, L2(6),   825000, 144 },
-	{ 1, {  652800, HFPLL, 1,  34 }, L2(7),   825000, 165 },
-	{ 1, {  729600, HFPLL, 1,  38 }, L2(7),   825000, 186 },
-	{ 0, {  806400, HFPLL, 1,  42 }, L2(10),  825000, 208 },
-	{ 1, {  883200, HFPLL, 1,  46 }, L2(10),  825000, 229 },
-	{ 0, {  960000, HFPLL, 1,  50 }, L2(10),  835000, 252 },
-	{ 1, { 1036800, HFPLL, 1,  54 }, L2(10),  855000, 275 },
-	{ 0, { 1113600, HFPLL, 1,  58 }, L2(12),  875000, 298 },
-	{ 0, { 1190400, HFPLL, 1,  62 }, L2(12),  895000, 321 },
-	{ 0, { 1267200, HFPLL, 1,  66 }, L2(12),  915000, 346 },
-	{ 1, { 1344000, HFPLL, 1,  70 }, L2(12),  930000, 371 },
-	{ 0, { 1420800, HFPLL, 1,  74 }, L2(16),  945000, 397 },
-	{ 0, { 1497600, HFPLL, 1,  78 }, L2(16),  960000, 423 },
-	{ 0, { 1574400, HFPLL, 1,  82 }, L2(16),  975000, 450 },
-	{ 0, { 1651200, HFPLL, 1,  86 }, L2(16),  990000, 477 },
-	{ 1, { 1728000, HFPLL, 1,  90 }, L2(16), 1000000, 506 },
-	{ 0, { 0 } }
-};
-
-static struct acpu_level acpu_freq_tbl_v1_pvs4[] __initdata = {
-	{ 1, {  300000, PLL_0, 0,   0 }, L2(0),  825000,  73 },
-	{ 0, {  345600, HFPLL, 2,  36 }, L2(3),  825000,  85 },
-	{ 1, {  422400, HFPLL, 2,  44 }, L2(3),  825000, 104 },
-	{ 0, {  499200, HFPLL, 2,  52 }, L2(6),  825000, 124 },
-	{ 1, {  576000, HFPLL, 1,  30 }, L2(6),  825000, 144 },
-	{ 1, {  652800, HFPLL, 1,  34 }, L2(7),  825000, 165 },
-	{ 1, {  729600, HFPLL, 1,  38 }, L2(7),  825000, 186 },
-	{ 0, {  806400, HFPLL, 1,  42 }, L2(10), 825000, 208 },
-	{ 1, {  883200, HFPLL, 1,  46 }, L2(10), 825000, 229 },
-	{ 0, {  960000, HFPLL, 1,  50 }, L2(10), 825000, 252 },
-	{ 1, { 1036800, HFPLL, 1,  54 }, L2(10), 825000, 275 },
-	{ 0, { 1113600, HFPLL, 1,  58 }, L2(12), 835000, 298 },
-	{ 0, { 1190400, HFPLL, 1,  62 }, L2(12), 855000, 321 },
-	{ 0, { 1267200, HFPLL, 1,  66 }, L2(12), 870000, 346 },
-	{ 1, { 1344000, HFPLL, 1,  70 }, L2(12), 885000, 371 },
-	{ 0, { 1420800, HFPLL, 1,  74 }, L2(16), 900000, 397 },
-	{ 0, { 1497600, HFPLL, 1,  78 }, L2(16), 910000, 423 },
-	{ 0, { 1574400, HFPLL, 1,  82 }, L2(16), 925000, 450 },
-	{ 0, { 1651200, HFPLL, 1,  86 }, L2(16), 940000, 477 },
-	{ 1, { 1728000, HFPLL, 1,  90 }, L2(16), 950000, 506 },
-	{ 0, { 0 } }
-};
-
-static struct msm_bus_paths bw_level_tbl_v2[] __initdata = {
+static struct msm_bus_paths bw_level_tbl[] __initdata = {
 	[0] =  BW_MBPS(600), /* At least  75 MHz on bus. */
 	[1] =  BW_MBPS(800), /* At least 100 MHz on bus. */
 	[2] = BW_MBPS(1200), /* At least 150 MHz on bus. */
@@ -259,7 +107,7 @@
 	[8] = BW_MBPS(7448), /* At least 931 MHz on bus. */
 };
 
-static struct l2_level l2_freq_tbl_v2[] __initdata = {
+static struct l2_level l2_freq_tbl[] __initdata = {
 	[0]  = { {  300000, PLL_0, 0,   0 }, LVL_LOW,   950000, 0 },
 	[1]  = { {  345600, HFPLL, 2,  36 }, LVL_LOW,   950000, 1 },
 	[2]  = { {  422400, HFPLL, 2,  44 }, LVL_LOW,   950000, 2 },
@@ -2440,15 +2288,6 @@
 	{ 0, { 0 } }
 };
 
-static struct pvs_table pvs_v1[NUM_PVS_REVS][NUM_SPEED_BINS][NUM_PVS] __initdata = {
-	/* 8974v1 1.7GHz Parts */
-	[0][0][0] = { acpu_freq_tbl_v1_pvs0, sizeof(acpu_freq_tbl_v1_pvs0) },
-	[0][0][1] = { acpu_freq_tbl_v1_pvs1, sizeof(acpu_freq_tbl_v1_pvs1) },
-	[0][0][2] = { acpu_freq_tbl_v1_pvs2, sizeof(acpu_freq_tbl_v1_pvs2) },
-	[0][0][3] = { acpu_freq_tbl_v1_pvs3, sizeof(acpu_freq_tbl_v1_pvs3) },
-	[0][0][4] = { acpu_freq_tbl_v1_pvs4, sizeof(acpu_freq_tbl_v1_pvs4) },
-};
-
 static struct pvs_table pvs_v2[NUM_PVS_REVS][NUM_SPEED_BINS][NUM_PVS] __initdata = {
 	/* 8974v2 2.0GHz Parts */
 	[0][0][0] = { acpu_freq_tbl_2g_pvs0, sizeof(acpu_freq_tbl_2g_pvs0) },
@@ -2560,8 +2399,8 @@
 };
 
 static struct msm_bus_scale_pdata bus_scale_data __initdata = {
-	.usecase = bw_level_tbl_v2,
-	.num_usecases = ARRAY_SIZE(bw_level_tbl_v2),
+	.usecase = bw_level_tbl,
+	.num_usecases = ARRAY_SIZE(bw_level_tbl),
 	.active_only = 1,
 	.name = "acpuclk-8974",
 };
@@ -2570,68 +2409,23 @@
 	.scalable = scalable,
 	.scalable_size = sizeof(scalable),
 	.hfpll_data = &hfpll_data,
-	.pvs_tables = pvs_v2,
-	.l2_freq_tbl = l2_freq_tbl_v2,
-	.l2_freq_tbl_size = sizeof(l2_freq_tbl_v2),
+	.l2_freq_tbl = l2_freq_tbl,
+	.l2_freq_tbl_size = sizeof(l2_freq_tbl),
 	.bus_scale = &bus_scale_data,
 	.pte_efuse_phys = 0xFC4B80B0,
 	.get_bin_info = get_krait_bin_format_b,
 	.stby_khz = 300000,
 };
 
-static void __init apply_pro_bringup_workaround(void)
-{
-	acpuclk_8974_params.pvs_tables = pvs_pro;
-}
-
-static void __init apply_v1_l2_workaround(void)
-{
-	static struct l2_level resticted_l2_tbl[] __initdata = {
-		[0] = { {  300000, PLL_0, 0,   0 }, LVL_LOW,  1050000, 0 },
-		[1] = { { 1497600, HFPLL, 1,  78 }, LVL_HIGH, 1050000, 7 },
-		{ }
-	};
-	struct acpu_level *l;
-	int s, p, r;
-
-	for (r = 0; r < NUM_PVS_REVS; r++)
-		for (s = 0; s < NUM_SPEED_BINS; s++)
-			for (p = 0; p < NUM_PVS; p++) {
-				l = pvs_v1[r][s][p].table;
-				for (; l && l->speed.khz; l++)
-					l->l2_level = l->l2_level > 5 ? 1 : 0;
-			}
-
-	acpuclk_8974_params.l2_freq_tbl = resticted_l2_tbl;
-	acpuclk_8974_params.l2_freq_tbl_size = sizeof(resticted_l2_tbl);
-}
-
 #define cpu_is_msm8974pro() (cpu_is_msm8974pro_aa() || cpu_is_msm8974pro_ab() \
 			     || cpu_is_msm8974pro_ac())
 
 static int __init acpuclk_8974_probe(struct platform_device *pdev)
 {
-	if (SOCINFO_VERSION_MAJOR(socinfo_get_version()) == 1
-	    && cpu_is_msm8974()) {
-		acpuclk_8974_params.pvs_tables = pvs_v1;
-		acpuclk_8974_params.l2_freq_tbl = l2_freq_tbl_v1;
-		bus_scale_data.usecase = bw_level_tbl_v1;
-		bus_scale_data.num_usecases = ARRAY_SIZE(bw_level_tbl_v1);
-		acpuclk_8974_params.l2_freq_tbl_size = sizeof(l2_freq_tbl_v1);
-
-		/*
-		 * 8974 hardware revisions older than v1.2 may experience L2
-		 * parity errors when running at some performance points between
-		 * 300MHz and 1497.6MHz (non-inclusive), or when vdd_mx is less
-		 * than 1.05V. Restrict L2 operation to safe performance points
-		 * on these devices.
-		 */
-		if (SOCINFO_VERSION_MINOR(socinfo_get_version()) < 2)
-			apply_v1_l2_workaround();
-	}
-
 	if (cpu_is_msm8974pro())
-		apply_pro_bringup_workaround();
+		acpuclk_8974_params.pvs_tables = pvs_pro;
+	else
+		acpuclk_8974_params.pvs_tables = pvs_v2;
 
 	return acpuclk_krait_init(&pdev->dev, &acpuclk_8974_params);
 }
diff --git a/arch/arm/mach-msm/board-8226-gpiomux.c b/arch/arm/mach-msm/board-8226-gpiomux.c
index 4dcbc3a..9767746 100644
--- a/arch/arm/mach-msm/board-8226-gpiomux.c
+++ b/arch/arm/mach-msm/board-8226-gpiomux.c
@@ -185,7 +185,14 @@
 
 static struct msm_gpiomux_config msm_lcd_configs[] __initdata = {
 	{
-		.gpio = 25,
+		.gpio = 25,		/* LCD Reset */
+		.settings = {
+			[GPIOMUX_ACTIVE]    = &lcd_rst_act_cfg,
+			[GPIOMUX_SUSPENDED] = &lcd_rst_sus_cfg,
+		},
+	},
+	{
+		.gpio = 109,		/* LCD Enable */
 		.settings = {
 			[GPIOMUX_ACTIVE]    = &lcd_rst_act_cfg,
 			[GPIOMUX_SUSPENDED] = &lcd_rst_sus_cfg,
@@ -303,13 +310,13 @@
 
 static struct gpiomux_setting goodix_ldo_en_sus_cfg = {
 	.func = GPIOMUX_FUNC_GPIO,
-	.drv = GPIOMUX_DRV_6MA,
-	.pull = GPIOMUX_PULL_UP,
+	.drv = GPIOMUX_DRV_2MA,
+	.pull = GPIOMUX_PULL_DOWN,
 };
 
 static struct gpiomux_setting goodix_int_act_cfg = {
 	.func = GPIOMUX_FUNC_GPIO,
-	.drv = GPIOMUX_DRV_8MA,
+	.drv = GPIOMUX_DRV_6MA,
 	.pull = GPIOMUX_PULL_UP,
 };
 
@@ -321,14 +328,14 @@
 
 static struct gpiomux_setting goodix_reset_act_cfg = {
 	.func = GPIOMUX_FUNC_GPIO,
-	.drv = GPIOMUX_DRV_8MA,
+	.drv = GPIOMUX_DRV_6MA,
 	.pull = GPIOMUX_PULL_UP,
 };
 
 static struct gpiomux_setting goodix_reset_sus_cfg = {
 	.func = GPIOMUX_FUNC_GPIO,
-	.drv = GPIOMUX_DRV_8MA,
-	.pull = GPIOMUX_PULL_UP,
+	.drv = GPIOMUX_DRV_2MA,
+	.pull = GPIOMUX_PULL_DOWN,
 };
 
 static struct msm_gpiomux_config msm_skuf_blsp_configs[] __initdata = {
diff --git a/arch/arm/mach-msm/board-8226.c b/arch/arm/mach-msm/board-8226.c
index aff2d75..5244918 100644
--- a/arch/arm/mach-msm/board-8226.c
+++ b/arch/arm/mach-msm/board-8226.c
@@ -82,6 +82,8 @@
 			"msm_sdcc.2", NULL),
 	OF_DEV_AUXDATA("qcom,sdhci-msm", 0xF9864900, \
 			"msm_sdcc.3", NULL),
+	OF_DEV_AUXDATA("qcom,hsic-host", 0xF9A00000, "msm_hsic_host", NULL),
+
 	{}
 };
 
diff --git a/arch/arm/mach-msm/clock-8610.c b/arch/arm/mach-msm/clock-8610.c
index 45a6b89..665c040 100644
--- a/arch/arm/mach-msm/clock-8610.c
+++ b/arch/arm/mach-msm/clock-8610.c
@@ -24,6 +24,7 @@
 #include <mach/rpm-regulator-smd.h>
 #include <mach/socinfo.h>
 #include <mach/rpm-smd.h>
+#include <mach/clock-generic.h>
 
 #include "clock-local2.h"
 #include "clock-pll.h"
@@ -2018,111 +2019,111 @@
 	},
 };
 
-static struct cam_mux_clk csi0phy_cam_mux_clk = {
-	.enable_reg = MMSS_CAMSS_MISC,
-	.enable_mask = BIT(11),
-	.select_reg = MMSS_CAMSS_MISC,
-	.select_mask = BIT(9),
-	.sources = (struct mux_source[]) {
-		{ &csi0phy_clk.c,     0 },
-		{ &csi1phy_clk.c, BIT(9) },
-		{ 0 },
-	},
+static struct mux_clk csi0phy_cam_mux_clk = {
+	.ops = &mux_reg_ops,
+	.en_mask = BIT(11),
+	.mask = 0x1,
+	.shift = 9,
+	.offset = MMSS_CAMSS_MISC,
+	MUX_SRC_LIST(
+		{ &csi0phy_clk.c, 0 },
+		{ &csi1phy_clk.c, 1 },
+	),
 	.base = &virt_bases[MMSS_BASE],
 	.c = {
 		.dbg_name = "csi0phy_cam_mux_clk",
-		.ops = &clk_ops_cam_mux,
+		.ops = &clk_ops_gen_mux,
 		CLK_INIT(csi0phy_cam_mux_clk.c),
 	},
 };
 
-static struct cam_mux_clk csi1phy_cam_mux_clk = {
-	.enable_reg = MMSS_CAMSS_MISC,
-	.enable_mask = BIT(10),
-	.select_reg = MMSS_CAMSS_MISC,
-	.select_mask = BIT(8),
-	.sources = (struct mux_source[]) {
-		{ &csi0phy_clk.c,     0 },
-		{ &csi1phy_clk.c, BIT(8) },
-		{ 0 },
-	},
+static struct mux_clk csi1phy_cam_mux_clk = {
+	.ops = &mux_reg_ops,
+	.en_mask = BIT(10),
+	.mask = 0x1,
+	.shift = 8,
+	.offset = MMSS_CAMSS_MISC,
+	MUX_SRC_LIST(
+		{ &csi0phy_clk.c, 0 },
+		{ &csi1phy_clk.c, 1 },
+	),
 	.base = &virt_bases[MMSS_BASE],
 	.c = {
 		.dbg_name = "csi1phy_cam_mux_clk",
-		.ops = &clk_ops_cam_mux,
+		.ops = &clk_ops_gen_mux,
 		CLK_INIT(csi1phy_cam_mux_clk.c),
 	},
 };
 
-static struct cam_mux_clk csi0pix_cam_mux_clk = {
-	.enable_reg = MMSS_CAMSS_MISC,
-	.enable_mask = BIT(7),
-	.select_reg = MMSS_CAMSS_MISC,
-	.select_mask = BIT(3),
-	.sources = (struct mux_source[]) {
-		{ &csi0pix_clk.c,      0 },
-		{ &csi1pix_clk.c, BIT(3) },
-		{ 0 },
-	},
+static struct mux_clk csi0pix_cam_mux_clk = {
+	.ops = &mux_reg_ops,
+	.en_mask = BIT(7),
+	.mask = 0x1,
+	.shift = 3,
+	.offset = MMSS_CAMSS_MISC,
+	MUX_SRC_LIST(
+		{ &csi0pix_clk.c, 0 },
+		{ &csi1pix_clk.c, 1 },
+	),
 	.base = &virt_bases[MMSS_BASE],
 	.c = {
 		.dbg_name = "csi0pix_cam_mux_clk",
-		.ops = &clk_ops_cam_mux,
+		.ops = &clk_ops_gen_mux,
 		CLK_INIT(csi0pix_cam_mux_clk.c),
 	},
 };
 
 
-static struct cam_mux_clk rdi2_cam_mux_clk = {
-	.enable_reg = MMSS_CAMSS_MISC,
-	.enable_mask = BIT(6),
-	.select_reg = MMSS_CAMSS_MISC,
-	.select_mask = BIT(2),
-	.sources = (struct mux_source[]) {
-		{ &csi0rdi_clk.c,      0 },
-		{ &csi1rdi_clk.c, BIT(2) },
-		{ 0 },
-	},
+static struct mux_clk rdi2_cam_mux_clk = {
+	.ops = &mux_reg_ops,
+	.en_mask = BIT(6),
+	.mask = 0x1,
+	.shift = 2,
+	.offset = MMSS_CAMSS_MISC,
+	MUX_SRC_LIST(
+		{ &csi0rdi_clk.c, 0 },
+		{ &csi1rdi_clk.c, 1 },
+	),
 	.base = &virt_bases[MMSS_BASE],
 	.c = {
 		.dbg_name = "rdi2_cam_mux_clk",
-		.ops = &clk_ops_cam_mux,
+		.ops = &clk_ops_gen_mux,
 		CLK_INIT(rdi2_cam_mux_clk.c),
 	},
 };
 
-static struct cam_mux_clk rdi1_cam_mux_clk = {
-	.enable_reg = MMSS_CAMSS_MISC,
-	.enable_mask = BIT(5),
-	.select_reg = MMSS_CAMSS_MISC,
-	.select_mask = BIT(1),
-	.sources = (struct mux_source[]) {
-		{ &csi0rdi_clk.c,      0 },
-		{ &csi1rdi_clk.c, BIT(1) },
-		{ 0 },
-	},
+static struct mux_clk rdi1_cam_mux_clk = {
+	.ops = &mux_reg_ops,
+	.en_mask = BIT(5),
+	.mask = 0x1,
+	.shift = 1,
+	.offset = MMSS_CAMSS_MISC,
+	MUX_SRC_LIST(
+		{ &csi0rdi_clk.c, 0 },
+		{ &csi1rdi_clk.c, 1 },
+	),
 	.base = &virt_bases[MMSS_BASE],
 	.c = {
 		.dbg_name = "rdi1_cam_mux_clk",
-		.ops = &clk_ops_cam_mux,
+		.ops = &clk_ops_gen_mux,
 		CLK_INIT(rdi1_cam_mux_clk.c),
 	},
 };
 
-static struct cam_mux_clk rdi0_cam_mux_clk = {
-	.enable_reg = MMSS_CAMSS_MISC,
-	.enable_mask = BIT(4),
-	.select_reg = MMSS_CAMSS_MISC,
-	.select_mask = BIT(0),
-	.sources = (struct mux_source[]) {
-		{ &csi0rdi_clk.c,      0 },
-		{ &csi1rdi_clk.c, BIT(0) },
-		{ 0 },
-	},
+static struct mux_clk rdi0_cam_mux_clk = {
+	.ops = &mux_reg_ops,
+	.en_mask = BIT(4),
+	.mask = 0x1,
+	.shift = 0,
+	.offset = MMSS_CAMSS_MISC,
+	MUX_SRC_LIST(
+		{ &csi0rdi_clk.c, 0 },
+		{ &csi1rdi_clk.c, 1 },
+	),
 	.base = &virt_bases[MMSS_BASE],
 	.c = {
 		.dbg_name = "rdi0_cam_mux_clk",
-		.ops = &clk_ops_cam_mux,
+		.ops = &clk_ops_gen_mux,
 		CLK_INIT(rdi0_cam_mux_clk.c),
 	},
 };
@@ -3040,10 +3041,12 @@
 		"fda00c00.qcom,csiphy"),
 	CLK_LOOKUP("csiphy_timer_clk", csi0phytimer_clk.c,
 		"fda00c00.qcom,csiphy"),
+	CLK_LOOKUP("csi_ahb_clk", csi_ahb_clk.c, "fda00c00.qcom,csiphy"),
 	CLK_LOOKUP("csiphy_timer_src_clk", csi1phytimer_clk_src.c,
 		"fda01000.qcom,csiphy"),
 	CLK_LOOKUP("csiphy_timer_clk", csi1phytimer_clk.c,
 		"fda01000.qcom,csiphy"),
+	CLK_LOOKUP("csi_ahb_clk", csi_ahb_clk.c,  "fda01000.qcom,csiphy"),
 
 	/* CSID clocks */
 	CLK_LOOKUP("csi_clk", csi0_clk.c, "fda00000.qcom,csid"),
diff --git a/arch/arm/mach-msm/clock-8974.c b/arch/arm/mach-msm/clock-8974.c
index 03fcb25..9feb2f0 100644
--- a/arch/arm/mach-msm/clock-8974.c
+++ b/arch/arm/mach-msm/clock-8974.c
@@ -4953,8 +4953,10 @@
 
 	CLK_LOOKUP("measure",	measure_clk.c,	"debug"),
 
+	CLK_LOOKUP("hfpll_src", cxo_a_clk_src.c,   "f9016000.qcom,clock-krait"),
+	CLK_LOOKUP("aux_clk",   gpll0_ao_clk_src.c,
+						"f9016000.qcom,clock-krait"),
 	CLK_LOOKUP("gpll0", gpll0_clk_src.c, ""),
-	CLK_LOOKUP("gpll0_ao", gpll0_ao_clk_src.c, ""),
 
 	CLK_LOOKUP("dma_bam_pclk", gcc_bam_dma_ahb_clk.c, "msm_sps"),
 	CLK_LOOKUP("iface_clk", gcc_blsp1_ahb_clk.c, "f991f000.serial"),
diff --git a/arch/arm/mach-msm/clock-generic.c b/arch/arm/mach-msm/clock-generic.c
index b0d32a0..c7d24a8 100644
--- a/arch/arm/mach-msm/clock-generic.c
+++ b/arch/arm/mach-msm/clock-generic.c
@@ -14,20 +14,21 @@
 #include <linux/kernel.h>
 #include <linux/errno.h>
 #include <linux/err.h>
-
 #include <linux/clk.h>
+#include <linux/io.h>
+
 #include <mach/clk-provider.h>
 #include <mach/clock-generic.h>
 
 /* ==================== Mux clock ==================== */
 
-static int parent_to_src_sel(struct mux_clk *mux, struct clk *p)
+int parent_to_src_sel(struct clk_src *parents, int num_parents, struct clk *p)
 {
 	int i;
 
-	for (i = 0; i < mux->num_parents; i++) {
-		if (mux->parents[i].src == p)
-			return mux->parents[i].sel;
+	for (i = 0; i < num_parents; i++) {
+		if (parents[i].src == p)
+			return parents[i].sel;
 	}
 
 	return -EINVAL;
@@ -36,11 +37,26 @@
 static int mux_set_parent(struct clk *c, struct clk *p)
 {
 	struct mux_clk *mux = to_mux_clk(c);
-	int sel = parent_to_src_sel(mux, p);
+	int sel = parent_to_src_sel(mux->parents, mux->num_parents, p);
 	struct clk *old_parent;
-	int rc = 0;
+	int rc = 0, i;
 	unsigned long flags;
 
+	if (sel < 0 && mux->rec_set_par) {
+		for (i = 0; i < mux->num_parents; i++) {
+			rc = clk_set_parent(mux->parents[i].src, p);
+			if (!rc) {
+				sel = mux->parents[i].sel;
+				/*
+				 * This is necessary to ensure prepare/enable
+				 * counts get propagated correctly.
+				 */
+				p = mux->parents[i].src;
+				break;
+			}
+		}
+	}
+
 	if (sel < 0)
 		return sel;
 
@@ -54,6 +70,7 @@
 
 	old_parent = c->parent;
 	c->parent = p;
+	c->rate = clk_get_rate(p);
 	__clk_post_reparent(c, old_parent, &flags);
 
 	return 0;
@@ -68,23 +85,17 @@
 {
 	struct mux_clk *mux = to_mux_clk(c);
 	int i;
-	unsigned long prate, max_prate = 0, rrate = ULONG_MAX;
+	unsigned long prate, rrate = 0;
 
 	for (i = 0; i < mux->num_parents; i++) {
 		prate = clk_round_rate(mux->parents[i].src, rate);
-		if (IS_ERR_VALUE(prate))
-			continue;
-		if (prate < rate) {
-			max_prate = max(prate, max_prate);
-			continue;
-		}
-
-		rrate = min(rrate, prate);
+		if (is_better_rate(rate, rrate, prate))
+			rrate = prate;
 	}
-	if (rrate == ULONG_MAX)
-		rrate = max_prate;
+	if (!rrate)
+		return -EINVAL;
 
-	return rrate ? rrate : -EINVAL;
+	return rrate;
 }
 
 static int mux_set_rate(struct clk *c, unsigned long rate)
@@ -136,7 +147,8 @@
 set_par_fail:
 	clk_set_rate(new_parent, new_par_curr_rate);
 set_rate_fail:
-	WARN(mux->ops->set_mux_sel(mux, parent_to_src_sel(mux, c->parent)),
+	WARN(mux->ops->set_mux_sel(mux,
+		parent_to_src_sel(mux->parents, mux->num_parents, c->parent)),
 		"Set rate failed for %s. Also in bad state!\n", c->dbg_name);
 	return rc;
 }
@@ -176,7 +188,8 @@
 	struct mux_clk *mux = to_mux_clk(c);
 
 	c->rate = clk_get_rate(c->parent);
-	mux->safe_sel = parent_to_src_sel(mux, mux->safe_parent);
+	mux->safe_sel = parent_to_src_sel(mux->parents, mux->num_parents,
+							mux->safe_parent);
 
 	if (mux->en_mask && mux->ops && mux->ops->is_enabled)
 		return mux->ops->is_enabled(mux)
@@ -205,30 +218,30 @@
 	.get_parent = mux_get_parent,
 };
 
-
 /* ==================== Divider clock ==================== */
 
-static long __div_round_rate(struct clk *c, unsigned long rate, int *best_div)
+static long __div_round_rate(struct div_data *data, unsigned long rate,
+	struct clk *parent, unsigned int *best_div, unsigned long *best_prate)
 {
-	struct div_clk *d = to_div_clk(c);
-	unsigned int div, min_div, max_div;
-	unsigned long p_rrate, rrate = ULONG_MAX;
+	unsigned int div, min_div, max_div, _best_div = 1;
+	unsigned long prate, _best_prate = 0, rrate = 0;
 
 	rate = max(rate, 1UL);
 
-	if (!d->ops || !d->ops->set_div)
-		min_div = max_div = d->div;
-	else {
-		min_div = max(d->min_div, 1U);
-		max_div = min(d->max_div, (unsigned int) (ULONG_MAX / rate));
-	}
+	min_div = max(data->min_div, 1U);
+	max_div = min(data->max_div, (unsigned int) (ULONG_MAX / rate));
 
 	for (div = min_div; div <= max_div; div++) {
-		p_rrate = clk_round_rate(c->parent, rate * div);
-		if (IS_ERR_VALUE(p_rrate))
+		prate = clk_round_rate(parent, rate * div);
+		if (IS_ERR_VALUE(prate))
 			break;
 
-		p_rrate /= div;
+		if (is_better_rate(rate, rrate, prate / div)) {
+			rrate = prate / div;
+			_best_div = div;
+			_best_prate = prate;
+		}
+
 		/*
 		 * Trying higher dividers is only going to ask the parent for
 		 * a higher rate. If it can't even output a rate higher than
@@ -236,42 +249,38 @@
 		 * going to be able to output an even higher rate required
 		 * for a higher divider. So, stop trying higher dividers.
 		 */
-		if (p_rrate < rate) {
-			if (rrate == ULONG_MAX) {
-				rrate = p_rrate;
-				if (best_div)
-					*best_div = div;
-			}
+		if (prate / div < rate)
 			break;
-		}
-		if (p_rrate < rrate) {
-			rrate = p_rrate;
-			if (best_div)
-				*best_div = div;
-		}
 
-		if (rrate <= rate + d->rate_margin)
+		if (rrate <= rate + data->rate_margin)
 			break;
 	}
 
-	if (rrate == ULONG_MAX)
+	if (!rrate)
 		return -EINVAL;
+	if (best_div)
+		*best_div = _best_div;
+	if (best_prate)
+		*best_prate = _best_prate;
 
 	return rrate;
 }
 
 static long div_round_rate(struct clk *c, unsigned long rate)
 {
-	return __div_round_rate(c, rate, NULL);
+	struct div_clk *d = to_div_clk(c);
+
+	return __div_round_rate(&d->data, rate, c->parent, NULL, NULL);
 }
 
 static int div_set_rate(struct clk *c, unsigned long rate)
 {
 	struct div_clk *d = to_div_clk(c);
 	int div, rc = 0;
-	long rrate, old_prate;
+	long rrate, old_prate, new_prate;
+	struct div_data *data = &d->data;
 
-	rrate = __div_round_rate(c, rate, &div);
+	rrate = __div_round_rate(data, rate, c->parent, &div, &new_prate);
 	if (rrate != rate)
 		return -EINVAL;
 
@@ -281,22 +290,22 @@
 	 * !d->ops and return an error. __div_round_rate() ensures div ==
 	 * d->div if !d->ops.
 	 */
-	if (div > d->div)
+	if (div > data->div)
 		rc = d->ops->set_div(d, div);
 	if (rc)
 		return rc;
 
 	old_prate = clk_get_rate(c->parent);
-	rc = clk_set_rate(c->parent, rate * div);
+	rc = clk_set_rate(c->parent, new_prate);
 	if (rc)
 		goto set_rate_fail;
 
-	if (div < d->div)
+	if (div < data->div)
 		rc = d->ops->set_div(d, div);
 	if (rc)
 		goto div_dec_fail;
 
-	d->div = div;
+	data->div = div;
 
 	return 0;
 
@@ -304,8 +313,8 @@
 	WARN(clk_set_rate(c->parent, old_prate),
 		"Set rate failed for %s. Also in bad state!\n", c->dbg_name);
 set_rate_fail:
-	if (div > d->div)
-		WARN(d->ops->set_div(d, d->div),
+	if (div > data->div)
+		WARN(d->ops->set_div(d, data->div),
 			"Set rate failed for %s. Also in bad state!\n",
 			c->dbg_name);
 	return rc;
@@ -329,11 +338,16 @@
 static enum handoff div_handoff(struct clk *c)
 {
 	struct div_clk *d = to_div_clk(c);
+	unsigned int div = d->data.div;
 
 	if (d->ops && d->ops->get_div)
-		d->div = max(d->ops->get_div(d), 1);
-	d->div = max(d->div, 1U);
-	c->rate = clk_get_rate(c->parent) / d->div;
+		div = max(d->ops->get_div(d), 1);
+	div = max(div, 1U);
+	c->rate = clk_get_rate(c->parent) / div;
+
+	if (!d->ops || !d->ops->set_div)
+		d->data.min_div = d->data.max_div = div;
+	d->data.div = div;
 
 	if (d->en_mask && d->ops && d->ops->is_enabled)
 		return d->ops->is_enabled(d)
@@ -369,12 +383,8 @@
 
 	rate = max(rate, 1UL);
 
-	if (!d->ops || !d->ops->set_div)
-		min_div = max_div = d->div;
-	else {
-		min_div = d->min_div;
-		max_div = d->max_div;
-	}
+	min_div = d->data.min_div;
+	max_div = d->data.max_div;
 
 	p_rate = clk_get_rate(c->parent);
 	div = p_rate / rate;
@@ -401,28 +411,320 @@
 	if (rrate != rate)
 		return -EINVAL;
 
-	if (div == d->div)
+	if (div == d->data.div)
 		return 0;
 
 	/*
 	 * For fixed divider clock we don't want to return an error if the
 	 * requested rate matches the achievable rate. So, don't check for
 	 * !d->ops and return an error. __slave_div_round_rate() ensures
-	 * div == d->div if !d->ops.
+	 * div == d->data.div if !d->ops.
 	 */
 	rc = d->ops->set_div(d, div);
 	if (rc)
 		return rc;
 
-	d->div = div;
+	d->data.div = div;
 
 	return 0;
 }
 
+static unsigned long slave_div_get_rate(struct clk *c)
+{
+	struct div_clk *d = to_div_clk(c);
+	if (!d->data.div)
+		return 0;
+	return clk_get_rate(c->parent) / d->data.div;
+}
+
 struct clk_ops clk_ops_slave_div = {
 	.enable = div_enable,
 	.disable = div_disable,
 	.round_rate = slave_div_round_rate,
 	.set_rate = slave_div_set_rate,
+	.get_rate = slave_div_get_rate,
 	.handoff = div_handoff,
 };
+
+
+/**
+ * External clock
+ * Some clock controllers have input clock signal that come from outside the
+ * clock controller. That input clock signal might then be used as a source for
+ * several clocks inside the clock controller. This external clock
+ * implementation models this input clock signal by just passing on the requests
+ * to the clock's parent, the original external clock source. The driver for the
+ * clock controller should clk_get() the original external clock in the probe
+ * function and set is as a parent to this external clock..
+ */
+
+static long ext_round_rate(struct clk *c, unsigned long rate)
+{
+	return clk_round_rate(c->parent, rate);
+}
+
+static int ext_set_rate(struct clk *c, unsigned long rate)
+{
+	return clk_set_rate(c->parent, rate);
+}
+
+static unsigned long ext_get_rate(struct clk *c)
+{
+	return clk_get_rate(c->parent);
+}
+
+static int ext_set_parent(struct clk *c, struct clk *p)
+{
+	return clk_set_parent(c->parent, p);
+}
+
+static enum handoff ext_handoff(struct clk *c)
+{
+	c->rate = clk_get_rate(c->parent);
+	/* Similar reasoning applied in div_handoff, see comment there. */
+	return HANDOFF_DISABLED_CLK;
+}
+
+struct clk_ops clk_ops_ext = {
+	.handoff = ext_handoff,
+	.round_rate = ext_round_rate,
+	.set_rate = ext_set_rate,
+	.get_rate = ext_get_rate,
+	.set_parent = ext_set_parent,
+};
+
+
+/* ==================== Mux_div clock ==================== */
+
+static int mux_div_clk_enable(struct clk *c)
+{
+	struct mux_div_clk *md = to_mux_div_clk(c);
+
+	if (md->ops->enable)
+		return md->ops->enable(md);
+	return 0;
+}
+
+static void mux_div_clk_disable(struct clk *c)
+{
+	struct mux_div_clk *md = to_mux_div_clk(c);
+
+	if (md->ops->disable)
+		return md->ops->disable(md);
+}
+
+static long __mux_div_round_rate(struct clk *c, unsigned long rate,
+	struct clk **best_parent, int *best_div, unsigned long *best_prate)
+{
+	struct mux_div_clk *md = to_mux_div_clk(c);
+	unsigned int i;
+	unsigned long rrate, best = 0, _best_div = 0, _best_prate = 0;
+	struct clk *_best_parent = 0;
+
+	for (i = 0; i < md->num_parents; i++) {
+		int div;
+		unsigned long prate;
+
+		rrate = __div_round_rate(&md->data, rate, md->parents[i].src,
+				&div, &prate);
+
+		if (is_better_rate(rate, best, rrate)) {
+			best = rrate;
+			_best_div = div;
+			_best_prate = prate;
+			_best_parent = md->parents[i].src;
+		}
+
+		if (rate <= rrate && rrate <= rate + md->data.rate_margin)
+			break;
+	}
+
+	if (best_div)
+		*best_div = _best_div;
+	if (best_prate)
+		*best_prate = _best_prate;
+	if (best_parent)
+		*best_parent = _best_parent;
+
+	if (best)
+		return best;
+	return -EINVAL;
+}
+
+static long mux_div_clk_round_rate(struct clk *c, unsigned long rate)
+{
+	return __mux_div_round_rate(c, rate, NULL, NULL, NULL);
+}
+
+/* requires enable lock to be held */
+static int __set_src_div(struct mux_div_clk *md, struct clk *parent, u32 div)
+{
+	u32 rc = 0, src_sel;
+
+	src_sel = parent_to_src_sel(md->parents, md->num_parents, parent);
+	/*
+	 * If the clock is disabled, don't change to the new settings until
+	 * the clock is reenabled
+	 */
+	if (md->c.count)
+		rc = md->ops->set_src_div(md, src_sel, div);
+	if (!rc) {
+		md->data.div = div;
+		md->src_sel = src_sel;
+	}
+
+	return rc;
+}
+
+static int set_src_div(struct mux_div_clk *md, struct clk *parent, u32 div)
+{
+	unsigned long flags;
+	u32 rc;
+
+	spin_lock_irqsave(&md->c.lock, flags);
+	rc = __set_src_div(md, parent, div);
+	spin_unlock_irqrestore(&md->c.lock, flags);
+
+	return rc;
+}
+
+/* Must be called after handoff to ensure parent clock rates are initialized */
+static int safe_parent_init_once(struct clk *c)
+{
+	unsigned long rrate;
+	u32 best_div;
+	struct clk *best_parent;
+	struct mux_div_clk *md = to_mux_div_clk(c);
+
+	if (IS_ERR(md->safe_parent))
+		return -EINVAL;
+	if (!md->safe_freq || md->safe_parent)
+		return 0;
+
+	rrate = __mux_div_round_rate(c, md->safe_freq, &best_parent,
+			&best_div, NULL);
+
+	if (rrate == md->safe_freq) {
+		md->safe_div = best_div;
+		md->safe_parent = best_parent;
+	} else {
+		md->safe_parent = ERR_PTR(-EINVAL);
+		return -EINVAL;
+	}
+	return 0;
+}
+
+static int mux_div_clk_set_rate(struct clk *c, unsigned long rate)
+{
+	struct mux_div_clk *md = to_mux_div_clk(c);
+	unsigned long flags, rrate;
+	unsigned long new_prate, old_prate;
+	struct clk *old_parent, *new_parent;
+	u32 new_div, old_div;
+	int rc;
+
+	rc = safe_parent_init_once(c);
+	if (rc)
+		return rc;
+
+	rrate = __mux_div_round_rate(c, rate, &new_parent, &new_div,
+							&new_prate);
+	if (rrate != rate)
+		return -EINVAL;
+
+	old_parent = c->parent;
+	old_div = md->data.div;
+	old_prate = clk_get_rate(c->parent);
+
+	/* Refer to the description of safe_freq in clock-generic.h */
+	if (md->safe_freq)
+		rc = set_src_div(md, md->safe_parent, md->safe_div);
+
+	else if (new_parent == old_parent && new_div >= old_div) {
+		/*
+		 * If both the parent_rate and divider changes, there may be an
+		 * intermediate frequency generated. Ensure this intermediate
+		 * frequency is less than both the new rate and previous rate.
+		 */
+		rc = set_src_div(md, old_parent, new_div);
+	}
+	if (rc)
+		return rc;
+
+	rc = clk_set_rate(new_parent, new_prate);
+	if (rc) {
+		pr_err("failed to set %s to %ld\n",
+			new_parent->dbg_name, new_prate);
+		goto err_set_rate;
+	}
+
+	rc = __clk_pre_reparent(c, new_parent, &flags);
+	if (rc)
+		goto err_pre_reparent;
+
+	/* Set divider and mux src atomically */
+	rc = __set_src_div(md, new_parent, new_div);
+	if (rc)
+		goto err_set_src_div;
+
+	c->parent = new_parent;
+
+	__clk_post_reparent(c, old_parent, &flags);
+	return 0;
+
+err_set_src_div:
+	/* Not switching to new_parent, so disable it */
+	__clk_post_reparent(c, new_parent, &flags);
+err_pre_reparent:
+	rc = clk_set_rate(old_parent, old_prate);
+	WARN(rc, "%s: error changing parent (%s) rate to %ld\n",
+		c->dbg_name, old_parent->dbg_name, old_prate);
+err_set_rate:
+	rc = set_src_div(md, old_parent, old_div);
+	WARN(rc, "%s: error changing back to original div (%d) and parent (%s)\n",
+		c->dbg_name, old_div, old_parent->dbg_name);
+
+	return rc;
+}
+
+static struct clk *mux_div_clk_get_parent(struct clk *c)
+{
+	struct mux_div_clk *md = to_mux_div_clk(c);
+	u32 i, div, src_sel;
+
+	md->ops->get_src_div(md, &src_sel, &div);
+
+	md->data.div = div;
+	md->src_sel = src_sel;
+
+	for (i = 0; i < md->num_parents; i++) {
+		if (md->parents[i].sel == src_sel)
+			return md->parents[i].src;
+	}
+
+	return NULL;
+}
+
+static enum handoff mux_div_clk_handoff(struct clk *c)
+{
+	struct mux_div_clk *md = to_mux_div_clk(c);
+	unsigned long parent_rate;
+
+	parent_rate = clk_get_rate(c->parent);
+	c->rate = parent_rate / md->data.div;
+
+	if (!md->ops->is_enabled)
+		return HANDOFF_DISABLED_CLK;
+	if (md->ops->is_enabled(md))
+		return HANDOFF_ENABLED_CLK;
+	return HANDOFF_DISABLED_CLK;
+}
+
+struct clk_ops clk_ops_mux_div_clk = {
+	.enable = mux_div_clk_enable,
+	.disable = mux_div_clk_disable,
+	.set_rate = mux_div_clk_set_rate,
+	.round_rate = mux_div_clk_round_rate,
+	.get_parent = mux_div_clk_get_parent,
+	.handoff = mux_div_clk_handoff,
+};
diff --git a/arch/arm/mach-msm/clock-krait-8974.c b/arch/arm/mach-msm/clock-krait-8974.c
new file mode 100644
index 0000000..6ada01f
--- /dev/null
+++ b/arch/arm/mach-msm/clock-krait-8974.c
@@ -0,0 +1,806 @@
+/* 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/init.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/err.h>
+#include <linux/ctype.h>
+#include <linux/io.h>
+#include <linux/clk.h>
+#include <linux/regulator/consumer.h>
+#include <linux/of.h>
+#include <linux/cpumask.h>
+
+#include <asm/cputype.h>
+
+#include <mach/rpm-regulator-smd.h>
+#include <mach/clk-provider.h>
+#include <mach/clock-generic.h>
+#include <mach/clk.h>
+#include "clock-krait.h"
+#include "clock.h"
+
+/* Clock inputs coming into Krait subsystem */
+DEFINE_FIXED_DIV_CLK(hfpll_src_clk, 1, NULL);
+DEFINE_FIXED_DIV_CLK(acpu_aux_clk, 2, NULL);
+
+static int hfpll_uv[] = {
+	RPM_REGULATOR_CORNER_NONE, 0,
+	RPM_REGULATOR_CORNER_SVS_SOC, 1800000,
+	RPM_REGULATOR_CORNER_NORMAL, 1800000,
+	RPM_REGULATOR_CORNER_SUPER_TURBO, 1800000,
+};
+static DEFINE_VDD_REGULATORS(vdd_hfpll, ARRAY_SIZE(hfpll_uv)/2, 2,
+				hfpll_uv, NULL);
+
+static unsigned long hfpll_fmax[] = { 0, 998400000, 1996800000, 2900000000UL };
+
+static struct hfpll_data hdata = {
+	.mode_offset = 0x0,
+	.l_offset = 0x4,
+	.m_offset = 0x8,
+	.n_offset = 0xC,
+	.user_offset = 0x10,
+	.config_offset = 0x14,
+	.status_offset = 0x1C,
+
+	.user_val = 0x8,
+	.low_vco_max_rate = 1248000000,
+	.min_rate = 537600000UL,
+	.max_rate = 2900000000UL,
+};
+
+static struct hfpll_clk hfpll0_clk = {
+	.d = &hdata,
+	.src_rate = 19200000,
+	.c = {
+		.parent = &hfpll_src_clk.c,
+		.dbg_name = "hfpll0_clk",
+		.ops = &clk_ops_hfpll,
+		.vdd_class = &vdd_hfpll,
+		.fmax = hfpll_fmax,
+		.num_fmax = ARRAY_SIZE(hfpll_fmax),
+		CLK_INIT(hfpll0_clk.c),
+	},
+};
+
+DEFINE_KPSS_DIV2_CLK(hfpll0_div_clk, &hfpll0_clk.c, 0x4501, true);
+
+static struct hfpll_clk hfpll1_clk = {
+	.d = &hdata,
+	.src_rate = 19200000,
+	.c = {
+		.parent = &hfpll_src_clk.c,
+		.dbg_name = "hfpll1_clk",
+		.ops = &clk_ops_hfpll,
+		.vdd_class = &vdd_hfpll,
+		.fmax = hfpll_fmax,
+		.num_fmax = ARRAY_SIZE(hfpll_fmax),
+		CLK_INIT(hfpll1_clk.c),
+	},
+};
+
+DEFINE_KPSS_DIV2_CLK(hfpll1_div_clk, &hfpll1_clk.c, 0x5501, true);
+
+static struct hfpll_clk hfpll2_clk = {
+	.d = &hdata,
+	.src_rate = 19200000,
+	.c = {
+		.parent = &hfpll_src_clk.c,
+		.dbg_name = "hfpll2_clk",
+		.ops = &clk_ops_hfpll,
+		.vdd_class = &vdd_hfpll,
+		.fmax = hfpll_fmax,
+		.num_fmax = ARRAY_SIZE(hfpll_fmax),
+		CLK_INIT(hfpll2_clk.c),
+	},
+};
+
+DEFINE_KPSS_DIV2_CLK(hfpll2_div_clk, &hfpll2_clk.c, 0x6501, true);
+
+static struct hfpll_clk hfpll3_clk = {
+	.d = &hdata,
+	.src_rate = 19200000,
+	.c = {
+		.parent = &hfpll_src_clk.c,
+		.dbg_name = "hfpll3_clk",
+		.ops = &clk_ops_hfpll,
+		.vdd_class = &vdd_hfpll,
+		.fmax = hfpll_fmax,
+		.num_fmax = ARRAY_SIZE(hfpll_fmax),
+		CLK_INIT(hfpll3_clk.c),
+	},
+};
+
+DEFINE_KPSS_DIV2_CLK(hfpll3_div_clk, &hfpll3_clk.c, 0x7501, true);
+
+static struct hfpll_clk hfpll_l2_clk = {
+	.d = &hdata,
+	.src_rate = 19200000,
+	.c = {
+		.parent = &hfpll_src_clk.c,
+		.dbg_name = "hfpll_l2_clk",
+		.ops = &clk_ops_hfpll,
+		.vdd_class = &vdd_hfpll,
+		.fmax = hfpll_fmax,
+		.num_fmax = ARRAY_SIZE(hfpll_fmax),
+		CLK_INIT(hfpll_l2_clk.c),
+	},
+};
+
+DEFINE_KPSS_DIV2_CLK(hfpll_l2_div_clk, &hfpll_l2_clk.c, 0x500, false);
+
+#define SEC_MUX_COMMON_DATA		\
+	.safe_parent = &acpu_aux_clk.c,	\
+	.ops = &clk_mux_ops_kpss,	\
+	.mask = 0x3,			\
+	.shift = 2,			\
+	MUX_SRC_LIST(			\
+		{&acpu_aux_clk.c, 2},	\
+		{NULL /* QSB */, 0},	\
+	)
+
+static struct mux_clk krait0_sec_mux_clk = {
+	.offset = 0x4501,
+	.priv = (void *) true,
+	SEC_MUX_COMMON_DATA,
+	.c = {
+		.dbg_name = "krait0_sec_mux_clk",
+		.ops = &clk_ops_gen_mux,
+		CLK_INIT(krait0_sec_mux_clk.c),
+	},
+};
+
+static struct mux_clk krait1_sec_mux_clk = {
+	.offset = 0x5501,
+	.priv = (void *) true,
+	SEC_MUX_COMMON_DATA,
+	.c = {
+		.dbg_name = "krait1_sec_mux_clk",
+		.ops = &clk_ops_gen_mux,
+		CLK_INIT(krait1_sec_mux_clk.c),
+	},
+};
+
+static struct mux_clk krait2_sec_mux_clk = {
+	.offset = 0x6501,
+	.priv = (void *) true,
+	SEC_MUX_COMMON_DATA,
+	.c = {
+		.dbg_name = "krait2_sec_mux_clk",
+		.ops = &clk_ops_gen_mux,
+		CLK_INIT(krait2_sec_mux_clk.c),
+	},
+};
+
+static struct mux_clk krait3_sec_mux_clk = {
+	.offset = 0x7501,
+	.priv = (void *) true,
+	SEC_MUX_COMMON_DATA,
+	.c = {
+		.dbg_name = "krait3_sec_mux_clk",
+		.ops = &clk_ops_gen_mux,
+		CLK_INIT(krait3_sec_mux_clk.c),
+	},
+};
+
+static struct mux_clk l2_sec_mux_clk = {
+	.offset = 0x500,
+	SEC_MUX_COMMON_DATA,
+	.c = {
+		.dbg_name = "l2_sec_mux_clk",
+		.ops = &clk_ops_gen_mux,
+		CLK_INIT(l2_sec_mux_clk.c),
+	},
+};
+
+#define PRI_MUX_COMMON_DATA		\
+	.ops = &clk_mux_ops_kpss,	\
+	.mask = 0x3,			\
+	.shift = 0
+
+static struct mux_clk krait0_pri_mux_clk = {
+	.offset = 0x4501,
+	.priv = (void *) true,
+	MUX_SRC_LIST(
+		{ &hfpll0_clk.c, 1 },
+		{ &hfpll0_div_clk.c, 2 },
+		{ &krait0_sec_mux_clk.c, 0 },
+	),
+	.safe_parent = &krait0_sec_mux_clk.c,
+	PRI_MUX_COMMON_DATA,
+	.c = {
+		.dbg_name = "krait0_pri_mux_clk",
+		.ops = &clk_ops_gen_mux,
+		CLK_INIT(krait0_pri_mux_clk.c),
+	},
+};
+
+static struct mux_clk krait1_pri_mux_clk = {
+	.offset = 0x5501,
+	.priv = (void *) true,
+	MUX_SRC_LIST(
+		{ &hfpll1_clk.c, 1 },
+		{ &hfpll1_div_clk.c, 2 },
+		{ &krait1_sec_mux_clk.c, 0 },
+	),
+	.safe_parent = &krait1_sec_mux_clk.c,
+	PRI_MUX_COMMON_DATA,
+	.c = {
+		.dbg_name = "krait1_pri_mux_clk",
+		.ops = &clk_ops_gen_mux,
+		CLK_INIT(krait1_pri_mux_clk.c),
+	},
+};
+
+static struct mux_clk krait2_pri_mux_clk = {
+	.offset = 0x6501,
+	.priv = (void *) true,
+	MUX_SRC_LIST(
+		{ &hfpll2_clk.c, 1 },
+		{ &hfpll2_div_clk.c, 2 },
+		{ &krait2_sec_mux_clk.c, 0 },
+	),
+	.safe_parent = &krait2_sec_mux_clk.c,
+	PRI_MUX_COMMON_DATA,
+	.c = {
+		.dbg_name = "krait2_pri_mux_clk",
+		.ops = &clk_ops_gen_mux,
+		CLK_INIT(krait2_pri_mux_clk.c),
+	},
+};
+
+static struct mux_clk krait3_pri_mux_clk = {
+	.offset = 0x7501,
+	.priv = (void *) true,
+	MUX_SRC_LIST(
+		{ &hfpll3_clk.c, 1 },
+		{ &hfpll3_div_clk.c, 2 },
+		{ &krait3_sec_mux_clk.c, 0 },
+	),
+	.safe_parent = &krait3_sec_mux_clk.c,
+	PRI_MUX_COMMON_DATA,
+	.c = {
+		.dbg_name = "krait3_pri_mux_clk",
+		.ops = &clk_ops_gen_mux,
+		CLK_INIT(krait3_pri_mux_clk.c),
+	},
+};
+
+static struct mux_clk l2_pri_mux_clk = {
+	.offset = 0x500,
+	MUX_SRC_LIST(
+		{&hfpll_l2_clk.c, 1 },
+		{&hfpll_l2_div_clk.c, 2},
+		{&l2_sec_mux_clk.c, 0}
+	),
+	.safe_parent = &l2_sec_mux_clk.c,
+	PRI_MUX_COMMON_DATA,
+	.c = {
+		.dbg_name = "l2_pri_mux_clk",
+		.ops = &clk_ops_gen_mux,
+		CLK_INIT(l2_pri_mux_clk.c),
+	},
+};
+
+static struct avs_data avs_table;
+
+static DEFINE_VDD_REGS_INIT(vdd_krait0, 1);
+static DEFINE_VDD_REGS_INIT(vdd_krait1, 1);
+static DEFINE_VDD_REGS_INIT(vdd_krait2, 1);
+static DEFINE_VDD_REGS_INIT(vdd_krait3, 1);
+static DEFINE_VDD_REGS_INIT(vdd_l2, 1);
+
+/*
+ * This clock is mostly a dummy clock in the sense it can't really gate the
+ * CPU/L2 clocks or affect their frequency. It exists solely to:
+ *
+ * - Capture the PVS requirements for each CPU.
+ * - Implement HW clock gating disable ops needed for measuring the freq of
+ *   Krait/L2 properly.
+ * - Implement AVS requirement.
+ */
+static struct kpss_core_clk krait0_clk = {
+	.id	= 0,
+	.avs_tbl = &avs_table,
+	.c = {
+		.parent = &krait0_pri_mux_clk.c,
+		.dbg_name = "krait0_clk",
+		.ops = &clk_ops_kpss_cpu,
+		.vdd_class = &vdd_krait0,
+		CLK_INIT(krait0_clk.c),
+	},
+};
+
+static struct kpss_core_clk krait1_clk = {
+	.id	= 1,
+	.avs_tbl = &avs_table,
+	.c = {
+		.parent = &krait1_pri_mux_clk.c,
+		.dbg_name = "krait1_clk",
+		.ops = &clk_ops_kpss_cpu,
+		.vdd_class = &vdd_krait1,
+		CLK_INIT(krait1_clk.c),
+	},
+};
+
+static struct kpss_core_clk krait2_clk = {
+	.id	= 2,
+	.avs_tbl = &avs_table,
+	.c = {
+		.parent = &krait2_pri_mux_clk.c,
+		.dbg_name = "krait2_clk",
+		.ops = &clk_ops_kpss_cpu,
+		.vdd_class = &vdd_krait2,
+		CLK_INIT(krait2_clk.c),
+	},
+};
+
+static struct kpss_core_clk krait3_clk = {
+	.id	= 3,
+	.avs_tbl = &avs_table,
+	.c = {
+		.parent = &krait3_pri_mux_clk.c,
+		.dbg_name = "krait3_clk",
+		.ops = &clk_ops_kpss_cpu,
+		.vdd_class = &vdd_krait3,
+		CLK_INIT(krait3_clk.c),
+	},
+};
+
+static struct kpss_core_clk l2_clk = {
+	.cp15_iaddr = 0x0500,
+	.c = {
+		.parent = &l2_pri_mux_clk.c,
+		.dbg_name = "l2_clk",
+		.ops = &clk_ops_kpss_l2,
+		.vdd_class = &vdd_l2,
+		CLK_INIT(l2_clk.c),
+	},
+};
+
+static struct clk_lookup kpss_clocks_8974[] = {
+	CLK_LOOKUP("",	hfpll_src_clk.c,	""),
+	CLK_LOOKUP("",	acpu_aux_clk.c,		""),
+	CLK_LOOKUP("",	hfpll0_clk.c,		""),
+	CLK_LOOKUP("",	hfpll0_div_clk.c,	""),
+	CLK_LOOKUP("",	hfpll0_clk.c,		""),
+	CLK_LOOKUP("",	hfpll1_div_clk.c,	""),
+	CLK_LOOKUP("",	hfpll1_clk.c,		""),
+	CLK_LOOKUP("",	hfpll2_div_clk.c,	""),
+	CLK_LOOKUP("",	hfpll2_clk.c,		""),
+	CLK_LOOKUP("",	hfpll3_div_clk.c,	""),
+	CLK_LOOKUP("",	hfpll3_clk.c,		""),
+	CLK_LOOKUP("",	hfpll_l2_div_clk.c,	""),
+	CLK_LOOKUP("",	hfpll_l2_clk.c,		""),
+	CLK_LOOKUP("",	krait0_sec_mux_clk.c,		""),
+	CLK_LOOKUP("",	krait1_sec_mux_clk.c,		""),
+	CLK_LOOKUP("",	krait2_sec_mux_clk.c,		""),
+	CLK_LOOKUP("",	krait3_sec_mux_clk.c,		""),
+	CLK_LOOKUP("",	l2_sec_mux_clk.c,		""),
+	CLK_LOOKUP("",	krait0_pri_mux_clk.c,		""),
+	CLK_LOOKUP("",	krait1_pri_mux_clk.c,		""),
+	CLK_LOOKUP("",	krait2_pri_mux_clk.c,		""),
+	CLK_LOOKUP("",	krait3_pri_mux_clk.c,		""),
+	CLK_LOOKUP("",	l2_pri_mux_clk.c,		""),
+	CLK_LOOKUP("l2_clk",	l2_clk.c,     "0.qcom,msm-cpufreq"),
+	CLK_LOOKUP("cpu0_clk",	krait0_clk.c, "0.qcom,msm-cpufreq"),
+	CLK_LOOKUP("cpu1_clk",	krait1_clk.c, "0.qcom,msm-cpufreq"),
+	CLK_LOOKUP("cpu2_clk",	krait2_clk.c, "0.qcom,msm-cpufreq"),
+	CLK_LOOKUP("cpu3_clk",	krait3_clk.c, "0.qcom,msm-cpufreq"),
+	CLK_LOOKUP("l2_clk",	l2_clk.c,     "fe805664.qcom,pm-8x60"),
+	CLK_LOOKUP("cpu0_clk",	krait0_clk.c, "fe805664.qcom,pm-8x60"),
+	CLK_LOOKUP("cpu1_clk",	krait1_clk.c, "fe805664.qcom,pm-8x60"),
+	CLK_LOOKUP("cpu2_clk",	krait2_clk.c, "fe805664.qcom,pm-8x60"),
+	CLK_LOOKUP("cpu3_clk",	krait3_clk.c, "fe805664.qcom,pm-8x60"),
+};
+
+static struct clk *cpu_clk[] = {
+	&krait0_clk.c,
+	&krait1_clk.c,
+	&krait2_clk.c,
+	&krait3_clk.c,
+};
+
+static void get_krait_bin_format_b(struct platform_device *pdev,
+					int *speed, int *pvs, int *ver)
+{
+	u32 pte_efuse, redundant_sel;
+	struct resource *res;
+	void __iomem *base;
+
+	*speed = 0;
+	*pvs = 0;
+	*ver = 0;
+
+	res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "efuse");
+	if (!res) {
+		dev_info(&pdev->dev,
+			 "No speed/PVS binning available. Defaulting to 0!\n");
+		return;
+	}
+
+	base = devm_ioremap(&pdev->dev, res->start, resource_size(res));
+	if (!base) {
+		dev_warn(&pdev->dev,
+			 "Unable to read efuse data. Defaulting to 0!\n");
+		return;
+	}
+
+	pte_efuse = readl_relaxed(base);
+	redundant_sel = (pte_efuse >> 24) & 0x7;
+	*speed = pte_efuse & 0x7;
+	/* 4 bits of PVS are in efuse register bits 31, 8-6. */
+	*pvs = ((pte_efuse >> 28) & 0x8) | ((pte_efuse >> 6) & 0x7);
+	*ver = (pte_efuse >> 4) & 0x3;
+
+	switch (redundant_sel) {
+	case 1:
+		*speed = (pte_efuse >> 27) & 0xF;
+		break;
+	case 2:
+		*pvs = (pte_efuse >> 27) & 0xF;
+		break;
+	}
+
+	/* Check SPEED_BIN_BLOW_STATUS */
+	if (pte_efuse & BIT(3)) {
+		dev_info(&pdev->dev, "Speed bin: %d\n", *speed);
+	} else {
+		dev_warn(&pdev->dev, "Speed bin not set. Defaulting to 0!\n");
+		*speed = 0;
+	}
+
+	/* Check PVS_BLOW_STATUS */
+	pte_efuse = readl_relaxed(base + 0x4) & BIT(21);
+	if (pte_efuse) {
+		dev_info(&pdev->dev, "PVS bin: %d\n", *pvs);
+	} else {
+		dev_warn(&pdev->dev, "PVS bin not set. Defaulting to 0!\n");
+		*pvs = 0;
+	}
+
+	dev_info(&pdev->dev, "PVS version: %d\n", *ver);
+
+	devm_iounmap(&pdev->dev, base);
+}
+
+static int parse_tbl(struct device *dev, char *prop, int num_cols,
+		u32 **col1, u32 **col2, u32 **col3)
+{
+	int ret, prop_len, num_rows, i, j, k;
+	u32 *prop_data;
+	u32 *col[num_cols];
+
+	if (!of_find_property(dev->of_node, prop, &prop_len))
+		return -EINVAL;
+
+	prop_len /= sizeof(*prop_data);
+
+	if (prop_len % num_cols || prop_len == 0)
+		return -EINVAL;
+
+	num_rows = prop_len / num_cols;
+
+	prop_data = devm_kzalloc(dev, prop_len * sizeof(*prop_data),
+				 GFP_KERNEL);
+	if (!prop_data)
+		return -ENOMEM;
+
+	for (i = 0; i < num_cols; i++) {
+		col[i] = devm_kzalloc(dev, num_rows * sizeof(u32), GFP_KERNEL);
+		if (!col[i])
+			return -ENOMEM;
+	}
+
+	ret = of_property_read_u32_array(dev->of_node, prop, prop_data,
+					 prop_len);
+	if (ret)
+		return ret;
+
+	k = 0;
+	for (i = 0; i < num_rows; i++) {
+		for (j = 0; j < num_cols; j++)
+			col[j][i] = prop_data[k++];
+	}
+	if (col1)
+		*col1 = col[0];
+	if (col2)
+		*col2 = col[1];
+	if (col3)
+		*col3 = col[2];
+
+	devm_kfree(dev, prop_data);
+
+	return num_rows;
+}
+
+static int clk_init_vdd_class(struct device *dev, struct clk *clk, int num,
+				 unsigned long *fmax, int *uv, int *ua)
+{
+	struct clk_vdd_class *vdd = clk->vdd_class;
+
+	vdd->level_votes = devm_kzalloc(dev, num * sizeof(int), GFP_KERNEL);
+	if (!vdd->level_votes) {
+		dev_err(dev, "Out of memory!\n");
+		return -ENOMEM;
+	}
+	vdd->num_levels = num;
+	vdd->cur_level = num;
+	vdd->vdd_uv = uv;
+	vdd->vdd_ua = ua;
+	clk->fmax = fmax;
+	clk->num_fmax = num;
+
+	return 0;
+}
+
+static int hfpll_base_init(struct platform_device *pdev, struct hfpll_clk *h)
+{
+	struct resource *res;
+	struct device *dev = &pdev->dev;
+
+	res = platform_get_resource_byname(pdev, IORESOURCE_MEM, h->c.dbg_name);
+	if (!res) {
+		dev_err(dev, "%s base addr not found!\n", h->c.dbg_name);
+		return -EINVAL;
+	}
+	h->base = devm_ioremap(dev, res->start, resource_size(res));
+	if (!h->base) {
+		dev_err(dev, "%s ioremap failed!\n", h->c.dbg_name);
+		return -ENOMEM;
+	}
+	return 0;
+}
+
+static bool enable_boost;
+module_param_named(boost, enable_boost, bool, S_IRUGO | S_IWUSR);
+
+static void krait_update_uv(int *uv, int num, int boost_uv)
+{
+	int i;
+
+	switch (read_cpuid_id()) {
+	case 0x511F04D0: /* KR28M2A20 */
+	case 0x511F04D1: /* KR28M2A21 */
+	case 0x510F06F0: /* KR28M4A10 */
+		for (i = 0; i < num; i++)
+			uv[i] = max(1150000, uv[i]);
+	};
+
+	if (enable_boost) {
+		for (i = 0; i < num; i++)
+			uv[i] += boost_uv;
+	}
+}
+
+static int clock_krait_8974_driver_probe(struct platform_device *pdev)
+{
+	struct device *dev = &pdev->dev;
+	struct clk *c;
+	int speed, pvs, ver, rows, cpu;
+	char prop_name[] = "qcom,speedXX-pvsXX-bin-vXX";
+	unsigned long *freq, cur_rate, aux_rate;
+	int *uv, *ua;
+	u32 *dscr, vco_mask, config_val;
+	int ret;
+
+	vdd_l2.regulator[0] = devm_regulator_get(dev, "l2-dig");
+	if (IS_ERR(vdd_l2.regulator[0])) {
+		dev_err(dev, "Unable to get l2-dig regulator!\n");
+		return PTR_ERR(vdd_l2.regulator[0]);
+	}
+
+	vdd_hfpll.regulator[0] = devm_regulator_get(dev, "hfpll-dig");
+	if (IS_ERR(vdd_hfpll.regulator[0])) {
+		dev_err(dev, "Unable to get hfpll-dig regulator!\n");
+		return PTR_ERR(vdd_hfpll.regulator[0]);
+	}
+
+	vdd_hfpll.regulator[1] = devm_regulator_get(dev, "hfpll-analog");
+	if (IS_ERR(vdd_hfpll.regulator[1])) {
+		dev_err(dev, "Unable to get hfpll-analog regulator!\n");
+		return PTR_ERR(vdd_hfpll.regulator[1]);
+	}
+
+	vdd_krait0.regulator[0] = devm_regulator_get(dev, "cpu0");
+	if (IS_ERR(vdd_krait0.regulator[0])) {
+		dev_err(dev, "Unable to get cpu0 regulator!\n");
+		return PTR_ERR(vdd_krait0.regulator[0]);
+	}
+
+	vdd_krait1.regulator[0] = devm_regulator_get(dev, "cpu1");
+	if (IS_ERR(vdd_krait1.regulator[0])) {
+		dev_err(dev, "Unable to get cpu1 regulator!\n");
+		return PTR_ERR(vdd_krait1.regulator[0]);
+	}
+
+	vdd_krait2.regulator[0] = devm_regulator_get(dev, "cpu2");
+	if (IS_ERR(vdd_krait2.regulator[0])) {
+		dev_err(dev, "Unable to get cpu2 regulator!\n");
+		return PTR_ERR(vdd_krait2.regulator[0]);
+	}
+
+	vdd_krait3.regulator[0] = devm_regulator_get(dev, "cpu3");
+	if (IS_ERR(vdd_krait3.regulator[0])) {
+		dev_err(dev, "Unable to get cpu3 regulator!\n");
+		return PTR_ERR(vdd_krait3.regulator[0]);
+	}
+
+	c = devm_clk_get(dev, "hfpll_src");
+	if (IS_ERR(c)) {
+		dev_err(dev, "Unable to get HFPLL source\n");
+		return PTR_ERR(c);
+	}
+	hfpll_src_clk.c.parent = c;
+
+	c = devm_clk_get(dev, "aux_clk");
+	if (IS_ERR(c)) {
+		dev_err(dev, "Unable to get AUX source\n");
+		return PTR_ERR(c);
+	}
+	acpu_aux_clk.c.parent = c;
+
+	if (hfpll_base_init(pdev, &hfpll0_clk))
+		return -EINVAL;
+	if (hfpll_base_init(pdev, &hfpll1_clk))
+		return -EINVAL;
+	if (hfpll_base_init(pdev, &hfpll2_clk))
+		return -EINVAL;
+	if (hfpll_base_init(pdev, &hfpll3_clk))
+		return -EINVAL;
+	if (hfpll_base_init(pdev, &hfpll_l2_clk))
+		return -EINVAL;
+
+	ret = of_property_read_u32(dev->of_node, "qcom,hfpll-config-val",
+			     &config_val);
+	if (!ret)
+		hdata.config_val = config_val;
+
+	ret = of_property_read_u32(dev->of_node, "qcom,hfpll-user-vco-mask",
+			     &vco_mask);
+	if (!ret)
+		hdata.user_vco_mask = vco_mask;
+
+	get_krait_bin_format_b(pdev, &speed, &pvs, &ver);
+	snprintf(prop_name, ARRAY_SIZE(prop_name),
+			"qcom,speed%d-pvs%d-bin-v%d", speed, pvs, ver);
+
+	rows = parse_tbl(dev, prop_name, 3,
+			(u32 **) &freq, (u32 **) &uv, (u32 **) &ua);
+	if (rows < 0) {
+		/* Fall back to most conservative PVS table */
+		dev_err(dev, "Unable to load voltage plan %s!\n", prop_name);
+		ret = parse_tbl(dev, "qcom,speed0-pvs0-bin-v0", 3,
+				(u32 **) &freq, (u32 **) &uv, (u32 **) &ua);
+		if (ret < 0) {
+			dev_err(dev, "Unable to load safe voltage plan\n");
+			return rows;
+		} else {
+			dev_info(dev, "Safe voltage plan loaded.\n");
+			pvs = 0;
+			rows = ret;
+		}
+	}
+
+	krait_update_uv(uv, rows, pvs ? 25000 : 0);
+
+	if (clk_init_vdd_class(dev, &krait0_clk.c, rows, freq, uv, ua))
+		return -ENOMEM;
+	if (clk_init_vdd_class(dev, &krait1_clk.c, rows, freq, uv, ua))
+		return -ENOMEM;
+	if (clk_init_vdd_class(dev, &krait2_clk.c, rows, freq, uv, ua))
+		return -ENOMEM;
+	if (clk_init_vdd_class(dev, &krait3_clk.c, rows, freq, uv, ua))
+		return -ENOMEM;
+
+	/* AVS is optional */
+	rows = parse_tbl(dev, "qcom,avs-tbl", 2, (u32 **) &freq, &dscr, NULL);
+	if (rows > 0) {
+		avs_table.rate = freq;
+		avs_table.dscr = dscr;
+		avs_table.num  = rows;
+	}
+
+	rows = parse_tbl(dev, "qcom,l2-fmax", 2, (u32 **) &freq, (u32 **) &uv,
+			 NULL);
+	if (rows < 0) {
+		dev_err(dev, "Unable to find L2 Fmax table!\n");
+		return rows;
+	}
+
+	if (clk_init_vdd_class(dev, &l2_clk.c, rows, freq, uv, NULL))
+		return -ENOMEM;
+
+	msm_clock_register(kpss_clocks_8974, ARRAY_SIZE(kpss_clocks_8974));
+
+	/*
+	 * We don't want the CPU or L2 clocks to be turned off at late init
+	 * if CPUFREQ or HOTPLUG configs are disabled. So, bump up the
+	 * refcount of these clocks. Any cpufreq/hotplug manager can assume
+	 * that the clocks have already been prepared and enabled by the time
+	 * they take over.
+	 */
+	clk_prepare_enable(&l2_clk.c);
+	for_each_online_cpu(cpu) {
+		WARN(clk_prepare_enable(cpu_clk[cpu]),
+			"Unable to turn on CPU%d clock", cpu);
+	}
+
+	/*
+	 * Force reinit of HFPLLs and muxes to overwrite any potential
+	 * incorrect configuration of HFPLLs and muxes by the bootloader.
+	 * While at it, also make sure the cores are running at known rates
+	 * and print the current rate.
+	 *
+	 * The clocks are set to aux clock rate first to make sure the
+	 * secondary mux is not sourcing off of QSB. The rate is then set to
+	 * two different rates to force a HFPLL reinit under all
+	 * circumstances.
+	 */
+	cur_rate = clk_get_rate(&l2_clk.c);
+	aux_rate = clk_get_rate(&acpu_aux_clk.c);
+	if (!cur_rate) {
+		pr_info("L2 @ unknown rate. Forcing new rate.\n");
+		cur_rate = aux_rate;
+	}
+	clk_set_rate(&l2_clk.c, aux_rate);
+	clk_set_rate(&l2_clk.c, clk_round_rate(&l2_clk.c, 1));
+	clk_set_rate(&l2_clk.c, cur_rate);
+	pr_info("L2 @ %lu KHz\n", clk_get_rate(&l2_clk.c) / 1000);
+	for_each_possible_cpu(cpu) {
+		struct clk *c = cpu_clk[cpu];
+		cur_rate = clk_get_rate(c);
+		if (!cur_rate) {
+			pr_info("CPU%d @ unknown rate. Forcing new rate.\n",
+				cpu);
+			cur_rate = aux_rate;
+		}
+		clk_set_rate(c, aux_rate);
+		clk_set_rate(c, clk_round_rate(c, 1));
+		clk_set_rate(c, clk_round_rate(c, cur_rate));
+		pr_info("CPU%d @ %lu KHz\n", cpu, clk_get_rate(c) / 1000);
+	}
+
+	return 0;
+}
+
+static struct of_device_id match_table[] = {
+	{ .compatible = "qcom,clock-krait-8974" },
+	{}
+};
+
+static struct platform_driver clock_krait_8974_driver = {
+	.probe = clock_krait_8974_driver_probe,
+	.driver = {
+		.name = "clock-krait-8974",
+		.of_match_table = match_table,
+		.owner = THIS_MODULE,
+	},
+};
+
+static int __init clock_krait_8974_init(void)
+{
+	return platform_driver_register(&clock_krait_8974_driver);
+}
+module_init(clock_krait_8974_init);
+
+static void __exit clock_krait_8974_exit(void)
+{
+	platform_driver_unregister(&clock_krait_8974_driver);
+}
+module_exit(clock_krait_8974_exit);
+
+MODULE_DESCRIPTION("Krait CPU clock driver for 8974");
+MODULE_LICENSE("GPL v2");
diff --git a/arch/arm/mach-msm/clock-krait.c b/arch/arm/mach-msm/clock-krait.c
index b96ba62..cdd53e5 100644
--- a/arch/arm/mach-msm/clock-krait.c
+++ b/arch/arm/mach-msm/clock-krait.c
@@ -29,6 +29,7 @@
 
 static DEFINE_SPINLOCK(kpss_clock_reg_lock);
 
+#define LPL_SHIFT	8
 static void __kpss_mux_set_sel(struct mux_clk *mux, int sel)
 {
 	unsigned long flags;
@@ -38,6 +39,10 @@
 	regval = get_l2_indirect_reg(mux->offset);
 	regval &= ~(mux->mask << mux->shift);
 	regval |= (sel & mux->mask) << mux->shift;
+	if (mux->priv) {
+		regval &= ~(mux->mask << (mux->shift + LPL_SHIFT));
+		regval |= (sel & mux->mask) << (mux->shift + LPL_SHIFT);
+	}
 	set_l2_indirect_reg(mux->offset, regval);
 	spin_unlock_irqrestore(&kpss_clock_reg_lock, flags);
 
@@ -95,8 +100,10 @@
 
 	spin_lock_irqsave(&kpss_clock_reg_lock, flags);
 	regval = get_l2_indirect_reg(div->offset);
-	val = (regval >> div->shift) && div->mask;
+	val = (regval >> div->shift) & div->mask;
 	regval &= ~(div->mask << div->shift);
+	if (div->priv)
+		regval &= ~(div->mask << (div->shift + LPL_SHIFT));
 	set_l2_indirect_reg(div->offset, regval);
 	spin_unlock_irqrestore(&kpss_clock_reg_lock, flags);
 
@@ -123,7 +130,8 @@
 		return;
 
 	/* Configure PLL parameters for integer mode. */
-	writel_relaxed(hd->config_val, h->base + hd->config_offset);
+	if (hd->config_val)
+		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);
 
@@ -134,7 +142,7 @@
 		rate = readl_relaxed(h->base + hd->l_offset) * h->src_rate;
 
 		/* Pick the right VCO. */
-		if (rate > hd->low_vco_max_rate)
+		if (hd->user_vco_mask && rate > hd->low_vco_max_rate)
 			regval |= hd->user_vco_mask;
 		writel_relaxed(regval, h->base + hd->user_offset);
 	}
@@ -243,7 +251,7 @@
 		hfpll_clk_disable(c);
 
 	/* Pick the right VCO. */
-	if (hd->user_offset) {
+	if (hd->user_offset && hd->user_vco_mask) {
 		u32 regval;
 		regval = readl_relaxed(h->base + hd->user_offset);
 		if (rate <= hd->low_vco_max_rate)
@@ -394,9 +402,6 @@
 	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;
@@ -412,9 +417,6 @@
 
 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);
 }
 
diff --git a/arch/arm/mach-msm/clock-krait.h b/arch/arm/mach-msm/clock-krait.h
index 2691a8c..07b72d5 100644
--- a/arch/arm/mach-msm/clock-krait.h
+++ b/arch/arm/mach-msm/clock-krait.h
@@ -20,15 +20,18 @@
 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) \
+#define DEFINE_KPSS_DIV2_CLK(clk_name, _parent, _offset, _lf_tree) \
 static struct div_clk clk_name = {		\
-	.div = 2,				\
-	.min_div = 2,				\
-	.max_div = 2,				\
+	.data = {				\
+		.div = 2,			\
+		.min_div = 2,			\
+		.max_div = 2,			\
+	},					\
 	.ops = &clk_div_ops_kpss_div2,		\
 	.offset = _offset,			\
 	.mask = 0x3,				\
 	.shift = 6,				\
+	.priv = (void *) _lf_tree,		\
 	.c = {					\
 		.parent = _parent,		\
 		.dbg_name = #clk_name,		\
@@ -49,9 +52,9 @@
 	const u32 status_offset;
 
 	const u32 droop_val;
-	const u32 config_val;
+	u32 config_val;
 	const u32 user_val;
-	const u32 user_vco_mask;
+	u32 user_vco_mask;
 	unsigned long low_vco_max_rate;
 
 	unsigned long min_rate;
diff --git a/arch/arm/mach-msm/clock-local2.c b/arch/arm/mach-msm/clock-local2.c
index 4488869..01ecba2 100644
--- a/arch/arm/mach-msm/clock-local2.c
+++ b/arch/arm/mach-msm/clock-local2.c
@@ -25,6 +25,7 @@
 
 #include <mach/clk.h>
 #include <mach/clk-provider.h>
+#include <mach/clock-generic.h>
 
 #include "clock-local2.h"
 
@@ -796,153 +797,65 @@
 }
 
 
-#define ENABLE_REG(x)	(*(x)->base + (x)->enable_reg)
-#define SELECT_REG(x)	(*(x)->base + (x)->select_reg)
+static DEFINE_SPINLOCK(mux_reg_lock);
 
-/*
- * mux clock functions
- */
-static void cam_mux_clk_halt_check(void)
+static int mux_reg_enable(struct mux_clk *clk)
 {
-	/* Ensure that the delay starts after the mux disable/enable. */
-	mb();
-	udelay(HALT_CHECK_DELAY_US);
-}
-
-static int cam_mux_clk_enable(struct clk *c)
-{
-	unsigned long flags;
 	u32 regval;
-	struct cam_mux_clk *mux = to_cam_mux_clk(c);
+	unsigned long flags;
+	u32 offset = clk->en_reg ? clk->en_offset : clk->offset;
 
-	spin_lock_irqsave(&local_clock_reg_lock, flags);
-	regval = readl_relaxed(ENABLE_REG(mux));
-	regval |= mux->enable_mask;
-	writel_relaxed(regval, ENABLE_REG(mux));
-	spin_unlock_irqrestore(&local_clock_reg_lock, flags);
-
-	/* Wait for clock to enable before continuing. */
-	cam_mux_clk_halt_check();
+	spin_lock_irqsave(&mux_reg_lock, flags);
+	regval = readl_relaxed(*clk->base + offset);
+	regval |= clk->en_mask;
+	writel_relaxed(regval, *clk->base + offset);
+	/* Ensure enable request goes through before returning */
+	mb();
+	spin_unlock_irqrestore(&mux_reg_lock, flags);
 
 	return 0;
 }
 
-static void cam_mux_clk_disable(struct clk *c)
+static void mux_reg_disable(struct mux_clk *clk)
 {
-	unsigned long flags;
-	struct cam_mux_clk *mux = to_cam_mux_clk(c);
 	u32 regval;
+	unsigned long flags;
+	u32 offset = clk->en_reg ? clk->en_offset : clk->offset;
 
-	spin_lock_irqsave(&local_clock_reg_lock, flags);
-	regval = readl_relaxed(ENABLE_REG(mux));
-	regval &= ~mux->enable_mask;
-	writel_relaxed(regval, ENABLE_REG(mux));
-	spin_unlock_irqrestore(&local_clock_reg_lock, flags);
-
-	/* Wait for clock to disable before continuing. */
-	cam_mux_clk_halt_check();
+	spin_lock_irqsave(&mux_reg_lock, flags);
+	regval = readl_relaxed(*clk->base + offset);
+	regval &= ~clk->en_mask;
+	writel_relaxed(regval, *clk->base + offset);
+	spin_unlock_irqrestore(&mux_reg_lock, flags);
 }
 
-static int mux_source_switch(struct cam_mux_clk *mux, struct mux_source *dest)
+static int mux_reg_set_mux_sel(struct mux_clk *clk, int sel)
 {
-	unsigned long flags;
 	u32 regval;
-	int ret = 0;
+	unsigned long flags;
 
-	ret = __clk_pre_reparent(&mux->c, dest->clk, &flags);
-	if (ret)
-		goto out;
-
-	regval = readl_relaxed(SELECT_REG(mux));
-	regval &= ~mux->select_mask;
-	regval |= dest->select_val;
-	writel_relaxed(regval, SELECT_REG(mux));
-
-	/* Make sure switch request goes through before proceeding. */
+	spin_lock_irqsave(&mux_reg_lock, flags);
+	regval = readl_relaxed(*clk->base + clk->offset);
+	regval &= ~(clk->mask << clk->shift);
+	regval |= (sel & clk->mask) << clk->shift;
+	writel_relaxed(regval, *clk->base + clk->offset);
+	/* Ensure switch request goes through before returning */
 	mb();
-
-	__clk_post_reparent(&mux->c, mux->c.parent, &flags);
-out:
-	return ret;
-}
-
-static int cam_mux_clk_set_parent(struct clk *c, struct clk *parent)
-{
-	struct cam_mux_clk *mux = to_cam_mux_clk(c);
-	struct mux_source *dest = NULL;
-	int ret;
-
-	if (!mux->sources || !parent)
-		return -EPERM;
-
-	dest = mux->sources;
-
-	while (dest->clk) {
-		if (dest->clk == parent)
-			break;
-		dest++;
-	}
-
-	if (!dest->clk)
-		return -EPERM;
-
-	ret = mux_source_switch(mux, dest);
-	if (ret)
-		return ret;
-
-	mux->c.rate = clk_get_rate(dest->clk);
+	spin_unlock_irqrestore(&mux_reg_lock, flags);
 
 	return 0;
 }
 
-static enum handoff cam_mux_clk_handoff(struct clk *c)
+static int mux_reg_get_mux_sel(struct mux_clk *clk)
 {
-	struct cam_mux_clk *mux = to_cam_mux_clk(c);
-	u32 mask = mux->enable_mask;
-	u32 regval = readl_relaxed(ENABLE_REG(mux));
-
-	c->rate = clk_get_rate(c->parent);
-
-	if (mask == (regval & mask))
-		return HANDOFF_ENABLED_CLK;
-
-	return HANDOFF_DISABLED_CLK;
+	u32 regval = readl_relaxed(*clk->base + clk->offset);
+	return !!((regval >> clk->shift) & clk->mask);
 }
 
-static struct clk *cam_mux_clk_get_parent(struct clk *c)
+static bool mux_reg_is_enabled(struct mux_clk *clk)
 {
-	struct cam_mux_clk *mux = to_cam_mux_clk(c);
-	struct mux_source *parent = NULL;
-	u32 regval = readl_relaxed(SELECT_REG(mux));
-
-	if (!mux->sources)
-		return ERR_PTR(-EPERM);
-
-	parent = mux->sources;
-
-	while (parent->clk) {
-		if ((regval & mux->select_mask) == parent->select_val)
-			return parent->clk;
-
-		parent++;
-	}
-
-	return ERR_PTR(-EPERM);
-}
-
-static long cam_mux_clk_list_rate(struct clk *c, unsigned n)
-{
-	struct cam_mux_clk *mux = to_cam_mux_clk(c);
-	int i;
-
-	for (i = 0; i < n; i++)
-		if (!mux->sources[i].clk)
-			break;
-
-	if (!mux->sources[i].clk)
-		return -ENXIO;
-
-	return clk_get_rate(mux->sources[i].clk);
+	u32 regval = readl_relaxed(*clk->base + clk->offset);
+	return !!(regval & clk->en_mask);
 }
 
 struct clk_ops clk_ops_empty;
@@ -1009,13 +922,10 @@
 	.handoff = local_vote_clk_handoff,
 };
 
-struct clk_ops clk_ops_cam_mux = {
-	.enable = cam_mux_clk_enable,
-	.disable = cam_mux_clk_disable,
-	.set_parent = cam_mux_clk_set_parent,
-	.get_parent = cam_mux_clk_get_parent,
-	.handoff = cam_mux_clk_handoff,
-	.list_rate = cam_mux_clk_list_rate,
+struct clk_mux_ops mux_reg_ops = {
+	.enable = mux_reg_enable,
+	.disable = mux_reg_disable,
+	.set_mux_sel = mux_reg_set_mux_sel,
+	.get_mux_sel = mux_reg_get_mux_sel,
+	.is_enabled = mux_reg_is_enabled,
 };
-
-
diff --git a/arch/arm/mach-msm/clock-local2.h b/arch/arm/mach-msm/clock-local2.h
index cee5b8c..8724f63 100644
--- a/arch/arm/mach-msm/clock-local2.h
+++ b/arch/arm/mach-msm/clock-local2.h
@@ -157,38 +157,6 @@
 	return container_of(clk, struct measure_clk, c);
 }
 
-struct mux_source {
-	struct clk *const clk;
-	const u32 select_val;
-};
-
-/**
- * struct cam_mux_clk - branch clock
- * @c: clk
- * @enable_reg: register that contains the enable bit(s) for the mux
- * @select_reg: register that contains the source selection bits for the mux
- * @enable_mask: mask that enables the mux
- * @select_mask: mask for the source selection bits
- * @sources: list of mux sources
- * @base: pointer to base address of ioremapped registers.
- */
-struct cam_mux_clk {
-	struct clk c;
-	const u32 enable_reg;
-	const u32 select_reg;
-	const u32 enable_mask;
-	const u32 select_mask;
-
-	struct mux_source *sources;
-
-	void *const __iomem *base;
-};
-
-static inline struct cam_mux_clk *to_cam_mux_clk(struct clk *clk)
-{
-	return container_of(clk, struct cam_mux_clk, c);
-}
-
 /*
  * Generic set-rate implementations
  */
@@ -200,7 +168,6 @@
  */
 extern spinlock_t local_clock_reg_lock;
 
-extern struct clk_ops clk_ops_cam_mux;
 extern struct clk_ops clk_ops_empty;
 extern struct clk_ops clk_ops_rcg;
 extern struct clk_ops clk_ops_rcg_mnd;
@@ -209,6 +176,7 @@
 extern struct clk_ops clk_ops_rcg_hdmi;
 extern struct clk_ops clk_ops_byte;
 extern struct clk_ops clk_ops_pixel;
+extern struct clk_mux_ops mux_reg_ops;
 
 enum handoff pixel_rcg_handoff(struct clk *clk);
 enum handoff byte_rcg_handoff(struct clk *clk);
diff --git a/arch/arm/mach-msm/clock-mdss-8974.c b/arch/arm/mach-msm/clock-mdss-8974.c
index cf2df18..2fa921a 100644
--- a/arch/arm/mach-msm/clock-mdss-8974.c
+++ b/arch/arm/mach-msm/clock-mdss-8974.c
@@ -727,7 +727,7 @@
 {
 	struct div_clk *div = to_div_clk(c);
 	/* Restore the divider's value */
-	return div->ops->set_div(div, div->div);
+	return div->ops->set_div(div, div->data.div);
 }
 
 int mux_prepare(struct clk *c)
@@ -1492,8 +1492,10 @@
 };
 
 struct div_clk analog_postdiv_clk_8226 = {
-	.max_div = 255,
-	.min_div = 1,
+	.data = {
+		.max_div = 255,
+		.min_div = 1,
+	},
 	.ops = &analog_postdiv_ops,
 	.c = {
 		.parent = &dsi_vco_clk_8226.c,
@@ -1506,7 +1508,11 @@
 
 struct div_clk indirect_path_div2_clk_8226 = {
 	.ops = &fixed_2div_ops,
-	.div = 2,
+	.data = {
+		.div = 2,
+		.min_div = 2,
+		.max_div = 2,
+	},
 	.c = {
 		.parent = &analog_postdiv_clk_8226.c,
 		.dbg_name = "indirect_path_div2_clk",
@@ -1517,8 +1523,10 @@
 };
 
 struct div_clk pixel_clk_src_8226 = {
-	.max_div = 255,
-	.min_div = 1,
+	.data = {
+		.max_div = 255,
+		.min_div = 1,
+	},
 	.ops = &digital_postdiv_ops,
 	.c = {
 		.parent = &dsi_vco_clk_8226.c,
@@ -1546,8 +1554,10 @@
 
 struct div_clk byte_clk_src_8226 = {
 	.ops = &fixed_4div_ops,
-	.min_div = 4,
-	.max_div = 4,
+	.data = {
+		.min_div = 4,
+		.max_div = 4,
+	},
 	.c = {
 		.parent = &byte_mux_8226.c,
 		.dbg_name = "byte_clk_src",
@@ -1585,8 +1595,10 @@
 };
 
 struct div_clk analog_postdiv_clk_8974 = {
-	.max_div = 255,
-	.min_div = 1,
+	.data = {
+		.max_div = 255,
+		.min_div = 1,
+	},
 	.ops = &analog_postdiv_ops,
 	.c = {
 		.parent = &dsi_vco_clk_8974.c,
@@ -1599,7 +1611,11 @@
 
 struct div_clk indirect_path_div2_clk_8974 = {
 	.ops = &fixed_2div_ops,
-	.div = 2,
+	.data = {
+		.div = 2,
+		.min_div = 2,
+		.max_div = 2,
+	},
 	.c = {
 		.parent = &analog_postdiv_clk_8974.c,
 		.dbg_name = "indirect_path_div2_clk",
@@ -1610,8 +1626,10 @@
 };
 
 struct div_clk pixel_clk_src_8974 = {
-	.max_div = 255,
-	.min_div = 1,
+	.data = {
+		.max_div = 255,
+		.min_div = 1,
+	},
 	.ops = &digital_postdiv_ops,
 	.c = {
 		.parent = &dsi_vco_clk_8974.c,
@@ -1639,8 +1657,10 @@
 
 struct div_clk byte_clk_src_8974 = {
 	.ops = &fixed_4div_ops,
-	.min_div = 4,
-	.max_div = 4,
+	.data = {
+		.min_div = 4,
+		.max_div = 4,
+	},
 	.c = {
 		.parent = &byte_mux_8974.c,
 		.dbg_name = "byte_clk_src",
diff --git a/arch/arm/mach-msm/clock.c b/arch/arm/mach-msm/clock.c
index e3c11c5..f7ee79c 100644
--- a/arch/arm/mach-msm/clock.c
+++ b/arch/arm/mach-msm/clock.c
@@ -63,36 +63,44 @@
 /* Update voltage level given the current votes. */
 static int update_vdd(struct clk_vdd_class *vdd_class)
 {
-	int level, rc = 0, i;
+	int level, rc = 0, i, ignore;
 	struct regulator **r = vdd_class->regulator;
 	int *uv = vdd_class->vdd_uv;
 	int *ua = vdd_class->vdd_ua;
 	int n_reg = vdd_class->num_regulators;
+	int cur_lvl = vdd_class->cur_level;
 	int max_lvl = vdd_class->num_levels - 1;
-	int lvl_base;
+	int cur_base = cur_lvl * n_reg;
+	int new_base;
 
+	/* aggregate votes */
 	for (level = max_lvl; level > 0; level--)
 		if (vdd_class->level_votes[level])
 			break;
 
-	if (level == vdd_class->cur_level)
+	if (level == cur_lvl)
 		return 0;
 
 	max_lvl = max_lvl * n_reg;
-	lvl_base = level * n_reg;
+	new_base = level * n_reg;
 	for (i = 0; i < vdd_class->num_regulators; i++) {
-		rc = regulator_set_voltage(r[i], uv[lvl_base + i],
+		rc = regulator_set_voltage(r[i], uv[new_base + i],
 					   uv[max_lvl + i]);
 		if (rc)
 			goto set_voltage_fail;
 
-		if (!ua)
-			continue;
-
-		rc = regulator_set_optimum_mode(r[i], ua[lvl_base + i]);
-		rc = rc > 0 ? 0 : rc;
+		if (ua) {
+			rc = regulator_set_optimum_mode(r[i], ua[new_base + i]);
+			rc = rc > 0 ? 0 : rc;
+			if (rc)
+				goto set_mode_fail;
+		}
+		if (cur_lvl == 0 || cur_lvl == vdd_class->num_levels)
+			rc = regulator_enable(r[i]);
+		else if (level == 0)
+			rc = regulator_disable(r[i]);
 		if (rc)
-			goto set_mode_fail;
+			goto enable_disable_fail;
 	}
 	if (vdd_class->set_vdd && !vdd_class->num_regulators)
 		rc = vdd_class->set_vdd(vdd_class, level);
@@ -102,20 +110,29 @@
 
 	return rc;
 
-set_mode_fail:
-	regulator_set_voltage(r[i], uv[vdd_class->cur_level * n_reg + i],
-			      uv[max_lvl + i]);
-
-set_voltage_fail:
-	lvl_base = vdd_class->cur_level * n_reg;
-	for (i--; i >= 0; i--) {
-		regulator_set_voltage(r[i], uv[lvl_base + i], uv[max_lvl + i]);
-
-		if (!ua)
-			continue;
-		regulator_set_optimum_mode(r[i], ua[lvl_base + i]);
+enable_disable_fail:
+	/*
+	 * set_optimum_mode could use voltage to derive mode.  Restore
+	 * previous voltage setting for r[i] first.
+	 */
+	if (ua) {
+		regulator_set_voltage(r[i], uv[cur_base + i], uv[max_lvl + i]);
+		regulator_set_optimum_mode(r[i], ua[cur_base + i]);
 	}
 
+set_mode_fail:
+	regulator_set_voltage(r[i], uv[cur_base + i], uv[max_lvl + i]);
+
+set_voltage_fail:
+	for (i--; i >= 0; i--) {
+		regulator_set_voltage(r[i], uv[cur_base + i], uv[max_lvl + i]);
+		if (ua)
+			regulator_set_optimum_mode(r[i], ua[cur_base + i]);
+		if (cur_lvl == 0 || cur_lvl == vdd_class->num_levels)
+			regulator_disable(r[i]);
+		else if (level == 0)
+			ignore = regulator_enable(r[i]);
+	}
 	return rc;
 }
 
@@ -527,13 +544,26 @@
 
 long clk_round_rate(struct clk *clk, unsigned long rate)
 {
+	long rrate;
+	unsigned long fmax = 0, i;
+
 	if (IS_ERR_OR_NULL(clk))
 		return -EINVAL;
 
 	if (!clk->ops->round_rate)
 		return -ENOSYS;
 
-	return clk->ops->round_rate(clk, rate);
+	for (i = 0; i < clk->num_fmax; i++)
+		fmax = max(fmax, clk->fmax[i]);
+
+	if (!fmax)
+		fmax = ULONG_MAX;
+
+	rate = min(rate, fmax);
+	rrate = clk->ops->round_rate(clk, rate);
+	if (rrate > fmax)
+		return -EINVAL;
+	return rrate;
 }
 EXPORT_SYMBOL(clk_round_rate);
 
@@ -553,15 +583,16 @@
 {
 	int rc = 0;
 
+	if (!clk->ops->set_parent && clk->parent == parent)
+		return 0;
+
 	if (!clk->ops->set_parent)
 		return -ENOSYS;
 
 	mutex_lock(&clk->prepare_lock);
-	if (clk->parent == parent)
+	if (clk->parent == parent && !(clk->flags & CLKFLAG_NO_RATE_CACHE))
 		goto out;
 	rc = clk->ops->set_parent(clk, parent);
-	if (!rc)
-		clk->parent = parent;
 out:
 	mutex_unlock(&clk->prepare_lock);
 
@@ -607,7 +638,6 @@
 static void vdd_class_init(struct clk_vdd_class *vdd)
 {
 	struct handoff_vdd *v;
-	int i;
 
 	if (!vdd)
 		return;
@@ -621,9 +651,6 @@
 	if (vote_vdd_level(vdd, vdd->num_levels - 1))
 		pr_err("failed to vote for %s\n", vdd->class_name);
 
-	for (i = 0; i < vdd->num_regulators; i++)
-		regulator_enable(vdd->regulator[i]);
-
 	v = kmalloc(sizeof(*v), GFP_KERNEL);
 	if (!v) {
 		pr_err("Unable to kmalloc. %s will be stuck at max.\n",
diff --git a/arch/arm/mach-msm/cpufreq.c b/arch/arm/mach-msm/cpufreq.c
index a6c86af..85a1468 100644
--- a/arch/arm/mach-msm/cpufreq.c
+++ b/arch/arm/mach-msm/cpufreq.c
@@ -27,17 +27,43 @@
 #include <linux/cpumask.h>
 #include <linux/sched.h>
 #include <linux/suspend.h>
+#include <linux/clk.h>
+#include <linux/err.h>
+#include <linux/platform_device.h>
 #include <trace/events/power.h>
 #include <mach/socinfo.h>
-#include <mach/cpufreq.h>
+#include <mach/msm_bus.h>
 
 #include "acpuclock.h"
 
+#ifdef CONFIG_DEBUG_FS
+#include <linux/debugfs.h>
+#include <linux/seq_file.h>
+#include <asm/div64.h>
+#endif
+
+static DEFINE_MUTEX(l2bw_lock);
+
+static struct clk *cpu_clk[NR_CPUS];
+static struct clk *l2_clk;
+static unsigned int freq_index[NR_CPUS];
+static struct cpufreq_frequency_table *freq_table;
+static unsigned int *l2_khz;
+static bool is_clk;
+static bool is_sync;
+static struct msm_bus_vectors *bus_vec_lst;
+static struct msm_bus_scale_pdata bus_bw = {
+	.name = "msm-cpufreq",
+	.active_only = 1,
+};
+static u32 bus_client;
+
 struct cpufreq_work_struct {
 	struct work_struct work;
 	struct cpufreq_policy *policy;
 	struct completion complete;
 	int frequency;
+	unsigned int index;
 	int status;
 };
 
@@ -51,37 +77,45 @@
 
 static DEFINE_PER_CPU(struct cpufreq_suspend_t, cpufreq_suspend);
 
-struct cpu_freq {
-	uint32_t max;
-	uint32_t min;
-	uint32_t allowed_max;
-	uint32_t allowed_min;
-	uint32_t limits_init;
-};
+static void update_l2_bw(int *also_cpu)
+{
+	int rc = 0, cpu;
+	unsigned int index = 0;
 
-static DEFINE_PER_CPU(struct cpu_freq, cpu_freq_info);
+	mutex_lock(&l2bw_lock);
 
-static int set_cpu_freq(struct cpufreq_policy *policy, unsigned int new_freq)
+	if (also_cpu)
+		index = freq_index[*also_cpu];
+
+	for_each_online_cpu(cpu) {
+		index = max(index, freq_index[cpu]);
+	}
+
+	if (l2_clk)
+		rc = clk_set_rate(l2_clk, l2_khz[index] * 1000);
+	if (rc) {
+		pr_err("Error setting L2 clock rate!\n");
+		goto out;
+	}
+
+	if (bus_client)
+		rc = msm_bus_scale_client_update_request(bus_client, index);
+	if (rc)
+		pr_err("Bandwidth req failed (%d)\n", rc);
+
+out:
+	mutex_unlock(&l2bw_lock);
+}
+
+static int set_cpu_freq(struct cpufreq_policy *policy, unsigned int new_freq,
+			unsigned int index)
 {
 	int ret = 0;
 	int saved_sched_policy = -EINVAL;
 	int saved_sched_rt_prio = -EINVAL;
 	struct cpufreq_freqs freqs;
-	struct cpu_freq *limit = &per_cpu(cpu_freq_info, policy->cpu);
 	struct sched_param param = { .sched_priority = MAX_RT_PRIO-1 };
 
-	if (limit->limits_init) {
-		if (new_freq > limit->allowed_max) {
-			new_freq = limit->allowed_max;
-			pr_debug("max: limiting freq to %d\n", new_freq);
-		}
-
-		if (new_freq < limit->allowed_min) {
-			new_freq = limit->allowed_min;
-			pr_debug("min: limiting freq to %d\n", new_freq);
-		}
-	}
-
 	freqs.old = policy->cur;
 	freqs.new = new_freq;
 	freqs.cpu = policy->cpu;
@@ -100,7 +134,18 @@
 	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 (is_clk) {
+		unsigned long rate = new_freq * 1000;
+		rate = clk_round_rate(cpu_clk[policy->cpu], rate);
+		ret = clk_set_rate(cpu_clk[policy->cpu], rate);
+		if (!ret) {
+			freq_index[policy->cpu] = index;
+			update_l2_bw(NULL);
+		}
+	} else {
+		ret = acpuclk_set_rate(policy->cpu, new_freq, SETRATE_CPUFREQ);
+	}
+
 	if (!ret) {
 		trace_cpu_frequency_switch_end(policy->cpu);
 		cpufreq_notify_transition(&freqs, CPUFREQ_POSTCHANGE);
@@ -119,7 +164,8 @@
 	struct cpufreq_work_struct *cpu_work =
 		container_of(work, struct cpufreq_work_struct, work);
 
-	cpu_work->status = set_cpu_freq(cpu_work->policy, cpu_work->frequency);
+	cpu_work->status = set_cpu_freq(cpu_work->policy, cpu_work->frequency,
+					cpu_work->index);
 	complete(&cpu_work->complete);
 }
 
@@ -157,6 +203,7 @@
 	cpu_work = &per_cpu(cpufreq_work, policy->cpu);
 	cpu_work->policy = policy;
 	cpu_work->frequency = table[index].frequency;
+	cpu_work->index = table[index].index;
 	cpu_work->status = -ENODEV;
 
 	cancel_work_sync(&cpu_work->work);
@@ -180,70 +227,12 @@
 
 static unsigned int msm_cpufreq_get_freq(unsigned int cpu)
 {
+	if (is_clk)
+		return clk_get_rate(cpu_clk[cpu]) / 1000;
+
 	return acpuclk_get_rate(cpu);
 }
 
-static inline int msm_cpufreq_limits_init(void)
-{
-	int cpu = 0;
-	int i = 0;
-	struct cpufreq_frequency_table *table = NULL;
-	uint32_t min = (uint32_t) -1;
-	uint32_t max = 0;
-	struct cpu_freq *limit = NULL;
-
-	for_each_possible_cpu(cpu) {
-		limit = &per_cpu(cpu_freq_info, cpu);
-		table = cpufreq_frequency_get_table(cpu);
-		if (table == NULL) {
-			pr_err("%s: error reading cpufreq table for cpu %d\n",
-					__func__, cpu);
-			continue;
-		}
-		for (i = 0; (table[i].frequency != CPUFREQ_TABLE_END); i++) {
-			if (table[i].frequency > max)
-				max = table[i].frequency;
-			if (table[i].frequency < min)
-				min = table[i].frequency;
-		}
-		limit->allowed_min = min;
-		limit->allowed_max = max;
-		limit->min = min;
-		limit->max = max;
-		limit->limits_init = 1;
-	}
-
-	return 0;
-}
-
-int msm_cpufreq_set_freq_limits(uint32_t cpu, uint32_t min, uint32_t max)
-{
-	struct cpu_freq *limit = &per_cpu(cpu_freq_info, cpu);
-
-	if (!limit->limits_init)
-		msm_cpufreq_limits_init();
-
-	if ((min != MSM_CPUFREQ_NO_LIMIT) &&
-		min >= limit->min && min <= limit->max)
-		limit->allowed_min = min;
-	else
-		limit->allowed_min = limit->min;
-
-
-	if ((max != MSM_CPUFREQ_NO_LIMIT) &&
-		max <= limit->max && max >= limit->min)
-		limit->allowed_max = max;
-	else
-		limit->allowed_max = limit->max;
-
-	pr_debug("%s: Limiting cpu %d min = %d, max = %d\n",
-			__func__, cpu,
-			limit->allowed_min, limit->allowed_max);
-
-	return 0;
-}
-EXPORT_SYMBOL(msm_cpufreq_set_freq_limits);
-
 static int __cpuinit msm_cpufreq_init(struct cpufreq_policy *policy)
 {
 	int cur_freq;
@@ -261,7 +250,7 @@
 	 * same frequency. Hence set the cpumask to all cpu.
 	 */
 	if (cpu_is_msm8625() || cpu_is_msm8625q() || cpu_is_msm8226()
-		|| cpu_is_msm8610())
+		|| cpu_is_msm8610() || (is_clk && is_sync))
 		cpumask_setall(policy->cpus);
 
 	if (cpufreq_frequency_table_cpuinfo(policy, table)) {
@@ -275,7 +264,11 @@
 	policy->max = CONFIG_MSM_CPU_FREQ_MAX;
 #endif
 
-	cur_freq = acpuclk_get_rate(policy->cpu);
+	if (is_clk)
+		cur_freq = clk_get_rate(cpu_clk[policy->cpu])/1000;
+	else
+		cur_freq = acpuclk_get_rate(policy->cpu);
+
 	if (cpufreq_frequency_table_target(policy, table, cur_freq,
 	    CPUFREQ_RELATION_H, &index) &&
 	    cpufreq_frequency_table_target(policy, table, cur_freq,
@@ -288,7 +281,7 @@
 	 * Call set_cpu_freq unconditionally so that when cpu is set to
 	 * online, frequency limit will always be updated.
 	 */
-	ret = set_cpu_freq(policy, table[index].frequency);
+	ret = set_cpu_freq(policy, table[index].frequency, table[index].index);
 	if (ret)
 		return ret;
 	pr_debug("cpufreq: cpu%d init at %d switching to %d\n",
@@ -309,22 +302,41 @@
 		unsigned long action, void *hcpu)
 {
 	unsigned int cpu = (unsigned long)hcpu;
+	int rc;
 
-	switch (action) {
+	switch (action & ~CPU_TASKS_FROZEN) {
 	case CPU_ONLINE:
-	case CPU_ONLINE_FROZEN:
 		per_cpu(cpufreq_suspend, cpu).device_suspended = 0;
 		break;
 	case CPU_DOWN_PREPARE:
-	case CPU_DOWN_PREPARE_FROZEN:
 		mutex_lock(&per_cpu(cpufreq_suspend, cpu).suspend_mutex);
 		per_cpu(cpufreq_suspend, cpu).device_suspended = 1;
 		mutex_unlock(&per_cpu(cpufreq_suspend, cpu).suspend_mutex);
 		break;
 	case CPU_DOWN_FAILED:
-	case CPU_DOWN_FAILED_FROZEN:
 		per_cpu(cpufreq_suspend, cpu).device_suspended = 0;
 		break;
+	/*
+	 * Scale down clock/power of CPU that is dead and scale it back up
+	 * before the CPU is brought up.
+	 */
+	case CPU_DEAD:
+	case CPU_UP_CANCELED:
+		if (is_clk) {
+			clk_disable_unprepare(cpu_clk[cpu]);
+			update_l2_bw(NULL);
+		}
+		break;
+	case CPU_UP_PREPARE:
+		if (is_clk) {
+			rc = clk_prepare_enable(cpu_clk[cpu]);
+			if (rc < 0)
+				return NOTIFY_BAD;
+			update_l2_bw(&cpu);
+		}
+		break;
+	default:
+		break;
 	}
 
 	return NOTIFY_OK;
@@ -380,6 +392,242 @@
 	.attr		= msm_freq_attr,
 };
 
+#define PROP_TBL "qcom,cpufreq-table"
+#define PROP_PORTS "qcom,cpu-mem-ports"
+static int cpufreq_parse_dt(struct device *dev)
+{
+	int ret, len, nf, num_cols = 1, num_paths = 0, i, j, k;
+	u32 *data, *ports = NULL;
+	struct msm_bus_vectors *v = NULL;
+
+	if (l2_clk)
+		num_cols++;
+
+	/* Parse optional bus ports parameter */
+	if (of_find_property(dev->of_node, PROP_PORTS, &len)) {
+		len /= sizeof(*ports);
+		if (len % 2)
+			return -EINVAL;
+
+		ports = devm_kzalloc(dev, len * sizeof(*ports), GFP_KERNEL);
+		if (!ports)
+			return -ENOMEM;
+		ret = of_property_read_u32_array(dev->of_node, PROP_PORTS,
+						 ports, len);
+		if (ret)
+			return ret;
+		num_paths = len / 2;
+		num_cols++;
+	}
+
+	/* Parse CPU freq -> L2/Mem BW map table. */
+	if (!of_find_property(dev->of_node, PROP_TBL, &len))
+		return -EINVAL;
+	len /= sizeof(*data);
+
+	if (len % num_cols || len == 0)
+		return -EINVAL;
+	nf = len / num_cols;
+
+	data = devm_kzalloc(dev, len * sizeof(*data), GFP_KERNEL);
+	if (!data)
+		return -ENOMEM;
+
+	ret = of_property_read_u32_array(dev->of_node, PROP_TBL, data, len);
+	if (ret)
+		return ret;
+
+	/* Allocate all data structures. */
+	freq_table = devm_kzalloc(dev, (nf + 1) * sizeof(*freq_table),
+				  GFP_KERNEL);
+	if (!freq_table)
+		return -ENOMEM;
+
+	if (l2_clk) {
+		l2_khz = devm_kzalloc(dev, nf * sizeof(*l2_khz), GFP_KERNEL);
+		if (!l2_khz)
+			return -ENOMEM;
+	}
+
+	if (num_paths) {
+		int sz_u = nf * sizeof(*bus_bw.usecase);
+		int sz_v = nf * num_paths * sizeof(*bus_vec_lst);
+		bus_bw.usecase = devm_kzalloc(dev, sz_u, GFP_KERNEL);
+		v = bus_vec_lst = devm_kzalloc(dev, sz_v, GFP_KERNEL);
+		if (!bus_bw.usecase || !bus_vec_lst)
+			return -ENOMEM;
+	}
+
+	j = 0;
+	for (i = 0; i < nf; i++) {
+		unsigned long f;
+
+		f = clk_round_rate(cpu_clk[0], data[j++] * 1000);
+		if (IS_ERR_VALUE(f))
+			break;
+		f /= 1000;
+
+		/*
+		 * Check if this is the last feasible frequency in the table.
+		 *
+		 * The table listing frequencies higher than what the HW can
+		 * support is not an error since the table might be shared
+		 * across CPUs in different speed bins. It's also not
+		 * sufficient to check if the rounded rate is lower than the
+		 * requested rate as it doesn't cover the following example:
+		 *
+		 * Table lists: 2.2 GHz and 2.5 GHz.
+		 * Rounded rate returns: 2.2 GHz and 2.3 GHz.
+		 *
+		 * In this case, we can CPUfreq to use 2.2 GHz and 2.3 GHz
+		 * instead of rejecting the 2.5 GHz table entry.
+		 */
+		if (i > 0 && f <= freq_table[i-1].frequency)
+			break;
+
+		freq_table[i].index = i;
+		freq_table[i].frequency = f;
+
+		if (l2_clk) {
+			f = clk_round_rate(l2_clk, data[j++] * 1000);
+			if (IS_ERR_VALUE(f)) {
+				pr_err("Error finding L2 rate for CPU %d KHz\n",
+					freq_table[i].frequency);
+				freq_table[i].frequency = CPUFREQ_ENTRY_INVALID;
+			} else {
+				f /= 1000;
+				l2_khz[i] = f;
+			}
+		}
+
+		if (num_paths) {
+			unsigned int bw_mbps = data[j++];
+			bus_bw.usecase[i].num_paths = num_paths;
+			bus_bw.usecase[i].vectors = v;
+			for (k = 0; k < num_paths; k++) {
+				v->src = ports[k * 2];
+				v->dst = ports[k * 2 + 1];
+				v->ib = bw_mbps * 1000000ULL;
+				v++;
+			}
+		}
+	}
+
+	bus_bw.num_usecases = i;
+	freq_table[i].index = i;
+	freq_table[i].frequency = CPUFREQ_TABLE_END;
+
+	if (ports)
+		devm_kfree(dev, ports);
+	devm_kfree(dev, data);
+
+	return 0;
+}
+
+#ifdef CONFIG_DEBUG_FS
+static int msm_cpufreq_show(struct seq_file *m, void *unused)
+{
+	unsigned int i, cpu_freq;
+	uint64_t ib;
+
+	if (!freq_table)
+		return 0;
+
+	seq_printf(m, "%10s%10s", "CPU (KHz)", "L2 (KHz)");
+	if (bus_bw.usecase)
+		seq_printf(m, "%12s", "Mem (MBps)");
+	seq_printf(m, "\n");
+
+	for (i = 0; freq_table[i].frequency != CPUFREQ_TABLE_END; i++) {
+		cpu_freq = freq_table[i].frequency;
+		if (cpu_freq == CPUFREQ_ENTRY_INVALID)
+			continue;
+		seq_printf(m, "%10d", cpu_freq);
+		seq_printf(m, "%10d", l2_khz ? l2_khz[i] : cpu_freq);
+		if (bus_bw.usecase) {
+			ib = bus_bw.usecase[i].vectors[0].ib;
+			do_div(ib, 1000000);
+			seq_printf(m, "%12llu", ib);
+		}
+		seq_printf(m, "\n");
+	}
+	return 0;
+}
+
+static int msm_cpufreq_open(struct inode *inode, struct file *file)
+{
+	return single_open(file, msm_cpufreq_show, inode->i_private);
+}
+
+const struct file_operations msm_cpufreq_fops = {
+	.open		= msm_cpufreq_open,
+	.read		= seq_read,
+	.llseek		= seq_lseek,
+	.release	= seq_release,
+};
+#endif
+
+static int __init msm_cpufreq_probe(struct platform_device *pdev)
+{
+	struct device *dev = &pdev->dev;
+	char clk_name[] = "cpu??_clk";
+	struct clk *c;
+	int cpu, ret;
+
+	l2_clk = devm_clk_get(dev, "l2_clk");
+	if (IS_ERR(l2_clk))
+		l2_clk = NULL;
+
+	for_each_possible_cpu(cpu) {
+		snprintf(clk_name, sizeof(clk_name), "cpu%d_clk", cpu);
+		c = devm_clk_get(dev, clk_name);
+		if (!IS_ERR(c))
+			cpu_clk[cpu] = c;
+		else
+			is_sync = true;
+	}
+
+	if (!cpu_clk[0])
+		return -ENODEV;
+
+	ret = cpufreq_parse_dt(dev);
+	if (ret)
+		return ret;
+
+	for_each_possible_cpu(cpu) {
+		cpufreq_frequency_table_get_attr(freq_table, cpu);
+	}
+
+	if (bus_bw.usecase) {
+		bus_client = msm_bus_scale_register_client(&bus_bw);
+		if (!bus_client)
+			dev_warn(dev, "Unable to register bus client\n");
+	}
+
+	is_clk = true;
+
+#ifdef CONFIG_DEBUG_FS
+	if (!debugfs_create_file("msm_cpufreq", S_IRUGO, NULL, NULL,
+		&msm_cpufreq_fops))
+		return -ENOMEM;
+#endif
+
+	return 0;
+}
+
+static struct of_device_id match_table[] = {
+	{ .compatible = "qcom,msm-cpufreq" },
+	{}
+};
+
+static struct platform_driver msm_cpufreq_plat_driver = {
+	.driver = {
+		.name = "msm-cpufreq",
+		.of_match_table = match_table,
+		.owner = THIS_MODULE,
+	},
+};
+
 static int __init msm_cpufreq_register(void)
 {
 	int cpu;
@@ -389,9 +637,9 @@
 		per_cpu(cpufreq_suspend, cpu).device_suspended = 0;
 	}
 
+	platform_driver_probe(&msm_cpufreq_plat_driver, msm_cpufreq_probe);
 	msm_cpufreq_wq = alloc_workqueue("msm-cpufreq", WQ_HIGHPRI, 0);
 	register_hotcpu_notifier(&msm_cpufreq_cpu_notifier);
-
 	return cpufreq_register_driver(&msm_cpufreq_driver);
 }
 
diff --git a/arch/arm/mach-msm/cpuidle.c b/arch/arm/mach-msm/cpuidle.c
index 7c06268..c480e56 100644
--- a/arch/arm/mach-msm/cpuidle.c
+++ b/arch/arm/mach-msm/cpuidle.c
@@ -112,8 +112,8 @@
 			continue;
 
 		state = &msm_cpuidle_driver.states[state_count];
-		snprintf(state->name, CPUIDLE_NAME_LEN, cstate->name);
-		snprintf(state->desc, CPUIDLE_DESC_LEN, cstate->desc);
+		snprintf(state->name, CPUIDLE_NAME_LEN, "%s", cstate->name);
+		snprintf(state->desc, CPUIDLE_DESC_LEN, "%s", cstate->desc);
 		state->flags = 0;
 		state->exit_latency = 0;
 		state->power_usage = 0;
diff --git a/arch/arm/mach-msm/idle-v7.S b/arch/arm/mach-msm/idle-v7.S
index f8a32b4..2956bd6 100644
--- a/arch/arm/mach-msm/idle-v7.S
+++ b/arch/arm/mach-msm/idle-v7.S
@@ -180,6 +180,7 @@
 	mov	r2, #1
 	and	r1, r2, r1, ASR #30 /* Check if the cache is write back */
 	orr	r1, r0, r1
+	and	r1, r1, #1
 	cmp	r1, #1
 	bne	skip
 	bl	v7_flush_dcache_all
diff --git a/arch/arm/mach-msm/include/mach/clk-provider.h b/arch/arm/mach-msm/include/mach/clk-provider.h
index 75dc240..027606e 100644
--- a/arch/arm/mach-msm/include/mach/clk-provider.h
+++ b/arch/arm/mach-msm/include/mach/clk-provider.h
@@ -17,6 +17,7 @@
 #define __MACH_CLK_PROVIDER_H
 
 #include <linux/types.h>
+#include <linux/err.h>
 #include <linux/list.h>
 #include <linux/clkdev.h>
 #include <linux/spinlock.h>
@@ -93,6 +94,14 @@
 		.lock = __MUTEX_INITIALIZER(_name.lock) \
 	}
 
+#define DEFINE_VDD_REGS_INIT(_name, _num_regulators) \
+	struct clk_vdd_class _name = { \
+		.class_name = #_name, \
+		.regulator = (struct regulator * [_num_regulators]) {}, \
+		.num_regulators = _num_regulators, \
+		.lock = __MUTEX_INITIALIZER(_name.lock) \
+	}
+
 enum handoff {
 	HANDOFF_ENABLED_CLK,
 	HANDOFF_DISABLED_CLK,
@@ -188,4 +197,13 @@
 
 #define CLK_LOOKUP(con, c, dev) { .con_id = con, .clk = &c, .dev_id = dev }
 
+static inline bool is_better_rate(unsigned long req, unsigned long best,
+				  unsigned long new)
+{
+	if (IS_ERR_VALUE(new))
+		return false;
+
+	return (req <= new && new < best) || (best < req && best < new);
+}
+
 #endif
diff --git a/arch/arm/mach-msm/include/mach/clock-generic.h b/arch/arm/mach-msm/include/mach/clock-generic.h
index f6feda0..30a2b93 100644
--- a/arch/arm/mach-msm/include/mach/clock-generic.h
+++ b/arch/arm/mach-msm/include/mach/clock-generic.h
@@ -46,10 +46,14 @@
 	struct clk	*safe_parent;
 	int		safe_sel;
 	struct clk_mux_ops *ops;
+	/* Recursively search for the requested parent. */
+	bool		rec_set_par;
 
 	/* Fields not used by helper function. */
 	void *const __iomem *base;
 	u32		offset;
+	u32		en_offset;
+	int		en_reg;
 	u32		mask;
 	u32		shift;
 	u32		en_mask;
@@ -63,6 +67,8 @@
 	return container_of(c, struct mux_clk, c);
 }
 
+int parent_to_src_sel(struct clk_src *parents, int num_parents, struct clk *p);
+
 extern struct clk_ops clk_ops_gen_mux;
 
 /* ==================== Divider clock ==================== */
@@ -77,11 +83,16 @@
 	void (*disable)(struct div_clk *clk);
 };
 
+struct div_data {
+	unsigned int div;
+	unsigned int min_div;
+	unsigned int max_div;
+	unsigned long rate_margin;
+};
+
 struct div_clk {
-	unsigned int	div;
-	unsigned int	min_div;
-	unsigned int	max_div;
-	unsigned long	rate_margin;
+	struct div_data data;
+
 	/* Optional */
 	struct clk_div_ops *ops;
 
@@ -103,9 +114,17 @@
 extern struct clk_ops clk_ops_div;
 extern struct clk_ops clk_ops_slave_div;
 
+struct ext_clk {
+	struct clk c;
+};
+
+extern struct clk_ops clk_ops_ext;
+
 #define DEFINE_FIXED_DIV_CLK(clk_name, _div, _parent) \
 static struct div_clk clk_name = {	\
-	.div = _div,				\
+	.data = {				\
+		.div = _div,			\
+	},					\
 	.c = {					\
 		.parent = _parent,		\
 		.dbg_name = #clk_name,		\
@@ -116,7 +135,9 @@
 
 #define DEFINE_FIXED_SLAVE_DIV_CLK(clk_name, _div, _parent) \
 static struct div_clk clk_name = {	\
-	.div = _div,				\
+	.data = {				\
+		.div = _div,			\
+	},					\
 	.c = {					\
 		.parent = _parent,		\
 		.dbg_name = #clk_name,		\
@@ -125,4 +146,90 @@
 	}					\
 }
 
+#define DEFINE_EXT_CLK(clk_name, _parent) \
+static struct ext_clk clk_name = {		\
+	.c = {					\
+		.parent = _parent,		\
+		.dbg_name = #clk_name,		\
+		.ops = &clk_ops_ext,		\
+		CLK_INIT(clk_name.c),		\
+	}					\
+}
+
+/* ==================== Mux Div clock ==================== */
+
+struct mux_div_clk;
+
+/*
+ * struct mux_div_ops
+ * the enable and disable ops are optional.
+ */
+
+struct mux_div_ops {
+	int (*set_src_div)(struct mux_div_clk *, u32 src_sel, u32 div);
+	void (*get_src_div)(struct mux_div_clk *, u32 *src_sel, u32 *div);
+	int (*enable)(struct mux_div_clk *);
+	void (*disable)(struct mux_div_clk *);
+	bool (*is_enabled)(struct mux_div_clk *);
+};
+
+/*
+ * struct mux_div_clk - combined mux/divider clock
+ * @priv
+		parameters needed by ops
+ * @safe_freq
+		when switching rates from A to B, the mux div clock will
+		instead switch from A -> safe_freq -> B. This allows the
+		mux_div clock to change rates while enabled, even if this
+		behavior is not supported by the parent clocks.
+
+		If changing the rate of parent A also causes the rate of
+		parent B to change, then safe_freq must be defined.
+
+		safe_freq is expected to have a source clock which is always
+		on and runs at only one rate.
+ * @parents
+		list of parents and mux indicies
+ * @ops
+		function pointers for hw specific operations
+ * @src_sel
+		the mux index which will be used if the clock is enabled.
+ */
+
+struct mux_div_clk {
+	/* Required parameters */
+	struct mux_div_ops		*ops;
+	struct div_data			data;
+	struct clk_src			*parents;
+	u32				num_parents;
+
+	struct clk			c;
+
+	/* Internal */
+	u32				src_sel;
+
+	/* Optional parameters */
+	void				*priv;
+	void __iomem			*base;
+	u32				div_mask;
+	u32				div_offset;
+	u32				div_shift;
+	u32				src_mask;
+	u32				src_offset;
+	u32				src_shift;
+	u32				en_mask;
+	u32				en_offset;
+
+	u32				safe_div;
+	struct clk			*safe_parent;
+	unsigned long			safe_freq;
+};
+
+static inline struct mux_div_clk *to_mux_div_clk(struct clk *clk)
+{
+	return container_of(clk, struct mux_div_clk, c);
+}
+
+extern struct clk_ops clk_ops_mux_div_clk;
+
 #endif
diff --git a/arch/arm/mach-msm/include/mach/cpufreq.h b/arch/arm/mach-msm/include/mach/cpufreq.h
deleted file mode 100644
index 1a6f2d9..0000000
--- a/arch/arm/mach-msm/include/mach/cpufreq.h
+++ /dev/null
@@ -1,42 +0,0 @@
-/* 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
- * 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_MACH_CPUFREQ_H
-#define __ARCH_ARM_MACH_MSM_MACH_CPUFREQ_H
-
-#define MSM_CPUFREQ_NO_LIMIT 0xFFFFFFFF
-
-#ifdef CONFIG_CPU_FREQ_MSM
-
-/**
- * msm_cpufreq_set_freq_limit() - Set max/min freq limits on cpu
- *
- * @cpu: The cpu core for which the limits apply
- * @max: The max frequency allowed
- * @min: The min frequency allowed
- *
- * If the @max or @min is set to MSM_CPUFREQ_NO_LIMIT, the limit
- * will default to the CPUFreq limit.
- *
- * returns 0 on success, errno on failure
- */
-extern int msm_cpufreq_set_freq_limits(
-		uint32_t cpu, uint32_t min, uint32_t max);
-#else
-static inline int msm_cpufreq_set_freq_limits(
-		uint32_t cpu, uint32_t min, uint32_t max)
-{
-	return -ENOSYS;
-}
-#endif
-
-#endif /* __ARCH_ARM_MACH_MSM_MACH_CPUFREQ_H */
diff --git a/arch/arm/mach-msm/iommu_domains.c b/arch/arm/mach-msm/iommu_domains.c
index 20a5249..1d5e0d9 100644
--- a/arch/arm/mach-msm/iommu_domains.c
+++ b/arch/arm/mach-msm/iommu_domains.c
@@ -553,7 +553,8 @@
 	ida_simple_remove(&domain_nums, data->domain_num);
 
 	for (i = 0; i < data->npools; ++i)
-		gen_pool_destroy(data->pools[i].gpool);
+		if (data->pools[i].gpool)
+			gen_pool_destroy(data->pools[i].gpool);
 
 	kfree(data->pools);
 	kfree(data);
diff --git a/arch/arm/mach-msm/krait-regulator.c b/arch/arm/mach-msm/krait-regulator.c
index 4fee0ae..f4456c0 100644
--- a/arch/arm/mach-msm/krait-regulator.c
+++ b/arch/arm/mach-msm/krait-regulator.c
@@ -222,6 +222,7 @@
 	int				ldo_threshold_uV;
 	int				ldo_delta_uV;
 	int				cpu_num;
+	bool				ldo_disable;
 	int				coeff1;
 	int				coeff2;
 	bool				reg_en;
@@ -656,6 +657,9 @@
 {
 	struct krait_power_vreg *kvreg = info;
 
+	if (kvreg->ldo_disable)
+		return;
+
 	/*
 	 * if the krait is in ldo mode and a voltage change is requested on the
 	 * ldo switch to using hs before changing ldo voltage
@@ -1052,6 +1056,7 @@
 			(int)action, cpu, cpu_online(cpu));
 	switch (action & ~CPU_TASKS_FROZEN) {
 	case CPU_UP_PREPARE:
+	case CPU_UP_CANCELED:
 		mutex_lock(&pvreg->krait_power_vregs_lock);
 		kvreg->force_bhs = true;
 		/*
@@ -1062,7 +1067,6 @@
 		__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;
@@ -1173,6 +1177,9 @@
 			& readl_relaxed(kvreg->reg_base + CPU_PWR_CTL);
 	kvreg->online_at_probe
 		= online ? (WAIT_FOR_LOAD | WAIT_FOR_VOLTAGE) : 0x0;
+
+	if (online)
+		kvreg->force_bhs = false;
 }
 
 static void glb_init(void __iomem *apcs_gcc_base)
@@ -1197,6 +1204,7 @@
 	int headroom_uV, retention_uV, ldo_default_uV, ldo_threshold_uV;
 	int ldo_delta_uV;
 	int cpu_num;
+	bool ldo_disable = false;
 
 	if (pdev->dev.of_node) {
 		/* Get init_data from device tree. */
@@ -1280,6 +1288,9 @@
 			pr_err("bad cpu-num= %d specified\n", cpu_num);
 			return -EINVAL;
 		}
+
+		ldo_disable = of_property_read_bool(pdev->dev.of_node,
+					"qcom,ldo-disable");
 	}
 
 	if (!init_data) {
@@ -1333,6 +1344,8 @@
 	kvreg->ldo_threshold_uV = ldo_threshold_uV;
 	kvreg->ldo_delta_uV	= ldo_delta_uV;
 	kvreg->cpu_num		= cpu_num;
+	kvreg->ldo_disable	= ldo_disable;
+	kvreg->force_bhs	= true;
 
 	platform_set_drvdata(pdev, kvreg);
 
@@ -1623,6 +1636,12 @@
 	void *mdd_base;
 	struct krait_power_vreg *kvreg;
 
+	if (version == 0) {
+		gcc_base_ptr = ioremap_nocache(GCC_BASE, SZ_4K);
+		version = readl_relaxed(gcc_base_ptr + VERSION);
+		iounmap(gcc_base_ptr);
+	}
+
 	/* Turn on the BHS, turn off LDO Bypass and power down LDO */
 	reg_val =  BHS_CNT_DEFAULT << BHS_CNT_BIT_POS
 		| LDO_PWR_DWN_MASK
@@ -1630,23 +1649,14 @@
 		| BHS_EN_MASK;
 	writel_relaxed(reg_val, base_ptr + APC_PWR_GATE_CTL);
 
-	if (version == 0) {
-		gcc_base_ptr = ioremap_nocache(GCC_BASE, SZ_4K);
-		version = readl_relaxed(gcc_base_ptr + VERSION);
-		iounmap(gcc_base_ptr);
-	}
+	/* complete the above write before the delay */
+	mb();
+	/* wait for the bhs to settle */
+	udelay(BHS_SETTLING_DELAY_US);
 
-	/* Turn on the BHS segments only for version < 2 */
-	if (version <= KPSS_VERSION_2P0) {
-		/* complete the above write before the delay */
-		mb();
-		/* wait for the bhs to settle */
-		udelay(BHS_SETTLING_DELAY_US);
-
-		/* Turn on BHS segments */
-		reg_val |= BHS_SEG_EN_DEFAULT << BHS_SEG_EN_BIT_POS;
-		writel_relaxed(reg_val, base_ptr + APC_PWR_GATE_CTL);
-	}
+	/* Turn on BHS segments */
+	reg_val |= BHS_SEG_EN_DEFAULT << BHS_SEG_EN_BIT_POS;
+	writel_relaxed(reg_val, base_ptr + APC_PWR_GATE_CTL);
 
 	/* complete the above write before the delay */
 	mb();
diff --git a/arch/arm/mach-msm/msm_watchdog_v2.c b/arch/arm/mach-msm/msm_watchdog_v2.c
index 52e94e6..ead2e95 100644
--- a/arch/arm/mach-msm/msm_watchdog_v2.c
+++ b/arch/arm/mach-msm/msm_watchdog_v2.c
@@ -68,7 +68,7 @@
 
 /*
  * On the kernel command line specify
- * msm_watchdog.enable=1 to enable the watchdog
+ * msm_watchdog_v2.enable=1 to enable the watchdog
  * By default watchdog is turned on
  */
 static int enable = 1;
@@ -76,7 +76,7 @@
 
 /*
  * On the kernel command line specify
- * msm_watchdog.WDT_HZ=<clock val in HZ> to set Watchdog
+ * msm_watchdog_v2.WDT_HZ=<clock val in HZ> to set Watchdog
  * ticks. By default it is set to 32765.
  */
 static long WDT_HZ = 32765;
diff --git a/arch/arm/mach-msm/pm-8x60.c b/arch/arm/mach-msm/pm-8x60.c
index af21584..c8a6496 100644
--- a/arch/arm/mach-msm/pm-8x60.c
+++ b/arch/arm/mach-msm/pm-8x60.c
@@ -16,6 +16,8 @@
 #include <linux/module.h>
 #include <linux/kernel.h>
 #include <linux/init.h>
+#include <linux/clk.h>
+#include <linux/clkdev.h>
 #include <linux/completion.h>
 #include <linux/cpuidle.h>
 #include <linux/interrupt.h>
@@ -82,6 +84,8 @@
 module_param_named(sleep_time_override,
 	msm_pm_sleep_time_override, int, S_IRUGO | S_IWUSR | S_IWGRP);
 
+static bool use_acpuclk_apis;
+
 enum {
 	MSM_PM_DEBUG_SUSPEND = BIT(0),
 	MSM_PM_DEBUG_POWER_COLLAPSE = BIT(1),
@@ -135,6 +139,9 @@
 static struct msm_pm_sleep_status_data *msm_pm_slp_sts;
 static bool msm_pm_pc_reset_timer;
 
+DEFINE_PER_CPU(struct clk *, cpu_clks);
+static struct clk *l2_clk;
+
 static int msm_pm_get_pc_mode(struct device_node *node,
 		const char *key, uint32_t *pc_mode_val)
 {
@@ -560,6 +567,58 @@
 	return collapsed;
 }
 
+static int ramp_down_last_cpu(int cpu)
+{
+	struct clk *cpu_clk = per_cpu(cpu_clks, cpu);
+	int ret = 0;
+
+	if (use_acpuclk_apis) {
+		ret = acpuclk_power_collapse();
+		if (MSM_PM_DEBUG_CLOCK & msm_pm_debug_mask)
+			pr_info("CPU%u: %s: change clk rate(old rate = %d)\n",
+					cpu, __func__, ret);
+	} else {
+		clk_disable(cpu_clk);
+		clk_disable(l2_clk);
+	}
+	return ret;
+}
+
+static int ramp_up_first_cpu(int cpu, int saved_rate)
+{
+	struct clk *cpu_clk = per_cpu(cpu_clks, cpu);
+	int rc = 0;
+
+	if (MSM_PM_DEBUG_CLOCK & msm_pm_debug_mask)
+		pr_info("CPU%u: %s: restore clock rate\n",
+				cpu, __func__);
+
+	if (use_acpuclk_apis) {
+		rc = acpuclk_set_rate(cpu, saved_rate, SETRATE_PC);
+		if (rc)
+			pr_err("CPU:%u: Error restoring cpu clk\n", cpu);
+	} else {
+		if (l2_clk) {
+			rc = clk_enable(l2_clk);
+			if (rc)
+				pr_err("%s(): Error restoring l2 clk\n",
+						__func__);
+		}
+
+		if (cpu_clk) {
+			int ret = clk_enable(cpu_clk);
+
+			if (ret) {
+				pr_err("%s(): Error restoring cpu clk\n",
+						__func__);
+				return ret;
+			}
+		}
+	}
+
+	return rc;
+}
+
 static bool msm_pm_power_collapse(bool from_idle)
 {
 	unsigned int cpu = smp_processor_id();
@@ -581,11 +640,7 @@
 	avs_set_avscsr(0); /* Disable AVS */
 
 	if (cpu_online(cpu) && !msm_no_ramp_down_pc)
-		saved_acpuclk_rate = acpuclk_power_collapse();
-
-	if (MSM_PM_DEBUG_CLOCK & msm_pm_debug_mask)
-		pr_info("CPU%u: %s: change clock rate (old rate = %lu)\n",
-			cpu, __func__, saved_acpuclk_rate);
+		saved_acpuclk_rate = ramp_down_last_cpu(cpu);
 
 	if (cp15_data.save_cp15)
 		msm_pm_save_cpu_reg();
@@ -595,15 +650,8 @@
 	if (cp15_data.save_cp15)
 		msm_pm_restore_cpu_reg();
 
-	if (cpu_online(cpu)) {
-		if (MSM_PM_DEBUG_CLOCK & msm_pm_debug_mask)
-			pr_info("CPU%u: %s: restore clock rate to %lu\n",
-				cpu, __func__, saved_acpuclk_rate);
-		if (!msm_no_ramp_down_pc &&
-			acpuclk_set_rate(cpu, saved_acpuclk_rate, SETRATE_PC)
-				< 0)
-			pr_err("CPU%u: %s: failed to restore clock rate(%lu)\n",
-				cpu, __func__, saved_acpuclk_rate);
+	if (cpu_online(cpu) && !msm_no_ramp_down_pc) {
+		ramp_up_first_cpu(cpu, saved_acpuclk_rate);
 	} else {
 		unsigned int gic_dist_enabled;
 		unsigned int gic_dist_pending;
@@ -1617,6 +1665,46 @@
 	.llseek = no_llseek,
 };
 
+static int msm_pm_clk_init(struct platform_device *pdev)
+{
+	bool synced_clocks;
+	u32 cpu;
+	char clk_name[] = "cpu??_clk";
+	bool cpu_as_clocks;
+	char *key;
+
+	key = "qcom,cpus-as-clocks";
+	cpu_as_clocks = of_property_read_bool(pdev->dev.of_node, key);
+
+	if (!cpu_as_clocks) {
+		use_acpuclk_apis = true;
+		return 0;
+	}
+
+	key = "qcom,synced-clocks";
+	synced_clocks = of_property_read_bool(pdev->dev.of_node, key);
+
+	for_each_possible_cpu(cpu) {
+		struct clk *clk;
+		snprintf(clk_name, sizeof(clk_name), "cpu%d_clk", cpu);
+		clk = devm_clk_get(&pdev->dev, clk_name);
+		if (IS_ERR(clk)) {
+			if (cpu && synced_clocks)
+				return 0;
+			else
+				return PTR_ERR(clk);
+		}
+		per_cpu(cpu_clks, cpu) = clk;
+	}
+
+	if (synced_clocks)
+		return 0;
+
+	l2_clk = devm_clk_get(&pdev->dev, "l2_clk");
+
+	return PTR_RET(l2_clk);
+}
+
 static int __devinit msm_pm_8x60_probe(struct platform_device *pdev)
 {
 	char *key = NULL;
@@ -1661,6 +1749,12 @@
 		memcpy(&pdata_local, d, sizeof(struct msm_pm_init_data_type));
 
 	} else {
+		ret = msm_pm_clk_init(pdev);
+		if (ret) {
+			pr_info("msm_pm_clk_init returned error\n");
+			return ret;
+		}
+
 		key = "qcom,pc-mode";
 		ret = msm_pm_get_pc_mode(pdev->dev.of_node,
 				key,
diff --git a/arch/arm/mach-msm/qdsp6v2/audio_utils.c b/arch/arm/mach-msm/qdsp6v2/audio_utils.c
index 85af4a7..ccacd3e 100644
--- a/arch/arm/mach-msm/qdsp6v2/audio_utils.c
+++ b/arch/arm/mach-msm/qdsp6v2/audio_utils.c
@@ -99,7 +99,7 @@
 int audio_in_disable(struct q6audio_in  *audio)
 {
 	int rc = 0;
-	if (audio->opened) {
+	if (!audio->stopped) {
 		audio->enabled = 0;
 		audio->opened = 0;
 		pr_debug("%s:session id %d: inbytes[%d] insamples[%d]\n",
diff --git a/arch/arm/mach-msm/qdsp6v2/audio_utils_aio.c b/arch/arm/mach-msm/qdsp6v2/audio_utils_aio.c
index a1463bc..5fa7b1b 100644
--- a/arch/arm/mach-msm/qdsp6v2/audio_utils_aio.c
+++ b/arch/arm/mach-msm/qdsp6v2/audio_utils_aio.c
@@ -179,6 +179,16 @@
 			pr_err("%s[%p]: pause cmd failed rc=%d\n",
 				__func__, audio, rc);
 
+		if (rc == 0) {
+			/* Send suspend only if pause was successful */
+			rc = q6asm_cmd(audio->ac, CMD_SUSPEND);
+			if (rc < 0)
+				pr_err("%s[%p]: suspend cmd failed rc=%d\n",
+					__func__, audio, rc);
+		} else
+			pr_err("%s[%p]: not sending suspend since pause failed\n",
+				__func__, audio);
+
 	} else
 		pr_err("%s[%p]: Driver not enabled\n", __func__, audio);
 	return rc;
diff --git a/arch/arm/mach-msm/rpm-regulator-smd.c b/arch/arm/mach-msm/rpm-regulator-smd.c
index 923e647..faf774f 100644
--- a/arch/arm/mach-msm/rpm-regulator-smd.c
+++ b/arch/arm/mach-msm/rpm-regulator-smd.c
@@ -1266,14 +1266,16 @@
 {
 	struct device *dev = &pdev->dev;
 	struct rpm_regulator *reg;
+	struct rpm_vreg *rpm_vreg;
 
 	reg = platform_get_drvdata(pdev);
 	if (reg) {
-		rpm_vreg_lock(reg->rpm_vreg);
+		rpm_vreg = reg->rpm_vreg;
+		rpm_vreg_lock(rpm_vreg);
 		regulator_unregister(reg->rdev);
 		list_del(&reg->list);
 		kfree(reg);
-		rpm_vreg_unlock(reg->rpm_vreg);
+		rpm_vreg_unlock(rpm_vreg);
 	} else {
 		dev_err(dev, "%s: drvdata missing\n", __func__);
 		return -EINVAL;
diff --git a/arch/arm/mach-msm/sensors_adsp.c b/arch/arm/mach-msm/sensors_adsp.c
index 1534358..fab10b8 100644
--- a/arch/arm/mach-msm/sensors_adsp.c
+++ b/arch/arm/mach-msm/sensors_adsp.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
@@ -355,6 +355,7 @@
 	if (temp == NULL) {
 		pr_err("%s: allocation failure\n", __func__);
 		rv = -ENOMEM;
+		goto out;
 	}
 
 	hdr->dst_module = SNS_OCMEM_MODULE_ADSP;
@@ -387,6 +388,7 @@
 
 	kfree(temp);
 
+out:
 	return rv;
 }
 
@@ -874,7 +876,7 @@
 
 	vectors = ocmem_get_vectors(SNS_OCMEM_CLIENT_ID, sns_ctl.buf);
 	if ((vectors != NULL)) {
-		memcpy(&msg.vectors, vectors, sizeof(vectors));
+		memcpy(&msg.vectors, vectors, sizeof(*vectors));
 		/* TODO: set vectors_len */
 		msg.vectors_valid = true;
 		msg.vectors_len = 0;
diff --git a/arch/arm/mach-msm/smd.c b/arch/arm/mach-msm/smd.c
index 110ab87..cb9697d 100644
--- a/arch/arm/mach-msm/smd.c
+++ b/arch/arm/mach-msm/smd.c
@@ -3243,7 +3243,7 @@
  */
 void smd_set_edge_subsys_name(uint32_t edge, const char *subsys_name)
 {
-	if (edge <= ARRAY_SIZE(edge_to_pids))
+	if (edge < ARRAY_SIZE(edge_to_pids))
 		strlcpy(edge_to_pids[edge].subsys_name,
 			subsys_name, SMD_MAX_CH_NAME_LEN);
 	else
@@ -3258,7 +3258,7 @@
  */
 void smd_set_edge_initialized(uint32_t edge)
 {
-	if (edge <= ARRAY_SIZE(edge_to_pids))
+	if (edge < ARRAY_SIZE(edge_to_pids))
 		edge_to_pids[edge].initialized = true;
 	else
 		pr_err("%s: Invalid edge type[%d]\n", __func__, edge);
diff --git a/arch/arm/mach-msm/socinfo.c b/arch/arm/mach-msm/socinfo.c
index 8af3890..4b68e66 100644
--- a/arch/arm/mach-msm/socinfo.c
+++ b/arch/arm/mach-msm/socinfo.c
@@ -1080,7 +1080,7 @@
 			msm_get_image_crm_version, msm_set_image_crm_version);
 
 static struct device_attribute select_image =
-	__ATTR(select_image, S_IRUGO | S_IWUGO,
+	__ATTR(select_image, S_IRUGO | S_IWUSR,
 			msm_get_image_number, msm_select_image);
 
 static struct sysdev_class soc_sysdev_class = {
diff --git a/arch/arm/vfp/vfpmodule.c b/arch/arm/vfp/vfpmodule.c
index 1d12b07..9a1a2eb 100644
--- a/arch/arm/vfp/vfpmodule.c
+++ b/arch/arm/vfp/vfpmodule.c
@@ -85,6 +85,7 @@
 	}
 #ifdef CONFIG_SMP
 	thread->vfpstate.hard.cpu = NR_CPUS;
+	vfp_current_hw_state[cpu] = NULL;
 #endif
 }
 
diff --git a/arch/sparc/mm/init_32.c b/arch/sparc/mm/init_32.c
index c5f9021..fbf4eeb 100644
--- a/arch/sparc/mm/init_32.c
+++ b/arch/sparc/mm/init_32.c
@@ -77,7 +77,7 @@
 	printk("Mem-info:\n");
 	show_free_areas(filter);
 	printk("Free swap:       %6ldkB\n",
-	       nr_swap_pages << (PAGE_SHIFT-10));
+	       get_nr_swap_pages() << (PAGE_SHIFT-10));
 	printk("%ld pages of RAM\n", totalram_pages);
 	printk("%ld free pages\n", nr_free_pages());
 #if 0 /* undefined pgtable_cache_size, pgd_cache_size */
diff --git a/arch/tile/mm/pgtable.c b/arch/tile/mm/pgtable.c
index 2410aa8..ea7dd38 100644
--- a/arch/tile/mm/pgtable.c
+++ b/arch/tile/mm/pgtable.c
@@ -61,7 +61,7 @@
 	       global_page_state(NR_PAGETABLE),
 	       global_page_state(NR_BOUNCE),
 	       global_page_state(NR_FILE_PAGES),
-	       nr_swap_pages);
+	       get_nr_swap_pages());
 
 	for_each_zone(zone) {
 		unsigned long flags, order, total = 0, largest_order = -1;
diff --git a/drivers/char/diag/diag_dci.c b/drivers/char/diag/diag_dci.c
index 97dc26d..91b90a8 100644
--- a/drivers/char/diag/diag_dci.c
+++ b/drivers/char/diag/diag_dci.c
@@ -419,6 +419,8 @@
 
 	/* Notify the DCI process that the peripheral DCI Channel is up */
 	for (i = 0; i < MAX_DCI_CLIENTS; i++) {
+		if (!driver->dci_client_tbl[i].client)
+			continue;
 		if (driver->dci_client_tbl[i].list & peripheral_mask) {
 			info.si_signo = driver->dci_client_tbl[i].signal_type;
 			stat = send_sig_info(
diff --git a/drivers/char/diag/diag_masks.c b/drivers/char/diag/diag_masks.c
index 69e6250..c28b3bd 100644
--- a/drivers/char/diag/diag_masks.c
+++ b/drivers/char/diag/diag_masks.c
@@ -229,83 +229,90 @@
 static void diag_disable_log_mask(void)
 {
 	int i = 0;
-	struct mask_info *parse_ptr = (struct mask_info *)(driver->log_masks);
+	struct diag_log_mask_t *log_item = NULL;
 
-	pr_debug("diag: disable log masks\n");
-	mutex_lock(&driver->diagchar_mutex);
-	for (i = 0; i < MAX_EQUIP_ID; i++) {
-		pr_debug("diag: equip id %d\n", parse_ptr->equip_id);
-		if (!(parse_ptr->equip_id)) /* Reached a null entry */
-			break;
-		memset(driver->log_masks + parse_ptr->index, 0,
-			    (parse_ptr->num_items + 7)/8);
-		parse_ptr++;
-	}
+	mutex_lock(&driver->log_mask_mutex);
+	log_item = (struct diag_log_mask_t *)driver->log_masks;
+	for (i = 0; i < MAX_EQUIP_ID; i++, log_item++)
+		memset(log_item->ptr, 0, MAX_ITEMS_PER_EQUIP_ID);
+
 	driver->log_status = DIAG_CTRL_MASK_ALL_DISABLED;
-	mutex_unlock(&driver->diagchar_mutex);
+	mutex_unlock(&driver->log_mask_mutex);
 }
 
-int chk_equip_id_and_mask(int equip_id, uint8_t *buf)
+static int copy_log_mask_equip(int equip_id, uint8_t *buf)
 {
-	int i = 0, flag = 0, num_items, offset;
-	unsigned char *ptr_data;
-	struct mask_info *ptr = (struct mask_info *)(driver->log_masks);
+	int i, ret = 0;
+	uint8_t *temp = buf;
+	struct diag_log_mask_t *log_item = NULL;
+	uint32_t mask_size = 0;
 
-	pr_debug("diag: received equip id = %d\n", equip_id);
-	/* Check if this is valid equipment ID */
-	for (i = 0; i < MAX_EQUIP_ID; i++) {
-		if ((ptr->equip_id == equip_id) && (ptr->index != 0)) {
-			offset = ptr->index;
-			num_items = ptr->num_items;
-			flag = 1;
+	if (!buf)
+		return ret;
+
+	log_item = (struct diag_log_mask_t *)driver->log_masks;
+	for (i = 0; i < MAX_EQUIP_ID; i++, log_item++) {
+		if (log_item->equip_id != equip_id)
+			continue;
+		*(int *)temp = log_item->equip_id;
+		temp += sizeof(int);
+		*(int *)(temp) = log_item->num_items;
+		temp += sizeof(int);
+		mask_size = LOG_ITEMS_TO_SIZE(log_item->num_items);
+		if (mask_size > MAX_ITEMS_PER_EQUIP_ID) {
+			pr_err("diag: Invalid length: %d in %s, perimissible: %d",
+				mask_size, __func__, MAX_ITEMS_PER_EQUIP_ID);
 			break;
 		}
-		ptr++;
+		if (mask_size > 0) {
+			memcpy(temp, log_item->ptr, mask_size);
+			/*
+			 * Return the total number of bytes copied = size of
+			 * equip_id (int) + size of num_items (int) + mask_size
+			 */
+			ret = (2 * sizeof(int)) + mask_size;
+		}
+		break;
 	}
-	if (!flag)
-		return -EPERM;
-	ptr_data = driver->log_masks + offset;
-	memcpy(buf, ptr_data, (num_items+7)/8);
-	return 0;
+
+	return ret;
 }
 
 static void diag_update_log_mask(int equip_id, uint8_t *buf, int num_items)
 {
-	uint8_t *temp = buf;
 	int i = 0;
-	unsigned char *ptr_data;
-	int offset = (sizeof(struct mask_info))*MAX_EQUIP_ID;
-	struct mask_info *ptr = (struct mask_info *)(driver->log_masks);
+	struct diag_log_mask_t *log_item = NULL;
+	uint32_t mask_size = 0;
 
-	pr_debug("diag: received equip id = %d\n", equip_id);
-	mutex_lock(&driver->diagchar_mutex);
-	/* Check if we already know index of this equipment ID */
-	for (i = 0; i < MAX_EQUIP_ID; i++) {
-		if ((ptr->equip_id == equip_id) && (ptr->index != 0)) {
-			offset = ptr->index;
-			break;
-		}
-		if ((ptr->equip_id == 0) && (ptr->index == 0)) {
-			/* Reached a null entry */
-			ptr->equip_id = equip_id;
-			ptr->num_items = num_items;
-			ptr->index = driver->log_masks_length;
-			offset = driver->log_masks_length;
-			driver->log_masks_length += ((num_items+7)/8);
-			break;
-		}
-		ptr++;
+	mutex_lock(&driver->log_mask_mutex);
+	driver->log_status = DIAG_CTRL_MASK_INVALID;
+	if (!buf || (equip_id < 0 || equip_id >= MAX_EQUIP_ID) ||
+							num_items < 1) {
+		pr_err("diag: Invalid params in %s, buf: %x equip_id: %d, num_items: %d\n",
+		       __func__, (unsigned int)buf, equip_id, num_items);
+		mutex_unlock(&driver->log_mask_mutex);
+		return;
 	}
-	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);
+	mask_size = LOG_ITEMS_TO_SIZE(num_items);
+	if (mask_size > MAX_ITEMS_PER_EQUIP_ID) {
+		pr_err("diag: In %s, Invalid mask_size %d\n", __func__,
+								mask_size);
+		mutex_unlock(&driver->log_mask_mutex);
+		return;
+	}
+
+	log_item = (struct diag_log_mask_t *)driver->log_masks;
+	for (i = 0; i < MAX_EQUIP_ID; i++, log_item++) {
+		if (log_item->equip_id != equip_id)
+			continue;
+		/* Found the equip id */
+		log_item->num_items = num_items;
+		if (mask_size > 0)
+			memcpy(log_item->ptr, buf, mask_size);
 		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;
+		break;
 	}
-	mutex_unlock(&driver->diagchar_mutex);
+	mutex_unlock(&driver->log_mask_mutex);
 }
 
 void diag_mask_update_fn(struct work_struct *work)
@@ -335,72 +342,76 @@
 void diag_send_log_mask_update(smd_channel_t *ch, int equip_id)
 {
 	void *buf = driver->buf_log_mask_update;
-	int header_size = sizeof(struct diag_ctrl_log_mask);
-	struct mask_info *ptr = (struct mask_info *)driver->log_masks;
-	int i, size, wr_size = -ENOMEM, retry_count = 0;
+	struct diag_log_mask_t *log_item = NULL;
+	struct diag_ctrl_log_mask ctrl_pkt;
+	uint32_t log_mask_size = 0;
+	int wr_size = -ENOMEM, retry_count = 0;
+	int i, header_size, send_once = 0;
 
+	header_size = sizeof(struct diag_ctrl_log_mask);
+	log_item = (struct diag_log_mask_t *)driver->log_masks;
 	mutex_lock(&driver->diag_cntl_mutex);
-	for (i = 0; i < MAX_EQUIP_ID; i++) {
-		size = (ptr->num_items+7)/8;
-		/* reached null entry */
-		if ((ptr->equip_id == 0) && (ptr->index == 0))
-			break;
-		driver->log_mask->cmd_type = DIAG_CTRL_MSG_LOG_MASK;
-		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->equip_id = ptr->equip_id;
-		driver->log_mask->status = driver->log_status;
+	for (i = 0; i < MAX_EQUIP_ID; i++, log_item++) {
+		if (equip_id != i && equip_id != ALL_EQUIP_ID)
+			continue;
+		log_mask_size = LOG_ITEMS_TO_SIZE(log_item->num_items);
+		ctrl_pkt.cmd_type = DIAG_CTRL_MSG_LOG_MASK;
+		ctrl_pkt.data_len = 11 + log_mask_size;
+		ctrl_pkt.stream_id = 1;
+		ctrl_pkt.status = driver->log_status;
 		switch (driver->log_status) {
 		case DIAG_CTRL_MASK_ALL_DISABLED:
-			driver->log_mask->log_mask_size = 0;
+			ctrl_pkt.equip_id = 0;
+			ctrl_pkt.num_items = 0;
+			ctrl_pkt.log_mask_size = 0;
+			send_once = 1;
 			break;
 		case DIAG_CTRL_MASK_ALL_ENABLED:
-			driver->log_mask->log_mask_size = 0;
+			ctrl_pkt.equip_id = 0;
+			ctrl_pkt.num_items = 0;
+			ctrl_pkt.log_mask_size = 0;
+			send_once = 1;
 			break;
 		case DIAG_CTRL_MASK_VALID:
-			driver->log_mask->log_mask_size = size;
+			ctrl_pkt.equip_id = i;
+			ctrl_pkt.num_items = log_item->num_items;
+			ctrl_pkt.log_mask_size = log_mask_size;
+			send_once = 0;
 			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) {
+				 driver->log_status);
 			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);
-			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,
-							 header_size + size);
-					if (wr_size == -ENOMEM) {
-						retry_count++;
-						usleep_range(10000, 10100);
-					} else
-						break;
-				}
-				if (wr_size != header_size + size)
-					pr_err("diag: log mask update failed %d, tried %d",
-						wr_size, header_size + size);
-				else
-					pr_debug("diag: updated log equip ID %d,len %d\n",
-					driver->log_mask->equip_id,
-					driver->log_mask->log_mask_size);
-			} else
-				pr_err("diag: ch not valid for log update\n");
+		memcpy(buf, &ctrl_pkt, header_size);
+		if (log_mask_size > 0) {
+			memcpy(buf + header_size, log_item->ptr,
+			       log_mask_size);
 		}
-		ptr++;
+
+		if (ch) {
+			while (retry_count < 3) {
+				wr_size = smd_write(ch, buf,
+						header_size + log_mask_size);
+				if (wr_size == -ENOMEM) {
+					retry_count++;
+					usleep_range(10000, 10100);
+				} else
+				break;
+			}
+			if (wr_size != header_size + log_mask_size)
+				pr_err("diag: log mask update failed %d, tried %d",
+					wr_size, header_size + log_mask_size);
+			else
+				pr_debug("diag: updated log equip ID %d,len %d\n",
+					 i, log_mask_size);
+		} else
+			pr_err("diag: ch not valid for log update\n");
+		if (send_once)
+			break;
 	}
+
 	mutex_unlock(&driver->diag_cntl_mutex);
 }
 
@@ -623,7 +634,7 @@
 	int ssid_first, ssid_last, ssid_range;
 	int rt_mask, rt_first_ssid, rt_last_ssid, rt_mask_size;
 	uint8_t *rt_mask_ptr;
-	int equip_id, num_items;
+	int equip_id, copy_len;
 #if defined(CONFIG_DIAG_OVER_USB)
 	int payload_length;
 #endif
@@ -631,7 +642,6 @@
 	/* Set log masks */
 	if (*buf == 0x73 && *(int *)(buf+4) == 3) {
 		buf += 8;
-		/* Read Equip ID and pass as first param below*/
 		diag_update_log_mask(*(int *)buf, buf+8, *(int *)(buf+4));
 		diag_update_userspace_clients(LOG_MASKS_TYPE);
 #if defined(CONFIG_DIAG_OVER_USB)
@@ -639,7 +649,8 @@
 			driver->apps_rsp_buf[0] = 0x73;
 			*(int *)(driver->apps_rsp_buf + 4) = 0x3; /* op. ID */
 			*(int *)(driver->apps_rsp_buf + 8) = 0x0; /* success */
-			payload_length = 8 + ((*(int *)(buf + 4)) + 7)/8;
+			payload_length = 8 +
+					LOG_ITEMS_TO_SIZE(*(int *)(buf + 4));
 			if (payload_length > APPS_BUF_SIZE - 12) {
 				pr_err("diag: log masks: buffer overflow\n");
 				return -EIO;
@@ -663,20 +674,16 @@
 		if (!(driver->smd_data[MODEM_DATA].ch) &&
 						chk_apps_only()) {
 			equip_id = *(int *)(buf + 8);
-			num_items = *(int *)(buf + 12);
 			driver->apps_rsp_buf[0] = 0x73;
 			driver->apps_rsp_buf[1] = 0x0;
 			driver->apps_rsp_buf[2] = 0x0;
 			driver->apps_rsp_buf[3] = 0x0;
 			*(int *)(driver->apps_rsp_buf + 4) = 0x4;
-			if (!chk_equip_id_and_mask(equip_id,
-				driver->apps_rsp_buf+20))
-				*(int *)(driver->apps_rsp_buf + 8) = 0x0;
-			else
-				*(int *)(driver->apps_rsp_buf + 8) = 0x1;
-			*(int *)(driver->apps_rsp_buf + 12) = equip_id;
-			*(int *)(driver->apps_rsp_buf + 16) = num_items;
-			encode_rsp_and_send(20+(num_items+7)/8-1);
+			copy_len = copy_log_mask_equip(equip_id,
+						driver->apps_rsp_buf + 12);
+			*(int *)(driver->apps_rsp_buf + 8) =
+						(copy_len == 0) ? 1 : 0;
+			encode_rsp_and_send(12 + copy_len);
 			return 0;
 		}
 #endif
@@ -858,6 +865,19 @@
 	return  packet_type;
 }
 
+static void diag_log_mask_init(void)
+{
+	struct diag_log_mask_t *log_item = NULL;
+	uint8_t i;
+
+	mutex_init(&driver->log_mask_mutex);
+	log_item = (struct diag_log_mask_t *)driver->log_masks;
+	for (i = 0; i < MAX_EQUIP_ID; i++, log_item++) {
+		log_item->equip_id = i;
+		log_item->num_items = LOG_GET_ITEM_NUM(log_code_last_tbl[i]);
+	}
+}
+
 void diag_masks_init(void)
 {
 	driver->event_status = DIAG_CTRL_MASK_INVALID;
@@ -936,7 +956,7 @@
 			goto err;
 		kmemleak_not_leak(driver->log_masks);
 	}
-	driver->log_masks_length = (sizeof(struct mask_info))*MAX_EQUIP_ID;
+	diag_log_mask_init();
 	if (driver->event_masks == NULL) {
 		driver->event_masks = kzalloc(EVENT_MASK_SIZE, GFP_KERNEL);
 		if (driver->event_masks == NULL)
diff --git a/drivers/char/diag/diag_masks.h b/drivers/char/diag/diag_masks.h
index c66a4b6..856d4fc 100644
--- a/drivers/char/diag/diag_masks.h
+++ b/drivers/char/diag/diag_masks.h
@@ -15,7 +15,12 @@
 
 #include "diagfwd.h"
 
-int chk_equip_id_and_mask(int equip_id, uint8_t *buf);
+struct diag_log_mask_t {
+	uint8_t equip_id;
+	uint32_t num_items;
+	uint8_t ptr[MAX_ITEMS_PER_EQUIP_ID];
+} __packed;
+
 void diag_send_event_mask_update(smd_channel_t *, int num_bytes);
 void diag_send_msg_mask_update(smd_channel_t *, int ssid_first,
 					 int ssid_last, int proc);
diff --git a/drivers/char/diag/diagchar.h b/drivers/char/diag/diagchar.h
index 9d9d89b..5be77c4 100644
--- a/drivers/char/diag/diagchar.h
+++ b/drivers/char/diag/diagchar.h
@@ -82,11 +82,14 @@
  * 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 MAX_EQUIP_ID		16
+#define MAX_ITEMS_PER_EQUIP_ID	512
+#define LOG_MASK_ITEM_SIZE	(5 + MAX_ITEMS_PER_EQUIP_ID)
+#define LOG_MASK_SIZE		(MAX_EQUIP_ID * LOG_MASK_ITEM_SIZE)
 #define EVENT_MASK_SIZE 1000
 #define USER_SPACE_DATA 8192
 #define PKT_SIZE 4096
-#define MAX_EQUIP_ID 15
+
 #define DIAG_CTRL_MSG_LOG_MASK	9
 #define DIAG_CTRL_MSG_EVENT_MASK	10
 #define DIAG_CTRL_MSG_F3_MASK	11
@@ -334,6 +337,7 @@
 	struct diag_ctrl_log_mask *log_mask;
 	struct diag_ctrl_msg_mask *msg_mask;
 	struct diag_ctrl_feature_mask *feature_mask;
+	struct mutex log_mask_mutex;
 	/* State for diag forwarding */
 	struct diag_smd_info smd_data[NUM_SMD_DATA_CHANNELS];
 	struct diag_smd_info smd_cntl[NUM_SMD_CONTROL_CHANNELS];
@@ -380,7 +384,6 @@
 	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;
diff --git a/drivers/char/diag/diagchar_core.c b/drivers/char/diag/diagchar_core.c
index 19ff6f4..f7c0d24 100644
--- a/drivers/char/diag/diagchar_core.c
+++ b/drivers/char/diag/diagchar_core.c
@@ -1485,26 +1485,25 @@
 		return err;
 	}
 	if (pkt_type == CALLBACK_DATA_TYPE) {
-		if (payload_size > itemsize) {
+		if (payload_size > driver->itemsize) {
 			pr_err("diag: Dropping packet, packet payload size crosses 4KB limit. Current payload size %d\n",
 				payload_size);
 			driver->dropped_count++;
 			return -EBADMSG;
 		}
 
-		mutex_lock(&driver->diagchar_mutex);
 		buf_copy = diagmem_alloc(driver, payload_size, POOL_TYPE_COPY);
 		if (!buf_copy) {
 			driver->dropped_count++;
-			mutex_unlock(&driver->diagchar_mutex);
 			return -ENOMEM;
 		}
 
 		err = copy_from_user(buf_copy, buf + 4, payload_size);
 		if (err) {
 			pr_err("diag: copy failed for user space data\n");
-			ret = -EIO;
-			goto fail_free_copy;
+			diagmem_free(driver, buf_copy, POOL_TYPE_COPY);
+			buf_copy = NULL;
+			return -EIO;
 		}
 		/* Check for proc_type */
 		remote_proc = diag_get_remote(*(int *)buf_copy);
@@ -1513,7 +1512,9 @@
 			wait_event_interruptible(driver->wait_q,
 				 (driver->in_busy_pktdata == 0));
 			ret = diag_process_apps_pkt(buf_copy, payload_size);
-			goto fail_free_copy;
+			diagmem_free(driver, buf_copy, POOL_TYPE_COPY);
+			buf_copy = NULL;
+			return ret;
 		}
 		/* The packet is for the remote processor */
 		token_offset = 4;
@@ -1526,7 +1527,7 @@
 							1 + payload_size);
 		send.terminate = 1;
 
-
+		mutex_lock(&driver->diagchar_mutex);
 		if (!buf_hdlc)
 			buf_hdlc = diagmem_alloc(driver, HDLC_OUT_BUF_SIZE,
 							POOL_TYPE_HDLC);
diff --git a/drivers/char/diag/diagfwd.c b/drivers/char/diag/diagfwd.c
index cdd315e..ba3ecc2 100644
--- a/drivers/char/diag/diagfwd.c
+++ b/drivers/char/diag/diagfwd.c
@@ -1051,9 +1051,10 @@
 	return is_mode_reset;
 }
 
-void diag_send_data(struct diag_master_table entry, unsigned char *buf,
+int diag_send_data(struct diag_master_table entry, unsigned char *buf,
 					 int len, int type)
 {
+	int success = 1;
 	driver->pkt_length = len;
 
 	/* If the process_id corresponds to an apps process */
@@ -1069,13 +1070,19 @@
 			if (entry.client_id < NUM_SMD_DATA_CHANNELS) {
 				struct diag_smd_info *smd_info;
 				int index = entry.client_id;
+				if (!driver->rcvd_feature_mask[
+					entry.client_id]) {
+					pr_debug("diag: In %s, feature mask for peripheral: %d not received yet\n",
+						__func__, entry.client_id);
+					return 0;
+				}
 				/*
 				 * Mode reset should work even if
 				 * modem is down
 				 */
 				if ((index == MODEM_DATA) &&
 					diag_check_mode_reset(buf)) {
-					return;
+					return 1;
 				}
 				smd_info = (driver->separate_cmdrsp[index] &&
 						index < NUM_SMD_CMD_CHANNELS) ?
@@ -1095,9 +1102,12 @@
 			} else {
 				pr_alert("diag: In %s, incorrect channel: %d",
 					__func__, entry.client_id);
+				success = 0;
 			}
 		}
 	}
+
+	return success;
 }
 
 void diag_process_stm_mask(uint8_t cmd, uint8_t data_mask, int data_type,
@@ -1191,6 +1201,7 @@
 	unsigned char *temp = buf;
 	int data_type;
 	int mask_ret;
+	int status = 0;
 #if defined(CONFIG_DIAG_OVER_USB)
 	unsigned char *ptr;
 #endif
@@ -1217,14 +1228,15 @@
 	pr_debug("diag: %d %d %d", cmd_code, subsys_id, subsys_cmd_code);
 	for (i = 0; i < diag_max_reg; i++) {
 		entry = driver->table[i];
-		if (entry.process_id != NO_PROCESS &&
-				driver->rcvd_feature_mask[entry.client_id]) {
+		if (entry.process_id != NO_PROCESS) {
 			if (entry.cmd_code == cmd_code && entry.subsys_id ==
 				 subsys_id && entry.cmd_code_lo <=
 							 subsys_cmd_code &&
 				  entry.cmd_code_hi >= subsys_cmd_code) {
-				diag_send_data(entry, buf, len, data_type);
-				packet_type = 0;
+				status = diag_send_data(entry, buf, len,
+								data_type);
+				if (status)
+					packet_type = 0;
 			} else if (entry.cmd_code == 255
 				  && cmd_code == 75) {
 				if (entry.subsys_id ==
@@ -1233,9 +1245,10 @@
 					subsys_cmd_code &&
 					 entry.cmd_code_hi >=
 					subsys_cmd_code) {
-					diag_send_data(entry, buf, len,
-								 data_type);
-					packet_type = 0;
+					status = diag_send_data(entry, buf,
+								len, data_type);
+					if (status)
+						packet_type = 0;
 				}
 			} else if (entry.cmd_code == 255 &&
 				  entry.subsys_id == 255) {
@@ -1243,9 +1256,10 @@
 						 cmd_code &&
 						 entry.
 						cmd_code_hi >= cmd_code) {
-					diag_send_data(entry, buf, len,
+					status = diag_send_data(entry, buf, len,
 								 data_type);
-					packet_type = 0;
+					if (status)
+						packet_type = 0;
 				}
 			}
 		}
@@ -1280,22 +1294,38 @@
 		driver->apps_rsp_buf[0] = 0x73;
 		*(int *)(driver->apps_rsp_buf + 4) = 0x1; /* operation ID */
 		*(int *)(driver->apps_rsp_buf + 8) = 0x0; /* success code */
-		*(int *)(driver->apps_rsp_buf + 12) = LOG_GET_ITEM_NUM(LOG_0);
-		*(int *)(driver->apps_rsp_buf + 16) = LOG_GET_ITEM_NUM(LOG_1);
-		*(int *)(driver->apps_rsp_buf + 20) = LOG_GET_ITEM_NUM(LOG_2);
-		*(int *)(driver->apps_rsp_buf + 24) = LOG_GET_ITEM_NUM(LOG_3);
-		*(int *)(driver->apps_rsp_buf + 28) = LOG_GET_ITEM_NUM(LOG_4);
-		*(int *)(driver->apps_rsp_buf + 32) = LOG_GET_ITEM_NUM(LOG_5);
-		*(int *)(driver->apps_rsp_buf + 36) = LOG_GET_ITEM_NUM(LOG_6);
-		*(int *)(driver->apps_rsp_buf + 40) = LOG_GET_ITEM_NUM(LOG_7);
-		*(int *)(driver->apps_rsp_buf + 44) = LOG_GET_ITEM_NUM(LOG_8);
-		*(int *)(driver->apps_rsp_buf + 48) = LOG_GET_ITEM_NUM(LOG_9);
-		*(int *)(driver->apps_rsp_buf + 52) = LOG_GET_ITEM_NUM(LOG_10);
-		*(int *)(driver->apps_rsp_buf + 56) = LOG_GET_ITEM_NUM(LOG_11);
-		*(int *)(driver->apps_rsp_buf + 60) = LOG_GET_ITEM_NUM(LOG_12);
-		*(int *)(driver->apps_rsp_buf + 64) = LOG_GET_ITEM_NUM(LOG_13);
-		*(int *)(driver->apps_rsp_buf + 68) = LOG_GET_ITEM_NUM(LOG_14);
-		*(int *)(driver->apps_rsp_buf + 72) = LOG_GET_ITEM_NUM(LOG_15);
+		*(int *)(driver->apps_rsp_buf + 12) =
+				LOG_GET_ITEM_NUM(log_code_last_tbl[0]);
+		*(int *)(driver->apps_rsp_buf + 16) =
+				LOG_GET_ITEM_NUM(log_code_last_tbl[1]);
+		*(int *)(driver->apps_rsp_buf + 20) =
+				LOG_GET_ITEM_NUM(log_code_last_tbl[2]);
+		*(int *)(driver->apps_rsp_buf + 24) =
+				LOG_GET_ITEM_NUM(log_code_last_tbl[3]);
+		*(int *)(driver->apps_rsp_buf + 28) =
+				LOG_GET_ITEM_NUM(log_code_last_tbl[4]);
+		*(int *)(driver->apps_rsp_buf + 32) =
+				LOG_GET_ITEM_NUM(log_code_last_tbl[5]);
+		*(int *)(driver->apps_rsp_buf + 36) =
+				LOG_GET_ITEM_NUM(log_code_last_tbl[6]);
+		*(int *)(driver->apps_rsp_buf + 40) =
+				LOG_GET_ITEM_NUM(log_code_last_tbl[7]);
+		*(int *)(driver->apps_rsp_buf + 44) =
+				LOG_GET_ITEM_NUM(log_code_last_tbl[8]);
+		*(int *)(driver->apps_rsp_buf + 48) =
+				LOG_GET_ITEM_NUM(log_code_last_tbl[9]);
+		*(int *)(driver->apps_rsp_buf + 52) =
+				LOG_GET_ITEM_NUM(log_code_last_tbl[10]);
+		*(int *)(driver->apps_rsp_buf + 56) =
+				LOG_GET_ITEM_NUM(log_code_last_tbl[11]);
+		*(int *)(driver->apps_rsp_buf + 60) =
+				LOG_GET_ITEM_NUM(log_code_last_tbl[12]);
+		*(int *)(driver->apps_rsp_buf + 64) =
+				LOG_GET_ITEM_NUM(log_code_last_tbl[13]);
+		*(int *)(driver->apps_rsp_buf + 68) =
+				LOG_GET_ITEM_NUM(log_code_last_tbl[14]);
+		*(int *)(driver->apps_rsp_buf + 72) =
+				LOG_GET_ITEM_NUM(log_code_last_tbl[15]);
 		encode_rsp_and_send(75);
 		return 0;
 	}
diff --git a/drivers/i2c/busses/i2c-qup.c b/drivers/i2c/busses/i2c-qup.c
index 74a252f..57aa835 100644
--- a/drivers/i2c/busses/i2c-qup.c
+++ b/drivers/i2c/busses/i2c-qup.c
@@ -192,6 +192,10 @@
 	struct qup_i2c_clk_path_vote clk_path_vote;
 };
 
+#ifdef CONFIG_PM
+static int i2c_qup_pm_resume_runtime(struct device *device);
+#endif
+
 #ifdef DEBUG
 static void
 qup_print_status(struct qup_i2c_dev *dev)
@@ -944,7 +948,13 @@
 	long timeout;
 	int err;
 
-	pm_runtime_get_sync(dev->dev);
+	/* Alternate if runtime power management is disabled */
+	if (!pm_runtime_enabled(dev->dev)) {
+		dev_dbg(dev->dev, "Runtime PM is disabled\n");
+		i2c_qup_pm_resume_runtime(dev->dev);
+	} else {
+		pm_runtime_get_sync(dev->dev);
+	}
 	mutex_lock(&dev->mlock);
 
 	if (dev->suspended) {
@@ -1754,22 +1764,24 @@
 	if (!pm_runtime_enabled(device) || !pm_runtime_suspended(device)) {
 		dev_dbg(device, "system suspend");
 		i2c_qup_pm_suspend_runtime(device);
+		/*
+		 * set the device's runtime PM status to 'suspended'
+		 */
+		pm_runtime_disable(device);
+		pm_runtime_set_suspended(device);
+		pm_runtime_enable(device);
 	}
 	return 0;
 }
 
 static int qup_i2c_resume(struct device *device)
 {
-	int ret = 0;
-	if (!pm_runtime_enabled(device) || !pm_runtime_suspended(device)) {
-		dev_dbg(device, "system resume");
-		ret = i2c_qup_pm_resume_runtime(device);
-		if (!ret) {
-			pm_runtime_mark_last_busy(device);
-			pm_request_autosuspend(device);
-		}
-		return ret;
-	}
+	/*
+	 * Rely on runtime-PM to call resume in case it is enabled
+	 * Even if it's not enabled, rely on 1st client transaction to do
+	 * clock ON and gpio configuration
+	 */
+	dev_dbg(device, "system resume");
 	return 0;
 }
 #endif /* CONFIG_PM */
diff --git a/drivers/input/misc/mma8x5x.c b/drivers/input/misc/mma8x5x.c
index a325d54..91aa928 100644
--- a/drivers/input/misc/mma8x5x.c
+++ b/drivers/input/misc/mma8x5x.c
@@ -53,6 +53,7 @@
 #define MMA8X5X_BUF_SIZE	7
 
 #define	MMA_SHUTTEDDOWN		(1 << 31)
+#define MMA_STATE_MASK		(~MMA_SHUTTEDDOWN)
 
 struct sensor_regulator {
 	struct regulator *vreg;
@@ -349,7 +350,7 @@
 	struct input_polled_dev *poll_dev = pdata->poll_dev;
 	struct mma8x5x_data_axis data;
 	mutex_lock(&pdata->data_lock);
-	if (pdata->active == MMA_STANDBY) {
+	if ((pdata->active & MMA_STATE_MASK) == MMA_STANDBY) {
 		poll_dev->poll_interval = POLL_STOP_TIME;
 		/* if standby ,set as 10s to slow the poll. */
 		goto out;
diff --git a/drivers/input/touchscreen/ft5x06_ts.c b/drivers/input/touchscreen/ft5x06_ts.c
index ef76e69..9a4301e 100644
--- a/drivers/input/touchscreen/ft5x06_ts.c
+++ b/drivers/input/touchscreen/ft5x06_ts.c
@@ -131,8 +131,9 @@
 #define FT_FW_PKT_DLY_MS	20
 #define FT_FW_LAST_PKT		0x6ffa
 #define FT_EARSE_DLY_MS		100
+#define FT_55_AA_DLY_NS		5000
 
-#define FT_UPGRADE_LOOP		10
+#define FT_UPGRADE_LOOP		30
 #define FT_CAL_START		0x04
 #define FT_CAL_FIN		0x00
 #define FT_CAL_STORE		0x05
@@ -142,6 +143,30 @@
 
 #define FT_INFO_MAX_LEN		512
 
+#define FT_BLOADER_SIZE_OFF	12
+#define FT_BLOADER_NEW_SIZE	30
+#define FT_DATA_LEN_OFF_OLD_FW	8
+#define FT_DATA_LEN_OFF_NEW_FW	14
+#define FT_FINISHING_PKT_LEN_OLD_FW	6
+#define FT_FINISHING_PKT_LEN_NEW_FW	12
+#define FT_MAGIC_BLOADER_Z7	0x7bfa
+#define FT_MAGIC_BLOADER_LZ4	0x6ffa
+#define FT_MAGIC_BLOADER_GZF_30	0x7ff4
+#define FT_MAGIC_BLOADER_GZF	0x7bf4
+
+enum {
+	FT_BLOADER_VERSION_LZ4 = 0,
+	FT_BLOADER_VERSION_Z7 = 1,
+	FT_BLOADER_VERSION_GZF = 2,
+};
+
+enum {
+	FT_FT5336_FAMILY_ID_0x11 = 0x11,
+	FT_FT5336_FAMILY_ID_0x12 = 0x12,
+	FT_FT5336_FAMILY_ID_0x13 = 0x13,
+	FT_FT5336_FAMILY_ID_0x14 = 0x14,
+};
+
 #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, \
@@ -645,11 +670,20 @@
 	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;
+	int i, j, temp;
 	u32 pkt_num, pkt_len;
+	u8 is_5336_new_bootloader = false;
+	u8 is_5336_fwsize_30 = false;
 	u8 fw_ecc;
 
+	/* determine firmware size */
+	if (*(data + data_len - FT_BLOADER_SIZE_OFF) == FT_BLOADER_NEW_SIZE)
+		is_5336_fwsize_30 = true;
+	else
+		is_5336_fwsize_30 = false;
+
 	for (i = 0, j = 0; i < FT_UPGRADE_LOOP; i++) {
+		msleep(FT_EARSE_DLY_MS);
 		/* reset - write 0xaa and 0x55 to reset register */
 		if (ts_data->family_id == FT6X06_ID)
 			reset_reg = FT_RST_CMD_REG2;
@@ -660,16 +694,17 @@
 		msleep(info.delay_aa);
 
 		ft5x0x_write_reg(client, reset_reg, FT_UPGRADE_55);
-		msleep(info.delay_55);
+		if (i <= (FT_UPGRADE_LOOP / 2))
+			msleep(info.delay_55 + i * 3);
+		else
+			msleep(info.delay_55 - (i - (FT_UPGRADE_LOOP / 2)) * 2);
 
 		/* Enter upgrade mode */
 		w_buf[0] = FT_UPGRADE_55;
-		w_buf[1] = FT_UPGRADE_AA;
-		do {
-			j++;
-			rc = ft5x06_i2c_write(client, w_buf, 2);
-			msleep(FT_RETRY_DLY);
-		} while (rc <= 0 && j < FT_MAX_TRIES);
+		ft5x06_i2c_write(client, w_buf, 1);
+		usleep(FT_55_AA_DLY_NS);
+		w_buf[0] = FT_UPGRADE_AA;
+		ft5x06_i2c_write(client, w_buf, 1);
 
 		/* check READ_ID */
 		msleep(info.delay_readid);
@@ -682,7 +717,9 @@
 
 		if (r_buf[0] != info.upgrade_id_1
 			|| r_buf[1] != info.upgrade_id_2) {
-			dev_err(&client->dev, "Upgrade ID mismatch(%d)\n", i);
+			dev_err(&client->dev, "Upgrade ID mismatch(%d), IC=0x%x 0x%x, info=0x%x 0x%x\n",
+				i, r_buf[0], r_buf[1],
+				info.upgrade_id_1, info.upgrade_id_2);
 		} else
 			break;
 	}
@@ -692,17 +729,44 @@
 		return -EIO;
 	}
 
+	w_buf[0] = 0xcd;
+	ft5x06_i2c_read(client, w_buf, 1, r_buf, 1);
+
+	if (r_buf[0] <= 4)
+		is_5336_new_bootloader = FT_BLOADER_VERSION_LZ4;
+	else if (r_buf[0] == 7)
+		is_5336_new_bootloader = FT_BLOADER_VERSION_Z7;
+	else if (r_buf[0] >= 0x0f &&
+		((ts_data->family_id == FT_FT5336_FAMILY_ID_0x11) ||
+		(ts_data->family_id == FT_FT5336_FAMILY_ID_0x12) ||
+		(ts_data->family_id == FT_FT5336_FAMILY_ID_0x13) ||
+		(ts_data->family_id == FT_FT5336_FAMILY_ID_0x14)))
+		is_5336_new_bootloader = FT_BLOADER_VERSION_GZF;
+	else
+		is_5336_new_bootloader = FT_BLOADER_VERSION_LZ4;
+
+	dev_dbg(&client->dev, "bootloader type=%d, r_buf=0x%x, family_id=0x%x\n",
+		is_5336_new_bootloader, r_buf[0], ts_data->family_id);
+	/* is_5336_new_bootloader = FT_BLOADER_VERSION_GZF; */
+
 	/* erase app and panel paramenter area */
 	w_buf[0] = FT_ERASE_APP_REG;
 	ft5x06_i2c_write(client, w_buf, 1);
 	msleep(info.delay_erase_flash);
 
-	w_buf[0] = FT_ERASE_PANEL_REG;
-	ft5x06_i2c_write(client, w_buf, 1);
+	if (is_5336_fwsize_30) {
+		w_buf[0] = FT_ERASE_PANEL_REG;
+		ft5x06_i2c_write(client, w_buf, 1);
+	}
 	msleep(FT_EARSE_DLY_MS);
 
 	/* program firmware */
-	data_len = data_len - 8;
+	if (is_5336_new_bootloader == FT_BLOADER_VERSION_LZ4
+		|| is_5336_new_bootloader == FT_BLOADER_VERSION_Z7)
+		data_len = data_len - FT_DATA_LEN_OFF_OLD_FW;
+	else
+		data_len = data_len - FT_DATA_LEN_OFF_NEW_FW;
+
 	pkt_num = (data_len) / FT_FW_PKT_LEN;
 	pkt_len = FT_FW_PKT_LEN;
 	pkt_buf[0] = FT_FW_START_REG;
@@ -745,17 +809,45 @@
 	}
 
 	/* send the finishing packet */
-	for (i = 0; i < 6; i++) {
-		temp = FT_FW_LAST_PKT + i;
-		pkt_buf[2] = (u8) (temp >> 8);
-		pkt_buf[3] = (u8) temp;
-		temp = 1;
-		pkt_buf[4] = (u8) (temp >> 8);
-		pkt_buf[5] = (u8) temp;
-		pkt_buf[6] = data[data_len + i];
-		fw_ecc ^= pkt_buf[6];
-		ft5x06_i2c_write(client, pkt_buf, temp + FT_FW_PKT_META_LEN);
-		msleep(FT_FW_PKT_DLY_MS);
+	if (is_5336_new_bootloader == FT_BLOADER_VERSION_LZ4 ||
+		is_5336_new_bootloader == FT_BLOADER_VERSION_Z7) {
+		for (i = 0; i < FT_FINISHING_PKT_LEN_OLD_FW; i++) {
+			if (is_5336_new_bootloader  == FT_BLOADER_VERSION_Z7)
+				temp = FT_MAGIC_BLOADER_Z7 + i;
+			else if (is_5336_new_bootloader ==
+						FT_BLOADER_VERSION_LZ4)
+				temp = FT_MAGIC_BLOADER_LZ4 + i;
+			pkt_buf[2] = (u8)(temp >> 8);
+			pkt_buf[3] = (u8)temp;
+			temp = 1;
+			pkt_buf[4] = (u8)(temp >> 8);
+			pkt_buf[5] = (u8)temp;
+			pkt_buf[6] = data[data_len + i];
+			fw_ecc ^= pkt_buf[6];
+
+			ft5x06_i2c_write(client,
+				pkt_buf, temp + FT_FW_PKT_META_LEN);
+			msleep(FT_FW_PKT_DLY_MS);
+		}
+	} else if (is_5336_new_bootloader == FT_BLOADER_VERSION_GZF) {
+		for (i = 0; i < FT_FINISHING_PKT_LEN_NEW_FW; i++) {
+			if (is_5336_fwsize_30)
+				temp = FT_MAGIC_BLOADER_GZF_30 + i;
+			else
+				temp = FT_MAGIC_BLOADER_GZF + i;
+			pkt_buf[2] = (u8)(temp >> 8);
+			pkt_buf[3] = (u8)temp;
+			temp = 1;
+			pkt_buf[4] = (u8)(temp >> 8);
+			pkt_buf[5] = (u8)temp;
+			pkt_buf[6] = data[data_len + i];
+			fw_ecc ^= pkt_buf[6];
+
+			ft5x06_i2c_write(client,
+				pkt_buf, temp + FT_FW_PKT_META_LEN);
+			msleep(FT_FW_PKT_DLY_MS);
+
+		}
 	}
 
 	/* verify checksum */
@@ -1451,7 +1543,7 @@
 		goto free_reset_gpio;
 	}
 
-	data->family_id = reg_value;
+	data->family_id = pdata->family_id;
 
 	err = request_threaded_irq(client->irq, NULL,
 				   ft5x06_ts_interrupt, pdata->irqflags,
diff --git a/drivers/input/touchscreen/gt9xx/gt9xx.c b/drivers/input/touchscreen/gt9xx/gt9xx.c
index 8b08ac9..ba38061 100644
--- a/drivers/input/touchscreen/gt9xx/gt9xx.c
+++ b/drivers/input/touchscreen/gt9xx/gt9xx.c
@@ -95,6 +95,8 @@
 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);
+static int goodix_power_off(struct goodix_ts_data *ts);
+static int goodix_power_on(struct goodix_ts_data *ts);
 
 #if defined(CONFIG_FB)
 static int fb_notifier_callback(struct notifier_block *self,
@@ -758,7 +760,7 @@
 	ts: private data.
 Output:
 	Executive outcomes.
-	1: succeed, otherwise failed.
+	>0: succeed, otherwise failed.
 *******************************************************/
 static s8 gtp_enter_sleep(struct goodix_ts_data  *ts)
 {
@@ -769,20 +771,37 @@
 		(u8)GTP_REG_SLEEP, 5};
 
 	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;
+	if (ret)
+		dev_err(&ts->client->dev,
+			"GTP sleep: Cannot reconfig gpio %d.\n",
+			ts->pdata->irq_gpio);
+	if (ts->pdata->enable_power_off) {
+		ret = gpio_direction_output(ts->pdata->reset_gpio, 0);
+		if (ret)
+			dev_err(&ts->client->dev,
+				"GTP sleep: Cannot reconfig gpio %d.\n",
+				ts->pdata->reset_gpio);
+		ret = goodix_power_off(ts);
+		if (ret) {
+			dev_err(&ts->client->dev, "GTP power off failed.\n");
+			return 0;
 		}
-		msleep(20);
+		return 1;
+	} else {
+		usleep(5000);
+		while (retry++ < 5) {
+			ret = gtp_i2c_write(ts->client, i2c_control_buf, 3);
+			if (ret == 1) {
+				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;
 	}
-	dev_err(&ts->client->dev, "GTP send sleep cmd failed.\n");
-	return ret;
 }
-#endif
+#endif /* !GTP_SLIDE_WAKEUP */
 
 /*******************************************************
 Function:
@@ -798,17 +817,36 @@
 	u8 retry = 0;
 	s8 ret = -1;
 
-#if GTP_POWER_CTRL_SLEEP
-	gtp_reset_guitar(ts, 20);
+	if (ts->pdata->enable_power_off) {
+		ret = gpio_direction_output(ts->pdata->irq_gpio, 0);
+		if (ret)
+			dev_err(&ts->client->dev,
+				"GTP wakeup: Cannot reconfig gpio %d.\n",
+				ts->pdata->irq_gpio);
+		ret = gpio_direction_output(ts->pdata->reset_gpio, 0);
+		if (ret)
+			dev_err(&ts->client->dev,
+				"GTP wakeup: Cannot reconfig gpio %d.\n",
+				ts->pdata->reset_gpio);
+		ret = goodix_power_on(ts);
+		if (ret) {
+			dev_err(&ts->client->dev, "GTP power on failed.\n");
+			return 0;
+		}
 
-	ret = gtp_send_cfg(ts);
-	if (ret > 0) {
+		gtp_reset_guitar(ts, 20);
+
+		ret = gtp_send_cfg(ts);
+		if (ret <= 0) {
+			dev_err(&ts->client->dev,
+				"GTP wakeup sleep failed.\n");
+			return ret;
+		}
+
 		dev_dbg(&ts->client->dev,
-			"Wakeup sleep send config success.");
-		return 1;
-	}
-#else
-	while (retry++ < 10) {
+				"Wakeup sleep send config success.");
+	} else {
+err_retry:
 #if GTP_SLIDE_WAKEUP
 		/* wakeup not by slide */
 		if (DOZE_WAKEUP != doze_status)
@@ -825,7 +863,7 @@
 		}
 #endif
 		ret = gtp_i2c_test(ts->client);
-		if (ret > 0) {
+		if (ret == 2) {
 			dev_dbg(&ts->client->dev, "GTP wakeup sleep.");
 #if (!GTP_SLIDE_WAKEUP)
 			if (chip_gt9xxs == 0) {
@@ -839,10 +877,10 @@
 			return ret;
 		}
 		gtp_reset_guitar(ts, 20);
+		if (retry++ < 10)
+			goto err_retry;
+		dev_err(&ts->client->dev, "GTP wakeup sleep failed.\n");
 	}
-#endif
-
-	dev_err(&ts->client->dev, "GTP wakeup sleep failed.\n");
 	return ret;
 }
 #endif /* !CONFIG_HAS_EARLYSUSPEND && !CONFIG_FB*/
@@ -1055,9 +1093,7 @@
 
 	dev_info(&client->dev, "Goodix Product ID = %s\n", product_id);
 
-	if (!IS_ERR(ts->pdata->product_id))
-		ret = strcmp(product_id, ts->pdata->product_id);
-
+	ret = strcmp(product_id, ts->pdata->product_id);
 	if (ret != 0)
 		return -EINVAL;
 
@@ -1292,6 +1328,12 @@
 {
 	int ret;
 
+	if (ts->power_on) {
+		dev_info(&ts->client->dev,
+				"Device already power on\n");
+		return 0;
+	}
+
 	if (!IS_ERR(ts->avdd)) {
 		ret = reg_set_optimum_mode_check(ts->avdd,
 			GOODIX_VDD_LOAD_MAX_UA);
@@ -1358,6 +1400,7 @@
 			}
 	}
 
+	ts->power_on = true;
 	return 0;
 
 err_enable_vcc_i2c:
@@ -1376,6 +1419,7 @@
 		regulator_disable(ts->avdd);
 err_enable_avdd:
 err_set_opt_avdd:
+	ts->power_on = false;
 	return ret;
 }
 
@@ -1389,6 +1433,12 @@
 {
 	int ret;
 
+	if (!ts->power_on) {
+		dev_info(&ts->client->dev,
+				"Device already power off\n");
+		return 0;
+	}
+
 	if (!IS_ERR(ts->vcc_i2c)) {
 		ret = regulator_set_voltage(ts->vcc_i2c, 0,
 			GOODIX_I2C_VTG_MAX_UV);
@@ -1421,6 +1471,7 @@
 				"Regulator avdd disable failed ret=%d\n", ret);
 	}
 
+	ts->power_on = false;
 	return 0;
 }
 
@@ -1473,6 +1524,50 @@
 	return 0;
 }
 
+static ssize_t gtp_fw_name_show(struct device *dev,
+				struct device_attribute *attr, char *buf)
+{
+	struct goodix_ts_data *ts = dev_get_drvdata(dev);
+
+	if (!strlen(ts->fw_name))
+		return snprintf(buf, GTP_FW_NAME_MAXSIZE - 1,
+			"No fw name has been given.");
+	else
+		return snprintf(buf, GTP_FW_NAME_MAXSIZE - 1,
+			"%s\n", ts->fw_name);
+}
+
+static ssize_t gtp_fw_name_store(struct device *dev,
+				struct device_attribute *attr,
+				const char *buf, size_t size)
+{
+	struct goodix_ts_data *ts = dev_get_drvdata(dev);
+
+	if (size > GTP_FW_NAME_MAXSIZE - 1) {
+		dev_err(dev, "FW name size exceeds the limit.");
+		return -EINVAL;
+	}
+
+	strlcpy(ts->fw_name, buf, size);
+	if (ts->fw_name[size-1] == '\n')
+		ts->fw_name[size-1] = '\0';
+
+	return size;
+}
+
+static DEVICE_ATTR(fw_name, (S_IRUGO | S_IWUSR | S_IWGRP),
+			gtp_fw_name_show,
+			gtp_fw_name_store);
+
+static struct attribute *gtp_attrs[] = {
+	&dev_attr_fw_name.attr,
+	NULL
+};
+
+static const struct attribute_group gtp_attr_grp = {
+	.attrs = gtp_attrs,
+};
+
 static int goodix_ts_get_dt_coords(struct device *dev, char *name,
 				struct goodix_ts_platform_data *pdata)
 {
@@ -1536,6 +1631,9 @@
 
 	pdata->no_force_update = of_property_read_bool(np,
 						"goodix,no-force-update");
+
+	pdata->enable_power_off = of_property_read_bool(np,
+						"goodix,enable-power-off");
 	/* reset, irq gpio info */
 	pdata->reset_gpio = of_get_named_gpio_flags(np, "reset-gpios",
 				0, &pdata->reset_gpio_flags);
@@ -1549,8 +1647,17 @@
 
 	rc = of_property_read_string(np, "goodix,product-id",
 						&pdata->product_id);
-	if (rc < 0 || strlen(pdata->product_id) > GTP_PRODUCT_ID_MAXSIZE)
-		return rc;
+	if (rc && (rc != -EINVAL)) {
+		dev_err(dev, "Failed to parse product_id.");
+		return -EINVAL;
+	}
+
+	rc = of_property_read_string(np, "goodix,fw_name",
+						&pdata->fw_name);
+	if (rc && (rc != -EINVAL)) {
+		dev_err(dev, "Failed to parse firmware name.\n");
+		return -EINVAL;
+	}
 
 	prop = of_find_property(np, "goodix,button-map", NULL);
 	if (prop) {
@@ -1662,6 +1769,7 @@
 	spin_lock_init(&ts->irq_lock);
 	i2c_set_clientdata(client, ts);
 	ts->gtp_rawdiff_mode = 0;
+	ts->power_on = false;
 
 	ret = goodix_power_init(ts);
 	if (ret) {
@@ -1689,12 +1797,16 @@
 		goto exit_free_io_port;
 	}
 
+	if (pdata->fw_name)
+		strlcpy(ts->fw_name, pdata->fw_name,
+						strlen(pdata->fw_name) + 1);
+
 #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;
+		goto exit_power_off;
 	}
 #endif
 
@@ -1711,7 +1823,9 @@
 		dev_err(&client->dev, "GTP request input dev failed.\n");
 		goto exit_free_inputdev;
 	}
+	input_set_drvdata(ts->input_dev, ts);
 
+	mutex_init(&ts->lock);
 #if defined(CONFIG_FB)
 	ts->fb_notif.notifier_call = fb_notifier_callback;
 	ret = fb_register_client(&ts->fb_notif);
@@ -1754,9 +1868,16 @@
 #if GTP_ESD_PROTECT
 	gtp_esd_switch(client, SWITCH_ON);
 #endif
+	ret = sysfs_create_group(&client->dev.kobj, &gtp_attr_grp);
+	if (ret < 0) {
+		dev_err(&client->dev, "sys file creation failed.\n");
+		goto exit_free_irq;
+	}
+
 	init_done = true;
 	return 0;
 exit_free_irq:
+	mutex_destroy(&ts->lock);
 #if defined(CONFIG_FB)
 	if (fb_unregister_client(&ts->fb_notif))
 		dev_err(&client->dev,
@@ -1806,6 +1927,8 @@
 {
 	struct goodix_ts_data *ts = i2c_get_clientdata(client);
 
+	sysfs_remove_group(&ts->input_dev->dev.kobj, &gtp_attr_grp);
+
 #if defined(CONFIG_FB)
 	if (fb_unregister_client(&ts->fb_notif))
 		dev_err(&client->dev,
@@ -1813,6 +1936,7 @@
 #elif defined(CONFIG_HAS_EARLYSUSPEND)
 	unregister_early_suspend(&ts->early_suspend);
 #endif
+	mutex_destroy(&ts->lock);
 
 #if GTP_CREATE_WR_NODE
 	uninit_wr_node();
@@ -1868,6 +1992,7 @@
 {
 	int ret = -1, i;
 
+	mutex_lock(&ts->lock);
 #if GTP_ESD_PROTECT
 	ts->gtp_is_suspend = 1;
 	gtp_esd_switch(ts->client, SWITCH_OFF);
@@ -1888,12 +2013,13 @@
 
 	ret = gtp_enter_sleep(ts);
 #endif
-	if (ret < 0)
+	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);
+	mutex_unlock(&ts->lock);
 }
 
 /*******************************************************
@@ -1908,13 +2034,14 @@
 {
 	int ret = -1;
 
+	mutex_lock(&ts->lock);
 	ret = gtp_wakeup_sleep(ts);
 
 #if GTP_SLIDE_WAKEUP
 	doze_status = DOZE_DISABLED;
 #endif
 
-	if (ret < 0)
+	if (ret <= 0)
 		dev_err(&ts->client->dev, "GTP resume failed.\n");
 
 	if (ts->use_irq)
@@ -1927,6 +2054,7 @@
 	ts->gtp_is_suspend = 0;
 	gtp_esd_switch(ts->client, SWITCH_ON);
 #endif
+	mutex_unlock(&ts->lock);
 }
 
 #if defined(CONFIG_FB)
diff --git a/drivers/input/touchscreen/gt9xx/gt9xx.h b/drivers/input/touchscreen/gt9xx/gt9xx.h
index 1fdbfa3..1d31f2a 100644
--- a/drivers/input/touchscreen/gt9xx/gt9xx.h
+++ b/drivers/input/touchscreen/gt9xx/gt9xx.h
@@ -36,6 +36,7 @@
 #include <linux/regulator/consumer.h>
 #include <linux/firmware.h>
 #include <linux/debugfs.h>
+#include <linux/mutex.h>
 
 #if defined(CONFIG_FB)
 #include <linux/notifier.h>
@@ -46,12 +47,15 @@
 #endif
 
 #define GOODIX_MAX_CFG_GROUP	6
+#define GTP_FW_NAME_MAXSIZE	50
+
 struct goodix_ts_platform_data {
 	int irq_gpio;
 	u32 irq_gpio_flags;
 	int reset_gpio;
 	u32 reset_gpio_flags;
 	const char *product_id;
+	const char *fw_name;
 	u32 x_max;
 	u32 y_max;
 	u32 x_min;
@@ -62,6 +66,7 @@
 	u32 panel_maxy;
 	bool no_force_update;
 	bool i2c_pull_up;
+	bool enable_power_off;
 	size_t config_data_len[GOODIX_MAX_CFG_GROUP];
 	u8 *config_data[GOODIX_MAX_CFG_GROUP];
 };
@@ -73,6 +78,7 @@
 	struct hrtimer timer;
 	struct workqueue_struct *goodix_wq;
 	struct work_struct	work;
+	char fw_name[GTP_FW_NAME_MAXSIZE];
 	s32 irq_is_disabled;
 	s32 use_irq;
 	u16 abs_x_max;
@@ -89,6 +95,8 @@
 	u8  fixed_cfg;
 	u8  esd_running;
 	u8  fw_error;
+	bool power_on;
+	struct mutex lock;
 	struct regulator *avdd;
 	struct regulator *vdd;
 	struct regulator *vcc_i2c;
@@ -107,7 +115,6 @@
 #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
@@ -119,6 +126,7 @@
 #define GTP_ESD_PROTECT			0
 #define GTP_WITH_PEN			0
 
+/* This cannot work when enable-power-off is on */
 #define GTP_SLIDE_WAKEUP		0
 /* double-click wakeup, function together with GTP_SLIDE_WAKEUP */
 #define GTP_DBL_CLK_WAKEUP		0
diff --git a/drivers/input/touchscreen/synaptics_fw_update.c b/drivers/input/touchscreen/synaptics_fw_update.c
index 70c1307..7282c2e 100644
--- a/drivers/input/touchscreen/synaptics_fw_update.c
+++ b/drivers/input/touchscreen/synaptics_fw_update.c
@@ -353,7 +353,7 @@
 
 	if (img->is_contain_build_info) {
 		img->firmware_id = extract_uint(data->firmware_id);
-		img->package_id = (data->pkg_id_rev_msb << 8) |
+		img->package_id = (data->pkg_id_msb << 8) |
 				data->pkg_id_lsb;
 		img->package_revision_id = (data->pkg_id_rev_msb << 8) |
 				data->pkg_id_rev_lsb;
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 5f36a4a..ea0195d 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
@@ -513,7 +513,9 @@
 		}
 		lo_tbl_ptr = cfg_data +
 			reg_cfg_cmd->u.dmi_info.lo_tbl_offset/4;
-
+		if (reg_cfg_cmd->cmd_type == VFE_WRITE_DMI_64BIT)
+			reg_cfg_cmd->u.dmi_info.len =
+				reg_cfg_cmd->u.dmi_info.len / 2;
 		for (i = 0; i < reg_cfg_cmd->u.dmi_info.len/4; i++) {
 			lo_val = *lo_tbl_ptr++;
 			if (reg_cfg_cmd->cmd_type == VFE_WRITE_DMI_16BIT) {
@@ -621,6 +623,12 @@
 		goto reg_cfg_failed;
 	}
 
+	if (!proc_cmd->cmd_len) {
+		pr_err("%s: Passed cmd_len as 0\n", __func__);
+		rc = -EINVAL;
+		goto cfg_data_failed;
+	}
+
 	cfg_data = kzalloc(proc_cmd->cmd_len, GFP_KERNEL);
 	if (!cfg_data) {
 		pr_err("%s: cfg_data alloc failed\n", __func__);
diff --git a/drivers/media/platform/msm/camera_v2/ispif/msm_ispif.c b/drivers/media/platform/msm/camera_v2/ispif/msm_ispif.c
old mode 100644
new mode 100755
index 89016ec..de098c9
--- a/drivers/media/platform/msm/camera_v2/ispif/msm_ispif.c
+++ b/drivers/media/platform/msm/camera_v2/ispif/msm_ispif.c
@@ -200,17 +200,17 @@
 			ispif->base + ISPIF_VFE_m_INTF_CMD_0(i));
 		msm_camera_io_w(ISPIF_STOP_INTF_IMMEDIATELY,
 			ispif->base + ISPIF_VFE_m_INTF_CMD_1(i));
-
+		pr_debug("%s: base %x", __func__, (unsigned int)ispif->base);
 		msm_camera_io_w(0, ispif->base +
 			ISPIF_VFE_m_PIX_INTF_n_CID_MASK(i, 0));
 		msm_camera_io_w(0, ispif->base +
 			ISPIF_VFE_m_PIX_INTF_n_CID_MASK(i, 1));
 		msm_camera_io_w(0, ispif->base +
-			ISPIF_VFE_m_PIX_INTF_n_CID_MASK(i, 0));
+			ISPIF_VFE_m_RDI_INTF_n_CID_MASK(i, 0));
 		msm_camera_io_w(0, ispif->base +
-			ISPIF_VFE_m_PIX_INTF_n_CID_MASK(i, 1));
+			ISPIF_VFE_m_RDI_INTF_n_CID_MASK(i, 1));
 		msm_camera_io_w(0, ispif->base +
-			ISPIF_VFE_m_PIX_INTF_n_CID_MASK(i, 2));
+			ISPIF_VFE_m_RDI_INTF_n_CID_MASK(i, 2));
 
 		msm_camera_io_w(0, ispif->base +
 			ISPIF_VFE_m_PIX_INTF_n_CROP(i, 0));
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 8b8d23b..2124b13 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
@@ -926,35 +926,35 @@
 
 	cpp_dev->cpp_open_cnt--;
 	if (cpp_dev->cpp_open_cnt == 0) {
-		pr_err("%s: irq_status: 0x%x\n", __func__,
+		pr_debug("irq_status: 0x%x\n",
 			msm_camera_io_r(cpp_dev->cpp_hw_base + 0x4));
-		pr_err("%s: DEBUG_SP: 0x%x\n", __func__,
+		pr_debug("DEBUG_SP: 0x%x\n",
 			msm_camera_io_r(cpp_dev->cpp_hw_base + 0x40));
-		pr_err("%s: DEBUG_T: 0x%x\n", __func__,
+		pr_debug("DEBUG_T: 0x%x\n",
 			msm_camera_io_r(cpp_dev->cpp_hw_base + 0x44));
-		pr_err("%s: DEBUG_N: 0x%x\n", __func__,
+		pr_debug("DEBUG_N: 0x%x\n",
 			msm_camera_io_r(cpp_dev->cpp_hw_base + 0x48));
-		pr_err("%s: DEBUG_R: 0x%x\n", __func__,
+		pr_debug("DEBUG_R: 0x%x\n",
 			msm_camera_io_r(cpp_dev->cpp_hw_base + 0x4C));
-		pr_err("%s: DEBUG_OPPC: 0x%x\n", __func__,
+		pr_debug("DEBUG_OPPC: 0x%x\n",
 			msm_camera_io_r(cpp_dev->cpp_hw_base + 0x50));
-		pr_err("%s: DEBUG_MO: 0x%x\n", __func__,
+		pr_debug("DEBUG_MO: 0x%x\n",
 			msm_camera_io_r(cpp_dev->cpp_hw_base + 0x54));
-		pr_err("%s: DEBUG_TIMER0: 0x%x\n", __func__,
+		pr_debug("DEBUG_TIMER0: 0x%x\n",
 			msm_camera_io_r(cpp_dev->cpp_hw_base + 0x60));
-		pr_err("%s: DEBUG_TIMER1: 0x%x\n", __func__,
+		pr_debug("DEBUG_TIMER1: 0x%x\n",
 			msm_camera_io_r(cpp_dev->cpp_hw_base + 0x64));
-		pr_err("%s: DEBUG_GPI: 0x%x\n", __func__,
+		pr_debug("DEBUG_GPI: 0x%x\n",
 			msm_camera_io_r(cpp_dev->cpp_hw_base + 0x70));
-		pr_err("%s: DEBUG_GPO: 0x%x\n", __func__,
+		pr_debug("DEBUG_GPO: 0x%x\n",
 			msm_camera_io_r(cpp_dev->cpp_hw_base + 0x74));
-		pr_err("%s: DEBUG_T0: 0x%x\n", __func__,
+		pr_debug("DEBUG_T0: 0x%x\n",
 			msm_camera_io_r(cpp_dev->cpp_hw_base + 0x80));
-		pr_err("%s: DEBUG_R0: 0x%x\n", __func__,
+		pr_debug("DEBUG_R0: 0x%x\n",
 			msm_camera_io_r(cpp_dev->cpp_hw_base + 0x84));
-		pr_err("%s: DEBUG_T1: 0x%x\n", __func__,
+		pr_debug("DEBUG_T1: 0x%x\n",
 			msm_camera_io_r(cpp_dev->cpp_hw_base + 0x88));
-		pr_err("%s: DEBUG_R1: 0x%x\n", __func__,
+		pr_debug("DEBUG_R1: 0x%x\n",
 			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);
@@ -1712,6 +1712,7 @@
 		struct cpp_device *cpp_dev = v4l2_get_subdevdata(sd);
 		struct msm_camera_v4l2_ioctl_t *ioctl_ptr = arg;
 		struct msm_cpp_frame_info_t inst_info;
+		memset(&inst_info, 0, sizeof(struct msm_cpp_frame_info_t));
 		for (i = 0; i < MAX_ACTIVE_CPP_INSTANCE; i++) {
 			if (cpp_dev->cpp_subscribe_list[i].vfh == vfh) {
 				inst_info.inst_id = i;
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
old mode 100644
new mode 100755
index 9384a5b..d8608ae
--- a/drivers/media/platform/msm/camera_v2/sensor/csiphy/msm_csiphy.c
+++ b/drivers/media/platform/msm/camera_v2/sensor/csiphy/msm_csiphy.c
@@ -177,6 +177,7 @@
 static struct msm_cam_clk_info csiphy_8610_clk_info[] = {
 	{"csiphy_timer_src_clk", 200000000},
 	{"csiphy_timer_clk", -1},
+	{"csi_ahb_clk", -1},
 };
 
 static struct msm_cam_clk_info csiphy_8974_clk_info[] = {
diff --git a/drivers/media/platform/msm/dvb/demux/mpq_dmx_plugin_common.c b/drivers/media/platform/msm/dvb/demux/mpq_dmx_plugin_common.c
index e3a539c..d3b9c0a 100644
--- a/drivers/media/platform/msm/dvb/demux/mpq_dmx_plugin_common.c
+++ b/drivers/media/platform/msm/dvb/demux/mpq_dmx_plugin_common.c
@@ -4036,6 +4036,13 @@
 				__func__);
 			return ret;
 		}
+
+		if (mpq_feed->sdmx_filter_handle ==
+			SDMX_INVALID_FILTER_HANDLE) {
+			MPQ_DVB_DBG_PRINT("%s: filter was stopped\n",
+				__func__);
+			return -ENODEV;
+		}
 	}
 
 	if (mpq_feed->sdmx_buf.pread + header->payload_length <
@@ -4089,6 +4096,13 @@
 
 		mutex_lock(&mpq_demux->mutex);
 
+		if (mpq_feed->sdmx_filter_handle ==
+			SDMX_INVALID_FILTER_HANDLE) {
+			MPQ_DVB_DBG_PRINT("%s: filter was stopped\n",
+					__func__);
+			return -ENODEV;
+		}
+
 		return ret;
 	}
 
@@ -4456,6 +4470,14 @@
 			return;
 		}
 
+		if (!header.payload_length) {
+			MPQ_DVB_DBG_PRINT(
+				"%s: warnning - video frame with 0 length, dropping\n",
+				__func__);
+			spin_unlock(&mpq_feed->video_info.video_buffer_lock);
+			continue;
+		}
+
 		packet.raw_data_len = header.payload_length;
 		packet.user_data_len = sizeof(meta_data);
 		mpq_streambuffer_get_buffer_handle(sbuf, 0,
diff --git a/drivers/media/platform/msm/vcap/Kconfig b/drivers/media/platform/msm/vcap/Kconfig
index 2bdcfbd..db3bc47 100644
--- a/drivers/media/platform/msm/vcap/Kconfig
+++ b/drivers/media/platform/msm/vcap/Kconfig
@@ -1,7 +1,6 @@
 config MSM_VCAP
 	tristate "Qualcomm MSM VCAP"
 	depends on VIDEO_DEV && VIDEO_V4L2
-	default y
 	---help---
 		Enables VCAP driver. This device allows for video capture and
 		video processing using the v4l2 api
diff --git a/drivers/media/platform/msm/vidc/hfi_packetization.c b/drivers/media/platform/msm/vidc/hfi_packetization.c
index 30ada3e..ae94287 100644
--- a/drivers/media/platform/msm/vidc/hfi_packetization.c
+++ b/drivers/media/platform/msm/vidc/hfi_packetization.c
@@ -803,7 +803,8 @@
 		pkt->rg_property_data[0] =
 			HFI_PROPERTY_PARAM_VDEC_PICTURE_TYPE_DECODE;
 		hfi = (struct hfi_enable_picture *) &pkt->rg_property_data[1];
-		hfi->picture_type = (u32) pdata;
+		hfi->picture_type =
+			((struct hfi_enable_picture *)pdata)->picture_type;
 		pkt->size += sizeof(u32) * 2;
 		break;
 	}
diff --git a/drivers/media/platform/msm/vidc/hfi_response_handler.c b/drivers/media/platform/msm/vidc/hfi_response_handler.c
index abdb039..3fd5d3a 100644
--- a/drivers/media/platform/msm/vidc/hfi_response_handler.c
+++ b/drivers/media/platform/msm/vidc/hfi_response_handler.c
@@ -1183,42 +1183,78 @@
 	callback(SESSION_GET_SEQ_HDR_DONE, &data_done);
 }
 
-void hfi_process_sys_property_info(
-		struct hfi_property_sys_image_version_info_type *pkt)
+static void hfi_process_sys_get_prop_image_version(
+		struct hfi_msg_sys_property_info_packet *pkt)
 {
 	int i = 0;
 	u32 smem_block_size = 0;
 	u8 *smem_table_ptr;
 	char version[256];
+	const u32 version_string_size = 128;
 	const u32 smem_image_index_venus = 14 * 128;
+	u8 *str_image_version;
+	int req_bytes;
 
-	if (!pkt || !pkt->string_size) {
+	req_bytes = pkt->size - sizeof(*pkt);
+	if (req_bytes < version_string_size ||
+			!pkt->rg_property_data[1] ||
+			pkt->num_properties > 1) {
+		dprintk(VIDC_ERR,
+				"hfi_process_sys_get_prop_image_version:bad_pkt: %d",
+				req_bytes);
+		return;
+	}
+	str_image_version = (u8 *)&pkt->rg_property_data[1];
+	/*
+	 * The version string returned by firmware includes null
+	 * characters at the start and in between. Replace the null
+	 * characters with space, to print the version info.
+	 */
+	for (i = 0; i < version_string_size; i++) {
+		if (str_image_version[i] != '\0')
+			version[i] = str_image_version[i];
+		else
+			version[i] = ' ';
+	}
+	version[i] = '\0';
+	dprintk(VIDC_DBG, "F/W version: %s\n", version);
+
+	smem_table_ptr = smem_get_entry(SMEM_IMAGE_VERSION_TABLE,
+			&smem_block_size);
+	if (smem_table_ptr &&
+			((smem_image_index_venus +
+				version_string_size) <= smem_block_size))
+		memcpy(smem_table_ptr + smem_image_index_venus,
+				str_image_version, version_string_size);
+}
+
+static void hfi_process_sys_property_info(
+		struct hfi_msg_sys_property_info_packet *pkt)
+{
+	if (!pkt) {
 		dprintk(VIDC_ERR, "%s: invalid param\n", __func__);
 		return;
 	}
-
-	if (pkt->string_size < sizeof(version)) {
-		/*
-		 * The version string returned by firmware includes null
-		 * characters at the start and in between. Replace the null
-		 * characters with space, to print the version info.
-		 */
-		for (i = 0; i < pkt->string_size; i++) {
-			if (pkt->str_image_version[i] != '\0')
-				version[i] = pkt->str_image_version[i];
-			else
-				version[i] = ' ';
-		}
-		version[i] = '\0';
-		dprintk(VIDC_DBG, "F/W version: %s\n", version);
+	if (pkt->size < sizeof(*pkt)) {
+		dprintk(VIDC_ERR,
+				"hfi_process_sys_property_info: bad_pkt_size\n");
+		return;
+	}
+	if (pkt->num_properties == 0) {
+		dprintk(VIDC_ERR,
+				"hfi_process_sys_property_info: no_properties\n");
+		return;
 	}
 
-	smem_table_ptr = smem_get_entry(SMEM_IMAGE_VERSION_TABLE,
-						&smem_block_size);
-	if (smem_table_ptr &&
-		((smem_image_index_venus + 128) <= smem_block_size))
-		memcpy(smem_table_ptr + smem_image_index_venus,
-			   (u8 *)pkt->str_image_version, 128);
+	switch (pkt->rg_property_data[0]) {
+	case HFI_PROPERTY_SYS_IMAGE_VERSION:
+		hfi_process_sys_get_prop_image_version(pkt);
+		break;
+	default:
+		dprintk(VIDC_ERR,
+				"hfi_process_sys_property_info:unknown_prop_id: %d\n",
+				pkt->rg_property_data[0]);
+	}
 }
 
 u32 hfi_process_msg_packet(
@@ -1263,7 +1299,7 @@
 		break;
 	case HFI_MSG_SYS_PROPERTY_INFO:
 		hfi_process_sys_property_info(
-		   (struct hfi_property_sys_image_version_info_type *)
+		   (struct hfi_msg_sys_property_info_packet *)
 			msg_hdr);
 		break;
 	case HFI_MSG_SYS_SESSION_END_DONE:
diff --git a/drivers/media/platform/msm/vidc/msm_vdec.c b/drivers/media/platform/msm/vidc/msm_vdec.c
index f4fdfe7..efa195e 100644
--- a/drivers/media/platform/msm/vidc/msm_vdec.c
+++ b/drivers/media/platform/msm/vidc/msm_vdec.c
@@ -686,6 +686,7 @@
 int msm_vdec_g_fmt(struct msm_vidc_inst *inst, struct v4l2_format *f)
 {
 	const struct msm_vidc_format *fmt = NULL;
+	unsigned int *plane_sizes = NULL;
 	struct hfi_device *hdev;
 	int stride, scanlines;
 	int extra_idx = 0;
@@ -741,9 +742,19 @@
 			goto exit;
 		}
 		if (f->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) {
+			plane_sizes =
+			&inst->bufq[OUTPUT_PORT].vb2_bufq.plane_sizes[0];
 			for (i = 0; i < fmt->num_planes; ++i) {
-				f->fmt.pix_mp.plane_fmt[i].sizeimage =
-				inst->bufq[OUTPUT_PORT].vb2_bufq.plane_sizes[i];
+				if (plane_sizes[i] == 0) {
+					f->fmt.pix_mp.plane_fmt[i].sizeimage =
+						fmt->get_frame_size(i,
+						inst->capability.height.max,
+						inst->capability.width.max);
+					plane_sizes[i] =
+					f->fmt.pix_mp.plane_fmt[i].sizeimage;
+				} else
+					f->fmt.pix_mp.plane_fmt[i].sizeimage =
+						plane_sizes[i];
 			}
 		} else {
 			switch (fmt->fourcc) {
@@ -979,8 +990,10 @@
 					inst->capability.height.max,
 					inst->capability.width.max);
 
-		if (f->fmt.pix_mp.plane_fmt[0].sizeimage > max_input_size)
+		if (f->fmt.pix_mp.plane_fmt[0].sizeimage > max_input_size ||
+			f->fmt.pix_mp.plane_fmt[0].sizeimage == 0) {
 			f->fmt.pix_mp.plane_fmt[0].sizeimage = max_input_size;
+		}
 
 		f->fmt.pix_mp.num_planes = fmt->num_planes;
 		for (i = 0; i < fmt->num_planes; ++i) {
@@ -1807,7 +1820,7 @@
 int msm_vdec_ctrl_init(struct msm_vidc_inst *inst)
 {
 	int idx = 0;
-	struct v4l2_ctrl_config ctrl_cfg;
+	struct v4l2_ctrl_config ctrl_cfg = {0};
 	int ret_val = 0;
 
 	ret_val = v4l2_ctrl_handler_init(&inst->ctrl_handler, NUM_CTRLS);
diff --git a/drivers/media/platform/msm/vidc/msm_venc.c b/drivers/media/platform/msm/vidc/msm_venc.c
index f9b5519..c0bf32c 100644
--- a/drivers/media/platform/msm/vidc/msm_venc.c
+++ b/drivers/media/platform/msm/vidc/msm_venc.c
@@ -2662,7 +2662,7 @@
 {
 
 	int idx = 0;
-	struct v4l2_ctrl_config ctrl_cfg;
+	struct v4l2_ctrl_config ctrl_cfg = {0};
 	int ret_val = 0;
 	ret_val = v4l2_ctrl_handler_init(&inst->ctrl_handler, NUM_CTRLS);
 	if (ret_val) {
diff --git a/drivers/media/platform/msm/vidc/q6_hfi.c b/drivers/media/platform/msm/vidc/q6_hfi.c
index 7c99ec3..8e91f34 100644
--- a/drivers/media/platform/msm/vidc/q6_hfi.c
+++ b/drivers/media/platform/msm/vidc/q6_hfi.c
@@ -560,17 +560,28 @@
 		dprintk(VIDC_ERR, "session_init: failed to create packet");
 		goto err_session_init;
 	}
+	/*
+	 * Add session id to the list entry and then send the apr pkt.
+	 * This will avoid scenarios where apr_send_pkt is taking more
+	 * time and Q6 is returning an ack even before the session id
+	 * gets added to the session list.
+	 */
+	mutex_lock(&dev->session_lock);
+	list_add_tail(&new_session->list, &dev->sess_head);
+	mutex_unlock(&dev->session_lock);
 
 	rc = apr_send_pkt(dev->apr, (uint32_t *)&apr);
 	if (rc != apr.hdr.pkt_size) {
 		dprintk(VIDC_ERR, "%s: apr_send_pkt failed rc: %d",
 				__func__, rc);
+		/* Delete the session id as the send pkt is not successful */
+		mutex_lock(&dev->session_lock);
+		list_del(&new_session->list);
+		mutex_unlock(&dev->session_lock);
 		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:
diff --git a/drivers/media/platform/msm/vidc/venus_hfi.c b/drivers/media/platform/msm/vidc/venus_hfi.c
index 916df1d..8cd3889 100644
--- a/drivers/media/platform/msm/vidc/venus_hfi.c
+++ b/drivers/media/platform/msm/vidc/venus_hfi.c
@@ -1057,30 +1057,32 @@
 		dprintk(VIDC_ERR, "cannot write to shared Q's");
 		goto err_q_null;
 	}
-	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->clk_load);
-	if (result) {
-		dprintk(VIDC_ERR, "Clock scaling failed\n");
-		goto err_q_write;
-	}
 	if (!venus_hfi_write_queue(q_info, (u8 *)pkt, &rx_req_is_set)) {
+		mutex_lock(&device->clk_pwr_lock);
+		result = venus_hfi_clk_gating_off(device);
+		if (result) {
+			dprintk(VIDC_ERR, "%s : Clock enable failed\n",
+					__func__);
+			mutex_unlock(&device->clk_pwr_lock);
+			goto err_q_write;
+		}
+		result = venus_hfi_scale_clocks(device, device->clk_load);
+		if (result) {
+			dprintk(VIDC_ERR, "Clock scaling failed\n");
+			mutex_unlock(&device->clk_pwr_lock);
+			goto err_q_write;
+		}
 		if (rx_req_is_set)
 			venus_hfi_write_register(
 				device,
 				VIDC_CPU_IC_SOFTINT,
 				1 << VIDC_CPU_IC_SOFTINT_H2A_SHFT, 0);
 		result = 0;
+		mutex_unlock(&device->clk_pwr_lock);
 	} else {
 		dprintk(VIDC_ERR, "venus_hfi_iface_cmdq_write:queue_full");
 	}
 err_q_write:
-	mutex_unlock(&device->clk_pwr_lock);
 err_q_null:
 	mutex_unlock(&device->write_lock);
 	return result;
@@ -1104,26 +1106,27 @@
 		goto read_error_null;
 	}
 	q_info = &device->iface_queues[VIDC_IFACEQ_MSGQ_IDX];
-	mutex_lock(&device->clk_pwr_lock);
-	rc = venus_hfi_clk_gating_off(device);
-	if (rc) {
-		dprintk(VIDC_ERR,
-			"%s : Clock enable failed\n", __func__);
-		goto read_error;
-	}
 	if (!venus_hfi_read_queue(q_info, (u8 *)pkt, &tx_req_is_set)) {
+		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->clk_pwr_lock);
+			goto read_error;
+		}
 		if (tx_req_is_set)
 			venus_hfi_write_register(
 				device,
 				VIDC_CPU_IC_SOFTINT,
 				1 << VIDC_CPU_IC_SOFTINT_H2A_SHFT, 0);
 		rc = 0;
+		mutex_unlock(&device->clk_pwr_lock);
 	} else {
 		dprintk(VIDC_INFO, "venus_hfi_iface_msgq_read:queue_empty");
 		rc = -ENODATA;
 	}
 read_error:
-	mutex_unlock(&device->clk_pwr_lock);
 read_error_null:
 	mutex_unlock(&device->read_lock);
 	return rc;
@@ -1146,27 +1149,28 @@
 		rc = -ENODATA;
 		goto dbg_error_null;
 	}
-	mutex_lock(&device->clk_pwr_lock);
-	rc = venus_hfi_clk_gating_off(device);
-	if (rc) {
-		dprintk(VIDC_ERR,
-			"%s : Clock enable failed\n", __func__);
-		goto dbg_error;
-	}
 	q_info = &device->iface_queues[VIDC_IFACEQ_DBGQ_IDX];
 	if (!venus_hfi_read_queue(q_info, (u8 *)pkt, &tx_req_is_set)) {
+		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->clk_pwr_lock);
+			goto dbg_error;
+		}
 		if (tx_req_is_set)
 			venus_hfi_write_register(
 				device,
 				VIDC_CPU_IC_SOFTINT,
 				1 << VIDC_CPU_IC_SOFTINT_H2A_SHFT, 0);
 		rc = 0;
+		mutex_unlock(&device->clk_pwr_lock);
 	} else {
 		dprintk(VIDC_INFO, "venus_hfi_iface_dbgq_read:queue_empty");
 		rc = -ENODATA;
 	}
 dbg_error:
-	mutex_unlock(&device->clk_pwr_lock);
 dbg_error_null:
 	mutex_unlock(&device->read_lock);
 	return rc;
@@ -1251,7 +1255,7 @@
 
 	for (i = 0; i < num_entries; i++) {
 		rc = msm_iommu_map_contig_buffer(venus_qdss_entries[i][0],
-			domain, 1 , venus_qdss_entries[i][1],
+			domain, partition, venus_qdss_entries[i][1],
 			SZ_4K, 0, &iova);
 		if (rc) {
 			dprintk(VIDC_ERR,
@@ -1567,20 +1571,59 @@
 	return 0;
 }
 
+static int venus_hfi_is_cmd_pending(struct venus_hfi_device *dev)
+{
+	struct hfi_queue_header *queue;
+	struct vidc_iface_q_info *q_info;
+	u32 write_ptr, read_ptr;
+	u32 rc = 0;
+	q_info = &dev->iface_queues[VIDC_IFACEQ_CMDQ_IDX];
+	if (!q_info)
+		dprintk(VIDC_ERR, "cannot read shared Q's");
+	queue = (struct hfi_queue_header *) q_info->q_hdr;
+	if (!queue) {
+		dprintk(VIDC_ERR, "queue not present");
+		return -ENOENT;
+	}
+	write_ptr = (u32)queue->qhdr_write_idx;
+	read_ptr = (u32)queue->qhdr_read_idx;
+	rc = read_ptr - write_ptr;
+	return rc;
+}
+
+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 void venus_hfi_core_clear_interrupt(struct venus_hfi_device *device)
 {
 	u32 intr_status = 0;
-	int rc = 0;
+	int rc = 0, ctrl_status;
 
 	if (!device->callback)
 		return;
+
+	mutex_lock(&device->write_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->clk_pwr_lock);
-		return;
+		goto err_clk_gating_off;
 	}
 	intr_status = venus_hfi_read_register(
 			device,
@@ -1603,8 +1646,23 @@
 			VIDC_CPU_CS_A2HSOFTINTCLR, 1, 0);
 	venus_hfi_write_register(device,
 			VIDC_WRAPPER_INTR_CLEAR, intr_status, 0);
-	mutex_unlock(&device->clk_pwr_lock);
+	rc = venus_hfi_is_cmd_pending(device);
+	ctrl_status = venus_hfi_read_register(
+			device,
+			VIDC_CPU_CS_SCIACMDARG0);
+	dprintk(VIDC_INFO,
+			"CLEAR INTERRUPT - cmd_pending %d, ctrl_status 0x%x\n",
+			rc, ctrl_status);
+	if ((ctrl_status & VIDC_CPU_CS_SCIACMDARG0_HFI_CTRL_INIT_IDLE_MSG_BMSK)
+			&& !rc) {
+		dprintk(VIDC_DBG, "SYS_IDLE interrupt, disable clocks\n");
+		venus_hfi_clk_gating_on(device);
+	}
+
 	dprintk(VIDC_DBG, "Cleared WRAPPER/A2H interrupt");
+err_clk_gating_off:
+	mutex_unlock(&device->clk_pwr_lock);
+	mutex_unlock(&device->write_lock);
 }
 
 static int venus_hfi_core_set_resource(void *device,
@@ -2321,26 +2379,6 @@
 	device->callback(SYS_WATCHDOG_TIMEOUT, &cmd_done);
 }
 
-static int venus_hfi_is_cmd_pending(struct venus_hfi_device *dev)
-{
-	struct hfi_queue_header *queue;
-	struct vidc_iface_q_info *q_info;
-	u32 write_ptr, read_ptr;
-	u32 rc = 0;
-	q_info = &dev->iface_queues[VIDC_IFACEQ_CMDQ_IDX];
-	if (!q_info)
-		dprintk(VIDC_ERR, "cannot read shared Q's");
-	queue = (struct hfi_queue_header *) q_info->q_hdr;
-	if (!queue) {
-		dprintk(VIDC_ERR, "queue not present");
-		return -ENOENT;
-	}
-	write_ptr = (u32)queue->qhdr_write_idx;
-	read_ptr = (u32)queue->qhdr_read_idx;
-	rc = read_ptr - write_ptr;
-	return rc;
-}
-
 static int venus_hfi_core_pc_prep(void *device)
 {
 	struct hfi_cmd_sys_pc_prep_packet pkt;
@@ -2408,24 +2446,6 @@
 	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;
@@ -2506,10 +2526,12 @@
 				(struct hfi_msg_sys_debug_packet *) packet;
 			dprintk(VIDC_FW, "FW-SAYS: %s", pkt->rg_msg_data);
 		}
-		if (rc == HFI_MSG_SYS_IDLE)
+		if (rc == HFI_MSG_SYS_IDLE) {
+			dprintk(VIDC_DBG, "Received HFI_MSG_SYS_IDLE\n");
 			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");
+		} else if (rc == HFI_MSG_SYS_PC_PREP_DONE) {
+			dprintk(VIDC_DBG,
+					"Received HFI_MSG_SYS_PC_PREP_DONE\n");
 			rc = venus_hfi_try_clk_gating(device);
 			if (rc)
 				dprintk(VIDC_ERR,
diff --git a/drivers/media/radio/radio-tavarua.c b/drivers/media/radio/radio-tavarua.c
index e0a99e2..6b9f2b3 100644
--- a/drivers/media/radio/radio-tavarua.c
+++ b/drivers/media/radio/radio-tavarua.c
@@ -3051,7 +3051,7 @@
 	int retval = 0;
 	int bytes_to_copy;
 	int bytes_copied = 0;
-	int bytes_left = 0;
+	__u32 bytes_left = 0;
 	int chunk_index = 0;
 	char tx_data[XFR_REG_NUM];
 	struct tavarua_device *radio = video_get_drvdata(video_devdata(file));
@@ -3066,15 +3066,15 @@
 
 		chunk_index = 0;
 		bytes_copied = 0;
-		bytes_left = min((int)(ctrl->controls[0]).size,
-			MAX_PS_LENGTH);
+		bytes_left = min((ctrl->controls[0]).size,
+			(__u32)MAX_PS_LENGTH);
 		data = (ctrl->controls[0]).string;
 
 		/* send payload to FM hardware */
 		while (bytes_left) {
 			chunk_index++;
 			FMDBG("chunk is %d", chunk_index);
-			bytes_to_copy = min(bytes_left, XFR_REG_NUM);
+			bytes_to_copy = min(bytes_left, (__u32)XFR_REG_NUM);
 			/*Clear the tx_data */
 			memset(tx_data, 0, XFR_REG_NUM);
 			if (copy_from_user(tx_data,
@@ -3116,12 +3116,12 @@
 		FMDBG("Passed RT String : %s\n",
 			(ctrl->controls[0]).string);
 		bytes_left =
-		    min((int)(ctrl->controls[0]).size, MAX_RT_LENGTH);
+		    min((ctrl->controls[0]).size, (__u32)MAX_RT_LENGTH);
 		data = (ctrl->controls[0]).string;
 		/* send payload to FM hardware */
 		while (bytes_left) {
 			chunk_index++;
-			bytes_to_copy = min(bytes_left, XFR_REG_NUM);
+			bytes_to_copy = min(bytes_left, (__u32)XFR_REG_NUM);
 			memset(tx_data, 0, XFR_REG_NUM);
 			if (copy_from_user(tx_data,
 				    data + bytes_copied, bytes_to_copy))
@@ -4466,8 +4466,8 @@
 
 	struct marimba_fm_platform_data *tavarua_pdata;
 	struct tavarua_device *radio;
-	int retval;
-	int i;
+	int retval = 0;
+	int i = 0, j = 0;
 	FMDBG("%s: probe called\n", __func__);
 	/* private data allocation */
 	radio = kzalloc(sizeof(struct tavarua_device), GFP_KERNEL);
@@ -4480,6 +4480,7 @@
 	tavarua_pdata = pdev->dev.platform_data;
 	radio->pdata = tavarua_pdata;
 	radio->dev = &pdev->dev;
+	radio->wqueue = NULL;
 	platform_set_drvdata(pdev, radio);
 
 	/* video device allocation */
@@ -4509,15 +4510,16 @@
 		if (kfifo_alloc_rc!=0) {
 			printk(KERN_ERR "%s: failed allocating buffers %d\n",
 				__func__, kfifo_alloc_rc);
-			goto err_bufs;
+		        retval = -ENOMEM;
+		        goto err_all;
 		}
 	}
 	/* initializing the device count  */
 	atomic_set(&radio->users, 1);
 	radio->xfr_in_progress = 0;
 	radio->xfr_bytes_left = 0;
-	for (i = 0; i < TAVARUA_XFR_MAX; i++)
-		radio->pending_xfrs[i] = 0;
+	for (j = 0; j < TAVARUA_XFR_MAX; j++)
+		radio->pending_xfrs[j] = 0;
 
 	/* init transmit data */
 	radio->tx_mode = TAVARUA_TX_RT;
@@ -4548,11 +4550,14 @@
     /*Start the worker thread for event handling and register read_int_stat
 	as worker function*/
 	radio->wqueue  = create_singlethread_workqueue("kfmradio");
-	if (!radio->wqueue)
-		return -ENOMEM;
+	if (!radio->wqueue) {
+	        retval = -ENOMEM;
+		goto err_all;
+        }
 
 	/* register video device */
-	if (video_register_device(radio->videodev, VFL_TYPE_RADIO, radio_nr)) {
+	retval = video_register_device(radio->videodev, VFL_TYPE_RADIO, radio_nr);
+	if (retval != 0) {
 		printk(KERN_WARNING DRIVER_NAME
 				": Could not register video device\n");
 		goto err_all;
@@ -4562,9 +4567,11 @@
 
 err_all:
 	video_device_release(radio->videodev);
-err_bufs:
-	for (; i > -1; i--)
+	if (radio->wqueue)
+		destroy_workqueue(radio->wqueue);
+	for (i--; i >= 0; i--) {
 		kfifo_free(&radio->data_buf[i]);
+        }
 err_radio:
 	kfree(radio);
 err_initial:
diff --git a/drivers/mmc/core/core.c b/drivers/mmc/core/core.c
index 293033b..a296e48 100644
--- a/drivers/mmc/core/core.c
+++ b/drivers/mmc/core/core.c
@@ -61,6 +61,7 @@
 
 /* Flushing a large amount of cached data may take a long time. */
 #define MMC_FLUSH_REQ_TIMEOUT_MS 90000 /* msec */
+#define MMC_CACHE_DISBALE_TIMEOUT_MS 180000 /* msec */
 
 static struct workqueue_struct *workqueue;
 
@@ -744,7 +745,11 @@
 				 */
 				mmc_update_clk_scaling(host);
 				err = mmc_stop_request(host);
-				if (err && !context_info->is_done_rcv) {
+				if (err == MMC_BLK_NO_REQ_TO_STOP) {
+					pending_is_urgent = true;
+					/* wait for done/new/urgent event */
+					continue;
+				} else if (err && !context_info->is_done_rcv) {
 					err = MMC_BLK_ABORT;
 					break;
 				}
@@ -3389,14 +3394,14 @@
 
 		if (card->ext_csd.cache_ctrl ^ enable) {
 			if (!enable)
-				timeout = MMC_FLUSH_REQ_TIMEOUT_MS;
+				timeout = MMC_CACHE_DISBALE_TIMEOUT_MS;
 
 			err = mmc_switch_ignore_timeout(card,
 					EXT_CSD_CMD_SET_NORMAL,
 					EXT_CSD_CACHE_CTRL, enable, timeout);
 
 			if (err == -ETIMEDOUT && !enable) {
-				pr_debug("%s:cache disable operation timeout\n",
+				pr_err("%s:cache disable operation timeout\n",
 						mmc_hostname(card->host));
 				rc = mmc_interrupt_hpi(card);
 				if (rc)
diff --git a/drivers/mmc/host/sdhci.c b/drivers/mmc/host/sdhci.c
index 758a79e..513ddfb 100644
--- a/drivers/mmc/host/sdhci.c
+++ b/drivers/mmc/host/sdhci.c
@@ -27,6 +27,7 @@
 
 #include <linux/mmc/mmc.h>
 #include <linux/mmc/host.h>
+#include <linux/mmc/card.h>
 
 #include "sdhci.h"
 
@@ -745,6 +746,12 @@
 	if (host->quirks & SDHCI_QUIRK_BROKEN_TIMEOUT_VAL)
 		return 0xE;
 
+	/* During initialization, don't use max timeout as the clock is slow */
+	if ((host->quirks2 & SDHCI_QUIRK2_USE_RESERVED_MAX_TIMEOUT) &&
+		(host->clock > 400000)) {
+		return 0xF;
+	}
+
 	/* Unspecified timeout, assume max */
 	if (!data && !cmd->cmd_timeout_ms)
 		return 0xE;
@@ -2223,10 +2230,13 @@
 	struct sdhci_host *host = mmc_priv(mmc);
 	unsigned long flags;
 	struct mmc_data *data;
+	int ret = 0;
 
 	spin_lock_irqsave(&host->lock, flags);
-	if (!host->mrq || !host->data)
+	if (!host->mrq || !host->data) {
+		ret = MMC_BLK_NO_REQ_TO_STOP;
 		goto out;
+	}
 
 	data = host->data;
 
@@ -2252,7 +2262,7 @@
 	host->data = NULL;
 out:
 	spin_unlock_irqrestore(&host->lock, flags);
-	return 0;
+	return ret;
 }
 
 static unsigned int sdhci_get_xfer_remain(struct mmc_host *mmc)
diff --git a/drivers/platform/msm/ipa/ipa.c b/drivers/platform/msm/ipa/ipa.c
index 6a16cf3..1ef1f1b 100644
--- a/drivers/platform/msm/ipa/ipa.c
+++ b/drivers/platform/msm/ipa/ipa.c
@@ -963,7 +963,7 @@
 	enum ipa_pipe_mem_type mem_type;
 
 	if (!pipe_connection || !node)
-		goto err;
+		return -EINVAL;
 
 	key = "qcom,src-bam-physical-address";
 	rc = of_property_read_u32(node, key, &val);
diff --git a/drivers/platform/msm/ipa/ipa_flt.c b/drivers/platform/msm/ipa/ipa_flt.c
index 2d75141..c3db716 100644
--- a/drivers/platform/msm/ipa/ipa_flt.c
+++ b/drivers/platform/msm/ipa/ipa_flt.c
@@ -802,8 +802,11 @@
 	IPADBG("reset flt ip=%d\n", ip);
 	list_for_each_entry_safe(entry, next, &tbl->head_flt_rule_list, link) {
 		node = ipa_search(&ipa_ctx->flt_rule_hdl_tree, (u32)entry);
-		if (node == NULL)
+		if (node == NULL) {
 			WARN_ON(1);
+			mutex_unlock(&ipa_ctx->lock);
+			return -EFAULT;
+		}
 
 		if ((ip == IPA_IP_v4 &&
 		     entry->rule.attrib.attrib_mask == IPA_FLT_PROTOCOL &&
@@ -833,8 +836,11 @@
 				link) {
 			node = ipa_search(&ipa_ctx->flt_rule_hdl_tree,
 					(u32)entry);
-			if (node == NULL)
+			if (node == NULL) {
 				WARN_ON(1);
+				mutex_unlock(&ipa_ctx->lock);
+				return -EFAULT;
+			}
 			list_del(&entry->link);
 			entry->tbl->rule_cnt--;
 			if (entry->rt_tbl)
diff --git a/drivers/platform/msm/ipa/ipa_hdr.c b/drivers/platform/msm/ipa/ipa_hdr.c
index 9618da2..54cbf5f 100644
--- a/drivers/platform/msm/ipa/ipa_hdr.c
+++ b/drivers/platform/msm/ipa/ipa_hdr.c
@@ -450,8 +450,11 @@
 			continue;
 
 		node = ipa_search(&ipa_ctx->hdr_hdl_tree, (u32) entry);
-		if (node == NULL)
+		if (node == NULL) {
 			WARN_ON(1);
+			mutex_unlock(&ipa_ctx->lock);
+			return -EFAULT;
+		}
 		list_del(&entry->link);
 		entry->cookie = 0;
 		kmem_cache_free(ipa_ctx->hdr_cache, entry);
diff --git a/drivers/platform/msm/ipa/ipa_rt.c b/drivers/platform/msm/ipa/ipa_rt.c
index 8d6d5e6..f453010 100644
--- a/drivers/platform/msm/ipa/ipa_rt.c
+++ b/drivers/platform/msm/ipa/ipa_rt.c
@@ -843,8 +843,11 @@
 					 &tbl->head_rt_rule_list, link) {
 			node = ipa_search(&ipa_ctx->rt_rule_hdl_tree,
 					  (u32)rule);
-			if (node == NULL)
+			if (node == NULL) {
 				WARN_ON(1);
+				mutex_unlock(&ipa_ctx->lock);
+				return -EFAULT;
+			}
 
 			/*
 			 * for the "default" routing tbl, remove all but the
@@ -866,8 +869,11 @@
 		}
 
 		node = ipa_search(&ipa_ctx->rt_tbl_hdl_tree, (u32)tbl);
-		if (node  == NULL)
+		if (node  == NULL) {
 			WARN_ON(1);
+			mutex_unlock(&ipa_ctx->lock);
+			return -EFAULT;
+		}
 
 		/* do not remove the "default" routing tbl which has index 0 */
 		if (tbl->idx != 0) {
diff --git a/drivers/power/qpnp-charger.c b/drivers/power/qpnp-charger.c
index a65ac5b..a627ec2 100644
--- a/drivers/power/qpnp-charger.c
+++ b/drivers/power/qpnp-charger.c
@@ -369,6 +369,7 @@
 	struct alarm			reduce_power_stage_alarm;
 	struct work_struct		reduce_power_stage_work;
 	bool				power_stage_workaround_running;
+	bool				power_stage_workaround_enable;
 };
 
 
@@ -2151,7 +2152,8 @@
 
 			if ((chip->flags & POWER_STAGE_WA)
 			&& ((ret.intval / 1000) > USB_WALL_THRESHOLD_MA)
-			&& !chip->power_stage_workaround_running) {
+			&& !chip->power_stage_workaround_running
+			&& chip->power_stage_workaround_enable) {
 				chip->power_stage_workaround_running = true;
 				pr_debug("usb wall chg inserted starting power stage workaround charger_monitor = %d\n",
 						charger_monitor);
@@ -4124,6 +4126,10 @@
 	if (chip->use_default_batt_values)
 		chip->charging_disabled = true;
 
+	chip->power_stage_workaround_enable =
+			of_property_read_bool(chip->spmi->dev.of_node,
+					"qcom,power-stage-reduced");
+
 	of_get_property(chip->spmi->dev.of_node, "qcom,thermal-mitigation",
 		&(chip->thermal_levels));
 
diff --git a/drivers/slimbus/slim-msm-ngd.c b/drivers/slimbus/slim-msm-ngd.c
index 0c9959c..67cf049 100644
--- a/drivers/slimbus/slim-msm-ngd.c
+++ b/drivers/slimbus/slim-msm-ngd.c
@@ -1065,7 +1065,7 @@
 	}
 
 	dev = kzalloc(sizeof(struct msm_slim_ctrl), GFP_KERNEL);
-	if (IS_ERR(dev)) {
+	if (IS_ERR_OR_NULL(dev)) {
 		dev_err(&pdev->dev, "no memory for MSM slimbus controller\n");
 		return PTR_ERR(dev);
 	}
diff --git a/drivers/staging/zram/Kconfig b/drivers/staging/zram/Kconfig
index 9d11a4c..983314c 100644
--- a/drivers/staging/zram/Kconfig
+++ b/drivers/staging/zram/Kconfig
@@ -1,9 +1,6 @@
 config ZRAM
 	tristate "Compressed RAM block device support"
-	# X86 dependency is because zsmalloc uses non-portable pte/tlb
-	# functions
-	depends on BLOCK && SYSFS && X86
-	select ZSMALLOC
+	depends on BLOCK && SYSFS && ZSMALLOC
 	select LZO_COMPRESS
 	select LZO_DECOMPRESS
 	default n
@@ -17,7 +14,7 @@
 	  disks and maybe many more.
 
 	  See zram.txt for more information.
-	  Project home: http://compcache.googlecode.com/
+	  Project home: <https://compcache.googlecode.com/>
 
 config ZRAM_DEBUG
 	bool "Compressed RAM block device debug support"
diff --git a/drivers/staging/zram/Makefile b/drivers/staging/zram/Makefile
index 7f4a301..cb0f9ce 100644
--- a/drivers/staging/zram/Makefile
+++ b/drivers/staging/zram/Makefile
@@ -1,3 +1,3 @@
-zram-y	:=	zram_drv.o zram_sysfs.o
+zram-y	:=	zram_drv.o
 
 obj-$(CONFIG_ZRAM)	+=	zram.o
diff --git a/drivers/staging/zram/zram.txt b/drivers/staging/zram/zram.txt
index 5f75d29..765d790 100644
--- a/drivers/staging/zram/zram.txt
+++ b/drivers/staging/zram/zram.txt
@@ -23,17 +23,17 @@
 	This creates 4 devices: /dev/zram{0,1,2,3}
 	(num_devices parameter is optional. Default: 1)
 
-2) Set Disksize (Optional):
-	Set disk size by writing the value to sysfs node 'disksize'
-	(in bytes). If disksize is not given, default value of 25%
-	of RAM is used.
+2) Set Disksize
+        Set disk size by writing the value to sysfs node 'disksize'.
+        The value can be either in bytes or you can use mem suffixes.
+        Examples:
+            # Initialize /dev/zram0 with 50MB disksize
+            echo $((50*1024*1024)) > /sys/block/zram0/disksize
 
-	# Initialize /dev/zram0 with 50MB disksize
-	echo $((50*1024*1024)) > /sys/block/zram0/disksize
-
-	NOTE: disksize cannot be changed if the disk contains any
-	data. So, for such a disk, you need to issue 'reset' (see below)
-	before you can change its disksize.
+            # Using mem suffixes
+            echo 256K > /sys/block/zram0/disksize
+            echo 512M > /sys/block/zram0/disksize
+            echo 1G > /sys/block/zram0/disksize
 
 3) Activate:
 	mkswap /dev/zram0
@@ -65,8 +65,9 @@
 	echo 1 > /sys/block/zram0/reset
 	echo 1 > /sys/block/zram1/reset
 
-	(This frees all the memory allocated for the given device).
-
+	This frees all the memory allocated for the given device and
+	resets the disksize to zero. You must set the disksize again
+	before reusing the device.
 
 Please report any problems at:
  - Mailing list: linux-mm-cc at laptop dot org
diff --git a/drivers/staging/zram/zram_drv.c b/drivers/staging/zram/zram_drv.c
index 685d612..91d94b5 100644
--- a/drivers/staging/zram/zram_drv.c
+++ b/drivers/staging/zram/zram_drv.c
@@ -37,56 +37,216 @@
 
 /* Globals */
 static int zram_major;
-struct zram *zram_devices;
+static struct zram *zram_devices;
 
 /* Module params (documentation at end) */
-static unsigned int num_devices;
+static unsigned int num_devices = 1;
 
-static void zram_stat_inc(u32 *v)
+static inline struct zram *dev_to_zram(struct device *dev)
 {
-	*v = *v + 1;
+	return (struct zram *)dev_to_disk(dev)->private_data;
 }
 
-static void zram_stat_dec(u32 *v)
+static ssize_t disksize_show(struct device *dev,
+		struct device_attribute *attr, char *buf)
 {
-	*v = *v - 1;
+	struct zram *zram = dev_to_zram(dev);
+
+	return sprintf(buf, "%llu\n", zram->disksize);
 }
 
-static void zram_stat64_add(struct zram *zram, u64 *v, u64 inc)
+static ssize_t initstate_show(struct device *dev,
+		struct device_attribute *attr, char *buf)
 {
-	spin_lock(&zram->stat64_lock);
-	*v = *v + inc;
-	spin_unlock(&zram->stat64_lock);
+	struct zram *zram = dev_to_zram(dev);
+
+	return sprintf(buf, "%u\n", zram->init_done);
 }
 
-static void zram_stat64_sub(struct zram *zram, u64 *v, u64 dec)
+static ssize_t num_reads_show(struct device *dev,
+		struct device_attribute *attr, char *buf)
 {
-	spin_lock(&zram->stat64_lock);
-	*v = *v - dec;
-	spin_unlock(&zram->stat64_lock);
+	struct zram *zram = dev_to_zram(dev);
+
+	return sprintf(buf, "%llu\n",
+			(u64)atomic64_read(&zram->stats.num_reads));
 }
 
-static void zram_stat64_inc(struct zram *zram, u64 *v)
+static ssize_t num_writes_show(struct device *dev,
+		struct device_attribute *attr, char *buf)
 {
-	zram_stat64_add(zram, v, 1);
+	struct zram *zram = dev_to_zram(dev);
+
+	return sprintf(buf, "%llu\n",
+			(u64)atomic64_read(&zram->stats.num_writes));
 }
 
-static int zram_test_flag(struct zram *zram, u32 index,
+static ssize_t invalid_io_show(struct device *dev,
+		struct device_attribute *attr, char *buf)
+{
+	struct zram *zram = dev_to_zram(dev);
+
+	return sprintf(buf, "%llu\n",
+			(u64)atomic64_read(&zram->stats.invalid_io));
+}
+
+static ssize_t notify_free_show(struct device *dev,
+		struct device_attribute *attr, char *buf)
+{
+	struct zram *zram = dev_to_zram(dev);
+
+	return sprintf(buf, "%llu\n",
+			(u64)atomic64_read(&zram->stats.notify_free));
+}
+
+static ssize_t zero_pages_show(struct device *dev,
+		struct device_attribute *attr, char *buf)
+{
+	struct zram *zram = dev_to_zram(dev);
+
+	return sprintf(buf, "%u\n", zram->stats.pages_zero);
+}
+
+static ssize_t orig_data_size_show(struct device *dev,
+		struct device_attribute *attr, char *buf)
+{
+	struct zram *zram = dev_to_zram(dev);
+
+	return sprintf(buf, "%llu\n",
+		(u64)(zram->stats.pages_stored) << PAGE_SHIFT);
+}
+
+static ssize_t compr_data_size_show(struct device *dev,
+		struct device_attribute *attr, char *buf)
+{
+	struct zram *zram = dev_to_zram(dev);
+
+	return sprintf(buf, "%llu\n",
+			(u64)atomic64_read(&zram->stats.compr_size));
+}
+
+static ssize_t mem_used_total_show(struct device *dev,
+		struct device_attribute *attr, char *buf)
+{
+	u64 val = 0;
+	struct zram *zram = dev_to_zram(dev);
+	struct zram_meta *meta = zram->meta;
+
+	down_read(&zram->init_lock);
+	if (zram->init_done)
+		val = zs_get_total_size_bytes(meta->mem_pool);
+	up_read(&zram->init_lock);
+
+	return sprintf(buf, "%llu\n", val);
+}
+
+static int zram_test_flag(struct zram_meta *meta, u32 index,
 			enum zram_pageflags flag)
 {
-	return zram->table[index].flags & BIT(flag);
+	return meta->table[index].flags & BIT(flag);
 }
 
-static void zram_set_flag(struct zram *zram, u32 index,
+static void zram_set_flag(struct zram_meta *meta, u32 index,
 			enum zram_pageflags flag)
 {
-	zram->table[index].flags |= BIT(flag);
+	meta->table[index].flags |= BIT(flag);
 }
 
-static void zram_clear_flag(struct zram *zram, u32 index,
+static void zram_clear_flag(struct zram_meta *meta, u32 index,
 			enum zram_pageflags flag)
 {
-	zram->table[index].flags &= ~BIT(flag);
+	meta->table[index].flags &= ~BIT(flag);
+}
+
+static inline int is_partial_io(struct bio_vec *bvec)
+{
+	return bvec->bv_len != PAGE_SIZE;
+}
+
+/*
+ * Check if request is within bounds and aligned on zram logical blocks.
+ */
+static inline int valid_io_request(struct zram *zram, struct bio *bio)
+{
+	u64 start, end, bound;
+
+	/* unaligned request */
+	if (unlikely(bio->bi_sector & (ZRAM_SECTOR_PER_LOGICAL_BLOCK - 1)))
+		return 0;
+	if (unlikely(bio->bi_size & (ZRAM_LOGICAL_BLOCK_SIZE - 1)))
+		return 0;
+
+	start = bio->bi_sector;
+	end = start + (bio->bi_size >> SECTOR_SHIFT);
+	bound = zram->disksize >> SECTOR_SHIFT;
+	/* out of range range */
+	if (unlikely(start >= bound || end > bound || start > end))
+		return 0;
+
+	/* I/O request is valid */
+	return 1;
+}
+
+static void zram_meta_free(struct zram_meta *meta)
+{
+	zs_destroy_pool(meta->mem_pool);
+	kfree(meta->compress_workmem);
+	free_pages((unsigned long)meta->compress_buffer, 1);
+	vfree(meta->table);
+	kfree(meta);
+}
+
+static struct zram_meta *zram_meta_alloc(u64 disksize)
+{
+	size_t num_pages;
+	struct zram_meta *meta = kmalloc(sizeof(*meta), GFP_KERNEL);
+	if (!meta)
+		goto out;
+
+	meta->compress_workmem = kzalloc(LZO1X_MEM_COMPRESS, GFP_KERNEL);
+	if (!meta->compress_workmem)
+		goto free_meta;
+
+	meta->compress_buffer =
+		(void *)__get_free_pages(GFP_KERNEL | __GFP_ZERO, 1);
+	if (!meta->compress_buffer) {
+		pr_err("Error allocating compressor buffer space\n");
+		goto free_workmem;
+	}
+
+	num_pages = disksize >> PAGE_SHIFT;
+	meta->table = vzalloc(num_pages * sizeof(*meta->table));
+	if (!meta->table) {
+		pr_err("Error allocating zram address table\n");
+		goto free_buffer;
+	}
+
+	meta->mem_pool = zs_create_pool(GFP_NOIO | __GFP_HIGHMEM);
+	if (!meta->mem_pool) {
+		pr_err("Error creating memory pool\n");
+		goto free_table;
+	}
+
+	return meta;
+
+free_table:
+	vfree(meta->table);
+free_buffer:
+	free_pages((unsigned long)meta->compress_buffer, 1);
+free_workmem:
+	kfree(meta->compress_workmem);
+free_meta:
+	kfree(meta);
+	meta = NULL;
+out:
+	return meta;
+}
+
+static void update_position(u32 *index, int *offset, struct bio_vec *bvec)
+{
+	if (*offset + bvec->bv_len >= PAGE_SIZE)
+		(*index)++;
+	*offset = (*offset + bvec->bv_len) % PAGE_SIZE;
 }
 
 static int page_zero_filled(void *ptr)
@@ -104,352 +264,269 @@
 	return 1;
 }
 
-static void zram_set_disksize(struct zram *zram, size_t totalram_bytes)
-{
-	if (!zram->disksize) {
-		pr_info(
-		"disk size not provided. You can use disksize_kb module "
-		"param to specify size.\nUsing default: (%u%% of RAM).\n",
-		default_disksize_perc_ram
-		);
-		zram->disksize = default_disksize_perc_ram *
-					(totalram_bytes / 100);
-	}
-
-	if (zram->disksize > 2 * (totalram_bytes)) {
-		pr_info(
-		"There is little point creating a zram of greater than "
-		"twice the size of memory since we expect a 2:1 compression "
-		"ratio. Note that zram uses about 0.1%% of the size of "
-		"the disk when not in use so a huge zram is "
-		"wasteful.\n"
-		"\tMemory Size: %zu kB\n"
-		"\tSize you selected: %llu kB\n"
-		"Continuing anyway ...\n",
-		totalram_bytes >> 10, zram->disksize
-		);
-	}
-
-	zram->disksize &= PAGE_MASK;
-}
-
-static void zram_free_page(struct zram *zram, size_t index)
-{
-	void *handle = zram->table[index].handle;
-
-	if (unlikely(!handle)) {
-		/*
-		 * No memory is allocated for zero filled pages.
-		 * Simply clear zero page flag.
-		 */
-		if (zram_test_flag(zram, index, ZRAM_ZERO)) {
-			zram_clear_flag(zram, index, ZRAM_ZERO);
-			zram_stat_dec(&zram->stats.pages_zero);
-		}
-		return;
-	}
-
-	if (unlikely(zram_test_flag(zram, index, ZRAM_UNCOMPRESSED))) {
-		__free_page(handle);
-		zram_clear_flag(zram, index, ZRAM_UNCOMPRESSED);
-		zram_stat_dec(&zram->stats.pages_expand);
-		goto out;
-	}
-
-	zs_free(zram->mem_pool, handle);
-
-	if (zram->table[index].size <= PAGE_SIZE / 2)
-		zram_stat_dec(&zram->stats.good_compress);
-
-out:
-	zram_stat64_sub(zram, &zram->stats.compr_size,
-			zram->table[index].size);
-	zram_stat_dec(&zram->stats.pages_stored);
-
-	zram->table[index].handle = NULL;
-	zram->table[index].size = 0;
-}
-
 static void handle_zero_page(struct bio_vec *bvec)
 {
 	struct page *page = bvec->bv_page;
 	void *user_mem;
 
 	user_mem = kmap_atomic(page);
-	memset(user_mem + bvec->bv_offset, 0, bvec->bv_len);
+	if (is_partial_io(bvec))
+		memset(user_mem + bvec->bv_offset, 0, bvec->bv_len);
+	else
+		clear_page(user_mem);
 	kunmap_atomic(user_mem);
 
 	flush_dcache_page(page);
 }
 
-static void handle_uncompressed_page(struct zram *zram, struct bio_vec *bvec,
-				     u32 index, int offset)
+static void zram_free_page(struct zram *zram, size_t index)
 {
-	struct page *page = bvec->bv_page;
-	unsigned char *user_mem, *cmem;
+	struct zram_meta *meta = zram->meta;
+	unsigned long handle = meta->table[index].handle;
+	u16 size = meta->table[index].size;
 
-	user_mem = kmap_atomic(page);
-	cmem = kmap_atomic(zram->table[index].handle);
+	if (unlikely(!handle)) {
+		/*
+		 * No memory is allocated for zero filled pages.
+		 * Simply clear zero page flag.
+		 */
+		if (zram_test_flag(meta, index, ZRAM_ZERO)) {
+			zram_clear_flag(meta, index, ZRAM_ZERO);
+			zram->stats.pages_zero--;
+		}
+		return;
+	}
 
-	memcpy(user_mem + bvec->bv_offset, cmem + offset, bvec->bv_len);
-	kunmap_atomic(cmem);
-	kunmap_atomic(user_mem);
+	if (unlikely(size > max_zpage_size))
+		zram->stats.bad_compress--;
 
-	flush_dcache_page(page);
+	zs_free(meta->mem_pool, handle);
+
+	if (size <= PAGE_SIZE / 2)
+		zram->stats.good_compress--;
+
+	atomic64_sub(meta->table[index].size, &zram->stats.compr_size);
+	zram->stats.pages_stored--;
+
+	meta->table[index].handle = 0;
+	meta->table[index].size = 0;
 }
 
-static inline int is_partial_io(struct bio_vec *bvec)
+static int zram_decompress_page(struct zram *zram, char *mem, u32 index)
 {
-	return bvec->bv_len != PAGE_SIZE;
+	int ret = LZO_E_OK;
+	size_t clen = PAGE_SIZE;
+	unsigned char *cmem;
+	struct zram_meta *meta = zram->meta;
+	unsigned long handle = meta->table[index].handle;
+
+	if (!handle || zram_test_flag(meta, index, ZRAM_ZERO)) {
+		clear_page(mem);
+		return 0;
+	}
+
+	cmem = zs_map_object(meta->mem_pool, handle, ZS_MM_RO);
+	if (meta->table[index].size == PAGE_SIZE)
+		copy_page(mem, cmem);
+	else
+		ret = lzo1x_decompress_safe(cmem, meta->table[index].size,
+						mem, &clen);
+	zs_unmap_object(meta->mem_pool, handle);
+
+	/* Should NEVER happen. Return bio error if it does. */
+	if (unlikely(ret != LZO_E_OK)) {
+		pr_err("Decompression failed! err=%d, page=%u\n", ret, index);
+		atomic64_inc(&zram->stats.failed_reads);
+		return ret;
+	}
+
+	return 0;
 }
 
 static int zram_bvec_read(struct zram *zram, struct bio_vec *bvec,
 			  u32 index, int offset, struct bio *bio)
 {
 	int ret;
-	size_t clen;
 	struct page *page;
-	struct zobj_header *zheader;
-	unsigned char *user_mem, *cmem, *uncmem = NULL;
-
+	unsigned char *user_mem, *uncmem = NULL;
+	struct zram_meta *meta = zram->meta;
 	page = bvec->bv_page;
 
-	if (zram_test_flag(zram, index, ZRAM_ZERO)) {
+	if (unlikely(!meta->table[index].handle) ||
+			zram_test_flag(meta, index, ZRAM_ZERO)) {
 		handle_zero_page(bvec);
 		return 0;
 	}
 
-	/* Requested page is not present in compressed area */
-	if (unlikely(!zram->table[index].handle)) {
-		pr_debug("Read before write: sector=%lu, size=%u",
-			 (ulong)(bio->bi_sector), bio->bi_size);
-		handle_zero_page(bvec);
-		return 0;
-	}
-
-	/* Page is stored uncompressed since it's incompressible */
-	if (unlikely(zram_test_flag(zram, index, ZRAM_UNCOMPRESSED))) {
-		handle_uncompressed_page(zram, bvec, index, offset);
-		return 0;
-	}
-
-	if (is_partial_io(bvec)) {
+	if (is_partial_io(bvec))
 		/* Use  a temporary buffer to decompress the page */
-		uncmem = kmalloc(PAGE_SIZE, GFP_KERNEL);
-		if (!uncmem) {
-			pr_info("Error allocating temp memory!\n");
-			return -ENOMEM;
-		}
-	}
+		uncmem = kmalloc(PAGE_SIZE, GFP_NOIO);
 
 	user_mem = kmap_atomic(page);
 	if (!is_partial_io(bvec))
 		uncmem = user_mem;
-	clen = PAGE_SIZE;
 
-	cmem = zs_map_object(zram->mem_pool, zram->table[index].handle);
-
-	ret = lzo1x_decompress_safe(cmem + sizeof(*zheader),
-				    zram->table[index].size,
-				    uncmem, &clen);
-
-	if (is_partial_io(bvec)) {
-		memcpy(user_mem + bvec->bv_offset, uncmem + offset,
-		       bvec->bv_len);
-		kfree(uncmem);
+	if (!uncmem) {
+		pr_info("Unable to allocate temp memory\n");
+		ret = -ENOMEM;
+		goto out_cleanup;
 	}
 
-	zs_unmap_object(zram->mem_pool, zram->table[index].handle);
-	kunmap_atomic(user_mem);
-
+	ret = zram_decompress_page(zram, uncmem, index);
 	/* Should NEVER happen. Return bio error if it does. */
-	if (unlikely(ret != LZO_E_OK)) {
-		pr_err("Decompression failed! err=%d, page=%u\n", ret, index);
-		zram_stat64_inc(zram, &zram->stats.failed_reads);
-		return ret;
-	}
+	if (unlikely(ret != LZO_E_OK))
+		goto out_cleanup;
+
+	if (is_partial_io(bvec))
+		memcpy(user_mem + bvec->bv_offset, uncmem + offset,
+				bvec->bv_len);
 
 	flush_dcache_page(page);
-
-	return 0;
-}
-
-static int zram_read_before_write(struct zram *zram, char *mem, u32 index)
-{
-	int ret;
-	size_t clen = PAGE_SIZE;
-	struct zobj_header *zheader;
-	unsigned char *cmem;
-
-	if (zram_test_flag(zram, index, ZRAM_ZERO) ||
-	    !zram->table[index].handle) {
-		memset(mem, 0, PAGE_SIZE);
-		return 0;
-	}
-
-	cmem = zs_map_object(zram->mem_pool, zram->table[index].handle);
-
-	/* Page is stored uncompressed since it's incompressible */
-	if (unlikely(zram_test_flag(zram, index, ZRAM_UNCOMPRESSED))) {
-		memcpy(mem, cmem, PAGE_SIZE);
-		kunmap_atomic(cmem);
-		return 0;
-	}
-
-	ret = lzo1x_decompress_safe(cmem + sizeof(*zheader),
-				    zram->table[index].size,
-				    mem, &clen);
-	zs_unmap_object(zram->mem_pool, zram->table[index].handle);
-
-	/* Should NEVER happen. Return bio error if it does. */
-	if (unlikely(ret != LZO_E_OK)) {
-		pr_err("Decompression failed! err=%d, page=%u\n", ret, index);
-		zram_stat64_inc(zram, &zram->stats.failed_reads);
-		return ret;
-	}
-
-	return 0;
+	ret = 0;
+out_cleanup:
+	kunmap_atomic(user_mem);
+	if (is_partial_io(bvec))
+		kfree(uncmem);
+	return ret;
 }
 
 static int zram_bvec_write(struct zram *zram, struct bio_vec *bvec, u32 index,
 			   int offset)
 {
-	int ret;
-	u32 store_offset;
+	int ret = 0;
 	size_t clen;
-	void *handle;
-	struct zobj_header *zheader;
-	struct page *page, *page_store;
+	unsigned long handle;
+	struct page *page;
 	unsigned char *user_mem, *cmem, *src, *uncmem = NULL;
+	struct zram_meta *meta = zram->meta;
 
 	page = bvec->bv_page;
-	src = zram->compress_buffer;
+	src = meta->compress_buffer;
 
 	if (is_partial_io(bvec)) {
 		/*
 		 * This is a partial IO. We need to read the full page
 		 * before to write the changes.
 		 */
-		uncmem = kmalloc(PAGE_SIZE, GFP_KERNEL);
+		uncmem = kmalloc(PAGE_SIZE, GFP_NOIO);
 		if (!uncmem) {
-			pr_info("Error allocating temp memory!\n");
 			ret = -ENOMEM;
 			goto out;
 		}
-		ret = zram_read_before_write(zram, uncmem, index);
-		if (ret) {
-			kfree(uncmem);
+		ret = zram_decompress_page(zram, uncmem, index);
+		if (ret)
 			goto out;
-		}
 	}
 
-	/*
-	 * System overwrites unused sectors. Free memory associated
-	 * with this sector now.
-	 */
-	if (zram->table[index].handle ||
-	    zram_test_flag(zram, index, ZRAM_ZERO))
-		zram_free_page(zram, index);
-
 	user_mem = kmap_atomic(page);
 
-	if (is_partial_io(bvec))
+	if (is_partial_io(bvec)) {
 		memcpy(uncmem + offset, user_mem + bvec->bv_offset,
 		       bvec->bv_len);
-	else
+		kunmap_atomic(user_mem);
+		user_mem = NULL;
+	} else {
 		uncmem = user_mem;
+	}
 
 	if (page_zero_filled(uncmem)) {
 		kunmap_atomic(user_mem);
-		if (is_partial_io(bvec))
-			kfree(uncmem);
-		zram_stat_inc(&zram->stats.pages_zero);
-		zram_set_flag(zram, index, ZRAM_ZERO);
+		/* Free memory associated with this sector now. */
+		zram_free_page(zram, index);
+
+		zram->stats.pages_zero++;
+		zram_set_flag(meta, index, ZRAM_ZERO);
 		ret = 0;
 		goto out;
 	}
 
-	ret = lzo1x_1_compress(uncmem, PAGE_SIZE, src, &clen,
-			       zram->compress_workmem);
+	/*
+	 * zram_slot_free_notify could miss free so that let's
+	 * double check.
+	 */
+	if (unlikely(meta->table[index].handle ||
+			zram_test_flag(meta, index, ZRAM_ZERO)))
+		zram_free_page(zram, index);
 
-	kunmap_atomic(user_mem);
-	if (is_partial_io(bvec))
-			kfree(uncmem);
+	ret = lzo1x_1_compress(uncmem, PAGE_SIZE, src, &clen,
+			       meta->compress_workmem);
+
+	if (!is_partial_io(bvec)) {
+		kunmap_atomic(user_mem);
+		user_mem = NULL;
+		uncmem = NULL;
+	}
 
 	if (unlikely(ret != LZO_E_OK)) {
 		pr_err("Compression failed! err=%d\n", ret);
 		goto out;
 	}
 
-	/*
-	 * Page is incompressible. Store it as-is (uncompressed)
-	 * since we do not want to return too many disk write
-	 * errors which has side effect of hanging the system.
-	 */
 	if (unlikely(clen > max_zpage_size)) {
+		zram->stats.bad_compress++;
 		clen = PAGE_SIZE;
-		page_store = alloc_page(GFP_NOIO | __GFP_HIGHMEM);
-		if (unlikely(!page_store)) {
-			pr_info("Error allocating memory for "
-				"incompressible page: %u\n", index);
-			ret = -ENOMEM;
-			goto out;
-		}
-
-		store_offset = 0;
-		zram_set_flag(zram, index, ZRAM_UNCOMPRESSED);
-		zram_stat_inc(&zram->stats.pages_expand);
-		handle = page_store;
-		src = kmap_atomic(page);
-		cmem = kmap_atomic(page_store);
-		goto memstore;
+		src = NULL;
+		if (is_partial_io(bvec))
+			src = uncmem;
 	}
 
-	handle = zs_malloc(zram->mem_pool, clen + sizeof(*zheader));
+	handle = zs_malloc(meta->mem_pool, clen);
 	if (!handle) {
-		pr_info("Error allocating memory for compressed "
-			"page: %u, size=%zu\n", index, clen);
+		pr_info("Error allocating memory for compressed page: %u, size=%zu\n",
+			index, clen);
 		ret = -ENOMEM;
 		goto out;
 	}
-	cmem = zs_map_object(zram->mem_pool, handle);
+	cmem = zs_map_object(meta->mem_pool, handle, ZS_MM_WO);
 
-memstore:
-#if 0
-	/* Back-reference needed for memory defragmentation */
-	if (!zram_test_flag(zram, index, ZRAM_UNCOMPRESSED)) {
-		zheader = (struct zobj_header *)cmem;
-		zheader->table_idx = index;
-		cmem += sizeof(*zheader);
-	}
-#endif
-
-	memcpy(cmem, src, clen);
-
-	if (unlikely(zram_test_flag(zram, index, ZRAM_UNCOMPRESSED))) {
-		kunmap_atomic(cmem);
+	if ((clen == PAGE_SIZE) && !is_partial_io(bvec)) {
+		src = kmap_atomic(page);
+		copy_page(cmem, src);
 		kunmap_atomic(src);
 	} else {
-		zs_unmap_object(zram->mem_pool, handle);
+		memcpy(cmem, src, clen);
 	}
 
-	zram->table[index].handle = handle;
-	zram->table[index].size = clen;
+	zs_unmap_object(meta->mem_pool, handle);
+
+	/*
+	 * Free memory associated with this sector
+	 * before overwriting unused sectors.
+	 */
+	zram_free_page(zram, index);
+
+	meta->table[index].handle = handle;
+	meta->table[index].size = clen;
 
 	/* Update stats */
-	zram_stat64_add(zram, &zram->stats.compr_size, clen);
-	zram_stat_inc(&zram->stats.pages_stored);
+	atomic64_add(clen, &zram->stats.compr_size);
+	zram->stats.pages_stored++;
 	if (clen <= PAGE_SIZE / 2)
-		zram_stat_inc(&zram->stats.good_compress);
-
-	return 0;
+		zram->stats.good_compress++;
 
 out:
+	if (is_partial_io(bvec))
+		kfree(uncmem);
+
 	if (ret)
-		zram_stat64_inc(zram, &zram->stats.failed_writes);
+		atomic64_inc(&zram->stats.failed_writes);
 	return ret;
 }
 
+static void handle_pending_slot_free(struct zram *zram)
+{
+	struct zram_slot_free *free_rq;
+
+	spin_lock(&zram->slot_free_lock);
+	while (zram->slot_free_rq) {
+		free_rq = zram->slot_free_rq;
+		zram->slot_free_rq = free_rq->next;
+		zram_free_page(zram, free_rq->index);
+		kfree(free_rq);
+	}
+	spin_unlock(&zram->slot_free_lock);
+}
+
 static int zram_bvec_rw(struct zram *zram, struct bio_vec *bvec, u32 index,
 			int offset, struct bio *bio, int rw)
 {
@@ -457,10 +534,12 @@
 
 	if (rw == READ) {
 		down_read(&zram->lock);
+		handle_pending_slot_free(zram);
 		ret = zram_bvec_read(zram, bvec, index, offset, bio);
 		up_read(&zram->lock);
 	} else {
 		down_write(&zram->lock);
+		handle_pending_slot_free(zram);
 		ret = zram_bvec_write(zram, bvec, index, offset);
 		up_write(&zram->lock);
 	}
@@ -468,11 +547,124 @@
 	return ret;
 }
 
-static void update_position(u32 *index, int *offset, struct bio_vec *bvec)
+static void zram_reset_device(struct zram *zram, bool reset_capacity)
 {
-	if (*offset + bvec->bv_len >= PAGE_SIZE)
-		(*index)++;
-	*offset = (*offset + bvec->bv_len) % PAGE_SIZE;
+	size_t index;
+	struct zram_meta *meta;
+
+	flush_work(&zram->free_work);
+
+	down_write(&zram->init_lock);
+	if (!zram->init_done) {
+		up_write(&zram->init_lock);
+		return;
+	}
+
+	meta = zram->meta;
+	zram->init_done = 0;
+
+	/* Free all pages that are still in this zram device */
+	for (index = 0; index < zram->disksize >> PAGE_SHIFT; index++) {
+		unsigned long handle = meta->table[index].handle;
+		if (!handle)
+			continue;
+
+		zs_free(meta->mem_pool, handle);
+	}
+
+	zram_meta_free(zram->meta);
+	zram->meta = NULL;
+	/* Reset stats */
+	memset(&zram->stats, 0, sizeof(zram->stats));
+
+	zram->disksize = 0;
+	if (reset_capacity)
+		set_capacity(zram->disk, 0);
+	up_write(&zram->init_lock);
+}
+
+static void zram_init_device(struct zram *zram, struct zram_meta *meta)
+{
+	if (zram->disksize > 2 * (totalram_pages << PAGE_SHIFT)) {
+		pr_info(
+		"There is little point creating a zram of greater than "
+		"twice the size of memory since we expect a 2:1 compression "
+		"ratio. Note that zram uses about 0.1%% of the size of "
+		"the disk when not in use so a huge zram is "
+		"wasteful.\n"
+		"\tMemory Size: %lu kB\n"
+		"\tSize you selected: %llu kB\n"
+		"Continuing anyway ...\n",
+		(totalram_pages << PAGE_SHIFT) >> 10, zram->disksize >> 10
+		);
+	}
+
+	/* zram devices sort of resembles non-rotational disks */
+	queue_flag_set_unlocked(QUEUE_FLAG_NONROT, zram->disk->queue);
+
+	zram->meta = meta;
+	zram->init_done = 1;
+
+	pr_debug("Initialization done!\n");
+}
+
+static ssize_t disksize_store(struct device *dev,
+		struct device_attribute *attr, const char *buf, size_t len)
+{
+	u64 disksize;
+	struct zram_meta *meta;
+	struct zram *zram = dev_to_zram(dev);
+
+	disksize = memparse(buf, NULL);
+	if (!disksize)
+		return -EINVAL;
+
+	disksize = PAGE_ALIGN(disksize);
+	meta = zram_meta_alloc(disksize);
+	down_write(&zram->init_lock);
+	if (zram->init_done) {
+		up_write(&zram->init_lock);
+		zram_meta_free(meta);
+		pr_info("Cannot change disksize for initialized device\n");
+		return -EBUSY;
+	}
+
+	zram->disksize = disksize;
+	set_capacity(zram->disk, zram->disksize >> SECTOR_SHIFT);
+	zram_init_device(zram, meta);
+	up_write(&zram->init_lock);
+
+	return len;
+}
+
+static ssize_t reset_store(struct device *dev,
+		struct device_attribute *attr, const char *buf, size_t len)
+{
+	int ret;
+	unsigned short do_reset;
+	struct zram *zram;
+	struct block_device *bdev;
+
+	zram = dev_to_zram(dev);
+	bdev = bdget_disk(zram->disk, 0);
+
+	/* Do not reset an active device! */
+	if (bdev->bd_holders)
+		return -EBUSY;
+
+	ret = kstrtou16(buf, 10, &do_reset);
+	if (ret)
+		return ret;
+
+	if (!do_reset)
+		return -EINVAL;
+
+	/* Make sure all pending I/O is finished */
+	if (bdev)
+		fsync_bdev(bdev);
+
+	zram_reset_device(zram, true);
+	return len;
 }
 
 static void __zram_make_request(struct zram *zram, struct bio *bio, int rw)
@@ -483,10 +675,10 @@
 
 	switch (rw) {
 	case READ:
-		zram_stat64_inc(zram, &zram->stats.num_reads);
+		atomic64_inc(&zram->stats.num_reads);
 		break;
 	case WRITE:
-		zram_stat64_inc(zram, &zram->stats.num_writes);
+		atomic64_inc(&zram->stats.num_writes);
 		break;
 	}
 
@@ -531,39 +723,19 @@
 }
 
 /*
- * Check if request is within bounds and aligned on zram logical blocks.
- */
-static inline int valid_io_request(struct zram *zram, struct bio *bio)
-{
-	if (unlikely(
-		(bio->bi_sector >= (zram->disksize >> SECTOR_SHIFT)) ||
-		(bio->bi_sector & (ZRAM_SECTOR_PER_LOGICAL_BLOCK - 1)) ||
-		(bio->bi_size & (ZRAM_LOGICAL_BLOCK_SIZE - 1)))) {
-
-		return 0;
-	}
-
-	/* I/O request is valid */
-	return 1;
-}
-
-/*
  * Handler function for all zram I/O requests.
  */
 static void zram_make_request(struct request_queue *queue, struct bio *bio)
 {
 	struct zram *zram = queue->queuedata;
 
-	if (unlikely(!zram->init_done) && zram_init_device(zram))
-		goto error;
-
 	down_read(&zram->init_lock);
 	if (unlikely(!zram->init_done))
-		goto error_unlock;
+		goto error;
 
 	if (!valid_io_request(zram, bio)) {
-		zram_stat64_inc(zram, &zram->stats.invalid_io);
-		goto error_unlock;
+		atomic64_inc(&zram->stats.invalid_io);
+		goto error;
 	}
 
 	__zram_make_request(zram, bio, bio_data_dir(bio));
@@ -571,129 +743,45 @@
 
 	return;
 
-error_unlock:
-	up_read(&zram->init_lock);
 error:
+	up_read(&zram->init_lock);
 	bio_io_error(bio);
 }
 
-void __zram_reset_device(struct zram *zram)
+static void zram_slot_free(struct work_struct *work)
 {
-	size_t index;
+	struct zram *zram;
 
-	zram->init_done = 0;
-
-	/* Free various per-device buffers */
-	kfree(zram->compress_workmem);
-	free_pages((unsigned long)zram->compress_buffer, 1);
-
-	zram->compress_workmem = NULL;
-	zram->compress_buffer = NULL;
-
-	/* Free all pages that are still in this zram device */
-	for (index = 0; index < zram->disksize >> PAGE_SHIFT; index++) {
-		void *handle = zram->table[index].handle;
-		if (!handle)
-			continue;
-
-		if (unlikely(zram_test_flag(zram, index, ZRAM_UNCOMPRESSED)))
-			__free_page(handle);
-		else
-			zs_free(zram->mem_pool, handle);
-	}
-
-	vfree(zram->table);
-	zram->table = NULL;
-
-	zs_destroy_pool(zram->mem_pool);
-	zram->mem_pool = NULL;
-
-	/* Reset stats */
-	memset(&zram->stats, 0, sizeof(zram->stats));
-
-	zram->disksize = 0;
+	zram = container_of(work, struct zram, free_work);
+	down_write(&zram->lock);
+	handle_pending_slot_free(zram);
+	up_write(&zram->lock);
 }
 
-void zram_reset_device(struct zram *zram)
+static void add_slot_free(struct zram *zram, struct zram_slot_free *free_rq)
 {
-	down_write(&zram->init_lock);
-	__zram_reset_device(zram);
-	up_write(&zram->init_lock);
-}
-
-int zram_init_device(struct zram *zram)
-{
-	int ret;
-	size_t num_pages;
-
-	down_write(&zram->init_lock);
-
-	if (zram->init_done) {
-		up_write(&zram->init_lock);
-		return 0;
-	}
-
-	zram_set_disksize(zram, totalram_pages << PAGE_SHIFT);
-
-	zram->compress_workmem = kzalloc(LZO1X_MEM_COMPRESS, GFP_KERNEL);
-	if (!zram->compress_workmem) {
-		pr_err("Error allocating compressor working memory!\n");
-		ret = -ENOMEM;
-		goto fail_no_table;
-	}
-
-	zram->compress_buffer =
-		(void *)__get_free_pages(GFP_KERNEL | __GFP_ZERO, 1);
-	if (!zram->compress_buffer) {
-		pr_err("Error allocating compressor buffer space\n");
-		ret = -ENOMEM;
-		goto fail_no_table;
-	}
-
-	num_pages = zram->disksize >> PAGE_SHIFT;
-	zram->table = vzalloc(num_pages * sizeof(*zram->table));
-	if (!zram->table) {
-		pr_err("Error allocating zram address table\n");
-		ret = -ENOMEM;
-		goto fail_no_table;
-	}
-
-	set_capacity(zram->disk, zram->disksize >> SECTOR_SHIFT);
-
-	/* zram devices sort of resembles non-rotational disks */
-	queue_flag_set_unlocked(QUEUE_FLAG_NONROT, zram->disk->queue);
-
-	zram->mem_pool = zs_create_pool("zram", GFP_NOIO | __GFP_HIGHMEM);
-	if (!zram->mem_pool) {
-		pr_err("Error creating memory pool\n");
-		ret = -ENOMEM;
-		goto fail;
-	}
-
-	zram->init_done = 1;
-	up_write(&zram->init_lock);
-
-	pr_debug("Initialization done!\n");
-	return 0;
-
-fail_no_table:
-	/* To prevent accessing table entries during cleanup */
-	zram->disksize = 0;
-fail:
-	__zram_reset_device(zram);
-	up_write(&zram->init_lock);
-	pr_err("Initialization failed: err=%d\n", ret);
-	return ret;
+	spin_lock(&zram->slot_free_lock);
+	free_rq->next = zram->slot_free_rq;
+	zram->slot_free_rq = free_rq;
+	spin_unlock(&zram->slot_free_lock);
 }
 
 static void zram_slot_free_notify(struct block_device *bdev,
 				unsigned long index)
 {
 	struct zram *zram;
+	struct zram_slot_free *free_rq;
 
 	zram = bdev->bd_disk->private_data;
-	zram_free_page(zram, index);
-	zram_stat64_inc(zram, &zram->stats.notify_free);
+	atomic64_inc(&zram->stats.notify_free);
+
+	free_rq = kmalloc(sizeof(struct zram_slot_free), GFP_ATOMIC);
+	if (!free_rq)
+		return;
+
+	free_rq->index = index;
+	add_slot_free(zram, free_rq);
+	schedule_work(&zram->free_work);
 }
 
 static const struct block_device_operations zram_devops = {
@@ -701,19 +789,53 @@
 	.owner = THIS_MODULE
 };
 
+static DEVICE_ATTR(disksize, S_IRUGO | S_IWUSR,
+		disksize_show, disksize_store);
+static DEVICE_ATTR(initstate, S_IRUGO, initstate_show, NULL);
+static DEVICE_ATTR(reset, S_IWUSR, NULL, reset_store);
+static DEVICE_ATTR(num_reads, S_IRUGO, num_reads_show, NULL);
+static DEVICE_ATTR(num_writes, S_IRUGO, num_writes_show, NULL);
+static DEVICE_ATTR(invalid_io, S_IRUGO, invalid_io_show, NULL);
+static DEVICE_ATTR(notify_free, S_IRUGO, notify_free_show, NULL);
+static DEVICE_ATTR(zero_pages, S_IRUGO, zero_pages_show, NULL);
+static DEVICE_ATTR(orig_data_size, S_IRUGO, orig_data_size_show, NULL);
+static DEVICE_ATTR(compr_data_size, S_IRUGO, compr_data_size_show, NULL);
+static DEVICE_ATTR(mem_used_total, S_IRUGO, mem_used_total_show, NULL);
+
+static struct attribute *zram_disk_attrs[] = {
+	&dev_attr_disksize.attr,
+	&dev_attr_initstate.attr,
+	&dev_attr_reset.attr,
+	&dev_attr_num_reads.attr,
+	&dev_attr_num_writes.attr,
+	&dev_attr_invalid_io.attr,
+	&dev_attr_notify_free.attr,
+	&dev_attr_zero_pages.attr,
+	&dev_attr_orig_data_size.attr,
+	&dev_attr_compr_data_size.attr,
+	&dev_attr_mem_used_total.attr,
+	NULL,
+};
+
+static struct attribute_group zram_disk_attr_group = {
+	.attrs = zram_disk_attrs,
+};
+
 static int create_device(struct zram *zram, int device_id)
 {
-	int ret = 0;
+	int ret = -ENOMEM;
 
 	init_rwsem(&zram->lock);
 	init_rwsem(&zram->init_lock);
-	spin_lock_init(&zram->stat64_lock);
+
+	INIT_WORK(&zram->free_work, zram_slot_free);
+	spin_lock_init(&zram->slot_free_lock);
+	zram->slot_free_rq = NULL;
 
 	zram->queue = blk_alloc_queue(GFP_KERNEL);
 	if (!zram->queue) {
 		pr_err("Error allocating disk queue for device %d\n",
 			device_id);
-		ret = -ENOMEM;
 		goto out;
 	}
 
@@ -723,11 +845,9 @@
 	 /* gendisk structure */
 	zram->disk = alloc_disk(1);
 	if (!zram->disk) {
-		blk_cleanup_queue(zram->queue);
-		pr_warning("Error allocating disk structure for device %d\n",
+		pr_warn("Error allocating disk structure for device %d\n",
 			device_id);
-		ret = -ENOMEM;
-		goto out;
+		goto out_free_queue;
 	}
 
 	zram->disk->major = zram_major;
@@ -755,12 +875,18 @@
 	ret = sysfs_create_group(&disk_to_dev(zram->disk)->kobj,
 				&zram_disk_attr_group);
 	if (ret < 0) {
-		pr_warning("Error creating sysfs group");
-		goto out;
+		pr_warn("Error creating sysfs group");
+		goto out_free_disk;
 	}
 
 	zram->init_done = 0;
+	return 0;
 
+out_free_disk:
+	del_gendisk(zram->disk);
+	put_disk(zram->disk);
+out_free_queue:
+	blk_cleanup_queue(zram->queue);
 out:
 	return ret;
 }
@@ -779,17 +905,12 @@
 		blk_cleanup_queue(zram->queue);
 }
 
-unsigned int zram_get_num_devices(void)
-{
-	return num_devices;
-}
-
 static int __init zram_init(void)
 {
 	int ret, dev_id;
 
 	if (num_devices > max_num_devices) {
-		pr_warning("Invalid value for num_devices: %u\n",
+		pr_warn("Invalid value for num_devices: %u\n",
 				num_devices);
 		ret = -EINVAL;
 		goto out;
@@ -797,18 +918,12 @@
 
 	zram_major = register_blkdev(0, "zram");
 	if (zram_major <= 0) {
-		pr_warning("Unable to get major number\n");
+		pr_warn("Unable to get major number\n");
 		ret = -EBUSY;
 		goto out;
 	}
 
-	if (!num_devices) {
-		pr_info("num_devices not specified. Using default: 1\n");
-		num_devices = 1;
-	}
-
 	/* Allocate the device array and initialize each one */
-	pr_info("Creating %u devices ...\n", num_devices);
 	zram_devices = kzalloc(num_devices * sizeof(struct zram), GFP_KERNEL);
 	if (!zram_devices) {
 		ret = -ENOMEM;
@@ -821,6 +936,8 @@
 			goto free_devices;
 	}
 
+	pr_info("Created %u device(s) ...\n", num_devices);
+
 	return 0;
 
 free_devices:
@@ -842,8 +959,11 @@
 		zram = &zram_devices[i];
 
 		destroy_device(zram);
-		if (zram->init_done)
-			zram_reset_device(zram);
+		/*
+		 * Shouldn't access zram->disk after destroy_device
+		 * because destroy_device already released zram->disk.
+		 */
+		zram_reset_device(zram, false);
 	}
 
 	unregister_blkdev(zram_major, "zram");
@@ -852,12 +972,13 @@
 	pr_debug("Cleanup done!\n");
 }
 
-module_param(num_devices, uint, 0);
-MODULE_PARM_DESC(num_devices, "Number of zram devices");
-
 module_init(zram_init);
 module_exit(zram_exit);
 
+module_param(num_devices, uint, 0);
+MODULE_PARM_DESC(num_devices, "Number of zram devices");
+
 MODULE_LICENSE("Dual BSD/GPL");
 MODULE_AUTHOR("Nitin Gupta <ngupta@vflare.org>");
 MODULE_DESCRIPTION("Compressed RAM Block Device");
+MODULE_ALIAS("devname:zram");
diff --git a/drivers/staging/zram/zram_drv.h b/drivers/staging/zram/zram_drv.h
index fbe8ac9..97a3acf 100644
--- a/drivers/staging/zram/zram_drv.h
+++ b/drivers/staging/zram/zram_drv.h
@@ -26,23 +26,8 @@
  */
 static const unsigned max_num_devices = 32;
 
-/*
- * Stored at beginning of each compressed object.
- *
- * It stores back-reference to table entry which points to this
- * object. This is required to support memory defragmentation.
- */
-struct zobj_header {
-#if 0
-	u32 table_idx;
-#endif
-};
-
 /*-- Configurable parameters */
 
-/* Default zram disk size: 25% of total RAM */
-static const unsigned default_disksize_perc_ram = 25;
-
 /*
  * Pages that compress to size greater than this are stored
  * uncompressed in memory.
@@ -51,8 +36,8 @@
 
 /*
  * NOTE: max_zpage_size must be less than or equal to:
- *   ZS_MAX_ALLOC_SIZE - sizeof(struct zobj_header)
- * otherwise, xv_malloc() would always return failure.
+ *   ZS_MAX_ALLOC_SIZE. Otherwise, zs_malloc() would
+ * always return failure.
  */
 
 /*-- End of configurable params */
@@ -68,9 +53,6 @@
 
 /* Flags for zram pages (table[page_no].flags) */
 enum zram_pageflags {
-	/* Page is stored uncompressed */
-	ZRAM_UNCOMPRESSED,
-
 	/* Page consists entirely of zeros */
 	ZRAM_ZERO,
 
@@ -81,34 +63,51 @@
 
 /* Allocated for each disk page */
 struct table {
-	void *handle;
+	unsigned long handle;
 	u16 size;	/* object size (excluding header) */
 	u8 count;	/* object ref count (not yet used) */
 	u8 flags;
-} __attribute__((aligned(4)));
+} __aligned(4);
 
+/*
+ * All 64bit fields should only be manipulated by 64bit atomic accessors.
+ * All modifications to 32bit counter should be protected by zram->lock.
+ */
 struct zram_stats {
-	u64 compr_size;		/* compressed size of pages stored */
-	u64 num_reads;		/* failed + successful */
-	u64 num_writes;		/* --do-- */
-	u64 failed_reads;	/* should NEVER! happen */
-	u64 failed_writes;	/* can happen when memory is too low */
-	u64 invalid_io;		/* non-page-aligned I/O requests */
-	u64 notify_free;	/* no. of swap slot free notifications */
+	atomic64_t compr_size;	/* compressed size of pages stored */
+	atomic64_t num_reads;	/* failed + successful */
+	atomic64_t num_writes;	/* --do-- */
+	atomic64_t failed_reads;	/* should NEVER! happen */
+	atomic64_t failed_writes;	/* can happen when memory is too low */
+	atomic64_t invalid_io;	/* non-page-aligned I/O requests */
+	atomic64_t notify_free;	/* no. of swap slot free notifications */
 	u32 pages_zero;		/* no. of zero filled pages */
 	u32 pages_stored;	/* no. of pages currently stored */
 	u32 good_compress;	/* % of pages with compression ratio<=50% */
-	u32 pages_expand;	/* % of incompressible pages */
+	u32 bad_compress;	/* % of pages with compression ratio>=75% */
 };
 
-struct zram {
-	struct zs_pool *mem_pool;
+struct zram_meta {
 	void *compress_workmem;
 	void *compress_buffer;
 	struct table *table;
-	spinlock_t stat64_lock;	/* protect 64-bit stats */
-	struct rw_semaphore lock; /* protect compression buffers and table
-				   * against concurrent read and writes */
+	struct zs_pool *mem_pool;
+};
+
+struct zram_slot_free {
+	unsigned long index;
+	struct zram_slot_free *next;
+};
+
+struct zram {
+	struct zram_meta *meta;
+	struct rw_semaphore lock; /* protect compression buffers, table,
+				   * 32bit stat counters against concurrent
+				   * notifications, reads and writes */
+
+	struct work_struct free_work;  /* handle pending free request */
+	struct zram_slot_free *slot_free_rq; /* list head of free request */
+
 	struct request_queue *queue;
 	struct gendisk *disk;
 	int init_done;
@@ -119,17 +118,8 @@
 	 * we can store in a disk.
 	 */
 	u64 disksize;	/* bytes */
+	spinlock_t slot_free_lock;
 
 	struct zram_stats stats;
 };
-
-extern struct zram *zram_devices;
-unsigned int zram_get_num_devices(void);
-#ifdef CONFIG_SYSFS
-extern struct attribute_group zram_disk_attr_group;
-#endif
-
-extern int zram_init_device(struct zram *zram);
-extern void __zram_reset_device(struct zram *zram);
-
 #endif
diff --git a/drivers/staging/zram/zram_sysfs.c b/drivers/staging/zram/zram_sysfs.c
deleted file mode 100644
index a7f3771..0000000
--- a/drivers/staging/zram/zram_sysfs.c
+++ /dev/null
@@ -1,227 +0,0 @@
-/*
- * Compressed RAM block device
- *
- * Copyright (C) 2008, 2009, 2010  Nitin Gupta
- *
- * This code is released using a dual license strategy: BSD/GPL
- * You can choose the licence that better fits your requirements.
- *
- * Released under the terms of 3-clause BSD License
- * Released under the terms of GNU General Public License Version 2.0
- *
- * Project home: http://compcache.googlecode.com/
- */
-
-#include <linux/device.h>
-#include <linux/genhd.h>
-#include <linux/mm.h>
-
-#include "zram_drv.h"
-
-static u64 zram_stat64_read(struct zram *zram, u64 *v)
-{
-	u64 val;
-
-	spin_lock(&zram->stat64_lock);
-	val = *v;
-	spin_unlock(&zram->stat64_lock);
-
-	return val;
-}
-
-static struct zram *dev_to_zram(struct device *dev)
-{
-	int i;
-	struct zram *zram = NULL;
-
-	for (i = 0; i < zram_get_num_devices(); i++) {
-		zram = &zram_devices[i];
-		if (disk_to_dev(zram->disk) == dev)
-			break;
-	}
-
-	return zram;
-}
-
-static ssize_t disksize_show(struct device *dev,
-		struct device_attribute *attr, char *buf)
-{
-	struct zram *zram = dev_to_zram(dev);
-
-	return sprintf(buf, "%llu\n", zram->disksize);
-}
-
-static ssize_t disksize_store(struct device *dev,
-		struct device_attribute *attr, const char *buf, size_t len)
-{
-	int ret;
-	u64 disksize;
-	struct zram *zram = dev_to_zram(dev);
-
-	ret = kstrtoull(buf, 10, &disksize);
-	if (ret)
-		return ret;
-
-	down_write(&zram->init_lock);
-	if (zram->init_done) {
-		up_write(&zram->init_lock);
-		pr_info("Cannot change disksize for initialized device\n");
-		return -EBUSY;
-	}
-
-	zram->disksize = PAGE_ALIGN(disksize);
-	set_capacity(zram->disk, zram->disksize >> SECTOR_SHIFT);
-	up_write(&zram->init_lock);
-
-	return len;
-}
-
-static ssize_t initstate_show(struct device *dev,
-		struct device_attribute *attr, char *buf)
-{
-	struct zram *zram = dev_to_zram(dev);
-
-	return sprintf(buf, "%u\n", zram->init_done);
-}
-
-static ssize_t reset_store(struct device *dev,
-		struct device_attribute *attr, const char *buf, size_t len)
-{
-	int ret;
-	unsigned short do_reset;
-	struct zram *zram;
-	struct block_device *bdev;
-
-	zram = dev_to_zram(dev);
-	bdev = bdget_disk(zram->disk, 0);
-
-	/* Do not reset an active device! */
-	if (bdev->bd_holders)
-		return -EBUSY;
-
-	ret = kstrtou16(buf, 10, &do_reset);
-	if (ret)
-		return ret;
-
-	if (!do_reset)
-		return -EINVAL;
-
-	/* Make sure all pending I/O is finished */
-	if (bdev)
-		fsync_bdev(bdev);
-
-	down_write(&zram->init_lock);
-	if (zram->init_done)
-		__zram_reset_device(zram);
-	up_write(&zram->init_lock);
-
-	return len;
-}
-
-static ssize_t num_reads_show(struct device *dev,
-		struct device_attribute *attr, char *buf)
-{
-	struct zram *zram = dev_to_zram(dev);
-
-	return sprintf(buf, "%llu\n",
-		zram_stat64_read(zram, &zram->stats.num_reads));
-}
-
-static ssize_t num_writes_show(struct device *dev,
-		struct device_attribute *attr, char *buf)
-{
-	struct zram *zram = dev_to_zram(dev);
-
-	return sprintf(buf, "%llu\n",
-		zram_stat64_read(zram, &zram->stats.num_writes));
-}
-
-static ssize_t invalid_io_show(struct device *dev,
-		struct device_attribute *attr, char *buf)
-{
-	struct zram *zram = dev_to_zram(dev);
-
-	return sprintf(buf, "%llu\n",
-		zram_stat64_read(zram, &zram->stats.invalid_io));
-}
-
-static ssize_t notify_free_show(struct device *dev,
-		struct device_attribute *attr, char *buf)
-{
-	struct zram *zram = dev_to_zram(dev);
-
-	return sprintf(buf, "%llu\n",
-		zram_stat64_read(zram, &zram->stats.notify_free));
-}
-
-static ssize_t zero_pages_show(struct device *dev,
-		struct device_attribute *attr, char *buf)
-{
-	struct zram *zram = dev_to_zram(dev);
-
-	return sprintf(buf, "%u\n", zram->stats.pages_zero);
-}
-
-static ssize_t orig_data_size_show(struct device *dev,
-		struct device_attribute *attr, char *buf)
-{
-	struct zram *zram = dev_to_zram(dev);
-
-	return sprintf(buf, "%llu\n",
-		(u64)(zram->stats.pages_stored) << PAGE_SHIFT);
-}
-
-static ssize_t compr_data_size_show(struct device *dev,
-		struct device_attribute *attr, char *buf)
-{
-	struct zram *zram = dev_to_zram(dev);
-
-	return sprintf(buf, "%llu\n",
-		zram_stat64_read(zram, &zram->stats.compr_size));
-}
-
-static ssize_t mem_used_total_show(struct device *dev,
-		struct device_attribute *attr, char *buf)
-{
-	u64 val = 0;
-	struct zram *zram = dev_to_zram(dev);
-
-	if (zram->init_done) {
-		val = zs_get_total_size_bytes(zram->mem_pool) +
-			((u64)(zram->stats.pages_expand) << PAGE_SHIFT);
-	}
-
-	return sprintf(buf, "%llu\n", val);
-}
-
-static DEVICE_ATTR(disksize, S_IRUGO | S_IWUSR,
-		disksize_show, disksize_store);
-static DEVICE_ATTR(initstate, S_IRUGO, initstate_show, NULL);
-static DEVICE_ATTR(reset, S_IWUSR, NULL, reset_store);
-static DEVICE_ATTR(num_reads, S_IRUGO, num_reads_show, NULL);
-static DEVICE_ATTR(num_writes, S_IRUGO, num_writes_show, NULL);
-static DEVICE_ATTR(invalid_io, S_IRUGO, invalid_io_show, NULL);
-static DEVICE_ATTR(notify_free, S_IRUGO, notify_free_show, NULL);
-static DEVICE_ATTR(zero_pages, S_IRUGO, zero_pages_show, NULL);
-static DEVICE_ATTR(orig_data_size, S_IRUGO, orig_data_size_show, NULL);
-static DEVICE_ATTR(compr_data_size, S_IRUGO, compr_data_size_show, NULL);
-static DEVICE_ATTR(mem_used_total, S_IRUGO, mem_used_total_show, NULL);
-
-static struct attribute *zram_disk_attrs[] = {
-	&dev_attr_disksize.attr,
-	&dev_attr_initstate.attr,
-	&dev_attr_reset.attr,
-	&dev_attr_num_reads.attr,
-	&dev_attr_num_writes.attr,
-	&dev_attr_invalid_io.attr,
-	&dev_attr_notify_free.attr,
-	&dev_attr_zero_pages.attr,
-	&dev_attr_orig_data_size.attr,
-	&dev_attr_compr_data_size.attr,
-	&dev_attr_mem_used_total.attr,
-	NULL,
-};
-
-struct attribute_group zram_disk_attr_group = {
-	.attrs = zram_disk_attrs,
-};
diff --git a/drivers/staging/zsmalloc/Kconfig b/drivers/staging/zsmalloc/Kconfig
index a5ab720..7fab032 100644
--- a/drivers/staging/zsmalloc/Kconfig
+++ b/drivers/staging/zsmalloc/Kconfig
@@ -1,9 +1,5 @@
 config ZSMALLOC
-	tristate "Memory allocator for compressed pages"
-	# X86 dependency is because of the use of __flush_tlb_one and set_pte
-	# in zsmalloc-main.c.
-	# TODO: convert these to portable functions
-	depends on X86
+	bool "Memory allocator for compressed pages"
 	default n
 	help
 	  zsmalloc is a slab-based memory allocator designed to store
diff --git a/drivers/staging/zsmalloc/zsmalloc-main.c b/drivers/staging/zsmalloc/zsmalloc-main.c
index 917461c..1a67537 100644
--- a/drivers/staging/zsmalloc/zsmalloc-main.c
+++ b/drivers/staging/zsmalloc/zsmalloc-main.c
@@ -10,6 +10,54 @@
  * Released under the terms of GNU General Public License Version 2.0
  */
 
+
+/*
+ * This allocator is designed for use with zcache and zram. Thus, the
+ * allocator is supposed to work well under low memory conditions. In
+ * particular, it never attempts higher order page allocation which is
+ * very likely to fail under memory pressure. On the other hand, if we
+ * just use single (0-order) pages, it would suffer from very high
+ * fragmentation -- any object of size PAGE_SIZE/2 or larger would occupy
+ * an entire page. This was one of the major issues with its predecessor
+ * (xvmalloc).
+ *
+ * To overcome these issues, zsmalloc allocates a bunch of 0-order pages
+ * and links them together using various 'struct page' fields. These linked
+ * pages act as a single higher-order page i.e. an object can span 0-order
+ * page boundaries. The code refers to these linked pages as a single entity
+ * called zspage.
+ *
+ * Following is how we use various fields and flags of underlying
+ * struct page(s) to form a zspage.
+ *
+ * Usage of struct page fields:
+ *	page->first_page: points to the first component (0-order) page
+ *	page->index (union with page->freelist): offset of the first object
+ *		starting in this page. For the first page, this is
+ *		always 0, so we use this field (aka freelist) to point
+ *		to the first free object in zspage.
+ *	page->lru: links together all component pages (except the first page)
+ *		of a zspage
+ *
+ *	For _first_ page only:
+ *
+ *	page->private (union with page->first_page): refers to the
+ *		component page after the first page
+ *	page->freelist: points to the first free object in zspage.
+ *		Free objects are linked together using in-place
+ *		metadata.
+ *	page->objects: maximum number of objects we can store in this
+ *		zspage (class->zspage_order * PAGE_SIZE / class->size)
+ *	page->lru: links together first pages of various zspages.
+ *		Basically forming list of zspages in a fullness group.
+ *	page->mapping: class index and fullness group of the zspage
+ *
+ * Usage of struct page flags:
+ *	PG_private: identifies the first component page
+ *	PG_private2: identifies the last component page
+ *
+ */
+
 #ifdef CONFIG_ZSMALLOC_DEBUG
 #define DEBUG
 #endif
@@ -27,9 +75,139 @@
 #include <linux/cpumask.h>
 #include <linux/cpu.h>
 #include <linux/vmalloc.h>
+#include <linux/hardirq.h>
+#include <linux/spinlock.h>
+#include <linux/types.h>
 
 #include "zsmalloc.h"
-#include "zsmalloc_int.h"
+
+/*
+ * This must be power of 2 and greater than of equal to sizeof(link_free).
+ * These two conditions ensure that any 'struct link_free' itself doesn't
+ * span more than 1 page which avoids complex case of mapping 2 pages simply
+ * to restore link_free pointer values.
+ */
+#define ZS_ALIGN		8
+
+/*
+ * A single 'zspage' is composed of up to 2^N discontiguous 0-order (single)
+ * pages. ZS_MAX_ZSPAGE_ORDER defines upper limit on N.
+ */
+#define ZS_MAX_ZSPAGE_ORDER 2
+#define ZS_MAX_PAGES_PER_ZSPAGE (_AC(1, UL) << ZS_MAX_ZSPAGE_ORDER)
+
+/*
+ * Object location (<PFN>, <obj_idx>) is encoded as
+ * as single (void *) handle value.
+ *
+ * Note that object index <obj_idx> is relative to system
+ * page <PFN> it is stored in, so for each sub-page belonging
+ * to a zspage, obj_idx starts with 0.
+ *
+ * This is made more complicated by various memory models and PAE.
+ */
+
+#ifndef MAX_PHYSMEM_BITS
+#ifdef CONFIG_HIGHMEM64G
+#define MAX_PHYSMEM_BITS 36
+#else /* !CONFIG_HIGHMEM64G */
+/*
+ * If this definition of MAX_PHYSMEM_BITS is used, OBJ_INDEX_BITS will just
+ * be PAGE_SHIFT
+ */
+#define MAX_PHYSMEM_BITS BITS_PER_LONG
+#endif
+#endif
+#define _PFN_BITS		(MAX_PHYSMEM_BITS - PAGE_SHIFT)
+#define OBJ_INDEX_BITS	(BITS_PER_LONG - _PFN_BITS)
+#define OBJ_INDEX_MASK	((_AC(1, UL) << OBJ_INDEX_BITS) - 1)
+
+#define MAX(a, b) ((a) >= (b) ? (a) : (b))
+/* ZS_MIN_ALLOC_SIZE must be multiple of ZS_ALIGN */
+#define ZS_MIN_ALLOC_SIZE \
+	MAX(32, (ZS_MAX_PAGES_PER_ZSPAGE << PAGE_SHIFT >> OBJ_INDEX_BITS))
+#define ZS_MAX_ALLOC_SIZE	PAGE_SIZE
+
+/*
+ * On systems with 4K page size, this gives 254 size classes! There is a
+ * trader-off here:
+ *  - Large number of size classes is potentially wasteful as free page are
+ *    spread across these classes
+ *  - Small number of size classes causes large internal fragmentation
+ *  - Probably its better to use specific size classes (empirically
+ *    determined). NOTE: all those class sizes must be set as multiple of
+ *    ZS_ALIGN to make sure link_free itself never has to span 2 pages.
+ *
+ *  ZS_MIN_ALLOC_SIZE and ZS_SIZE_CLASS_DELTA must be multiple of ZS_ALIGN
+ *  (reason above)
+ */
+#define ZS_SIZE_CLASS_DELTA	(PAGE_SIZE >> 8)
+#define ZS_SIZE_CLASSES		((ZS_MAX_ALLOC_SIZE - ZS_MIN_ALLOC_SIZE) / \
+					ZS_SIZE_CLASS_DELTA + 1)
+
+/*
+ * We do not maintain any list for completely empty or full pages
+ */
+enum fullness_group {
+	ZS_ALMOST_FULL,
+	ZS_ALMOST_EMPTY,
+	_ZS_NR_FULLNESS_GROUPS,
+
+	ZS_EMPTY,
+	ZS_FULL
+};
+
+/*
+ * We assign a page to ZS_ALMOST_EMPTY fullness group when:
+ *	n <= N / f, where
+ * n = number of allocated objects
+ * N = total number of objects zspage can store
+ * f = 1/fullness_threshold_frac
+ *
+ * Similarly, we assign zspage to:
+ *	ZS_ALMOST_FULL	when n > N / f
+ *	ZS_EMPTY	when n == 0
+ *	ZS_FULL		when n == N
+ *
+ * (see: fix_fullness_group())
+ */
+static const int fullness_threshold_frac = 4;
+
+struct size_class {
+	/*
+	 * Size of objects stored in this class. Must be multiple
+	 * of ZS_ALIGN.
+	 */
+	int size;
+	unsigned int index;
+
+	/* Number of PAGE_SIZE sized pages to combine to form a 'zspage' */
+	int pages_per_zspage;
+
+	spinlock_t lock;
+
+	/* stats */
+	u64 pages_allocated;
+
+	struct page *fullness_list[_ZS_NR_FULLNESS_GROUPS];
+};
+
+/*
+ * Placed within free objects to form a singly linked list.
+ * For every zspage, first_page->freelist gives head of this list.
+ *
+ * This must be power of 2 and less than or equal to ZS_ALIGN
+ */
+struct link_free {
+	/* Handle of next free chunk (encodes <PFN, obj_idx>) */
+	void *next;
+};
+
+struct zs_pool {
+	struct size_class size_class[ZS_SIZE_CLASSES];
+
+	gfp_t flags;	/* allocation flags used when growing pool */
+};
 
 /*
  * A zspage's class index and fullness group
@@ -40,17 +218,39 @@
 #define CLASS_IDX_MASK	((1 << CLASS_IDX_BITS) - 1)
 #define FULLNESS_MASK	((1 << FULLNESS_BITS) - 1)
 
+/*
+ * By default, zsmalloc uses a copy-based object mapping method to access
+ * allocations that span two pages. However, if a particular architecture
+ * performs VM mapping faster than copying, then it should be added here
+ * so that USE_PGTABLE_MAPPING is defined. This causes zsmalloc to use
+ * page table mapping rather than copying for object mapping.
+ */
+#if defined(CONFIG_ARM) && !defined(MODULE)
+#define USE_PGTABLE_MAPPING
+#endif
+
+struct mapping_area {
+#ifdef USE_PGTABLE_MAPPING
+	struct vm_struct *vm; /* vm area for mapping object that span pages */
+#else
+	char *vm_buf; /* copy buffer for objects that span pages */
+#endif
+	char *vm_addr; /* address of kmap_atomic()'ed pages */
+	enum zs_mapmode vm_mm; /* mapping mode */
+};
+
+
 /* per-cpu VM mapping areas for zspage accesses that cross page boundaries */
 static DEFINE_PER_CPU(struct mapping_area, zs_map_area);
 
 static int is_first_page(struct page *page)
 {
-	return test_bit(PG_private, &page->flags);
+	return PagePrivate(page);
 }
 
 static int is_last_page(struct page *page)
 {
-	return test_bit(PG_private_2, &page->flags);
+	return PagePrivate2(page);
 }
 
 static void get_zspage_mapping(struct page *page, unsigned int *class_idx,
@@ -180,7 +380,7 @@
  * link together 3 PAGE_SIZE sized pages to form a zspage
  * since then we can perfectly fit in 8 such objects.
  */
-static int get_zspage_order(int class_size)
+static int get_pages_per_zspage(int class_size)
 {
 	int i, max_usedpc = 0;
 	/* zspage order which gives maximum used size per KB */
@@ -223,7 +423,7 @@
 	if (is_last_page(page))
 		next = NULL;
 	else if (is_first_page(page))
-		next = (struct page *)page->private;
+		next = (struct page *)page_private(page);
 	else
 		next = list_entry(page->lru.next, struct page, lru);
 
@@ -247,13 +447,11 @@
 }
 
 /* Decode <page, obj_idx> pair from the given object handle */
-static void obj_handle_to_location(void *handle, struct page **page,
+static void obj_handle_to_location(unsigned long handle, struct page **page,
 				unsigned long *obj_idx)
 {
-	unsigned long hval = (unsigned long)handle;
-
-	*page = pfn_to_page(hval >> OBJ_INDEX_BITS);
-	*obj_idx = hval & OBJ_INDEX_MASK;
+	*page = pfn_to_page(handle >> OBJ_INDEX_BITS);
+	*obj_idx = handle & OBJ_INDEX_MASK;
 }
 
 static unsigned long obj_idx_to_offset(struct page *page,
@@ -274,7 +472,7 @@
 	set_page_private(page, 0);
 	page->mapping = NULL;
 	page->freelist = NULL;
-	reset_page_mapcount(page);
+	page_mapcount_reset(page);
 }
 
 static void free_zspage(struct page *first_page)
@@ -354,7 +552,7 @@
 static struct page *alloc_zspage(struct size_class *class, gfp_t flags)
 {
 	int i, error;
-	struct page *first_page = NULL;
+	struct page *first_page = NULL, *uninitialized_var(prev_page);
 
 	/*
 	 * Allocate individual pages and link them together as:
@@ -368,8 +566,8 @@
 	 * identify the last page.
 	 */
 	error = -ENOMEM;
-	for (i = 0; i < class->zspage_order; i++) {
-		struct page *page, *prev_page;
+	for (i = 0; i < class->pages_per_zspage; i++) {
+		struct page *page;
 
 		page = alloc_page(flags);
 		if (!page)
@@ -377,20 +575,19 @@
 
 		INIT_LIST_HEAD(&page->lru);
 		if (i == 0) {	/* first page */
-			set_bit(PG_private, &page->flags);
+			SetPagePrivate(page);
 			set_page_private(page, 0);
 			first_page = page;
 			first_page->inuse = 0;
 		}
 		if (i == 1)
-			first_page->private = (unsigned long)page;
+			set_page_private(first_page, (unsigned long)page);
 		if (i >= 1)
 			page->first_page = first_page;
 		if (i >= 2)
 			list_add(&page->lru, &prev_page->lru);
-		if (i == class->zspage_order - 1)	/* last page */
-			set_bit(PG_private_2, &page->flags);
-
+		if (i == class->pages_per_zspage - 1)	/* last page */
+			SetPagePrivate2(page);
 		prev_page = page;
 	}
 
@@ -398,7 +595,7 @@
 
 	first_page->freelist = obj_location_to_handle(first_page, 0);
 	/* Maximum number of objects we can store in this zspage */
-	first_page->objects = class->zspage_order * PAGE_SIZE / class->size;
+	first_page->objects = class->pages_per_zspage * PAGE_SIZE / class->size;
 
 	error = 0; /* Success */
 
@@ -425,34 +622,141 @@
 	return page;
 }
 
+#ifdef USE_PGTABLE_MAPPING
+static inline int __zs_cpu_up(struct mapping_area *area)
+{
+	/*
+	 * Make sure we don't leak memory if a cpu UP notification
+	 * and zs_init() race and both call zs_cpu_up() on the same cpu
+	 */
+	if (area->vm)
+		return 0;
+	area->vm = alloc_vm_area(PAGE_SIZE * 2, NULL);
+	if (!area->vm)
+		return -ENOMEM;
+	return 0;
+}
 
-/*
- * If this becomes a separate module, register zs_init() with
- * module_init(), zs_exit with module_exit(), and remove zs_initialized
-*/
-static int zs_initialized;
+static inline void __zs_cpu_down(struct mapping_area *area)
+{
+	if (area->vm)
+		free_vm_area(area->vm);
+	area->vm = NULL;
+}
+
+static inline void *__zs_map_object(struct mapping_area *area,
+				struct page *pages[2], int off, int size)
+{
+	BUG_ON(map_vm_area(area->vm, PAGE_KERNEL, &pages));
+	area->vm_addr = area->vm->addr;
+	return area->vm_addr + off;
+}
+
+static inline void __zs_unmap_object(struct mapping_area *area,
+				struct page *pages[2], int off, int size)
+{
+	unsigned long addr = (unsigned long)area->vm_addr;
+
+	unmap_kernel_range(addr, PAGE_SIZE * 2);
+}
+
+#else /* USE_PGTABLE_MAPPING */
+
+static inline int __zs_cpu_up(struct mapping_area *area)
+{
+	/*
+	 * Make sure we don't leak memory if a cpu UP notification
+	 * and zs_init() race and both call zs_cpu_up() on the same cpu
+	 */
+	if (area->vm_buf)
+		return 0;
+	area->vm_buf = (char *)__get_free_page(GFP_KERNEL);
+	if (!area->vm_buf)
+		return -ENOMEM;
+	return 0;
+}
+
+static inline void __zs_cpu_down(struct mapping_area *area)
+{
+	if (area->vm_buf)
+		free_page((unsigned long)area->vm_buf);
+	area->vm_buf = NULL;
+}
+
+static void *__zs_map_object(struct mapping_area *area,
+			struct page *pages[2], int off, int size)
+{
+	int sizes[2];
+	void *addr;
+	char *buf = area->vm_buf;
+
+	/* disable page faults to match kmap_atomic() return conditions */
+	pagefault_disable();
+
+	/* no read fastpath */
+	if (area->vm_mm == ZS_MM_WO)
+		goto out;
+
+	sizes[0] = PAGE_SIZE - off;
+	sizes[1] = size - sizes[0];
+
+	/* copy object to per-cpu buffer */
+	addr = kmap_atomic(pages[0]);
+	memcpy(buf, addr + off, sizes[0]);
+	kunmap_atomic(addr);
+	addr = kmap_atomic(pages[1]);
+	memcpy(buf + sizes[0], addr, sizes[1]);
+	kunmap_atomic(addr);
+out:
+	return area->vm_buf;
+}
+
+static void __zs_unmap_object(struct mapping_area *area,
+			struct page *pages[2], int off, int size)
+{
+	int sizes[2];
+	void *addr;
+	char *buf = area->vm_buf;
+
+	/* no write fastpath */
+	if (area->vm_mm == ZS_MM_RO)
+		goto out;
+
+	sizes[0] = PAGE_SIZE - off;
+	sizes[1] = size - sizes[0];
+
+	/* copy per-cpu buffer to object */
+	addr = kmap_atomic(pages[0]);
+	memcpy(addr + off, buf, sizes[0]);
+	kunmap_atomic(addr);
+	addr = kmap_atomic(pages[1]);
+	memcpy(addr, buf + sizes[0], sizes[1]);
+	kunmap_atomic(addr);
+
+out:
+	/* enable page faults to match kunmap_atomic() return conditions */
+	pagefault_enable();
+}
+
+#endif /* USE_PGTABLE_MAPPING */
 
 static int zs_cpu_notifier(struct notifier_block *nb, unsigned long action,
 				void *pcpu)
 {
-	int cpu = (long)pcpu;
+	int ret, cpu = (long)pcpu;
 	struct mapping_area *area;
 
 	switch (action) {
 	case CPU_UP_PREPARE:
 		area = &per_cpu(zs_map_area, cpu);
-		if (area->vm)
-			break;
-		area->vm = alloc_vm_area(2 * PAGE_SIZE, area->vm_ptes);
-		if (!area->vm)
-			return notifier_from_errno(-ENOMEM);
+		ret = __zs_cpu_up(area);
+		if (ret)
+			return notifier_from_errno(ret);
 		break;
 	case CPU_DEAD:
 	case CPU_UP_CANCELED:
 		area = &per_cpu(zs_map_area, cpu);
-		if (area->vm)
-			free_vm_area(area->vm);
-		area->vm = NULL;
+		__zs_cpu_down(area);
 		break;
 	}
 
@@ -488,14 +792,21 @@
 	return notifier_to_errno(ret);
 }
 
-struct zs_pool *zs_create_pool(const char *name, gfp_t flags)
+/**
+ * zs_create_pool - Creates an allocation pool to work from.
+ * @flags: allocation flags used to allocate pool metadata
+ *
+ * This function must be called before anything when using
+ * the zsmalloc allocator.
+ *
+ * On success, a pointer to the newly created pool is returned,
+ * otherwise NULL.
+ */
+struct zs_pool *zs_create_pool(gfp_t flags)
 {
-	int i, error, ovhd_size;
+	int i, ovhd_size;
 	struct zs_pool *pool;
 
-	if (!name)
-		return NULL;
-
 	ovhd_size = roundup(sizeof(*pool), PAGE_SIZE);
 	pool = kzalloc(ovhd_size, GFP_KERNEL);
 	if (!pool)
@@ -513,31 +824,11 @@
 		class->size = size;
 		class->index = i;
 		spin_lock_init(&class->lock);
-		class->zspage_order = get_zspage_order(size);
+		class->pages_per_zspage = get_pages_per_zspage(size);
 
 	}
 
-	/*
-	 * If this becomes a separate module, register zs_init with
-	 * module_init, and remove this block
-	*/
-	if (!zs_initialized) {
-		error = zs_init();
-		if (error)
-			goto cleanup;
-		zs_initialized = 1;
-	}
-
 	pool->flags = flags;
-	pool->name = name;
-
-	error = 0; /* Success */
-
-cleanup:
-	if (error) {
-		zs_destroy_pool(pool);
-		pool = NULL;
-	}
 
 	return pool;
 }
@@ -553,8 +844,7 @@
 
 		for (fg = 0; fg < _ZS_NR_FULLNESS_GROUPS; fg++) {
 			if (class->fullness_list[fg]) {
-				pr_info("Freeing non-empty class with size "
-					"%db, fullness group %d\n",
+				pr_info("Freeing non-empty class with size %db, fullness group %d\n",
 					class->size, fg);
 			}
 		}
@@ -567,18 +857,14 @@
  * zs_malloc - Allocate block of given size from pool.
  * @pool: pool to allocate from
  * @size: size of block to allocate
- * @page: page no. that holds the object
- * @offset: location of object within page
  *
- * On success, <page, offset> identifies block allocated
- * and 0 is returned. On failure, <page, offset> is set to
- * 0 and -ENOMEM is returned.
- *
+ * On success, handle to the allocated object is returned,
+ * otherwise 0.
  * Allocation requests with size > ZS_MAX_ALLOC_SIZE will fail.
  */
-void *zs_malloc(struct zs_pool *pool, size_t size)
+unsigned long zs_malloc(struct zs_pool *pool, size_t size)
 {
-	void *obj;
+	unsigned long obj;
 	struct link_free *link;
 	int class_idx;
 	struct size_class *class;
@@ -587,7 +873,7 @@
 	unsigned long m_objidx, m_offset;
 
 	if (unlikely(!size || size > ZS_MAX_ALLOC_SIZE))
-		return NULL;
+		return 0;
 
 	class_idx = get_size_class_index(size);
 	class = &pool->size_class[class_idx];
@@ -600,14 +886,14 @@
 		spin_unlock(&class->lock);
 		first_page = alloc_zspage(class, pool->flags);
 		if (unlikely(!first_page))
-			return NULL;
+			return 0;
 
 		set_zspage_mapping(first_page, class->index, ZS_EMPTY);
 		spin_lock(&class->lock);
-		class->pages_allocated += class->zspage_order;
+		class->pages_allocated += class->pages_per_zspage;
 	}
 
-	obj = first_page->freelist;
+	obj = (unsigned long)first_page->freelist;
 	obj_handle_to_location(obj, &m_page, &m_objidx);
 	m_offset = obj_idx_to_offset(m_page, m_objidx, class->size);
 
@@ -626,7 +912,7 @@
 }
 EXPORT_SYMBOL_GPL(zs_malloc);
 
-void zs_free(struct zs_pool *pool, void *obj)
+void zs_free(struct zs_pool *pool, unsigned long obj)
 {
 	struct link_free *link;
 	struct page *first_page, *f_page;
@@ -653,13 +939,13 @@
 							+ f_offset);
 	link->next = first_page->freelist;
 	kunmap_atomic(link);
-	first_page->freelist = obj;
+	first_page->freelist = (void *)obj;
 
 	first_page->inuse--;
 	fullness = fix_fullness_group(pool, first_page);
 
 	if (fullness == ZS_EMPTY)
-		class->pages_allocated -= class->zspage_order;
+		class->pages_allocated -= class->pages_per_zspage;
 
 	spin_unlock(&class->lock);
 
@@ -668,7 +954,22 @@
 }
 EXPORT_SYMBOL_GPL(zs_free);
 
-void *zs_map_object(struct zs_pool *pool, void *handle)
+/**
+ * zs_map_object - get address of allocated object from handle.
+ * @pool: pool from which the object was allocated
+ * @handle: handle returned from zs_malloc
+ *
+ * Before using an object allocated from zs_malloc, it must be mapped using
+ * this function. When done with the object, it must be unmapped using
+ * zs_unmap_object.
+ *
+ * Only one object can be mapped per cpu at a time. There is no protection
+ * against nested mappings.
+ *
+ * This function returns with preemption and page faults disabled.
+ */
+void *zs_map_object(struct zs_pool *pool, unsigned long handle,
+			enum zs_mapmode mm)
 {
 	struct page *page;
 	unsigned long obj_idx, off;
@@ -677,38 +978,40 @@
 	enum fullness_group fg;
 	struct size_class *class;
 	struct mapping_area *area;
+	struct page *pages[2];
 
 	BUG_ON(!handle);
 
+	/*
+	 * Because we use per-cpu mapping areas shared among the
+	 * pools/users, we can't allow mapping in interrupt context
+	 * because it can corrupt another users mappings.
+	 */
+	BUG_ON(in_interrupt());
+
 	obj_handle_to_location(handle, &page, &obj_idx);
 	get_zspage_mapping(get_first_page(page), &class_idx, &fg);
 	class = &pool->size_class[class_idx];
 	off = obj_idx_to_offset(page, obj_idx, class->size);
 
 	area = &get_cpu_var(zs_map_area);
+	area->vm_mm = mm;
 	if (off + class->size <= PAGE_SIZE) {
 		/* this object is contained entirely within a page */
 		area->vm_addr = kmap_atomic(page);
-	} else {
-		/* this object spans two pages */
-		struct page *nextp;
-
-		nextp = get_next_page(page);
-		BUG_ON(!nextp);
-
-
-		set_pte(area->vm_ptes[0], mk_pte(page, PAGE_KERNEL));
-		set_pte(area->vm_ptes[1], mk_pte(nextp, PAGE_KERNEL));
-
-		/* We pre-allocated VM area so mapping can never fail */
-		area->vm_addr = area->vm->addr;
+		return area->vm_addr + off;
 	}
 
-	return area->vm_addr + off;
+	/* this object spans two pages */
+	pages[0] = page;
+	pages[1] = get_next_page(page);
+	BUG_ON(!pages[1]);
+
+	return __zs_map_object(area, pages, off, class->size);
 }
 EXPORT_SYMBOL_GPL(zs_map_object);
 
-void zs_unmap_object(struct zs_pool *pool, void *handle)
+void zs_unmap_object(struct zs_pool *pool, unsigned long handle)
 {
 	struct page *page;
 	unsigned long obj_idx, off;
@@ -726,13 +1029,16 @@
 	off = obj_idx_to_offset(page, obj_idx, class->size);
 
 	area = &__get_cpu_var(zs_map_area);
-	if (off + class->size <= PAGE_SIZE) {
+	if (off + class->size <= PAGE_SIZE)
 		kunmap_atomic(area->vm_addr);
-	} else {
-		set_pte(area->vm_ptes[0], __pte(0));
-		set_pte(area->vm_ptes[1], __pte(0));
-		__flush_tlb_one((unsigned long)area->vm_addr);
-		__flush_tlb_one((unsigned long)area->vm_addr + PAGE_SIZE);
+	else {
+		struct page *pages[2];
+
+		pages[0] = page;
+		pages[1] = get_next_page(page);
+		BUG_ON(!pages[1]);
+
+		__zs_unmap_object(area, pages, off, class->size);
 	}
 	put_cpu_var(zs_map_area);
 }
@@ -749,3 +1055,9 @@
 	return npages << PAGE_SHIFT;
 }
 EXPORT_SYMBOL_GPL(zs_get_total_size_bytes);
+
+module_init(zs_init);
+module_exit(zs_exit);
+
+MODULE_LICENSE("Dual BSD/GPL");
+MODULE_AUTHOR("Nitin Gupta <ngupta@vflare.org>");
diff --git a/drivers/staging/zsmalloc/zsmalloc.h b/drivers/staging/zsmalloc/zsmalloc.h
index 949384e..fbe6bec 100644
--- a/drivers/staging/zsmalloc/zsmalloc.h
+++ b/drivers/staging/zsmalloc/zsmalloc.h
@@ -15,16 +15,28 @@
 
 #include <linux/types.h>
 
+/*
+ * zsmalloc mapping modes
+ *
+ * NOTE: These only make a difference when a mapped object spans pages
+ */
+enum zs_mapmode {
+	ZS_MM_RW, /* normal read-write mapping */
+	ZS_MM_RO, /* read-only (no copy-out at unmap time) */
+	ZS_MM_WO /* write-only (no copy-in at map time) */
+};
+
 struct zs_pool;
 
-struct zs_pool *zs_create_pool(const char *name, gfp_t flags);
+struct zs_pool *zs_create_pool(gfp_t flags);
 void zs_destroy_pool(struct zs_pool *pool);
 
-void *zs_malloc(struct zs_pool *pool, size_t size);
-void zs_free(struct zs_pool *pool, void *obj);
+unsigned long zs_malloc(struct zs_pool *pool, size_t size);
+void zs_free(struct zs_pool *pool, unsigned long obj);
 
-void *zs_map_object(struct zs_pool *pool, void *handle);
-void zs_unmap_object(struct zs_pool *pool, void *handle);
+void *zs_map_object(struct zs_pool *pool, unsigned long handle,
+			enum zs_mapmode mm);
+void zs_unmap_object(struct zs_pool *pool, unsigned long handle);
 
 u64 zs_get_total_size_bytes(struct zs_pool *pool);
 
diff --git a/drivers/staging/zsmalloc/zsmalloc_int.h b/drivers/staging/zsmalloc/zsmalloc_int.h
deleted file mode 100644
index 92eefc6..0000000
--- a/drivers/staging/zsmalloc/zsmalloc_int.h
+++ /dev/null
@@ -1,155 +0,0 @@
-/*
- * zsmalloc memory allocator
- *
- * Copyright (C) 2011  Nitin Gupta
- *
- * This code is released using a dual license strategy: BSD/GPL
- * You can choose the license that better fits your requirements.
- *
- * Released under the terms of 3-clause BSD License
- * Released under the terms of GNU General Public License Version 2.0
- */
-
-#ifndef _ZS_MALLOC_INT_H_
-#define _ZS_MALLOC_INT_H_
-
-#include <linux/kernel.h>
-#include <linux/spinlock.h>
-#include <linux/types.h>
-
-/*
- * This must be power of 2 and greater than of equal to sizeof(link_free).
- * These two conditions ensure that any 'struct link_free' itself doesn't
- * span more than 1 page which avoids complex case of mapping 2 pages simply
- * to restore link_free pointer values.
- */
-#define ZS_ALIGN		8
-
-/*
- * A single 'zspage' is composed of up to 2^N discontiguous 0-order (single)
- * pages. ZS_MAX_ZSPAGE_ORDER defines upper limit on N.
- */
-#define ZS_MAX_ZSPAGE_ORDER 2
-#define ZS_MAX_PAGES_PER_ZSPAGE (_AC(1, UL) << ZS_MAX_ZSPAGE_ORDER)
-
-/*
- * Object location (<PFN>, <obj_idx>) is encoded as
- * as single (void *) handle value.
- *
- * Note that object index <obj_idx> is relative to system
- * page <PFN> it is stored in, so for each sub-page belonging
- * to a zspage, obj_idx starts with 0.
- *
- * This is made more complicated by various memory models and PAE.
- */
-
-#ifndef MAX_PHYSMEM_BITS
-#ifdef CONFIG_HIGHMEM64G
-#define MAX_PHYSMEM_BITS 36
-#else /* !CONFIG_HIGHMEM64G */
-/*
- * If this definition of MAX_PHYSMEM_BITS is used, OBJ_INDEX_BITS will just
- * be PAGE_SHIFT
- */
-#define MAX_PHYSMEM_BITS BITS_PER_LONG
-#endif
-#endif
-#define _PFN_BITS		(MAX_PHYSMEM_BITS - PAGE_SHIFT)
-#define OBJ_INDEX_BITS	(BITS_PER_LONG - _PFN_BITS)
-#define OBJ_INDEX_MASK	((_AC(1, UL) << OBJ_INDEX_BITS) - 1)
-
-#define MAX(a, b) ((a) >= (b) ? (a) : (b))
-/* ZS_MIN_ALLOC_SIZE must be multiple of ZS_ALIGN */
-#define ZS_MIN_ALLOC_SIZE \
-	MAX(32, (ZS_MAX_PAGES_PER_ZSPAGE << PAGE_SHIFT >> OBJ_INDEX_BITS))
-#define ZS_MAX_ALLOC_SIZE	PAGE_SIZE
-
-/*
- * On systems with 4K page size, this gives 254 size classes! There is a
- * trader-off here:
- *  - Large number of size classes is potentially wasteful as free page are
- *    spread across these classes
- *  - Small number of size classes causes large internal fragmentation
- *  - Probably its better to use specific size classes (empirically
- *    determined). NOTE: all those class sizes must be set as multiple of
- *    ZS_ALIGN to make sure link_free itself never has to span 2 pages.
- *
- *  ZS_MIN_ALLOC_SIZE and ZS_SIZE_CLASS_DELTA must be multiple of ZS_ALIGN
- *  (reason above)
- */
-#define ZS_SIZE_CLASS_DELTA	16
-#define ZS_SIZE_CLASSES		((ZS_MAX_ALLOC_SIZE - ZS_MIN_ALLOC_SIZE) / \
-					ZS_SIZE_CLASS_DELTA + 1)
-
-/*
- * We do not maintain any list for completely empty or full pages
- */
-enum fullness_group {
-	ZS_ALMOST_FULL,
-	ZS_ALMOST_EMPTY,
-	_ZS_NR_FULLNESS_GROUPS,
-
-	ZS_EMPTY,
-	ZS_FULL
-};
-
-/*
- * We assign a page to ZS_ALMOST_EMPTY fullness group when:
- *	n <= N / f, where
- * n = number of allocated objects
- * N = total number of objects zspage can store
- * f = 1/fullness_threshold_frac
- *
- * Similarly, we assign zspage to:
- *	ZS_ALMOST_FULL	when n > N / f
- *	ZS_EMPTY	when n == 0
- *	ZS_FULL		when n == N
- *
- * (see: fix_fullness_group())
- */
-static const int fullness_threshold_frac = 4;
-
-struct mapping_area {
-	struct vm_struct *vm;
-	pte_t *vm_ptes[2];
-	char *vm_addr;
-};
-
-struct size_class {
-	/*
-	 * Size of objects stored in this class. Must be multiple
-	 * of ZS_ALIGN.
-	 */
-	int size;
-	unsigned int index;
-
-	/* Number of PAGE_SIZE sized pages to combine to form a 'zspage' */
-	int zspage_order;
-
-	spinlock_t lock;
-
-	/* stats */
-	u64 pages_allocated;
-
-	struct page *fullness_list[_ZS_NR_FULLNESS_GROUPS];
-};
-
-/*
- * Placed within free objects to form a singly linked list.
- * For every zspage, first_page->freelist gives head of this list.
- *
- * This must be power of 2 and less than or equal to ZS_ALIGN
- */
-struct link_free {
-	/* Handle of next free chunk (encodes <PFN, obj_idx>) */
-	void *next;
-};
-
-struct zs_pool {
-	struct size_class size_class[ZS_SIZE_CLASSES];
-
-	gfp_t flags;	/* allocation flags used when growing pool */
-	const char *name;
-};
-
-#endif
diff --git a/drivers/thermal/msm_thermal.c b/drivers/thermal/msm_thermal.c
index 00df613..c6f6f03 100644
--- a/drivers/thermal/msm_thermal.c
+++ b/drivers/thermal/msm_thermal.c
@@ -32,7 +32,6 @@
 #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>
 #include <linux/regulator/consumer.h>
@@ -40,7 +39,8 @@
 #define MAX_RAILS 5
 
 static struct msm_thermal_data msm_thermal_info;
-static uint32_t limited_max_freq = MSM_CPUFREQ_NO_LIMIT;
+static uint32_t limited_max_freq = UINT_MAX;
+static uint32_t limited_min_freq;
 static struct delayed_work check_temp_work;
 static bool core_control_enabled;
 static uint32_t cpus_offlined;
@@ -154,6 +154,25 @@
 
 #define PSM_REG_MODE_FROM_ATTRIBS(attr) \
 	(container_of(attr, struct psm_rail, mode_attr));
+
+static int  msm_thermal_cpufreq_callback(struct notifier_block *nfb,
+		unsigned long event, void *data)
+{
+	struct cpufreq_policy *policy = data;
+
+	switch (event) {
+	case CPUFREQ_INCOMPATIBLE:
+		cpufreq_verify_within_limits(policy, limited_min_freq,
+				limited_max_freq);
+		break;
+	}
+	return NOTIFY_OK;
+}
+
+static struct notifier_block msm_thermal_cpufreq_notifier = {
+	.notifier_call = msm_thermal_cpufreq_callback,
+};
+
 /* If freq table exists, then we can send freq request */
 static int check_freq_table(void)
 {
@@ -174,37 +193,26 @@
 {
 	int cpu = 0;
 	int ret = 0;
-	struct cpufreq_policy *policy = NULL;
 
 	if (!freq_table_get) {
 		ret = check_freq_table();
 		if (ret) {
-			pr_err("%s:Fail to get freq table\n", __func__);
+			pr_err("%s:Fail to get freq table\n", KBUILD_MODNAME);
 			return ret;
 		}
 	}
 	/* If min is larger than allowed max */
-	if (min != MSM_CPUFREQ_NO_LIMIT &&
-			min > table[limit_idx_high].frequency)
-		min = table[limit_idx_high].frequency;
+	min = min(min, table[limit_idx_high].frequency);
 
-	for_each_possible_cpu(cpu) {
-		ret = msm_cpufreq_set_freq_limits(cpu, min, limited_max_freq);
-		if (ret) {
-			pr_err("%s:Fail to set limits for cpu%d\n",
-					__func__, cpu);
-			return ret;
-		}
+	limited_min_freq = min;
 
-		if (cpu_online(cpu)) {
-			policy = cpufreq_cpu_get(cpu);
-			if (!policy)
-				continue;
-			cpufreq_driver_target(policy, policy->cur,
-					CPUFREQ_RELATION_L);
-			cpufreq_cpu_put(policy);
-		}
+	get_online_cpus();
+	for_each_online_cpu(cpu) {
+		if (cpufreq_update_policy(cpu))
+			pr_info("%s: Unable to update policy for cpu:%d\n",
+				KBUILD_MODNAME, cpu);
 	}
+	put_online_cpus();
 
 	return ret;
 }
@@ -599,26 +607,19 @@
 {
 	int ret = 0;
 
-	ret = msm_cpufreq_set_freq_limits(cpu, MSM_CPUFREQ_NO_LIMIT, max_freq);
-	if (ret)
-		return ret;
-
-	limited_max_freq = max_freq;
-	if (max_freq != MSM_CPUFREQ_NO_LIMIT)
+	if (max_freq != UINT_MAX)
 		pr_info("%s: Limiting cpu%d max frequency to %d\n",
 				KBUILD_MODNAME, cpu, max_freq);
 	else
 		pr_info("%s: Max frequency reset for cpu%d\n",
 				KBUILD_MODNAME, cpu);
-
-	if (cpu_online(cpu)) {
-		struct cpufreq_policy *policy = cpufreq_cpu_get(cpu);
-		if (!policy)
-			return ret;
-		ret = cpufreq_driver_target(policy, policy->cur,
-				CPUFREQ_RELATION_H);
-		cpufreq_cpu_put(policy);
+	get_online_cpus();
+	for_each_online_cpu(cpu) {
+		if (cpufreq_update_policy(cpu))
+			pr_info("%s: Unable to update policy for cpu:%d\n",
+				KBUILD_MODNAME, cpu);
 	}
+	put_online_cpus();
 
 	return ret;
 }
@@ -835,7 +836,6 @@
 
 static void __ref do_freq_control(long temp)
 {
-	int ret = 0;
 	int cpu = 0;
 	uint32_t max_freq = limited_max_freq;
 
@@ -855,7 +855,7 @@
 		limit_idx += msm_thermal_info.freq_step;
 		if (limit_idx >= limit_idx_high) {
 			limit_idx = limit_idx_high;
-			max_freq = MSM_CPUFREQ_NO_LIMIT;
+			max_freq = UINT_MAX;
 		} else
 			max_freq = table[limit_idx].frequency;
 	}
@@ -863,17 +863,13 @@
 	if (max_freq == limited_max_freq)
 		return;
 
+	limited_max_freq = max_freq;
 	/* Update new limits */
 	for_each_possible_cpu(cpu) {
 		if (!(msm_thermal_info.freq_control_mask & BIT(cpu)))
 			continue;
-		ret = update_cpu_max_freq(cpu, max_freq);
-		if (ret)
-			pr_debug(
-			"%s: Unable to limit cpu%d max freq to %d\n",
-					KBUILD_MODNAME, cpu, max_freq);
+		update_cpu_max_freq(cpu, max_freq);
 	}
-
 }
 
 static void __ref check_temp(struct work_struct *work)
@@ -1086,12 +1082,17 @@
 	cancel_delayed_work(&check_temp_work);
 	flush_scheduled_work();
 
-	if (limited_max_freq == MSM_CPUFREQ_NO_LIMIT)
+	if (limited_max_freq == UINT_MAX)
 		return;
 
-	for_each_possible_cpu(cpu) {
-		update_cpu_max_freq(cpu, MSM_CPUFREQ_NO_LIMIT);
+	limited_max_freq = UINT_MAX;
+	get_online_cpus();
+	for_each_online_cpu(cpu) {
+		if (cpufreq_update_policy(cpu))
+			pr_info("%s: Unable to update policy for cpu:%d\n",
+				KBUILD_MODNAME, cpu);
 	}
+	put_online_cpus();
 }
 
 static int __ref set_enabled(const char *val, const struct kernel_param *kp)
@@ -1104,7 +1105,7 @@
 		hotplug_init();
 	} else
 		pr_info("%s: no action for enabled = %d\n",
-				KBUILD_MODNAME, enabled);
+			KBUILD_MODNAME, enabled);
 
 	pr_info("%s: enabled = %d\n", KBUILD_MODNAME, enabled);
 
@@ -1346,6 +1347,12 @@
 
 	enabled = 1;
 
+	ret = cpufreq_register_notifier(&msm_thermal_cpufreq_notifier,
+			CPUFREQ_POLICY_NOTIFIER);
+	if (ret)
+		pr_err("%s: cannot register cpufreq notifier\n",
+			KBUILD_MODNAME);
+
 	INIT_DELAYED_WORK(&check_temp_work, check_temp);
 	schedule_delayed_work(&check_temp_work, 0);
 
@@ -1659,7 +1666,7 @@
 		key = "qcom,freq-req";
 		rails[i].freq_req = of_property_read_bool(child_node, key);
 		if (rails[i].freq_req)
-			rails[i].min_level = MSM_CPUFREQ_NO_LIMIT;
+			rails[i].min_level = 0;
 		else {
 			key = "qcom,min-level";
 			ret = of_property_read_u32(child_node, key,
diff --git a/drivers/tty/serial/msm_serial_hs.c b/drivers/tty/serial/msm_serial_hs.c
index a243a05..078929b 100644
--- a/drivers/tty/serial/msm_serial_hs.c
+++ b/drivers/tty/serial/msm_serial_hs.c
@@ -155,7 +155,6 @@
 	struct tasklet_struct tlet;
 	struct msm_hs_sps_ep_conn_data prod;
 };
-
 enum buffer_states {
 	NONE_PENDING = 0x0,
 	FIFO_OVERRUN = 0x1,
@@ -219,6 +218,7 @@
 	struct msm_bus_scale_pdata *bus_scale_table;
 	bool rx_discard_flush_issued;
 	int rx_count_callback;
+	bool rx_bam_inprogress;
 	unsigned int *reg_ptr;
 };
 
@@ -998,6 +998,14 @@
 	mutex_lock(&msm_uport->clk_mutex);
 	msm_hs_write(uport, UART_DM_IMR, 0);
 
+	/* Clear the Rx Ready Ctl bit - This ensures that
+	* flow control lines stop the other side from sending
+	* data while we change the parameters
+	*/
+	data = msm_hs_read(uport, UART_DM_MR1);
+	data &= ~UARTDM_MR1_RX_RDY_CTL_BMSK;
+	msm_hs_write(uport, UART_DM_MR1, data);
+
 	/*
 	 * Disable Rx channel of UARTDM
 	 * DMA Rx Stall happens if enqueue and flush of Rx command happens
@@ -1071,18 +1079,6 @@
 	/* write parity/bits per char/stop bit configuration */
 	msm_hs_write(uport, UART_DM_MR2, data);
 
-	/* Configure HW flow control */
-	data = msm_hs_read(uport, UART_DM_MR1);
-
-	data &= ~(UARTDM_MR1_CTS_CTL_BMSK | UARTDM_MR1_RX_RDY_CTL_BMSK);
-
-	if (c_cflag & CRTSCTS) {
-		data |= UARTDM_MR1_CTS_CTL_BMSK;
-		data |= UARTDM_MR1_RX_RDY_CTL_BMSK;
-	}
-
-	msm_hs_write(uport, UART_DM_MR1, data);
-
 	uport->ignore_status_mask = termios->c_iflag & INPCK;
 	uport->ignore_status_mask |= termios->c_iflag & IGNPAR;
 	uport->ignore_status_mask |= termios->c_iflag & IGNBRK;
@@ -1106,6 +1102,10 @@
 		 */
 		mb();
 		if (is_blsp_uart(msm_uport)) {
+			if (msm_uport->rx_bam_inprogress)
+				ret = wait_event_timeout(msm_uport->rx.wait,
+					msm_uport->rx_bam_inprogress == false,
+					RX_FLUSH_COMPLETE_TIMEOUT);
 			ret = sps_disconnect(sps_pipe_handle);
 			if (ret)
 				pr_err("%s(): sps_disconnect failed\n",
@@ -1127,6 +1127,20 @@
 		}
 	}
 
+	/* Configure HW flow control
+	 * UART Core would see status of CTS line when it is sending data
+	 * to remote uart to confirm that it can receive or not.
+	 * UART Core would trigger RFR if it is not having any space with
+	 * RX FIFO.
+	 */
+	data = msm_hs_read(uport, UART_DM_MR1);
+	data &= ~(UARTDM_MR1_CTS_CTL_BMSK | UARTDM_MR1_RX_RDY_CTL_BMSK);
+	if (c_cflag & CRTSCTS) {
+		data |= UARTDM_MR1_CTS_CTL_BMSK;
+		data |= UARTDM_MR1_RX_RDY_CTL_BMSK;
+	}
+	msm_hs_write(uport, UART_DM_MR1, data);
+
 	msm_hs_write(uport, UART_DM_IMR, msm_uport->imr_reg);
 	mb();
 	mutex_unlock(&msm_uport->clk_mutex);
@@ -1358,10 +1372,13 @@
 	msm_uport->rx.flush = FLUSH_NONE;
 
 	if (is_blsp_uart(msm_uport)) {
+		msm_uport->rx_bam_inprogress = true;
 		sps_pipe_handle = rx->prod.pipe_handle;
 		/* Queue transfer request to SPS */
 		sps_transfer_one(sps_pipe_handle, rx->rbuffer,
 			UARTDM_RX_BUF_SIZE, msm_uport, flags);
+		msm_uport->rx_bam_inprogress = false;
+		wake_up(&msm_uport->rx.wait);
 	} else {
 		msm_dmov_enqueue_cmd(msm_uport->dma_rx_channel,
 				&msm_uport->rx.xfer);
@@ -1531,10 +1548,13 @@
 	if (!msm_uport->rx.buffer_pending) {
 		if (is_blsp_uart(msm_uport)) {
 			msm_uport->rx.flush = FLUSH_NONE;
+			msm_uport->rx_bam_inprogress = true;
 			sps_pipe_handle = rx->prod.pipe_handle;
 			/* Queue transfer request to SPS */
 			sps_transfer_one(sps_pipe_handle, rx->rbuffer,
 				UARTDM_RX_BUF_SIZE, msm_uport, sps_flags);
+			msm_uport->rx_bam_inprogress = false;
+			wake_up(&msm_uport->rx.wait);
 		} else {
 			msm_hs_start_rx_locked(uport);
 		}
@@ -2832,9 +2852,9 @@
 	/* Now save the sps pipe handle */
 	ep->pipe_handle = sps_pipe_handle;
 	pr_debug("msm_serial_hs: success !! %s: pipe_handle=0x%x\n"
-		"desc_fifo.phys_base=0x%x\n",
+		"desc_fifo.phys_base=0x%llx\n",
 		is_producer ? "READ" : "WRITE",
-		(u32)sps_pipe_handle, sps_config->desc.phys_base);
+		(u32) sps_pipe_handle, (u64) sps_config->desc.phys_base);
 	return 0;
 
 get_config_err:
diff --git a/drivers/usb/dwc3/dwc3-msm.c b/drivers/usb/dwc3/dwc3-msm.c
index 554cce8..97592c4 100644
--- a/drivers/usb/dwc3/dwc3-msm.c
+++ b/drivers/usb/dwc3/dwc3-msm.c
@@ -2288,8 +2288,12 @@
 		if (mdwc->otg_xceiv && !mdwc->ext_inuse &&
 		    (mdwc->ext_xceiv.otg_capability || !init)) {
 			mdwc->ext_xceiv.bsv = val->intval;
+			/*
+			 * set debouncing delay to 120msec. Otherwise battery
+			 * charging CDP complaince test fails if delay > 120ms.
+			 */
 			queue_delayed_work(system_nrt_wq,
-							&mdwc->resume_work, 20);
+							&mdwc->resume_work, 12);
 
 			if (!init)
 				init = true;
diff --git a/drivers/usb/dwc3/dwc3_otg.c b/drivers/usb/dwc3/dwc3_otg.c
index 9599936..cacd635 100644
--- a/drivers/usb/dwc3/dwc3_otg.c
+++ b/drivers/usb/dwc3/dwc3_otg.c
@@ -93,6 +93,19 @@
 	return 0;
 }
 
+static void dwc3_otg_set_hsphy_auto_suspend(struct dwc3_otg *dotg, bool susp)
+{
+	struct dwc3 *dwc = dotg->dwc;
+	u32 reg;
+
+	reg = dwc3_readl(dwc->regs, DWC3_GUSB2PHYCFG(0));
+	if (susp)
+		reg |= DWC3_GUSB2PHYCFG_SUSPHY;
+	else
+		reg &= ~(DWC3_GUSB2PHYCFG_SUSPHY);
+	dwc3_writel(dwc->regs, DWC3_GUSB2PHYCFG(0), reg);
+}
+
 /**
  * dwc3_otg_set_host_power - Enable port power control for host operation
  *
@@ -194,6 +207,7 @@
 		 * remove_hcd, But we may not use standard set_host method
 		 * anymore.
 		 */
+		dwc3_otg_set_hsphy_auto_suspend(dotg, true);
 		dwc3_otg_set_host_regs(dotg);
 		/*
 		 * FIXME If micro A cable is disconnected during system suspend,
@@ -242,6 +256,7 @@
 						ext_xceiv->ext_block_reset)
 			ext_xceiv->ext_block_reset(ext_xceiv, true);
 
+		dwc3_otg_set_hsphy_auto_suspend(dotg, false);
 		dwc3_otg_set_peripheral_regs(dotg);
 
 		/* re-init core and OTG registers as block reset clears these */
@@ -309,12 +324,14 @@
 						ext_xceiv->ext_block_reset)
 			ext_xceiv->ext_block_reset(ext_xceiv, false);
 
+		dwc3_otg_set_hsphy_auto_suspend(dotg, true);
 		dwc3_otg_set_peripheral_regs(dotg);
 		usb_gadget_vbus_connect(otg->gadget);
 	} else {
 		dev_dbg(otg->phy->dev, "%s: turn off gadget %s\n",
 					__func__, otg->gadget->name);
 		usb_gadget_vbus_disconnect(otg->gadget);
+		dwc3_otg_set_hsphy_auto_suspend(dotg, false);
 	}
 
 	return 0;
diff --git a/drivers/usb/dwc3/gadget.c b/drivers/usb/dwc3/gadget.c
index 38c4b86..ad3a3a9 100644
--- a/drivers/usb/dwc3/gadget.c
+++ b/drivers/usb/dwc3/gadget.c
@@ -2623,13 +2623,10 @@
 		}
 	}
 
-	/*
-	 * Notify suspend only to gadget driver, but not resume. Resume is
-	 * notified as part of wakeup event in dwc3_gadget_wakeup_interrupt().
-	 */
 	if (next == DWC3_LINK_STATE_U0) {
 		if (dwc->link_state == DWC3_LINK_STATE_U3) {
 			dbg_event(0xFF, "RESUME", 0);
+			dwc->gadget_driver->resume(&dwc->gadget);
 		}
 	} else if (next == DWC3_LINK_STATE_U3) {
 		dbg_event(0xFF, "SUSPEND", 0);
@@ -2920,7 +2917,11 @@
 
 		dwc3_writel(dwc->regs, DWC3_DCTL, reg);
 
-		dwc3_gadget_usb2_phy_suspend(dwc, true);
+		/*
+		 * Clear autosuspend bit in dwc3 register for USB2. It will be
+		 * enabled before setting run/stop bit.
+		 */
+		dwc3_gadget_usb2_phy_suspend(dwc, false);
 		dwc3_gadget_usb3_phy_suspend(dwc, true);
 	}
 
diff --git a/drivers/usb/gadget/android.c b/drivers/usb/gadget/android.c
index 6765078..c65ed25 100644
--- a/drivers/usb/gadget/android.c
+++ b/drivers/usb/gadget/android.c
@@ -2181,6 +2181,22 @@
 	}
 }
 
+static inline void check_streaming_func(struct usb_gadget *gadget,
+		struct android_usb_platform_data *pdata,
+		char *name)
+{
+	int i;
+
+	for (i = 0; i < pdata->streaming_func_count; i++) {
+		if (!strcmp(name,
+			pdata->streaming_func[i])) {
+			pr_debug("set streaming_enabled to true\n");
+			gadget->streaming_enabled = true;
+			break;
+		}
+	}
+}
+
 static int android_enable_function(struct android_dev *dev,
 				   struct android_configuration *conf,
 				   char *name)
@@ -2188,6 +2204,9 @@
 	struct android_usb_function **functions = dev->functions;
 	struct android_usb_function *f;
 	struct android_usb_function_holder *f_holder;
+	struct android_usb_platform_data *pdata = dev->pdata;
+	struct usb_gadget *gadget = dev->cdev->gadget;
+
 	while ((f = *functions++)) {
 		if (!strcmp(name, f->name)) {
 			if (f->android_dev && f->android_dev != dev)
@@ -2205,6 +2224,13 @@
 				f_holder->f = f;
 				list_add_tail(&f_holder->enabled_list,
 					      &conf->enabled_functions);
+				pr_debug("func:%s is enabled.\n", f->name);
+				/*
+				 * compare enable function with streaming func
+				 * list and based on the same request streaming.
+				 */
+				check_streaming_func(gadget, pdata, f->name);
+
 				return 0;
 			}
 		}
@@ -2577,6 +2603,10 @@
 {
 	struct android_dev *dev = cdev_to_android_dev(c->cdev);
 
+	if (c->cdev->gadget->streaming_enabled) {
+		c->cdev->gadget->streaming_enabled = false;
+		pr_debug("setting streaming_enabled to false.\n");
+	}
 	android_unbind_enabled_functions(dev, c);
 }
 
@@ -2745,8 +2775,10 @@
 	unsigned long flags;
 
 	spin_lock_irqsave(&cdev->lock, flags);
-	dev->suspended = 1;
-	schedule_work(&dev->work);
+	if (!dev->suspended) {
+		dev->suspended = 1;
+		schedule_work(&dev->work);
+	}
 	spin_unlock_irqrestore(&cdev->lock, flags);
 
 	composite_suspend(gadget);
@@ -2759,8 +2791,10 @@
 	unsigned long flags;
 
 	spin_lock_irqsave(&cdev->lock, flags);
-	dev->suspended = 0;
-	schedule_work(&dev->work);
+	if (dev->suspended) {
+		dev->suspended = 0;
+		schedule_work(&dev->work);
+	}
 	spin_unlock_irqrestore(&cdev->lock, flags);
 
 	composite_resume(gadget);
@@ -2895,7 +2929,7 @@
 	struct android_usb_platform_data *pdata;
 	struct android_dev *android_dev;
 	struct resource *res;
-	int ret = 0;
+	int ret = 0, i, len = 0;
 
 	if (pdev->dev.of_node) {
 		dev_dbg(&pdev->dev, "device tree enabled\n");
@@ -2912,6 +2946,33 @@
 				"qcom,android-usb-cdrom");
 		pdata->internal_ums = of_property_read_bool(pdev->dev.of_node,
 				"qcom,android-usb-internal-ums");
+		len = of_property_count_strings(pdev->dev.of_node,
+				"qcom,streaming-func");
+		if (len > MAX_STREAMING_FUNCS) {
+			pr_err("Invalid number of functions used.\n");
+			return -EINVAL;
+		}
+
+		for (i = 0; i < len; i++) {
+			const char *name = NULL;
+
+			of_property_read_string_index(pdev->dev.of_node,
+				"qcom,streaming-func", i, &name);
+			if (!name)
+				continue;
+
+			if (sizeof(name) > FUNC_NAME_LEN) {
+				pr_err("Function name is bigger than allowed.\n");
+				continue;
+			}
+
+			strlcpy(pdata->streaming_func[i], name,
+				sizeof(pdata->streaming_func[i]));
+			pr_debug("name of streaming function:%s\n",
+				pdata->streaming_func[i]);
+		}
+
+		pdata->streaming_func_count = len;
 	} else {
 		pdata = pdev->dev.platform_data;
 	}
diff --git a/drivers/usb/gadget/ci13xxx_msm.c b/drivers/usb/gadget/ci13xxx_msm.c
index a9c073b..f1e4220 100644
--- a/drivers/usb/gadget/ci13xxx_msm.c
+++ b/drivers/usb/gadget/ci13xxx_msm.c
@@ -271,6 +271,10 @@
 				1 << (pdata->log2_itc-1);
 
 		is_l1_supported = pdata->l1_supported;
+		/* Set ahb2ahb bypass flag if it is requested. */
+		if (pdata->enable_ahb2ahb_bypass)
+			ci13xxx_msm_udc_driver.flags |=
+				CI13XXX_ENABLE_AHB2AHB_BYPASS;
 	}
 
 	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
diff --git a/drivers/usb/gadget/ci13xxx_udc.c b/drivers/usb/gadget/ci13xxx_udc.c
index 3f8d924..6a92684 100644
--- a/drivers/usb/gadget/ci13xxx_udc.c
+++ b/drivers/usb/gadget/ci13xxx_udc.c
@@ -70,10 +70,6 @@
 #include <mach/usb_trace.h>
 #include "ci13xxx_udc.h"
 
-/* Turns on streaming. overrides CI13XXX_DISABLE_STREAMING */
-static unsigned int streaming;
-module_param(streaming, uint, S_IRUGO | S_IWUSR);
-
 /******************************************************************************
  * DEFINE
  *****************************************************************************/
@@ -392,20 +388,32 @@
 static int hw_device_state(u32 dma)
 {
 	struct ci13xxx *udc = _udc;
+	struct usb_gadget *gadget = &udc->gadget;
 
 	if (dma) {
-		if (streaming || !(udc->udc_driver->flags &
-				CI13XXX_DISABLE_STREAMING))
+		if (gadget->streaming_enabled || !(udc->udc_driver->flags &
+				CI13XXX_DISABLE_STREAMING)) {
 			hw_cwrite(CAP_USBMODE, USBMODE_SDIS, 0);
-		else
+			pr_debug("%s(): streaming mode is enabled. USBMODE:%x\n",
+				__func__, hw_cread(CAP_USBMODE, ~0));
+		} else {
 			hw_cwrite(CAP_USBMODE, USBMODE_SDIS, USBMODE_SDIS);
-
+			pr_debug("%s(): streaming mode is disabled. USBMODE:%x\n",
+				__func__, hw_cread(CAP_USBMODE, ~0));
+		}
 		hw_cwrite(CAP_ENDPTLISTADDR, ~0, dma);
 
 		if (udc->udc_driver->notify_event)
 			udc->udc_driver->notify_event(udc,
 				CI13XXX_CONTROLLER_CONNECT_EVENT);
 
+		/* Set BIT(31) to enable AHB2AHB Bypass functionality */
+		if (udc->udc_driver->flags & CI13XXX_ENABLE_AHB2AHB_BYPASS) {
+			hw_awrite(ABS_AHBMODE, AHB2AHB_BYPASS, AHB2AHB_BYPASS);
+			pr_debug("%s(): ByPass Mode is enabled. AHBMODE:%x\n",
+					__func__, hw_aread(ABS_AHBMODE, ~0));
+		}
+
 		/* interrupt, error, port change, reset, sleep/suspend */
 		hw_cwrite(CAP_USBINTR, ~0,
 			     USBi_UI|USBi_UEI|USBi_PCI|USBi_URI|USBi_SLI);
@@ -413,6 +421,12 @@
 	} else {
 		hw_cwrite(CAP_USBCMD, USBCMD_RS, 0);
 		hw_cwrite(CAP_USBINTR, ~0, 0);
+		/* Clear BIT(31) to disable AHB2AHB Bypass functionality */
+		if (udc->udc_driver->flags & CI13XXX_ENABLE_AHB2AHB_BYPASS) {
+			hw_awrite(ABS_AHBMODE, AHB2AHB_BYPASS, 0);
+			pr_debug("%s(): ByPass Mode is disabled. AHBMODE:%x\n",
+					__func__, hw_aread(ABS_AHBMODE, ~0));
+		}
 	}
 	return 0;
 }
diff --git a/drivers/usb/gadget/ci13xxx_udc.h b/drivers/usb/gadget/ci13xxx_udc.h
index f90ea86..47fe138 100644
--- a/drivers/usb/gadget/ci13xxx_udc.h
+++ b/drivers/usb/gadget/ci13xxx_udc.h
@@ -136,6 +136,7 @@
 #define CI13XXX_DISABLE_STREAMING	BIT(3)
 #define CI13XXX_ZERO_ITC		BIT(4)
 #define CI13XXX_IS_OTG			BIT(5)
+#define CI13XXX_ENABLE_AHB2AHB_BYPASS	BIT(6)
 
 #define CI13XXX_CONTROLLER_RESET_EVENT			0
 #define CI13XXX_CONTROLLER_CONNECT_EVENT		1
@@ -197,6 +198,9 @@
 /* TESTMODE */
 #define TESTMODE_FORCE        BIT(0)
 
+/* AHB_MODE */
+#define AHB2AHB_BYPASS	      BIT(31)
+
 /* USBCMD */
 #define USBCMD_RS             BIT(0)
 #define USBCMD_RST            BIT(1)
diff --git a/drivers/usb/gadget/f_qdss.c b/drivers/usb/gadget/f_qdss.c
index f649248..7e474f3 100644
--- a/drivers/usb/gadget/f_qdss.c
+++ b/drivers/usb/gadget/f_qdss.c
@@ -18,6 +18,7 @@
 #include <linux/usb/usb_qdss.h>
 #include <linux/usb/msm_hsusb.h>
 
+#include "gadget_chips.h"
 #include "f_qdss.h"
 #include "u_qdss.c"
 
@@ -395,7 +396,9 @@
 			goto fail;
 		}
 	}
-	dwc3_tx_fifo_resize_request(qdss->data, true);
+
+	if (gadget_is_dwc3(gadget))
+		dwc3_tx_fifo_resize_request(qdss->data, true);
 
 	return 0;
 fail:
@@ -408,12 +411,15 @@
 static void qdss_unbind(struct usb_configuration *c, struct usb_function *f)
 {
 	struct f_qdss  *qdss = func_to_qdss(f);
+	struct usb_gadget *gadget = c->cdev->gadget;
 
 	pr_debug("qdss_unbind\n");
 
-	dwc3_tx_fifo_resize_request(qdss->data, false);
+	if (gadget_is_dwc3(gadget))
+		dwc3_tx_fifo_resize_request(qdss->data, false);
+
 	clear_eps(f);
-	clear_desc(c->cdev->gadget, f);
+	clear_desc(gadget, f);
 }
 
 static void qdss_eps_disable(struct usb_function *f)
@@ -605,7 +611,7 @@
 
 	spin_lock_irqsave(&d_lock, flags);
 	list_for_each_entry(ch, &usb_qdss_ch_list, list) {
-		if (!strncmp(name, ch->name, sizeof(ch->name))) {
+		if (!strcmp(name, ch->name)) {
 			found = 1;
 			break;
 		}
@@ -767,7 +773,7 @@
 	spin_lock_irqsave(&d_lock, flags);
 	/* Check if we already have a channel with this name */
 	list_for_each_entry(ch, &usb_qdss_ch_list, list) {
-		if (!strncmp(name, ch->name, sizeof(ch->name))) {
+		if (!strcmp(name, ch->name)) {
 			found = 1;
 			break;
 		}
@@ -824,7 +830,8 @@
 	ch->app_conn = 0;
 	spin_unlock_irqrestore(&d_lock, flags);
 
-	msm_dwc3_restart_usb_session(gadget);
+	if (gadget_is_dwc3(gadget))
+		msm_dwc3_restart_usb_session(gadget);
 }
 EXPORT_SYMBOL(usb_qdss_close);
 
diff --git a/drivers/usb/gadget/f_rndis.c b/drivers/usb/gadget/f_rndis.c
index 7903764..aee7b58 100644
--- a/drivers/usb/gadget/f_rndis.c
+++ b/drivers/usb/gadget/f_rndis.c
@@ -379,13 +379,35 @@
 					struct sk_buff *skb)
 {
 	struct sk_buff *skb2;
+	struct rndis_packet_msg_type *header = NULL;
+	struct f_rndis *rndis = func_to_rndis(&port->func);
 
-	skb2 = skb_realloc_headroom(skb, sizeof(struct rndis_packet_msg_type));
-	if (skb2)
-		rndis_add_hdr(skb2);
+	if (rndis->port.multi_pkt_xfer) {
+		if (port->header) {
+			header = port->header;
+			memset(header, 0, sizeof(*header));
+			header->MessageType = cpu_to_le32(REMOTE_NDIS_PACKET_MSG);
+			header->MessageLength = cpu_to_le32(skb->len +
+							sizeof(*header));
+			header->DataOffset = cpu_to_le32(36);
+			header->DataLength = cpu_to_le32(skb->len);
+			pr_debug("MessageLength:%d DataLength:%d\n",
+						header->MessageLength,
+						header->DataLength);
+			return skb;
+		} else {
+			pr_err("RNDIS header is NULL.\n");
+			return NULL;
+		}
+	} else {
+		skb2 = skb_realloc_headroom(skb,
+				sizeof(struct rndis_packet_msg_type));
+		if (skb2)
+			rndis_add_hdr(skb2);
 
-	dev_kfree_skb_any(skb);
-	return skb2;
+		dev_kfree_skb_any(skb);
+		return skb2;
+	}
 }
 
 static void rndis_response_available(void *_rndis)
diff --git a/drivers/usb/gadget/u_ether.c b/drivers/usb/gadget/u_ether.c
index 9e789c5..734619f 100644
--- a/drivers/usb/gadget/u_ether.c
+++ b/drivers/usb/gadget/u_ether.c
@@ -197,6 +197,7 @@
 }
 
 static void rx_complete(struct usb_ep *ep, struct usb_request *req);
+static void tx_complete(struct usb_ep *ep, struct usb_request *req);
 
 static int
 rx_submit(struct eth_dev *dev, struct usb_request *req, gfp_t gfp_flags)
@@ -256,7 +257,6 @@
 
 	req->buf = skb->data;
 	req->length = size;
-	req->complete = rx_complete;
 	req->context = skb;
 
 	retval = usb_ep_queue(out, req, gfp_flags);
@@ -349,6 +349,7 @@
 {
 	unsigned		i;
 	struct usb_request	*req;
+	bool			usb_in;
 
 	if (!n)
 		return -ENOMEM;
@@ -359,10 +360,22 @@
 		if (i-- == 0)
 			goto extra;
 	}
+
+	if (ep->desc->bEndpointAddress & USB_DIR_IN)
+		usb_in = true;
+	else
+		usb_in = false;
+
 	while (i--) {
 		req = usb_ep_alloc_request(ep, GFP_ATOMIC);
 		if (!req)
 			return list_empty(list) ? -ENOMEM : 0;
+		/* update completion handler */
+		if (usb_in)
+			req->complete = tx_complete;
+		else
+			req->complete = rx_complete;
+
 		list_add(&req->list, list);
 	}
 	return 0;
@@ -479,7 +492,7 @@
 
 static void tx_complete(struct usb_ep *ep, struct usb_request *req)
 {
-	struct sk_buff	*skb = req->context;
+	struct sk_buff	*skb;
 	struct eth_dev	*dev;
 	struct net_device *net;
 	struct usb_request *new_req;
@@ -553,7 +566,6 @@
 				}
 
 				new_req->length = length;
-				new_req->complete = tx_complete;
 				retval = usb_ep_queue(in, new_req, GFP_ATOMIC);
 				switch (retval) {
 				default:
@@ -585,6 +597,7 @@
 			spin_unlock(&dev->req_lock);
 		}
 	} else {
+		skb = req->context;
 		spin_unlock(&dev->req_lock);
 		dev_kfree_skb_any(skb);
 	}
@@ -613,7 +626,7 @@
 	list_for_each(act, &dev->tx_reqs) {
 		req = container_of(act, struct usb_request, list);
 		if (!req->buf)
-			req->buf = kmalloc(dev->tx_req_bufsize,
+			req->buf = kzalloc(dev->tx_req_bufsize,
 						GFP_ATOMIC);
 			if (!req->buf)
 				goto free_buf;
@@ -626,6 +639,7 @@
 	list_for_each(act, &dev->tx_reqs) {
 		req = container_of(act, struct usb_request, list);
 		kfree(req->buf);
+		req->buf = NULL;
 	}
 	return -ENOMEM;
 }
@@ -710,28 +724,37 @@
 	 * or the hardware can't use skb buffers.
 	 * or there's not enough space for extra headers we need
 	 */
+	spin_lock_irqsave(&dev->lock, flags);
 	if (dev->wrap) {
-		unsigned long	flags;
-
-		spin_lock_irqsave(&dev->lock, flags);
 		if (dev->port_usb)
 			skb = dev->wrap(dev->port_usb, skb);
-		spin_unlock_irqrestore(&dev->lock, flags);
-		if (!skb)
+		if (!skb) {
+			spin_unlock_irqrestore(&dev->lock, flags);
 			goto drop;
+		}
 	}
 
-	spin_lock_irqsave(&dev->req_lock, flags);
-	dev->tx_skb_hold_count++;
-	spin_unlock_irqrestore(&dev->req_lock, flags);
-
 	if (multi_pkt_xfer) {
+
+		pr_debug("req->length:%d header_len:%u\n"
+				"skb->len:%d skb->data_len:%d\n",
+				req->length, dev->header_len,
+				skb->len, skb->data_len);
+		/* Add RNDIS Header */
+		memcpy(req->buf + req->length, dev->port_usb->header,
+						dev->header_len);
+		/* Increment req length by header size */
+		req->length += dev->header_len;
+		spin_unlock_irqrestore(&dev->lock, flags);
+		/* Copy received IP data from SKB */
 		memcpy(req->buf + req->length, skb->data, skb->len);
-		req->length = req->length + skb->len;
+		/* Increment req length by skb data length */
+		req->length += skb->len;
 		length = req->length;
 		dev_kfree_skb_any(skb);
 
 		spin_lock_irqsave(&dev->req_lock, flags);
+		dev->tx_skb_hold_count++;
 		if (dev->tx_skb_hold_count < dev->dl_max_pkts_per_xfer) {
 			if (dev->no_tx_req_used > TX_REQ_THRESHOLD) {
 				list_add(&req->list, &dev->tx_reqs);
@@ -741,19 +764,15 @@
 		}
 
 		dev->no_tx_req_used++;
-		spin_unlock_irqrestore(&dev->req_lock, flags);
-
-		spin_lock_irqsave(&dev->lock, flags);
 		dev->tx_skb_hold_count = 0;
-		spin_unlock_irqrestore(&dev->lock, flags);
+		spin_unlock_irqrestore(&dev->req_lock, flags);
 	} else {
+		spin_unlock_irqrestore(&dev->lock, flags);
 		length = skb->len;
 		req->buf = skb->data;
 		req->context = skb;
 	}
 
-	req->complete = tx_complete;
-
 	/* NCM requires no zlp if transfer is dwNtbInMaxSize */
 	if (dev->port_usb->is_fixed &&
 	    length == dev->port_usb->fixed_in_len &&
@@ -806,7 +825,7 @@
 		spin_lock_irqsave(&dev->req_lock, flags);
 		if (list_empty(&dev->tx_reqs))
 			netif_start_queue(net);
-		list_add(&req->list, &dev->tx_reqs);
+		list_add_tail(&req->list, &dev->tx_reqs);
 		spin_unlock_irqrestore(&dev->req_lock, flags);
 	}
 success:
@@ -1085,6 +1104,14 @@
 	if (!dev)
 		return ERR_PTR(-EINVAL);
 
+	link->header = kzalloc(sizeof(struct rndis_packet_msg_type),
+							GFP_ATOMIC);
+	if (!link->header) {
+		pr_err("RNDIS header memory allocation failed.\n");
+		result = -ENOMEM;
+		goto fail;
+	}
+
 	link->in_ep->driver_data = dev;
 	result = usb_ep_enable(link->in_ep);
 	if (result != 0) {
@@ -1105,6 +1132,7 @@
 		result = alloc_requests(dev, link, qlen(dev->gadget));
 
 	if (result == 0) {
+
 		dev->zlp = link->is_zlp_ok;
 		DBG(dev, "qlen %d\n", qlen(dev->gadget));
 
@@ -1139,10 +1167,15 @@
 fail1:
 		(void) usb_ep_disable(link->in_ep);
 	}
-fail0:
+
 	/* caller is responsible for cleanup on error */
-	if (result < 0)
+	if (result < 0) {
+fail0:
+		kfree(link->header);
+fail:
 		return ERR_PTR(result);
+	}
+
 	return dev->net;
 }
 
@@ -1184,11 +1217,16 @@
 		list_del(&req->list);
 
 		spin_unlock(&dev->req_lock);
-		if (link->multi_pkt_xfer)
+		if (link->multi_pkt_xfer) {
 			kfree(req->buf);
+			req->buf = NULL;
+		}
 		usb_ep_free_request(link->in_ep, req);
 		spin_lock(&dev->req_lock);
 	}
+	/* Free rndis header buffer memory */
+	kfree(link->header);
+	link->header = NULL;
 	spin_unlock(&dev->req_lock);
 	link->in_ep->driver_data = NULL;
 	link->in_ep->desc = NULL;
diff --git a/drivers/usb/gadget/u_ether.h b/drivers/usb/gadget/u_ether.h
index 05984d8..2c5da77 100644
--- a/drivers/usb/gadget/u_ether.h
+++ b/drivers/usb/gadget/u_ether.h
@@ -66,6 +66,8 @@
 	/* called on network open/close */
 	void				(*open)(struct gether *);
 	void				(*close)(struct gether *);
+	struct rndis_packet_msg_type	*header;
+
 };
 
 #define	DEFAULT_FILTER	(USB_CDC_PACKET_TYPE_BROADCAST \
diff --git a/drivers/usb/gadget/u_qdss.c b/drivers/usb/gadget/u_qdss.c
index e241e29..23d4d06 100644
--- a/drivers/usb/gadget/u_qdss.c
+++ b/drivers/usb/gadget/u_qdss.c
@@ -14,6 +14,7 @@
 #include <linux/device.h>
 #include <linux/usb/msm_hsusb.h>
 #include <mach/usb_bam.h>
+#include "gadget_chips.h"
 
 struct  usb_qdss_bam_connect_info {
 	u32 usb_bam_pipe_idx;
@@ -88,8 +89,11 @@
 			&bam_info.usb_bam_pipe_idx, &bam_info.peer_pipe_idx,
 			NULL, bam_info.data_fifo);
 
-		msm_data_fifo_config(data_ep, bam_info.data_fifo->phys_base,
-			bam_info.data_fifo->size, bam_info.usb_bam_pipe_idx);
+		if (gadget_is_dwc3(gadget))
+			msm_data_fifo_config(data_ep,
+					     bam_info.data_fifo->phys_base,
+					     bam_info.data_fifo->size,
+					     bam_info.usb_bam_pipe_idx);
 	} else {
 		kfree(bam_info.data_fifo);
 		res = usb_bam_disconnect_pipe(idx);
diff --git a/drivers/usb/host/ehci-msm-hsic.c b/drivers/usb/host/ehci-msm-hsic.c
index 5d58f16..5f20ad1 100644
--- a/drivers/usb/host/ehci-msm-hsic.c
+++ b/drivers/usb/host/ehci-msm-hsic.c
@@ -1947,7 +1947,6 @@
 	if (pdev->dev.of_node) {
 		dev_dbg(&pdev->dev, "device tree enabled\n");
 		pdev->dev.platform_data = msm_hsic_dt_to_pdata(pdev);
-		dev_set_name(&pdev->dev, ehci_msm_hsic_driver.driver.name);
 	} else {
 		/* explicitly pass wakeup_irq flag for !DT */
 		wakeup_irq_flags = IRQF_TRIGGER_HIGH;
diff --git a/drivers/usb/otg/msm_otg.c b/drivers/usb/otg/msm_otg.c
index 276bbb0..45fbfa8 100644
--- a/drivers/usb/otg/msm_otg.c
+++ b/drivers/usb/otg/msm_otg.c
@@ -470,6 +470,20 @@
 	int ret;
 	struct msm_otg_platform_data *pdata = motg->pdata;
 
+	/*
+	 * AHB2AHB Bypass mode shouldn't be enable before doing
+	 * async clock reset. If it is enable, disable the same.
+	 */
+	val = readl_relaxed(USB_AHBMODE);
+	if (val & AHB2AHB_BYPASS) {
+		pr_err("%s(): AHB2AHB_BYPASS SET: AHBMODE:%x\n",
+				__func__, val);
+		val &= ~AHB2AHB_BYPASS_BIT_MASK;
+		writel_relaxed(val | AHB2AHB_BYPASS_CLEAR, USB_AHBMODE);
+		pr_err("%s(): AHBMODE: %x\n", __func__,
+				readl_relaxed(USB_AHBMODE));
+	}
+
 	ret = msm_otg_link_clk_reset(motg, 1);
 	if (ret)
 		return ret;
@@ -1275,7 +1289,8 @@
 	else if (motg->chg_type == USB_CDP_CHARGER)
 		charger_type = POWER_SUPPLY_TYPE_USB_CDP;
 	else if (motg->chg_type == USB_DCP_CHARGER ||
-			motg->chg_type == USB_PROPRIETARY_CHARGER)
+			motg->chg_type == USB_PROPRIETARY_CHARGER ||
+			motg->chg_type == USB_FLOATED_CHARGER)
 		charger_type = POWER_SUPPLY_TYPE_USB_DCP;
 	else if ((motg->chg_type == USB_ACA_DOCK_CHARGER ||
 		motg->chg_type == USB_ACA_A_CHARGER ||
@@ -3834,6 +3849,8 @@
 		ci_pdata.log2_itc = otg_pdata->log2_itc;
 		ci_pdata.usb_core_id = 0;
 		ci_pdata.l1_supported = otg_pdata->l1_supported;
+		ci_pdata.enable_ahb2ahb_bypass =
+				otg_pdata->enable_ahb2ahb_bypass;
 		retval = platform_device_add_data(pdev, &ci_pdata,
 			sizeof(ci_pdata));
 		if (retval)
@@ -4164,6 +4181,8 @@
 
 	pdata->l1_supported = of_property_read_bool(node,
 				"qcom,hsusb-l1-supported");
+	pdata->enable_ahb2ahb_bypass = of_property_read_bool(node,
+				"qcom,ahb-async-bridge-bypass");
 
 	return pdata;
 }
diff --git a/drivers/video/fbcmap.c b/drivers/video/fbcmap.c
index 5c3960d..31e93a5 100644
--- a/drivers/video/fbcmap.c
+++ b/drivers/video/fbcmap.c
@@ -166,6 +166,9 @@
 	int tooff = 0, fromoff = 0;
 	int size;
 
+	if (!to || !from)
+		return -EINVAL;
+
 	if (to->start > from->start)
 		fromoff = to->start - from->start;
 	else
@@ -177,9 +180,12 @@
 		return -EINVAL;
 	size *= sizeof(u16);
 
-	memcpy(to->red+tooff, from->red+fromoff, size);
-	memcpy(to->green+tooff, from->green+fromoff, size);
-	memcpy(to->blue+tooff, from->blue+fromoff, size);
+	if (from->red && to->red)
+		memcpy(to->red+tooff, from->red+fromoff, size);
+	if (from->green && to->green)
+		memcpy(to->green+tooff, from->green+fromoff, size);
+	if (from->blue && to->blue)
+		memcpy(to->blue+tooff, from->blue+fromoff, size);
 	if (from->transp && to->transp)
 		memcpy(to->transp+tooff, from->transp+fromoff, size);
 	return 0;
@@ -190,6 +196,9 @@
 	int tooff = 0, fromoff = 0;
 	int size;
 
+	if (!to || !from)
+		return -EINVAL;
+
 	if (to->start > from->start)
 		fromoff = to->start - from->start;
 	else
@@ -201,12 +210,15 @@
 		return -EINVAL;
 	size *= sizeof(u16);
 
-	if (copy_to_user(to->red+tooff, from->red+fromoff, size))
-		return -EFAULT;
-	if (copy_to_user(to->green+tooff, from->green+fromoff, size))
-		return -EFAULT;
-	if (copy_to_user(to->blue+tooff, from->blue+fromoff, size))
-		return -EFAULT;
+	if (from->red && to->red)
+		if (copy_to_user(to->red+tooff, from->red+fromoff, size))
+			return -EFAULT;
+	if (from->green && to->green)
+		if (copy_to_user(to->green+tooff, from->green+fromoff, size))
+			return -EFAULT;
+	if (from->blue && to->blue)
+		if (copy_to_user(to->blue+tooff, from->blue+fromoff, size))
+			return -EFAULT;
 	if (from->transp && to->transp)
 		if (copy_to_user(to->transp+tooff, from->transp+fromoff, size))
 			return -EFAULT;
diff --git a/drivers/video/fbmem.c b/drivers/video/fbmem.c
index d6a664a..6b84107 100644
--- a/drivers/video/fbmem.c
+++ b/drivers/video/fbmem.c
@@ -1113,6 +1113,10 @@
 		if (copy_from_user(&cmap, argp, sizeof(cmap)))
 			return -EFAULT;
 		ret = fb_set_user_cmap(&cmap, info);
+		if (ret) {
+			if (info)
+				fb_dealloc_cmap(&info->cmap);
+		}
 		break;
 	case FBIOGETCMAP:
 		if (copy_from_user(&cmap, argp, sizeof(cmap)))
diff --git a/drivers/video/msm/mdss/Kconfig b/drivers/video/msm/mdss/Kconfig
index 7682a49..b49e08e 100644
--- a/drivers/video/msm/mdss/Kconfig
+++ b/drivers/video/msm/mdss/Kconfig
@@ -20,3 +20,11 @@
 	  Support the HDMI to MHL conversion.
 	  MHL (Mobile High-Definition Link) technology
 	  uses USB connector to output HDMI content
+
+config FB_MSM_MDSS_DSI_CTRL_STATUS
+	tristate "DSI controller status check feature"
+	---help---
+	  Check DSI controller status periodically (default period is 5
+	  seconds) by sending Bus-Turn-Around (BTA) command. If DSI controller
+	  fails to acknowledge the BTA command, it sends PANEL_ALIVE=0 status
+	  to HAL layer to reset the controller.
diff --git a/drivers/video/msm/mdss/Makefile b/drivers/video/msm/mdss/Makefile
index ba14d67..8f5fa26 100644
--- a/drivers/video/msm/mdss/Makefile
+++ b/drivers/video/msm/mdss/Makefile
@@ -41,3 +41,5 @@
 obj-$(CONFIG_FB_MSM_QPIC_ILI_QVGA_PANEL) += qpic_panel_ili_qvga.o
 
 obj-$(CONFIG_FB_MSM_MDSS) += mdss_fb.o
+
+obj-$(CONFIG_FB_MSM_MDSS_DSI_CTRL_STATUS) += mdss_dsi_status.o
diff --git a/drivers/video/msm/mdss/dsi_host_v2.c b/drivers/video/msm/mdss/dsi_host_v2.c
index e416a55..7d57f64 100644
--- a/drivers/video/msm/mdss/dsi_host_v2.c
+++ b/drivers/video/msm/mdss/dsi_host_v2.c
@@ -77,7 +77,7 @@
 
 	if (status) {
 		MIPI_OUTP(ctrl_base + DSI_ACK_ERR_STATUS, status);
-		pr_debug("%s: status=%x\n", __func__, status);
+		pr_err("%s: status=%x\n", __func__, status);
 	}
 }
 
@@ -88,7 +88,7 @@
 	status = MIPI_INP(ctrl_base + DSI_TIMEOUT_STATUS);
 	if (status & 0x0111) {
 		MIPI_OUTP(ctrl_base + DSI_TIMEOUT_STATUS, status);
-		pr_debug("%s: status=%x\n", __func__, status);
+		pr_err("%s: status=%x\n", __func__, status);
 	}
 }
 
@@ -100,7 +100,7 @@
 
 	if (status & 0x011111) {
 		MIPI_OUTP(ctrl_base + DSI_DLN0_PHY_ERR, status);
-		pr_debug("%s: status=%x\n", __func__, status);
+		pr_err("%s: status=%x\n", __func__, status);
 	}
 }
 
@@ -112,7 +112,7 @@
 
 	if (status & 0x44444489) {
 		MIPI_OUTP(ctrl_base + DSI_FIFO_STATUS, status);
-		pr_debug("%s: status=%x\n", __func__, status);
+		pr_err("%s: status=%x\n", __func__, status);
 	}
 }
 
@@ -124,7 +124,7 @@
 
 	if (status & 0x80000000) {
 		MIPI_OUTP(ctrl_base + DSI_STATUS, status);
-		pr_debug("%s: status=%x\n", __func__, status);
+		pr_err("%s: status=%x\n", __func__, status);
 	}
 }
 
diff --git a/drivers/video/msm/mdss/mdp3.c b/drivers/video/msm/mdss/mdp3.c
index 638fcb3..d642093 100644
--- a/drivers/video/msm/mdss/mdp3.c
+++ b/drivers/video/msm/mdss/mdp3.c
@@ -1726,7 +1726,7 @@
 		rc = (status == 0x080000);
 	}
 
-	mdp3_res->splash_mem_addr = MDP3_REG_READ(MDP3_REG_DMA_S_IBUF_ADDR);
+	mdp3_res->splash_mem_addr = MDP3_REG_READ(MDP3_REG_DMA_P_IBUF_ADDR);
 
 	mdp3_clk_update(MDP3_CLK_AHB, 0);
 	mdp3_clk_update(MDP3_CLK_CORE, 0);
@@ -1859,6 +1859,52 @@
 			mdp3_res->underrun_cnt);
 }
 
+static ssize_t mdp3_show_capabilities(struct device *dev,
+		struct device_attribute *attr, char *buf)
+{
+	size_t len = PAGE_SIZE;
+	int cnt = 0;
+
+#define SPRINT(fmt, ...) \
+		(cnt += scnprintf(buf + cnt, len - cnt, fmt, ##__VA_ARGS__))
+
+	SPRINT("mdp_version=3\n");
+	SPRINT("hw_rev=%d\n", 304);
+	SPRINT("dma_pipes=%d\n", 1);
+	SPRINT("\n");
+
+	return cnt;
+}
+
+static DEVICE_ATTR(caps, S_IRUGO, mdp3_show_capabilities, NULL);
+
+static struct attribute *mdp3_fs_attrs[] = {
+	&dev_attr_caps.attr,
+	NULL
+};
+
+static struct attribute_group mdp3_fs_attr_group = {
+	.attrs = mdp3_fs_attrs
+};
+
+static int mdp3_register_sysfs(struct platform_device *pdev)
+{
+	struct device *dev = &pdev->dev;
+	int rc;
+
+	rc = sysfs_create_group(&dev->kobj, &mdp3_fs_attr_group);
+
+	return rc;
+}
+
+int mdp3_create_sysfs_link(struct device *dev)
+{
+	int rc;
+	rc = sysfs_create_link_nowarn(&dev->kobj,
+			&mdp3_res->pdev->dev.kobj, "mdp");
+
+	return rc;
+}
 
 static int mdp3_probe(struct platform_device *pdev)
 {
@@ -1918,6 +1964,10 @@
 		goto probe_done;
 	}
 
+	rc = mdp3_register_sysfs(pdev);
+	if (rc)
+		pr_err("unable to register mdp sysfs nodes\n");
+
 	rc = mdss_fb_register_mdp_instance(&mdp3_interface);
 	if (rc)
 		pr_err("unable to register mdp instance\n");
diff --git a/drivers/video/msm/mdss/mdp3.h b/drivers/video/msm/mdss/mdp3.h
index 4480c20..e66b5ac 100644
--- a/drivers/video/msm/mdss/mdp3.h
+++ b/drivers/video/msm/mdss/mdp3.h
@@ -186,6 +186,7 @@
 void mdp3_free(void);
 int mdp3_parse_dt_splash(struct msm_fb_data_type *mfd);
 void mdp3_release_splash_memory(void);
+int mdp3_create_sysfs_link(struct device *dev);
 
 #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 e92e178..b123ccb 100644
--- a/drivers/video/msm/mdss/mdp3_ctrl.c
+++ b/drivers/video/msm/mdss/mdp3_ctrl.c
@@ -509,6 +509,9 @@
 	panel = mdp3_session->panel;
 	mutex_lock(&mdp3_session->lock);
 
+	if (panel && panel->set_backlight)
+		panel->set_backlight(panel, 0);
+
 	if (!mdp3_session->status) {
 		pr_debug("fb%d is off already", mfd->index);
 		goto off_error;
@@ -1355,7 +1358,7 @@
 	int rc = -EINVAL;
 	struct mdp3_session_data *mdp3_session;
 	struct msmfb_metadata metadata;
-	struct mdp_overlay req;
+	struct mdp_overlay *req = NULL;
 	struct msmfb_overlay_data ov_data;
 	int val;
 
@@ -1363,6 +1366,8 @@
 	if (!mdp3_session)
 		return -ENODEV;
 
+	req = &mdp3_session->req_overlay;
+
 	if (!mdp3_session->status && cmd != MSMFB_METADATA_GET) {
 		pr_err("mdp3_ctrl_ioctl_handler, display off!\n");
 		return -EPERM;
@@ -1402,23 +1407,23 @@
 			rc = copy_to_user(argp, &metadata, sizeof(metadata));
 		break;
 	case MSMFB_OVERLAY_GET:
-		rc = copy_from_user(&req, argp, sizeof(req));
+		rc = copy_from_user(req, argp, sizeof(*req));
 		if (!rc) {
-			rc = mdp3_overlay_get(mfd, &req);
+			rc = mdp3_overlay_get(mfd, req);
 
 		if (!IS_ERR_VALUE(rc))
-			rc = copy_to_user(argp, &req, sizeof(req));
+			rc = copy_to_user(argp, req, sizeof(*req));
 		}
 		if (rc)
 			pr_err("OVERLAY_GET failed (%d)\n", rc);
 		break;
 	case MSMFB_OVERLAY_SET:
-		rc = copy_from_user(&req, argp, sizeof(req));
+		rc = copy_from_user(req, argp, sizeof(*req));
 		if (!rc) {
-			rc = mdp3_overlay_set(mfd, &req);
+			rc = mdp3_overlay_set(mfd, req);
 
 		if (!IS_ERR_VALUE(rc))
-			rc = copy_to_user(argp, &req, sizeof(req));
+			rc = copy_to_user(argp, req, sizeof(*req));
 		}
 		if (rc)
 			pr_err("OVERLAY_SET failed (%d)\n", rc);
@@ -1525,6 +1530,10 @@
 		goto init_done;
 	}
 
+	rc = mdp3_create_sysfs_link(dev);
+	if (rc)
+		pr_warn("problem creating link to mdp sysfs\n");
+
 	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 7c4f6ac..66ed3d5 100644
--- a/drivers/video/msm/mdss/mdp3_ctrl.h
+++ b/drivers/video/msm/mdss/mdp3_ctrl.h
@@ -45,6 +45,7 @@
 	int vsync_period;
 	struct sysfs_dirent *vsync_event_sd;
 	struct mdp_overlay overlay;
+	struct mdp_overlay req_overlay;
 	struct mdp3_buffer_queue bufq_in;
 	struct mdp3_buffer_queue bufq_out;
 	int histo_status;
diff --git a/drivers/video/msm/mdss/mdss_dsi.c b/drivers/video/msm/mdss/mdss_dsi.c
index 865775a..bb1f8ae 100644
--- a/drivers/video/msm/mdss/mdss_dsi.c
+++ b/drivers/video/msm/mdss/mdss_dsi.c
@@ -1216,7 +1216,8 @@
 		}
 	}
 
-	if (gpio_is_valid(ctrl_pdata->disp_te_gpio)) {
+	if (gpio_is_valid(ctrl_pdata->disp_te_gpio) &&
+					pinfo->type == MIPI_CMD_PANEL) {
 		rc = gpio_request(ctrl_pdata->disp_te_gpio, "disp_te");
 		if (rc) {
 			pr_err("request TE gpio failed, rc=%d\n",
@@ -1304,6 +1305,7 @@
 	}
 
 	ctrl_pdata->panel_data.event_handler = mdss_dsi_event_handler;
+	ctrl_pdata->check_status = mdss_dsi_bta_status_check;
 
 	if (ctrl_pdata->bklt_ctrl == BL_PWM)
 		mdss_dsi_panel_pwm_cfg(ctrl_pdata);
diff --git a/drivers/video/msm/mdss/mdss_dsi.h b/drivers/video/msm/mdss/mdss_dsi.h
index 13dad06..7202c62 100644
--- a/drivers/video/msm/mdss/mdss_dsi.h
+++ b/drivers/video/msm/mdss/mdss_dsi.h
@@ -118,6 +118,8 @@
 
 #define DSI_INTR_ERROR_MASK		BIT(25)
 #define DSI_INTR_ERROR			BIT(24)
+#define DSI_INTR_BTA_DONE_MASK          BIT(21)
+#define DSI_INTR_BTA_DONE               BIT(20)
 #define DSI_INTR_VIDEO_DONE_MASK	BIT(17)
 #define DSI_INTR_VIDEO_DONE		BIT(16)
 #define DSI_INTR_CMD_MDP_DONE_MASK	BIT(9)
@@ -133,6 +135,7 @@
 
 #define DSI_VIDEO_TERM  BIT(16)
 #define DSI_MDP_TERM    BIT(8)
+#define DSI_BTA_TERM    BIT(1)
 #define DSI_CMD_TERM    BIT(0)
 
 extern struct device dsi_dev;
@@ -315,6 +318,7 @@
 	int (*on) (struct mdss_panel_data *pdata);
 	int (*off) (struct mdss_panel_data *pdata);
 	int (*partial_update_fnc) (struct mdss_panel_data *pdata);
+	int (*check_status) (struct mdss_dsi_ctrl_pdata *pdata);
 	struct mdss_panel_data panel_data;
 	unsigned char *ctrl_base;
 	int reg_size;
@@ -360,6 +364,7 @@
 	struct completion dma_comp;
 	struct completion mdp_comp;
 	struct completion video_comp;
+	struct completion bta_comp;
 	spinlock_t irq_lock;
 	spinlock_t mdp_lock;
 	int mdp_busy;
@@ -428,6 +433,7 @@
 				struct dcs_cmd_req *cmdreq);
 struct dcs_cmd_req *mdss_dsi_cmdlist_get(struct mdss_dsi_ctrl_pdata *ctrl);
 void mdss_dsi_cmdlist_kickoff(int intf);
+int mdss_dsi_bta_status_check(struct mdss_dsi_ctrl_pdata *ctrl);
 
 int mdss_dsi_panel_init(struct device_node *node,
 		struct mdss_dsi_ctrl_pdata *ctrl_pdata,
diff --git a/drivers/video/msm/mdss/mdss_dsi_host.c b/drivers/video/msm/mdss/mdss_dsi_host.c
index bb2818b..750fbf3 100644
--- a/drivers/video/msm/mdss/mdss_dsi_host.c
+++ b/drivers/video/msm/mdss/mdss_dsi_host.c
@@ -49,6 +49,8 @@
 
 #define DSI_EVENT_Q_MAX	4
 
+#define DSI_BTA_EVENT_TIMEOUT (HZ / 10)
+
 /* event */
 struct dsi_event_q {
 	struct mdss_dsi_ctrl_pdata *ctrl;
@@ -98,6 +100,7 @@
 	init_completion(&ctrl->dma_comp);
 	init_completion(&ctrl->mdp_comp);
 	init_completion(&ctrl->video_comp);
+	init_completion(&ctrl->bta_comp);
 	spin_lock_init(&ctrl->irq_lock);
 	spin_lock_init(&ctrl->mdp_lock);
 	mutex_init(&ctrl->mutex);
@@ -1107,14 +1110,14 @@
 
 	if (mode == DSI_VIDEO_MODE) {
 		dsi_ctrl |= 0x03;
-		intr_ctrl = DSI_INTR_CMD_DMA_DONE_MASK;
+		intr_ctrl = DSI_INTR_CMD_DMA_DONE_MASK | DSI_INTR_BTA_DONE_MASK;
 	} else {		/* command mode */
 		dsi_ctrl |= 0x05;
 		if (pdata->panel_info.type == MIPI_VIDEO_PANEL)
 			dsi_ctrl |= 0x02;
 
 		intr_ctrl = DSI_INTR_CMD_DMA_DONE_MASK | DSI_INTR_ERROR_MASK |
-				DSI_INTR_CMD_MDP_DONE_MASK;
+			DSI_INTR_CMD_MDP_DONE_MASK | DSI_INTR_BTA_DONE_MASK;
 	}
 
 	if (ctrl_pdata->shared_pdata.broadcast_enable)
@@ -1160,6 +1163,45 @@
 	pr_debug("%s: BTA done, status = %d\n", __func__, status);
 }
 
+int mdss_dsi_bta_status_check(struct mdss_dsi_ctrl_pdata *ctrl_pdata)
+{
+	int ret = 0;
+	unsigned long flag;
+
+	if (ctrl_pdata == NULL) {
+		pr_err("%s: Invalid input data\n", __func__);
+
+		/*
+		 * This should not return error otherwise
+		 * BTA status thread will treat it as dead panel scenario
+		 * and request for blank/unblank
+		 */
+		return 0;
+	}
+
+	pr_debug("%s: Checking BTA status\n", __func__);
+
+	mdss_dsi_clk_ctrl(ctrl_pdata, 1);
+	spin_lock_irqsave(&ctrl_pdata->mdp_lock, flag);
+	INIT_COMPLETION(ctrl_pdata->bta_comp);
+	mdss_dsi_enable_irq(ctrl_pdata, DSI_BTA_TERM);
+	spin_unlock_irqrestore(&ctrl_pdata->mdp_lock, flag);
+	MIPI_OUTP(ctrl_pdata->ctrl_base + 0x098, 0x01); /* trigger  */
+	wmb();
+
+	ret = wait_for_completion_killable_timeout(&ctrl_pdata->bta_comp,
+						DSI_BTA_EVENT_TIMEOUT);
+	if (ret <= 0) {
+		mdss_dsi_disable_irq(ctrl_pdata, DSI_BTA_TERM);
+		pr_err("%s: DSI BTA error: %i\n", __func__, ret);
+	}
+
+	mdss_dsi_clk_ctrl(ctrl_pdata, 0);
+	pr_debug("%s: BTA done with ret: %d\n", __func__, ret);
+
+	return ret;
+}
+
 static char set_tear_on[2] = {0x35, 0x00};
 static struct dsi_cmd_desc dsi_tear_on_cmd = {
 	{DTYPE_DCS_WRITE1, 1, 0, 0, 0, sizeof(set_tear_on)}, set_tear_on};
@@ -2078,5 +2120,12 @@
 		spin_unlock(&ctrl->mdp_lock);
 	}
 
+	if (isr & DSI_INTR_BTA_DONE) {
+		spin_lock(&ctrl->mdp_lock);
+		mdss_dsi_disable_irq_nosync(ctrl, DSI_BTA_TERM);
+		complete(&ctrl->bta_comp);
+		spin_unlock(&ctrl->mdp_lock);
+	}
+
 	return IRQ_HANDLED;
 }
diff --git a/drivers/video/msm/mdss/mdss_dsi_panel.c b/drivers/video/msm/mdss/mdss_dsi_panel.c
index 9932186..890066e 100644
--- a/drivers/video/msm/mdss/mdss_dsi_panel.c
+++ b/drivers/video/msm/mdss/mdss_dsi_panel.c
@@ -293,6 +293,15 @@
 	ctrl_pdata = container_of(pdata, struct mdss_dsi_ctrl_pdata,
 				panel_data);
 
+	/*
+	 * Some backlight controllers specify a minimum duty cycle
+	 * for the backlight brightness. If the brightness is less
+	 * than it, the controller can malfunction.
+	 */
+
+	if ((bl_level < pdata->panel_info.bl_min) && (bl_level != 0))
+		bl_level = pdata->panel_info.bl_min;
+
 	switch (ctrl_pdata->bklt_ctrl) {
 	case BL_WLED:
 		led_trigger_event(bl_led_trigger, bl_level);
diff --git a/drivers/video/msm/mdss/mdss_dsi_status.c b/drivers/video/msm/mdss/mdss_dsi_status.c
new file mode 100644
index 0000000..f0c4f4c
--- /dev/null
+++ b/drivers/video/msm/mdss/mdss_dsi_status.c
@@ -0,0 +1,208 @@
+/* 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/kernel.h>
+#include <linux/init.h>
+#include <linux/fb.h>
+#include <linux/notifier.h>
+#include <linux/workqueue.h>
+#include <linux/delay.h>
+#include <linux/debugfs.h>
+#include <linux/slab.h>
+#include <linux/uaccess.h>
+#include <linux/iopoll.h>
+#include <linux/kobject.h>
+#include <linux/string.h>
+#include <linux/sysfs.h>
+
+#include "mdss_fb.h"
+#include "mdss_dsi.h"
+#include "mdss_panel.h"
+#include "mdss_mdp.h"
+
+#define STATUS_CHECK_INTERVAL 5000
+
+struct dsi_status_data {
+	struct notifier_block fb_notifier;
+	struct delayed_work check_status;
+	struct msm_fb_data_type *mfd;
+	uint32_t check_interval;
+};
+struct dsi_status_data *pstatus_data;
+static uint32_t interval = STATUS_CHECK_INTERVAL;
+
+/*
+ * check_dsi_ctrl_status() - Check DSI controller status periodically.
+ * @work  : dsi controller status data
+ *
+ * This function calls check_status API on DSI controller to send the BTA
+ * command. If DSI controller fails to acknowledge the BTA command, it sends
+ * the PANEL_ALIVE=0 status to HAL layer.
+ */
+static void check_dsi_ctrl_status(struct work_struct *work)
+{
+	struct dsi_status_data *pdsi_status = NULL;
+	struct mdss_panel_data *pdata = NULL;
+	struct mdss_dsi_ctrl_pdata *ctrl_pdata = NULL;
+	struct mdss_overlay_private *mdp5_data = NULL;
+	struct mdss_mdp_ctl *ctl = NULL;
+	int ret = 0;
+
+	pdsi_status = container_of(to_delayed_work(work),
+		struct dsi_status_data, check_status);
+	if (!pdsi_status) {
+		pr_err("%s: DSI status data not available\n", __func__);
+		return;
+	}
+
+	pdata = dev_get_platdata(&pdsi_status->mfd->pdev->dev);
+	if (!pdata) {
+		pr_err("%s: Panel data not available\n", __func__);
+		return;
+	}
+
+	ctrl_pdata = container_of(pdata, struct mdss_dsi_ctrl_pdata,
+							panel_data);
+	if (!ctrl_pdata || !ctrl_pdata->check_status) {
+		pr_err("%s: DSI ctrl or status_check callback not available\n",
+								__func__);
+		return;
+	}
+
+	mdp5_data = mfd_to_mdp5_data(pdsi_status->mfd);
+	ctl = mfd_to_ctl(pdsi_status->mfd);
+
+	if (ctl->shared_lock)
+		mutex_lock(ctl->shared_lock);
+	mutex_lock(&mdp5_data->ov_lock);
+
+	/*
+	 * For the command mode panels, we return pan display
+	 * IOCTL on vsync interrupt. So, after vsync interrupt comes
+	 * and when DMA_P is in progress, if the panel stops responding
+	 * and if we trigger BTA before DMA_P finishes, then the DSI
+	 * FIFO will not be cleared since the DSI data bus control
+	 * doesn't come back to the host after BTA. This may cause the
+	 * display reset not to be proper. Hence, wait for DMA_P done
+	 * for command mode panels before triggering BTA.
+	 */
+	if (ctl->wait_pingpong)
+		ctl->wait_pingpong(ctl, NULL);
+
+	pr_debug("%s: DSI ctrl wait for ping pong done\n", __func__);
+
+	mdss_mdp_clk_ctrl(MDP_BLOCK_POWER_ON, false);
+	ret = ctrl_pdata->check_status(ctrl_pdata);
+	mdss_mdp_clk_ctrl(MDP_BLOCK_POWER_OFF, false);
+
+	mutex_unlock(&mdp5_data->ov_lock);
+	if (ctl->shared_lock)
+		mutex_unlock(ctl->shared_lock);
+
+	if ((pdsi_status->mfd->panel_power_on)) {
+		if (ret > 0) {
+			schedule_delayed_work(&pdsi_status->check_status,
+				msecs_to_jiffies(pdsi_status->check_interval));
+		} else {
+			char *envp[2] = {"PANEL_ALIVE=0", NULL};
+			pdata->panel_info.panel_dead = true;
+			ret = kobject_uevent_env(
+				&pdsi_status->mfd->fbi->dev->kobj,
+							KOBJ_CHANGE, envp);
+			pr_err("%s: Panel has gone bad, sending uevent - %s\n",
+							__func__, envp[0]);
+		}
+	}
+}
+
+/*
+ * fb_event_callback() - Call back function for the fb_register_client()
+ *			 notifying events
+ * @self  : notifier block
+ * @event : The event that was triggered
+ * @data  : Of type struct fb_event
+ *
+ * This function listens for FB_BLANK_UNBLANK and FB_BLANK_POWERDOWN events
+ * from frame buffer. DSI status check work is either scheduled again after
+ * PANEL_STATUS_CHECK_INTERVAL or cancelled based on the event.
+ */
+static int fb_event_callback(struct notifier_block *self,
+				unsigned long event, void *data)
+{
+	struct fb_event *evdata = data;
+	struct dsi_status_data *pdata = container_of(self,
+				struct dsi_status_data, fb_notifier);
+	pdata->mfd = evdata->info->par;
+
+	if (event == FB_EVENT_BLANK && evdata) {
+		int *blank = evdata->data;
+		switch (*blank) {
+		case FB_BLANK_UNBLANK:
+			schedule_delayed_work(&pdata->check_status,
+				msecs_to_jiffies(pdata->check_interval));
+			break;
+		case FB_BLANK_POWERDOWN:
+			cancel_delayed_work(&pdata->check_status);
+			break;
+		}
+	}
+	return 0;
+}
+
+int __init mdss_dsi_status_init(void)
+{
+	int rc = 0;
+
+	pstatus_data = kzalloc(sizeof(struct dsi_status_data), GFP_KERNEL);
+	if (!pstatus_data) {
+		pr_err("%s: can't allocate memory\n", __func__);
+		return -ENOMEM;
+	}
+
+	pstatus_data->fb_notifier.notifier_call = fb_event_callback;
+
+	rc = fb_register_client(&pstatus_data->fb_notifier);
+	if (rc < 0) {
+		pr_err("%s: fb_register_client failed, returned with rc=%d\n",
+								__func__, rc);
+		kfree(pstatus_data);
+		return -EPERM;
+	}
+
+	pstatus_data->check_interval = interval;
+	pr_info("%s: DSI status check interval:%d\n", __func__,	interval);
+
+	INIT_DELAYED_WORK(&pstatus_data->check_status, check_dsi_ctrl_status);
+
+	pr_debug("%s: DSI ctrl status work queue initialized\n", __func__);
+
+	return rc;
+}
+
+void __exit mdss_dsi_status_exit(void)
+{
+	fb_unregister_client(&pstatus_data->fb_notifier);
+	cancel_delayed_work_sync(&pstatus_data->check_status);
+	kfree(pstatus_data);
+	pr_debug("%s: DSI ctrl status work queue removed\n", __func__);
+}
+
+module_param(interval, uint, 0);
+MODULE_PARM_DESC(interval,
+		"Duration in milliseconds to send BTA command for checking"
+		"DSI status periodically");
+
+module_init(mdss_dsi_status_init);
+module_exit(mdss_dsi_status_exit);
+
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/video/msm/mdss/mdss_fb.c b/drivers/video/msm/mdss/mdss_fb.c
index 105dd1a..81473db 100644
--- a/drivers/video/msm/mdss/mdss_fb.c
+++ b/drivers/video/msm/mdss/mdss_fb.c
@@ -98,8 +98,10 @@
 void mdss_fb_no_update_notify_timer_cb(unsigned long data)
 {
 	struct msm_fb_data_type *mfd = (struct msm_fb_data_type *)data;
-	if (!mfd)
+	if (!mfd) {
 		pr_err("%s mfd NULL\n", __func__);
+		return;
+	}
 	mfd->no_update.value = NOTIFY_TYPE_NO_UPDATE;
 	complete(&mfd->no_update.comp);
 }
@@ -107,9 +109,10 @@
 static int mdss_fb_notify_update(struct msm_fb_data_type *mfd,
 							unsigned long *argp)
 {
-	int ret, notify, to_user;
+	int ret;
+	unsigned long notify = 0x0, to_user = 0x0;
 
-	ret = copy_from_user(&notify, argp, sizeof(int));
+	ret = copy_from_user(&notify, argp, sizeof(unsigned long));
 	if (ret) {
 		pr_err("%s:ioctl failed\n", __func__);
 		return ret;
@@ -122,12 +125,12 @@
 		INIT_COMPLETION(mfd->update.comp);
 		ret = wait_for_completion_interruptible_timeout(
 						&mfd->update.comp, 4 * HZ);
-		to_user = mfd->update.value;
+		to_user = (unsigned int)mfd->update.value;
 	} else if (notify == NOTIFY_UPDATE_STOP) {
 		INIT_COMPLETION(mfd->no_update.comp);
 		ret = wait_for_completion_interruptible_timeout(
 						&mfd->no_update.comp, 4 * HZ);
-		to_user = mfd->no_update.value;
+		to_user = (unsigned int)mfd->no_update.value;
 	} else {
 		if (mfd->panel_power_on) {
 			INIT_COMPLETION(mfd->power_off_comp);
@@ -139,7 +142,7 @@
 	if (ret == 0)
 		ret = -ETIMEDOUT;
 	else if (ret > 0)
-		ret = copy_to_user(argp, &to_user, sizeof(int));
+		ret = copy_to_user(argp, &to_user, sizeof(unsigned long));
 	return ret;
 }
 
@@ -616,11 +619,11 @@
 		 * scaling fraction (x/1024)
 		 */
 		temp = (temp * mfd->bl_scale) / 1024;
-	}
-	/*if less than minimum level, use min level*/
-	else if ((temp < mfd->bl_min_lvl) && (0 != temp))
-		temp = mfd->bl_min_lvl;
 
+		/*if less than minimum level, use min level*/
+		if (temp < mfd->bl_min_lvl)
+			temp = mfd->bl_min_lvl;
+	}
 	pr_debug("output = %d", temp);
 
 	(*bl_lvl) = temp;
@@ -635,11 +638,8 @@
 
 	if (((!mfd->panel_power_on && mfd->dcm_state != DCM_ENTER)
 		|| !mfd->bl_updated) && !IS_CALIB_MODE_BL(mfd)) {
-			if (bkl_lvl < mfd->bl_min_lvl)
-				mfd->unset_bl_level = mfd->bl_min_lvl;
-			else
-				mfd->unset_bl_level = bkl_lvl;
-			return;
+		mfd->unset_bl_level = bkl_lvl;
+		return;
 	} else {
 		mfd->unset_bl_level = 0;
 	}
@@ -708,8 +708,10 @@
 	case FB_BLANK_UNBLANK:
 		if (!mfd->panel_power_on && mfd->mdp.on_fnc) {
 			ret = mfd->mdp.on_fnc(mfd);
-			if (ret == 0)
+			if (ret == 0) {
 				mfd->panel_power_on = true;
+				mfd->panel_info->panel_dead = false;
+			}
 			mutex_lock(&mfd->update.lock);
 			mfd->update.type = NOTIFY_TYPE_UPDATE;
 			mutex_unlock(&mfd->update.lock);
@@ -1413,7 +1415,7 @@
 	u32 wait_for_finish = disp_commit->wait_for_finish;
 	int ret = 0;
 
-	if ((!mfd->op_enable) || (!mfd->panel_power_on))
+	if (!mfd || (!mfd->op_enable) || (!mfd->panel_power_on))
 		return -EPERM;
 
 	if (var->xoffset > (info->var.xres_virtual - info->var.xres))
@@ -1972,7 +1974,8 @@
 		return -EINVAL;
 	mfd = (struct msm_fb_data_type *)info->par;
 	mdss_fb_power_setting_idle(mfd);
-	if ((cmd != MSMFB_VSYNC_CTRL) && (cmd != MSMFB_OVERLAY_VSYNC_CTRL))
+	if ((cmd != MSMFB_VSYNC_CTRL) && (cmd != MSMFB_OVERLAY_VSYNC_CTRL) &&
+			(cmd != MSMFB_ASYNC_BLIT) && (cmd != MSMFB_BLIT))
 		mdss_fb_pan_idle(mfd);
 
 	switch (cmd) {
diff --git a/drivers/video/msm/mdss/mdss_hdmi_edid.c b/drivers/video/msm/mdss/mdss_hdmi_edid.c
index cf0c287..a45876b 100644
--- a/drivers/video/msm/mdss/mdss_hdmi_edid.c
+++ b/drivers/video/msm/mdss/mdss_hdmi_edid.c
@@ -16,6 +16,13 @@
 #include "mdss_hdmi_edid.h"
 
 #define DBC_START_OFFSET 4
+
+/*
+ * As per CEA-861-E specification 7.5.2, there can be
+ * upto 31 bytes following any tag (data block type).
+ */
+#define MAX_DATA_BLOCK_SIZE 31
+
 #define HDMI_VSDB_3D_EVF_DATA_OFFSET(vsd) \
 	(!((vsd)[8] & BIT(7)) ? 9 : (!((vsd)[8] & BIT(6)) ? 11 : 13))
 
@@ -32,6 +39,17 @@
 /* Support for first 5 EDID blocks */
 #define MAX_EDID_BLOCK_SIZE (0x80 * 5)
 
+enum data_block_types {
+	RESERVED,
+	AUDIO_DATA_BLOCK,
+	VIDEO_DATA_BLOCK,
+	VENDOR_SPECIFIC_DATA_BLOCK,
+	SPEAKER_ALLOCATION_DATA_BLOCK,
+	VESA_DTC_DATA_BLOCK,
+	RESERVED2,
+	USE_EXTENDED_TAG
+};
+
 struct hdmi_edid_sink_data {
 	u32 disp_mode_list[HDMI_VFRMT_MAX];
 	u32 disp_3d_mode_list[HDMI_VFRMT_MAX];
@@ -524,7 +542,8 @@
 	}
 
 	/* A Tage code of 7 identifies extended data blocks */
-	etag = hdmi_edid_find_block(in_buf, start_offset, 7, &len);
+	etag = hdmi_edid_find_block(in_buf, start_offset, USE_EXTENDED_TAG,
+		&len);
 
 	while (etag != NULL) {
 		/* The extended data block should at least be 2 bytes long */
@@ -570,7 +589,8 @@
 
 		/* There could be more that one extended data block */
 		start_offset = etag - in_buf + len + 1;
-		etag = hdmi_edid_find_block(in_buf, start_offset, 7, &len);
+		etag = hdmi_edid_find_block(in_buf, start_offset,
+			USE_EXTENDED_TAG, &len);
 	}
 } /* hdmi_edid_extract_extended_data_blocks */
 
@@ -585,11 +605,12 @@
 		return;
 	}
 
-	vsd = hdmi_edid_find_block(in_buf, DBC_START_OFFSET, 3, &len);
+	vsd = hdmi_edid_find_block(in_buf, DBC_START_OFFSET,
+		VENDOR_SPECIFIC_DATA_BLOCK, &len);
 
 	edid_ctrl->present_3d = 0;
-	if (vsd == NULL || len < 9) {
-		DEV_DBG("%s: blk-id 3 not found or not long enough\n",
+	if (vsd == NULL || len == 0 || len > MAX_DATA_BLOCK_SIZE) {
+		DEV_DBG("%s: No/Invalid vendor Specific Data Block\n",
 			__func__);
 		return;
 	}
@@ -616,9 +637,13 @@
 		return;
 	}
 
-	adb = hdmi_edid_find_block(in_buf, DBC_START_OFFSET, 1, &len);
-	if ((adb == NULL) || (len > MAX_AUDIO_DATA_BLOCK_SIZE))
+	adb = hdmi_edid_find_block(in_buf, DBC_START_OFFSET, AUDIO_DATA_BLOCK,
+		&len);
+	if ((adb == NULL) || (len > MAX_AUDIO_DATA_BLOCK_SIZE)) {
+		DEV_DBG("%s: No/Invalid Audio Data Block\n",
+			__func__);
 		return;
+	}
 
 	memcpy(edid_ctrl->audio_data_block, adb + 1, len);
 	edid_ctrl->adb_size = len;
@@ -644,9 +669,13 @@
 		return;
 	}
 
-	sadb = hdmi_edid_find_block(in_buf, DBC_START_OFFSET, 4, &len);
-	if ((sadb == NULL) || (len != MAX_SPKR_ALLOC_DATA_BLOCK_SIZE))
+	sadb = hdmi_edid_find_block(in_buf, DBC_START_OFFSET,
+		SPEAKER_ALLOCATION_DATA_BLOCK, &len);
+	if ((sadb == NULL) || (len != MAX_SPKR_ALLOC_DATA_BLOCK_SIZE)) {
+		DEV_DBG("%s: No/Invalid Speaker Allocation Data Block\n",
+			__func__);
 		return;
+	}
 
 	memcpy(edid_ctrl->spkr_alloc_data_block, sadb + 1, len);
 	edid_ctrl->sadb_size = len;
@@ -673,9 +702,11 @@
 		return;
 	}
 
-	vsd = hdmi_edid_find_block(in_buf, DBC_START_OFFSET, 3, &len);
+	vsd = hdmi_edid_find_block(in_buf, DBC_START_OFFSET,
+		VENDOR_SPECIFIC_DATA_BLOCK, &len);
 
-	if (vsd == NULL || len < 12 || !(vsd[8] & BIT(7))) {
+	if (vsd == NULL || len == 0 || len > MAX_DATA_BLOCK_SIZE ||
+		!(vsd[8] & BIT(7))) {
 		edid_ctrl->video_latency = (u16)-1;
 		edid_ctrl->audio_latency = (u16)-1;
 		DEV_DBG("%s: EDID: No audio/video latency present\n", __func__);
@@ -699,9 +730,14 @@
 		return 0;
 	}
 
-	vsd = hdmi_edid_find_block(in_buf, DBC_START_OFFSET, 3, &len);
-	if (vsd == NULL || len < 8)
+	vsd = hdmi_edid_find_block(in_buf, DBC_START_OFFSET,
+		VENDOR_SPECIFIC_DATA_BLOCK, &len);
+
+	if (vsd == NULL || len == 0 || len > MAX_DATA_BLOCK_SIZE) {
+		DEV_DBG("%s: No/Invalid Vendor Specific Data Block\n",
+			__func__);
 		return 0;
+	}
 
 	DEV_DBG("%s: EDID: VSD PhyAddr=%04x, MaxTMDS=%dMHz\n", __func__,
 		((u32)vsd[4] << 8) + (u32)vsd[5], (u32)vsd[7] * 5);
@@ -898,11 +934,14 @@
 	u16 structure_all, structure_mask;
 	const u8 *vsd = num_of_cea_blocks ?
 		hdmi_edid_find_block(data_buf+0x80, DBC_START_OFFSET,
-				3, &len) : NULL;
+			VENDOR_SPECIFIC_DATA_BLOCK, &len) : NULL;
 	int i;
 
-	if (!vsd)
+	if (vsd == NULL || len == 0 || len > MAX_DATA_BLOCK_SIZE) {
+		DEV_DBG("%s: No/Invalid Vendor Specific Data Block\n",
+			__func__);
 		return -ENXIO;
+	}
 
 	offset = HDMI_VSDB_3D_EVF_DATA_OFFSET(vsd);
 	if (offset >= len - 1)
@@ -1044,10 +1083,11 @@
 		return;
 	}
 
-	vsd = hdmi_edid_find_block(in_buf, DBC_START_OFFSET, 3, &db_len);
+	vsd = hdmi_edid_find_block(in_buf, DBC_START_OFFSET,
+		VENDOR_SPECIFIC_DATA_BLOCK, &db_len);
 
-	if (vsd == NULL || db_len < 9) {
-		DEV_DBG("%s: blk-id 3 not found or not long enough\n",
+	if (vsd == NULL || db_len == 0 || db_len > MAX_DATA_BLOCK_SIZE) {
+		DEV_DBG("%s: No/Invalid Vendor Specific Data Block\n",
 			__func__);
 		return;
 	}
@@ -1097,8 +1137,14 @@
 	edid_blk0 = &data_buf[0x0];
 	edid_blk1 = &data_buf[0x80];
 	svd = num_of_cea_blocks ?
-		hdmi_edid_find_block(data_buf+0x80, DBC_START_OFFSET, 2,
-			&len) : NULL;
+		hdmi_edid_find_block(data_buf+0x80, DBC_START_OFFSET,
+			VIDEO_DATA_BLOCK, &len) : NULL;
+
+	if (svd == NULL || len == 0 || len > MAX_DATA_BLOCK_SIZE) {
+		DEV_DBG("%s: No/Invalid Video Data Block\n",
+			__func__);
+		return;
+	}
 
 	sink_data = &edid_ctrl->sink_data;
 
diff --git a/drivers/video/msm/mdss/mdss_hdmi_hdcp.c b/drivers/video/msm/mdss/mdss_hdmi_hdcp.c
index 80b27ed..ca21b51 100644
--- a/drivers/video/msm/mdss/mdss_hdmi_hdcp.c
+++ b/drivers/video/msm/mdss/mdss_hdmi_hdcp.c
@@ -289,6 +289,10 @@
 	}
 	DEV_DBG("%s: %s: BCAPS=%02x\n", __func__, HDCP_STATE_NAME, bcaps);
 
+	/* receiver (0), repeater (1) */
+	hdcp_ctrl->current_tp.ds_type =
+		(bcaps & BIT(6)) >> 6 ? DS_REPEATER : DS_RECEIVER;
+
 	/*
 	 * HDCP setup prior to enabling HDCP_CTRL.
 	 * Setup seed values for random number An.
@@ -644,40 +648,12 @@
 	memset(ksv_fifo, 0,
 		sizeof(hdcp_ctrl->current_tp.ksv_list));
 
-	/* Read BCAPS at offset 0x40 */
-	memset(&ddc_data, 0, sizeof(ddc_data));
-	ddc_data.dev_addr = 0x74;
-	ddc_data.offset = 0x40;
-	ddc_data.data_buf = &bcaps;
-	ddc_data.data_len = 1;
-	ddc_data.request_len = 1;
-	ddc_data.retry = 5;
-	ddc_data.what = "Bcaps";
-	ddc_data.no_align = false;
-	rc = hdmi_ddc_read(hdcp_ctrl->init_data.ddc_ctrl, &ddc_data);
-	if (rc) {
-		DEV_ERR("%s: %s: BCAPS read failed\n", __func__,
-			HDCP_STATE_NAME);
-		goto error;
-	}
-	DEV_DBG("%s: %s: BCAPS=%02x (%s)\n", __func__, HDCP_STATE_NAME, bcaps,
-		(bcaps & BIT(6)) ? "repeater" : "no repeater");
-
-	/* receiver (0), repeater (1) */
-	hdcp_ctrl->current_tp.ds_type =
-		(bcaps & BIT(6)) >> 6 ? DS_REPEATER : DS_RECEIVER;
-
-	/* if REPEATER (Bit 6), perform Part2 Authentication */
-	if (!(bcaps & BIT(6))) {
-		DEV_INFO("%s: %s: auth part II skipped, no repeater\n",
-			__func__, HDCP_STATE_NAME);
-		return 0;
-	}
-
-	/* Wait until READY bit is set in BCAPS */
+	/*
+	 * Wait until READY bit is set in BCAPS, as per HDCP specifications
+	 * maximum permitted time to check for READY bit is five seconds.
+	 */
 	timeout_count = 50;
-	while (!(bcaps & BIT(5)) && timeout_count) {
-		msleep(100);
+	do {
 		timeout_count--;
 		/* Read BCAPS at offset 0x40 */
 		memset(&ddc_data, 0, sizeof(ddc_data));
@@ -695,7 +671,8 @@
 				HDCP_STATE_NAME);
 			goto error;
 		}
-	}
+		msleep(100);
+	} while (!(bcaps & BIT(5)) && timeout_count);
 
 	/* Read BSTATUS at offset 0x41 */
 	memset(&ddc_data, 0, sizeof(ddc_data));
@@ -976,11 +953,15 @@
 		goto error;
 	}
 
-	rc = hdmi_hdcp_authentication_part2(hdcp_ctrl);
-	if (rc) {
-		DEV_DBG("%s: %s: HDCP Auth Part II failed\n", __func__,
-			HDCP_STATE_NAME);
-		goto error;
+	if (hdcp_ctrl->current_tp.ds_type == DS_REPEATER) {
+		rc = hdmi_hdcp_authentication_part2(hdcp_ctrl);
+		if (rc) {
+			DEV_DBG("%s: %s: HDCP Auth Part II failed\n", __func__,
+				HDCP_STATE_NAME);
+			goto error;
+		}
+	} else {
+		DEV_INFO("%s: Downstream device is not a repeater\n", __func__);
 	}
 	/* Disabling software DDC before going into part3 to make sure
 	 * there is no Arbitration between software and hardware for DDC */
diff --git a/drivers/video/msm/mdss/mdss_hdmi_tx.c b/drivers/video/msm/mdss/mdss_hdmi_tx.c
index 0cd0543..87b7526 100644
--- a/drivers/video/msm/mdss/mdss_hdmi_tx.c
+++ b/drivers/video/msm/mdss/mdss_hdmi_tx.c
@@ -2493,6 +2493,10 @@
 	mutex_unlock(&hdmi_ctrl->mutex);
 
 	DEV_INFO("%s: HDMI Core: OFF\n", __func__);
+
+	if (hdmi_ctrl->hdmi_tx_hpd_done)
+		hdmi_ctrl->hdmi_tx_hpd_done(
+			hdmi_ctrl->downstream_data);
 } /* hdmi_tx_power_off_work */
 
 static int hdmi_tx_power_off(struct mdss_panel_data *panel_data)
@@ -2595,6 +2599,9 @@
 
 	hdmi_tx_hpd_polarity_setup(hdmi_ctrl, HPD_DISCONNECT_POLARITY);
 
+	if (hdmi_ctrl->hdmi_tx_hpd_done)
+		hdmi_ctrl->hdmi_tx_hpd_done(hdmi_ctrl->downstream_data);
+
 	return 0;
 } /* hdmi_tx_power_on */
 
diff --git a/drivers/video/msm/mdss/mdss_hdmi_tx.h b/drivers/video/msm/mdss/mdss_hdmi_tx.h
index 5f2a23e..66071e9 100644
--- a/drivers/video/msm/mdss/mdss_hdmi_tx.h
+++ b/drivers/video/msm/mdss/mdss_hdmi_tx.h
@@ -86,6 +86,9 @@
 
 	struct hdmi_tx_ddc_ctrl ddc_ctrl;
 
+	void (*hdmi_tx_hpd_done) (void *data);
+	void *downstream_data;
+
 	void *feature_data[HDMI_TX_FEAT_MAX];
 };
 
diff --git a/drivers/video/msm/mdss/mdss_mdp.h b/drivers/video/msm/mdss/mdss_mdp.h
index 5442d9d..d140ea0 100644
--- a/drivers/video/msm/mdss/mdss_mdp.h
+++ b/drivers/video/msm/mdss/mdss_mdp.h
@@ -37,7 +37,6 @@
 #define MAX_IMG_HEIGHT		0x3FFF
 #define MAX_DST_W		MAX_MIXER_WIDTH
 #define MAX_DST_H		MAX_MIXER_HEIGHT
-#define MAX_PLANES		4
 #define MAX_DOWNSCALE_RATIO	4
 #define MAX_UPSCALE_RATIO	20
 #define MAX_DECIMATION		4
@@ -52,6 +51,11 @@
 /* wait for at most 2 vsync for lowest refresh rate (24hz) */
 #define KOFF_TIMEOUT msecs_to_jiffies(84)
 
+#define OVERFETCH_DISABLE_TOP		BIT(0)
+#define OVERFETCH_DISABLE_BOTTOM	BIT(1)
+#define OVERFETCH_DISABLE_LEFT		BIT(2)
+#define OVERFETCH_DISABLE_RIGHT		BIT(3)
+
 #ifdef MDSS_MDP_DEBUG_REG
 static inline void mdss_mdp_reg_write(u32 addr, u32 val)
 {
@@ -341,9 +345,6 @@
 	u8 vert_deci;
 	struct mdss_mdp_img_rect src;
 	struct mdss_mdp_img_rect dst;
-	u32 phase_step_x;
-	u32 phase_step_y;
-
 	struct mdss_mdp_format_params *src_fmt;
 	struct mdss_mdp_plane_sizes src_planes;
 
@@ -370,11 +371,13 @@
 
 	struct mdp_overlay_pp_params pp_cfg;
 	struct mdss_pipe_pp_res pp_res;
+	struct mdp_scale_data scale;
+	u8 chroma_sample_h;
+	u8 chroma_sample_v;
 };
 
 struct mdss_mdp_writeback_arg {
 	struct mdss_mdp_data *data;
-	void (*callback_fnc) (void *arg);
 	void *priv_data;
 };
 
@@ -633,6 +636,7 @@
 int mdss_mdp_wb_set_secure(struct msm_fb_data_type *mfd, int enable);
 int mdss_mdp_wb_get_secure(struct msm_fb_data_type *mfd, uint8_t *enable);
 
+int mdss_mdp_pipe_program_pixel_extn(struct mdss_mdp_pipe *pipe);
 #define mfd_to_mdp5_data(mfd) (mfd->mdp.private1)
 #define mfd_to_mdata(mfd) (((struct mdss_overlay_private *)\
 				(mfd->mdp.private1))->mdata)
diff --git a/drivers/video/msm/mdss/mdss_mdp_ctl.c b/drivers/video/msm/mdss/mdss_mdp_ctl.c
index 82937e3..aa7c4dd 100644
--- a/drivers/video/msm/mdss/mdss_mdp_ctl.c
+++ b/drivers/video/msm/mdss/mdss_mdp_ctl.c
@@ -28,7 +28,7 @@
 #define MDSS_MDP_BUS_FUDGE_FACTOR_IB(val) (((val) / 2) * 3)
 #define MDSS_MDP_BUS_FUDGE_FACTOR_HIGH_IB(val) (val << 1)
 #define MDSS_MDP_BUS_FUDGE_FACTOR_AB(val) (val << 1)
-#define MDSS_MDP_BUS_FLOOR_BW (3200000000ULL >> MDSS_MDP_BUS_FACTOR_SHIFT)
+#define MDSS_MDP_BUS_FLOOR_BW (1600000000ULL >> MDSS_MDP_BUS_FACTOR_SHIFT)
 
 /* 1.25 clock fudge factor */
 #define MDSS_MDP_CLK_FUDGE_FACTOR(val) (((val) * 5) / 4)
@@ -1560,9 +1560,17 @@
 struct mdss_mdp_mixer *mdss_mdp_mixer_get(struct mdss_mdp_ctl *ctl, int mux)
 {
 	struct mdss_mdp_mixer *mixer = NULL;
-	struct mdss_overlay_private *mdp5_data = mfd_to_mdp5_data(ctl->mfd);
-	if (!ctl)
+	struct mdss_overlay_private *mdp5_data = NULL;
+	if (!ctl || !ctl->mfd) {
+		pr_err("ctl not initialized\n");
 		return NULL;
+	}
+
+	mdp5_data = mfd_to_mdp5_data(ctl->mfd);
+	if (!mdp5_data) {
+		pr_err("ctl not initialized\n");
+		return NULL;
+	}
 
 	switch (mux) {
 	case MDSS_MDP_MIXER_MUX_DEFAULT:
diff --git a/drivers/video/msm/mdss/mdss_mdp_hwio.h b/drivers/video/msm/mdss/mdss_mdp_hwio.h
index c8af903..52ca42c 100644
--- a/drivers/video/msm/mdss/mdss_mdp_hwio.h
+++ b/drivers/video/msm/mdss/mdss_mdp_hwio.h
@@ -201,6 +201,9 @@
 #define MDSS_MDP_REG_SSPP_CURRENT_SRC2_ADDR		0x0AC
 #define MDSS_MDP_REG_SSPP_CURRENT_SRC3_ADDR		0x0B0
 #define MDSS_MDP_REG_SSPP_DECIMATION_CONFIG		0x0B4
+#define MDSS_MDP_REG_SSPP_SW_PIX_EXT_C0_LR		0x100
+#define MDSS_MDP_REG_SSPP_SW_PIX_EXT_C0_TB		0x104
+#define MDSS_MDP_REG_SSPP_SW_PIX_EXT_C0_REQ_PIXELS	0x108
 
 #define MDSS_MDP_REG_VIG_OP_MODE			0x200
 #define MDSS_MDP_REG_VIG_QSEED2_CONFIG			0x204
diff --git a/drivers/video/msm/mdss/mdss_mdp_intf_cmd.c b/drivers/video/msm/mdss/mdss_mdp_intf_cmd.c
index 6056f21..d3e18ac 100644
--- a/drivers/video/msm/mdss/mdss_mdp_intf_cmd.c
+++ b/drivers/video/msm/mdss/mdss_mdp_intf_cmd.c
@@ -532,6 +532,7 @@
 int mdss_mdp_cmd_stop(struct mdss_mdp_ctl *ctl)
 {
 	struct mdss_mdp_cmd_ctx *ctx;
+	struct mdss_panel_info *pinfo;
 	unsigned long flags;
 	struct mdss_mdp_vsync_handler *tmp, *handle;
 	int need_wait = 0;
@@ -555,9 +556,23 @@
 
 	if (need_wait)
 		if (wait_for_completion_timeout(&ctx->stop_comp, STOP_TIMEOUT)
-		    <= 0)
+		    <= 0) {
 			WARN(1, "stop cmd time out\n");
 
+			if (IS_ERR_OR_NULL(ctl->panel_data)) {
+				pr_err("no panel data\n");
+			} else {
+				pinfo = &ctl->panel_data->panel_info;
+
+				if (pinfo->panel_dead) {
+					mdss_mdp_irq_disable
+						(MDSS_MDP_IRQ_PING_PONG_RD_PTR,
+								ctx->pp_num);
+					ctx->rdptr_enabled = 0;
+				}
+			}
+		}
+
 	if (cancel_work_sync(&ctx->clk_work))
 		pr_debug("no pending clk work\n");
 
diff --git a/drivers/video/msm/mdss/mdss_mdp_intf_video.c b/drivers/video/msm/mdss/mdss_mdp_intf_video.c
index 7c79ceb..bd1c3eb 100644
--- a/drivers/video/msm/mdss/mdss_mdp_intf_video.c
+++ b/drivers/video/msm/mdss/mdss_mdp_intf_video.c
@@ -294,6 +294,7 @@
 	struct mdss_mdp_video_ctx *ctx;
 	struct mdss_mdp_vsync_handler *tmp, *handle;
 	int rc;
+	u32 frame_rate = 0;
 
 	pr_debug("stop ctl=%d\n", ctl->num);
 
@@ -313,6 +314,14 @@
 		WARN(rc, "intf %d blank error (%d)\n", ctl->intf_num, rc);
 
 		mdp_video_write(ctx, MDSS_MDP_REG_INTF_TIMING_ENGINE_EN, 0);
+		/* wait for at least one VSYNC on HDMI intf for proper TG OFF */
+		if (MDSS_INTF_HDMI == ctx->intf_type) {
+			frame_rate = mdss_panel_get_framerate
+					(&(ctl->panel_data->panel_info));
+			if (!(frame_rate >= 24 && frame_rate <= 240))
+				frame_rate = 24;
+			msleep((1000/frame_rate) + 1);
+		}
 		mdss_mdp_clk_ctrl(MDP_BLOCK_POWER_OFF, false);
 		ctx->timegen_en = false;
 
@@ -429,10 +438,9 @@
 		} else {
 			rc = 0;
 		}
-
-		mdss_mdp_ctl_notify(ctl,
-			rc ? MDP_NOTIFY_FRAME_TIMEOUT : MDP_NOTIFY_FRAME_DONE);
 	}
+	mdss_mdp_ctl_notify(ctl,
+			rc ? MDP_NOTIFY_FRAME_TIMEOUT : MDP_NOTIFY_FRAME_DONE);
 
 	if (ctx->wait_pending) {
 		ctx->wait_pending = 0;
diff --git a/drivers/video/msm/mdss/mdss_mdp_intf_writeback.c b/drivers/video/msm/mdss/mdss_mdp_intf_writeback.c
index 3929501..ff55c57 100644
--- a/drivers/video/msm/mdss/mdss_mdp_intf_writeback.c
+++ b/drivers/video/msm/mdss/mdss_mdp_intf_writeback.c
@@ -46,8 +46,6 @@
 
 	struct mdss_mdp_plane_sizes dst_planes;
 
-	void (*callback_fnc) (void *arg);
-	void *callback_arg;
 	spinlock_t wb_lock;
 	struct list_head vsync_handlers;
 };
@@ -365,6 +363,8 @@
 		mdss_mdp_set_intr_callback(ctx->intr_type, ctx->intf_num,
 				NULL, NULL);
 
+		complete_all(&ctx->wb_comp);
+
 		ctl->priv_data = NULL;
 		ctx->ref_cnt--;
 	}
@@ -389,9 +389,6 @@
 
 	mdss_mdp_irq_disable_nosync(ctx->intr_type, ctx->intf_num);
 
-	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);
@@ -467,9 +464,6 @@
 	mdss_mdp_set_intr_callback(ctx->intr_type, ctx->intf_num,
 		   mdss_mdp_writeback_intr_done, ctl);
 
-	ctx->callback_fnc = wb_args->callback_fnc;
-	ctx->callback_arg = wb_args->priv_data;
-
 	flush_bits = BIT(16); /* WB */
 	mdp_wb_write(ctx, MDSS_MDP_REG_WB_DST_ADDR_SW_STATUS, ctl->is_secure);
 	mdss_mdp_ctl_write(ctl, MDSS_MDP_REG_CTL_FLUSH, flush_bits);
@@ -529,6 +523,8 @@
 
 int mdss_mdp_writeback_display_commit(struct mdss_mdp_ctl *ctl, void *arg)
 {
+	int ret = 0;
+
 	if (ctl->shared_lock && !mutex_is_locked(ctl->shared_lock)) {
 		pr_err("shared mutex is not locked before commit on ctl=%d\n",
 			ctl->num);
@@ -542,5 +538,10 @@
 			ctl->mixer_right->params_changed++;
 	}
 
-	return mdss_mdp_display_commit(ctl, arg);
+	ret = mdss_mdp_display_commit(ctl, arg);
+
+	if (!IS_ERR_VALUE(ret))
+		mdss_mdp_display_wait4comp(ctl);
+
+	return ret;
 }
diff --git a/drivers/video/msm/mdss/mdss_mdp_overlay.c b/drivers/video/msm/mdss/mdss_mdp_overlay.c
index c296edb..0fb01ad 100644
--- a/drivers/video/msm/mdss/mdss_mdp_overlay.c
+++ b/drivers/video/msm/mdss/mdss_mdp_overlay.c
@@ -282,7 +282,12 @@
 	int rc;
 
 	src = pipe->src.w >> pipe->horz_deci;
-	rc = mdss_mdp_calc_phase_step(src, pipe->dst.w, &pipe->phase_step_x);
+
+	if (pipe->scale.enable_pxl_ext)
+		return 0;
+	memset(&pipe->scale, 0, sizeof(struct mdp_scale_data));
+	rc = mdss_mdp_calc_phase_step(src, pipe->dst.w,
+			&pipe->scale.phase_step_x[0]);
 	if (rc) {
 		pr_err("Horizontal scaling calculation failed=%d! %d->%d\n",
 				rc, src, pipe->dst.w);
@@ -290,16 +295,43 @@
 	}
 
 	src = pipe->src.h >> pipe->vert_deci;
-	rc = mdss_mdp_calc_phase_step(src, pipe->dst.h, &pipe->phase_step_y);
+	rc = mdss_mdp_calc_phase_step(src, pipe->dst.h,
+			&pipe->scale.phase_step_y[0]);
 	if (rc) {
 		pr_err("Vertical scaling calculation failed=%d! %d->%d\n",
 				rc, src, pipe->dst.h);
 		return rc;
 	}
-
+	pipe->scale.init_phase_x[0] = (pipe->scale.phase_step_x[0] -
+					(1 << PHASE_STEP_SHIFT)) / 2;
+	pipe->scale.init_phase_y[0] = (pipe->scale.phase_step_y[0] -
+					(1 << PHASE_STEP_SHIFT)) / 2;
 	return 0;
 }
 
+static inline void __mdss_mdp_overlay_set_chroma_sample(
+	struct mdss_mdp_pipe *pipe)
+{
+	pipe->chroma_sample_v = pipe->chroma_sample_h = 0;
+
+	switch (pipe->src_fmt->chroma_sample) {
+	case MDSS_MDP_CHROMA_H1V2:
+		pipe->chroma_sample_v = 1;
+		break;
+	case MDSS_MDP_CHROMA_H2V1:
+		pipe->chroma_sample_h = 1;
+		break;
+	case MDSS_MDP_CHROMA_420:
+		pipe->chroma_sample_v = 1;
+		pipe->chroma_sample_h = 1;
+		break;
+	}
+	if (pipe->horz_deci)
+		pipe->chroma_sample_h = 0;
+	if (pipe->vert_deci)
+		pipe->chroma_sample_v = 0;
+}
+
 static int mdss_mdp_overlay_pipe_setup(struct msm_fb_data_type *mfd,
 				       struct mdp_overlay *req,
 				       struct mdss_mdp_pipe **ppipe)
@@ -442,7 +474,10 @@
 	pipe->dst.h = req->dst_rect.h;
 	pipe->horz_deci = req->horz_deci;
 	pipe->vert_deci = req->vert_deci;
+
+	memcpy(&pipe->scale, &req->scale, sizeof(struct mdp_scale_data));
 	pipe->src_fmt = fmt;
+	__mdss_mdp_overlay_set_chroma_sample(pipe);
 
 	pipe->mixer_stage = req->z_order;
 	pipe->is_fg = req->is_fg;
@@ -458,8 +493,17 @@
 		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);
+	if (fmt->is_yuv && !(pipe->flags & MDP_SOURCE_ROTATED_90) &&
+			!pipe->scale.enable_pxl_ext) {
+		pipe->overfetch_disable = OVERFETCH_DISABLE_BOTTOM;
+
+		if (!(pipe->flags & MDSS_MDP_DUAL_PIPE) ||
+				(pipe->flags & MDSS_MDP_RIGHT_MIXER))
+			pipe->overfetch_disable |= OVERFETCH_DISABLE_RIGHT;
+		pr_debug("overfetch flags=%x\n", pipe->overfetch_disable);
+	} else {
+		pipe->overfetch_disable = 0;
+	}
 
 	req->id = pipe->ndx;
 	pipe->req_data = *req;
@@ -516,7 +560,7 @@
 		}
 	}
 
-	if (pipe->flags & MDP_DEINTERLACE) {
+	if ((pipe->flags & MDP_DEINTERLACE) && !pipe->scale.enable_pxl_ext) {
 		if (pipe->flags & MDP_SOURCE_ROTATED_90) {
 			pipe->src.w /= 2;
 			pipe->img_width /= 2;
@@ -539,6 +583,12 @@
 		!mdp5_data->mdata->has_wfd_blk)
 		mdss_mdp_smp_release(pipe);
 
+	/*
+	 * Clear previous SMP reservations and reserve according to the
+	 * latest configuration
+	 */
+	mdss_mdp_smp_unreserve(pipe);
+
 	ret = mdss_mdp_smp_reserve(pipe);
 	if (ret) {
 		pr_debug("mdss_mdp_smp_reserve failed. ret=%d\n", ret);
@@ -1475,15 +1525,26 @@
 static void mdss_mdp_overlay_handle_vsync(struct mdss_mdp_ctl *ctl,
 						ktime_t t)
 {
-	struct msm_fb_data_type *mfd = ctl->mfd;
-	struct mdss_overlay_private *mdp5_data;
+	struct msm_fb_data_type *mfd = NULL;
+	struct mdss_overlay_private *mdp5_data = NULL;
 
+	if (!ctl) {
+		pr_err("ctl is NULL\n");
+		return;
+	}
+
+	mfd = ctl->mfd;
 	if (!mfd || !mfd->mdp.private1) {
 		pr_warn("Invalid handle for vsync\n");
 		return;
 	}
 
 	mdp5_data = mfd_to_mdp5_data(mfd);
+	if (!mdp5_data) {
+		pr_err("mdp5_data is NULL\n");
+		return;
+	}
+
 	pr_debug("vsync on fb%d play_cnt=%d\n", mfd->index, ctl->play_cnt);
 
 	mdp5_data->vsync_time = t;
@@ -2111,7 +2172,7 @@
 					  u32 cmd, void __user *argp)
 {
 	struct mdss_overlay_private *mdp5_data = mfd_to_mdp5_data(mfd);
-	struct mdp_overlay req;
+	struct mdp_overlay *req = NULL;
 	int val, ret = -ENOSYS;
 	struct msmfb_metadata metadata;
 
@@ -2127,12 +2188,15 @@
 		break;
 
 	case MSMFB_OVERLAY_GET:
-		ret = copy_from_user(&req, argp, sizeof(req));
+		req = kmalloc(sizeof(struct mdp_overlay), GFP_KERNEL);
+		if (!req)
+			return -ENOMEM;
+		ret = copy_from_user(req, argp, sizeof(*req));
 		if (!ret) {
-			ret = mdss_mdp_overlay_get(mfd, &req);
+			ret = mdss_mdp_overlay_get(mfd, req);
 
 			if (!IS_ERR_VALUE(ret))
-				ret = copy_to_user(argp, &req, sizeof(req));
+				ret = copy_to_user(argp, req, sizeof(*req));
 		}
 
 		if (ret)
@@ -2140,12 +2204,15 @@
 		break;
 
 	case MSMFB_OVERLAY_SET:
-		ret = copy_from_user(&req, argp, sizeof(req));
+		req = kmalloc(sizeof(struct mdp_overlay), GFP_KERNEL);
+		if (!req)
+			return -ENOMEM;
+		ret = copy_from_user(req, argp, sizeof(*req));
 		if (!ret) {
-			ret = mdss_mdp_overlay_set(mfd, &req);
+			ret = mdss_mdp_overlay_set(mfd, req);
 
 			if (!IS_ERR_VALUE(ret))
-				ret = copy_to_user(argp, &req, sizeof(req));
+				ret = copy_to_user(argp, req, sizeof(*req));
 		}
 		if (ret)
 			pr_debug("OVERLAY_SET failed (%d)\n", ret);
@@ -2230,6 +2297,7 @@
 		break;
 	}
 
+	kfree(req);
 	return ret;
 }
 
diff --git a/drivers/video/msm/mdss/mdss_mdp_pipe.c b/drivers/video/msm/mdss/mdss_mdp_pipe.c
index 779f74c..25cb9dd 100644
--- a/drivers/video/msm/mdss/mdss_mdp_pipe.c
+++ b/drivers/video/msm/mdss/mdss_mdp_pipe.c
@@ -581,6 +581,8 @@
 	mdss_mdp_smp_free(pipe);
 	pipe->flags = 0;
 	pipe->bwc_mode = 0;
+	memset(&pipe->scale, 0, sizeof(struct mdp_scale_data));
+
 	mdss_mdp_clk_ctrl(MDP_BLOCK_POWER_OFF, false);
 
 	return 0;
@@ -728,24 +730,43 @@
 	dst = pipe->dst;
 	src = pipe->src;
 
-	mdss_mdp_crop_rect(&src, &dst, &sci);
+	if (pipe->mixer->type == MDSS_MDP_MIXER_TYPE_INTF)
+		mdss_mdp_crop_rect(&src, &dst, &sci);
 
 	src_size = (src.h << 16) | src.w;
 	src_xy = (src.y << 16) | src.x;
 	dst_size = (dst.h << 16) | dst.w;
 	dst_xy = (dst.y << 16) | dst.x;
 
-	img_size = (height << 16) | width;
-
 	ystride0 =  (pipe->src_planes.ystride[0]) |
 			(pipe->src_planes.ystride[1] << 16);
 	ystride1 =  (pipe->src_planes.ystride[2]) |
 			(pipe->src_planes.ystride[3] << 16);
 
-	if (pipe->overfetch_disable) {
-		img_size = src_size;
-		src_xy = 0;
+	/*
+	 * Software overfetch is used when scalar pixel extension is
+	 * not enabled
+	 */
+	if (pipe->overfetch_disable && !pipe->scale.enable_pxl_ext) {
+		if (pipe->overfetch_disable & OVERFETCH_DISABLE_BOTTOM) {
+			height = pipe->src.h;
+			if (!(pipe->overfetch_disable & OVERFETCH_DISABLE_TOP))
+				height += pipe->src.y;
+		}
+		if (pipe->overfetch_disable & OVERFETCH_DISABLE_RIGHT) {
+			width = pipe->src.w;
+			if (!(pipe->overfetch_disable & OVERFETCH_DISABLE_LEFT))
+				width += pipe->src.x;
+		}
+		if (pipe->overfetch_disable & OVERFETCH_DISABLE_LEFT)
+			src_xy &= ~0xFFFF;
+		if (pipe->overfetch_disable & OVERFETCH_DISABLE_TOP)
+			src_xy &= ~(0xFFFF << 16);
+
+		pr_debug("overfetch w=%d/%d h=%d/%d src_xy=0x%08x\n", width,
+			pipe->img_width, height, pipe->img_height, src_xy);
 	}
+	img_size = (height << 16) | width;
 
 	mdss_mdp_pipe_write(pipe, MDSS_MDP_REG_SSPP_SRC_IMG_SIZE, img_size);
 	mdss_mdp_pipe_write(pipe, MDSS_MDP_REG_SSPP_SRC_SIZE, src_size);
@@ -812,6 +833,9 @@
 
 	mdss_mdp_pipe_sspp_setup(pipe, &opmode);
 
+	if (pipe->scale.enable_pxl_ext)
+		opmode |= (1 << 31);
+
 	mdss_mdp_pipe_write(pipe, MDSS_MDP_REG_SSPP_SRC_FORMAT, src_format);
 	mdss_mdp_pipe_write(pipe, MDSS_MDP_REG_SSPP_SRC_UNPACK_PATTERN, unpack);
 	mdss_mdp_pipe_write(pipe, MDSS_MDP_REG_SSPP_SRC_OP_MODE, opmode);
@@ -843,33 +867,42 @@
 }
 
 static int mdss_mdp_src_addr_setup(struct mdss_mdp_pipe *pipe,
-				   struct mdss_mdp_data *data)
+				   struct mdss_mdp_data *src_data)
 {
 	struct mdss_data_type *mdata = mdss_mdp_get_mdata();
+	struct mdss_mdp_data data = *src_data;
 	int ret = 0;
 
 	pr_debug("pnum=%d\n", pipe->num);
 
-	data->bwc_enabled = pipe->bwc_mode;
+	data.bwc_enabled = pipe->bwc_mode;
 
-	ret = mdss_mdp_data_check(data, &pipe->src_planes);
+	ret = mdss_mdp_data_check(&data, &pipe->src_planes);
 	if (ret)
 		return ret;
 
-	if (pipe->overfetch_disable)
-		mdss_mdp_data_calc_offset(data, pipe->src.x, pipe->src.y,
+	if (pipe->overfetch_disable && !pipe->scale.enable_pxl_ext) {
+		u32 x = 0, y = 0;
+
+		if (pipe->overfetch_disable & OVERFETCH_DISABLE_LEFT)
+			x = pipe->src.x;
+		if (pipe->overfetch_disable & OVERFETCH_DISABLE_TOP)
+			y = pipe->src.y;
+
+		mdss_mdp_data_calc_offset(&data, x, y,
 			&pipe->src_planes, pipe->src_fmt);
+	}
 
 	/* planar format expects YCbCr, swap chroma planes if YCrCb */
 	if (mdata->mdp_rev < MDSS_MDP_HW_REV_102 &&
 			(pipe->src_fmt->fetch_planes == MDSS_MDP_PLANE_PLANAR)
 				&& (pipe->src_fmt->element[0] == C1_B_Cb))
-		swap(data->p[1].addr, data->p[2].addr);
+		swap(data.p[1].addr, data.p[2].addr);
 
-	mdss_mdp_pipe_write(pipe, MDSS_MDP_REG_SSPP_SRC0_ADDR, data->p[0].addr);
-	mdss_mdp_pipe_write(pipe, MDSS_MDP_REG_SSPP_SRC1_ADDR, data->p[1].addr);
-	mdss_mdp_pipe_write(pipe, MDSS_MDP_REG_SSPP_SRC2_ADDR, data->p[2].addr);
-	mdss_mdp_pipe_write(pipe, MDSS_MDP_REG_SSPP_SRC3_ADDR, data->p[3].addr);
+	mdss_mdp_pipe_write(pipe, MDSS_MDP_REG_SSPP_SRC0_ADDR, data.p[0].addr);
+	mdss_mdp_pipe_write(pipe, MDSS_MDP_REG_SSPP_SRC1_ADDR, data.p[1].addr);
+	mdss_mdp_pipe_write(pipe, MDSS_MDP_REG_SSPP_SRC2_ADDR, data.p[2].addr);
+	mdss_mdp_pipe_write(pipe, MDSS_MDP_REG_SSPP_SRC3_ADDR, data.p[3].addr);
 
 	return 0;
 }
@@ -900,8 +933,9 @@
 			     struct mdss_mdp_data *src_data)
 {
 	int ret = 0;
-	u32 params_changed, opmode;
 	struct mdss_mdp_ctl *ctl;
+	u32 params_changed;
+	u32 opmode = 0;
 
 	if (!pipe) {
 		pr_err("pipe not setup properly for queue\n");
@@ -982,3 +1016,53 @@
 {
 	return (pipe == pipe->mixer->stage_pipe[pipe->mixer_stage]);
 }
+
+static inline void __mdss_mdp_pipe_program_pixel_extn_helper(
+	struct mdss_mdp_pipe *pipe, u32 plane, u32 off)
+{
+	u32 src_h = pipe->src.h >> pipe->vert_deci;
+	u32 mask = 0xFF;
+
+	/*
+	 * CB CR plane required pxls need to be accounted
+	 * for chroma decimation.
+	 */
+	if (plane == 1)
+		src_h >>= pipe->chroma_sample_v;
+	writel_relaxed(((pipe->scale.right_ftch[plane] & mask) << 24)|
+		((pipe->scale.right_rpt[plane] & mask) << 16)|
+		((pipe->scale.left_ftch[plane] & mask) << 8)|
+		(pipe->scale.left_rpt[plane] & mask), pipe->base +
+			MDSS_MDP_REG_SSPP_SW_PIX_EXT_C0_LR + off);
+	writel_relaxed(((pipe->scale.btm_ftch[plane] & mask) << 24)|
+		((pipe->scale.btm_rpt[plane] & mask) << 16)|
+		((pipe->scale.top_ftch[plane] & mask) << 8)|
+		(pipe->scale.top_rpt[plane] & mask), pipe->base +
+			MDSS_MDP_REG_SSPP_SW_PIX_EXT_C0_TB + off);
+	mask = 0xFFFF;
+	writel_relaxed((((src_h + pipe->scale.num_ext_pxls_top[plane] +
+		pipe->scale.num_ext_pxls_btm[plane]) & mask) << 16) |
+		((pipe->scale.roi_w[plane] +
+		pipe->scale.num_ext_pxls_left[plane] +
+		pipe->scale.num_ext_pxls_right[plane]) & mask), pipe->base +
+			MDSS_MDP_REG_SSPP_SW_PIX_EXT_C0_REQ_PIXELS + off);
+}
+
+/**
+ * mdss_mdp_pipe_program_pixel_extn - Program the source pipe's
+ *				      sw pixel extension
+ * @pipe:	Source pipe struct containing pixel extn values
+ *
+ * Function programs the pixel extn values calculated during
+ * scale setup.
+ */
+int mdss_mdp_pipe_program_pixel_extn(struct mdss_mdp_pipe *pipe)
+{
+	/* Y plane pixel extn */
+	__mdss_mdp_pipe_program_pixel_extn_helper(pipe, 0, 0);
+	/* CB CR plane pixel extn */
+	__mdss_mdp_pipe_program_pixel_extn_helper(pipe, 1, 16);
+	/* Alpha plane pixel extn */
+	__mdss_mdp_pipe_program_pixel_extn_helper(pipe, 3, 32);
+	return 0;
+}
diff --git a/drivers/video/msm/mdss/mdss_mdp_pp.c b/drivers/video/msm/mdss/mdss_mdp_pp.c
index b31f6c1..dc7b8b3 100644
--- a/drivers/video/msm/mdss/mdss_mdp_pp.c
+++ b/drivers/video/msm/mdss/mdss_mdp_pp.c
@@ -629,7 +629,7 @@
 		}
 	}
 
-	*op = opmode;
+	*op |= opmode;
 
 	return 0;
 }
@@ -637,12 +637,15 @@
 static int mdss_mdp_scale_setup(struct mdss_mdp_pipe *pipe)
 {
 	u32 scale_config = 0;
-	u32 phasex_step = 0, phasey_step = 0;
+	int init_phasex = 0, init_phasey = 0;
+	int phasex_step = 0, phasey_step = 0;
 	u32 chroma_sample;
 	u32 filter_mode;
 	struct mdss_data_type *mdata;
 	u32 src_w, src_h;
 
+	pr_debug("pipe=%d, change pxl ext=%d\n", pipe->num,
+			pipe->scale.enable_pxl_ext);
 	mdata = mdss_mdp_get_mdata();
 	if (mdata->mdp_rev >= MDSS_MDP_HW_REV_102 && pipe->src_fmt->is_yuv)
 		filter_mode = MDSS_MDP_SCALE_FILTER_CA;
@@ -689,7 +692,8 @@
 	if ((src_h != pipe->dst.h) ||
 	    (pipe->pp_res.pp_sts.sharp_sts & PP_STS_ENABLE) ||
 	    (chroma_sample == MDSS_MDP_CHROMA_420) ||
-	    (chroma_sample == MDSS_MDP_CHROMA_H1V2)) {
+	    (chroma_sample == MDSS_MDP_CHROMA_H1V2) ||
+	    pipe->scale.enable_pxl_ext) {
 		pr_debug("scale y - src_h=%d dst_h=%d\n", src_h, pipe->dst.h);
 
 		if ((src_h / MAX_DOWNSCALE_RATIO) > pipe->dst.h) {
@@ -699,7 +703,8 @@
 		}
 
 		scale_config |= MDSS_MDP_SCALEY_EN;
-		phasey_step = pipe->phase_step_y;
+		phasey_step = pipe->scale.phase_step_y[0];
+		init_phasey = pipe->scale.init_phase_y[0];
 
 		if (pipe->type == MDSS_MDP_PIPE_TYPE_VIG) {
 			u32 chroma_shift = 0;
@@ -708,11 +713,11 @@
 			    (chroma_sample == MDSS_MDP_CHROMA_H1V2)))
 				chroma_shift = 1; /* 2x upsample chroma */
 
-			if (src_h <= pipe->dst.h) {
+			if (src_h <= pipe->dst.h)
 				scale_config |= /* G/Y, A */
 					(filter_mode << 10) |
 					(MDSS_MDP_SCALE_FILTER_BIL << 18);
-			} else
+			else
 				scale_config |= /* G/Y, A */
 					(MDSS_MDP_SCALE_FILTER_PCMN << 10) |
 					(MDSS_MDP_SCALE_FILTER_PCMN << 18);
@@ -724,6 +729,8 @@
 				scale_config |= /* CrCb */
 					(MDSS_MDP_SCALE_FILTER_PCMN << 14);
 
+			writel_relaxed(init_phasey, pipe->base +
+				MDSS_MDP_REG_VIG_QSEED2_C12_INIT_PHASEY);
 			writel_relaxed(phasey_step >> chroma_shift, pipe->base +
 				MDSS_MDP_REG_VIG_QSEED2_C12_PHASESTEPY);
 		} else {
@@ -741,7 +748,8 @@
 	if ((src_w != pipe->dst.w) ||
 	    (pipe->pp_res.pp_sts.sharp_sts & PP_STS_ENABLE) ||
 	    (chroma_sample == MDSS_MDP_CHROMA_420) ||
-	    (chroma_sample == MDSS_MDP_CHROMA_H2V1)) {
+	    (chroma_sample == MDSS_MDP_CHROMA_H2V1) ||
+	    pipe->scale.enable_pxl_ext) {
 		pr_debug("scale x - src_w=%d dst_w=%d\n", src_w, pipe->dst.w);
 
 		if ((src_w / MAX_DOWNSCALE_RATIO) > pipe->dst.w) {
@@ -751,7 +759,8 @@
 		}
 
 		scale_config |= MDSS_MDP_SCALEX_EN;
-		phasex_step = pipe->phase_step_x;
+		init_phasex = pipe->scale.init_phase_x[0];
+		phasex_step = pipe->scale.phase_step_x[0];
 
 		if (pipe->type == MDSS_MDP_PIPE_TYPE_VIG) {
 			u32 chroma_shift = 0;
@@ -761,11 +770,11 @@
 			    (chroma_sample == MDSS_MDP_CHROMA_H2V1)))
 				chroma_shift = 1; /* 2x upsample chroma */
 
-			if (src_w <= pipe->dst.w) {
+			if (src_w <= pipe->dst.w)
 				scale_config |= /* G/Y, A */
 					(filter_mode << 8) |
 					(MDSS_MDP_SCALE_FILTER_BIL << 16);
-			} else
+			else
 				scale_config |= /* G/Y, A */
 					(MDSS_MDP_SCALE_FILTER_PCMN << 8) |
 					(MDSS_MDP_SCALE_FILTER_PCMN << 16);
@@ -777,6 +786,8 @@
 				scale_config |= /* CrCb */
 					(MDSS_MDP_SCALE_FILTER_PCMN << 12);
 
+			writel_relaxed(init_phasex, pipe->base +
+				MDSS_MDP_REG_VIG_QSEED2_C12_INIT_PHASEX);
 			writel_relaxed(phasex_step >> chroma_shift, pipe->base +
 				MDSS_MDP_REG_VIG_QSEED2_C12_PHASESTEPX);
 		} else {
@@ -791,12 +802,44 @@
 		}
 	}
 
+	if (pipe->scale.enable_pxl_ext &&
+		pipe->type == MDSS_MDP_PIPE_TYPE_VIG) {
+
+		/*program x,y initial phase and phase step*/
+		writel_relaxed(pipe->scale.init_phase_x[0],
+			pipe->base + MDSS_MDP_REG_VIG_QSEED2_C03_INIT_PHASEX);
+		writel_relaxed(pipe->scale.phase_step_x[0],
+			pipe->base + MDSS_MDP_REG_VIG_QSEED2_C03_PHASESTEPX);
+		writel_relaxed(pipe->scale.init_phase_x[1],
+			pipe->base + MDSS_MDP_REG_VIG_QSEED2_C12_INIT_PHASEX);
+		writel_relaxed(pipe->scale.phase_step_x[1],
+			pipe->base + MDSS_MDP_REG_VIG_QSEED2_C12_PHASESTEPX);
+
+		writel_relaxed(pipe->scale.init_phase_y[0],
+			pipe->base + MDSS_MDP_REG_VIG_QSEED2_C03_INIT_PHASEY);
+		writel_relaxed(pipe->scale.phase_step_y[0],
+			pipe->base + MDSS_MDP_REG_VIG_QSEED2_C03_PHASESTEPY);
+		writel_relaxed(pipe->scale.init_phase_y[1],
+			pipe->base + MDSS_MDP_REG_VIG_QSEED2_C12_INIT_PHASEY);
+		writel_relaxed(pipe->scale.phase_step_y[1],
+			pipe->base + MDSS_MDP_REG_VIG_QSEED2_C12_PHASESTEPY);
+
+		/*program pixel extn values for the SSPP*/
+		mdss_mdp_pipe_program_pixel_extn(pipe);
+	} else {
+		writel_relaxed(phasex_step, pipe->base +
+		   MDSS_MDP_REG_SCALE_PHASE_STEP_X);
+		writel_relaxed(phasey_step, pipe->base +
+		   MDSS_MDP_REG_SCALE_PHASE_STEP_Y);
+		writel_relaxed(init_phasex, pipe->base +
+			MDSS_MDP_REG_SCALE_INIT_PHASE_X);
+		writel_relaxed(init_phasey, pipe->base +
+			MDSS_MDP_REG_SCALE_INIT_PHASE_Y);
+	}
+
 	writel_relaxed(scale_config, pipe->base +
 	   MDSS_MDP_REG_SCALE_CONFIG);
-	writel_relaxed(phasex_step, pipe->base +
-	   MDSS_MDP_REG_SCALE_PHASE_STEP_X);
-	writel_relaxed(phasey_step, pipe->base +
-	   MDSS_MDP_REG_SCALE_PHASE_STEP_Y);
+
 	return 0;
 }
 
diff --git a/drivers/video/msm/mdss/mdss_mdp_rotator.c b/drivers/video/msm/mdss/mdss_mdp_rotator.c
index 1d172f3..057914b 100644
--- a/drivers/video/msm/mdss/mdss_mdp_rotator.c
+++ b/drivers/video/msm/mdss/mdss_mdp_rotator.c
@@ -137,7 +137,6 @@
 {
 	int ret;
 	struct mdss_mdp_writeback_arg wb_args = {
-		.callback_fnc = NULL,
 		.data = dst_data,
 		.priv_data = rot,
 	};
diff --git a/drivers/video/msm/mdss/mdss_mdp_util.c b/drivers/video/msm/mdss/mdss_mdp_util.c
index 1170d1e..b680823 100644
--- a/drivers/video/msm/mdss/mdss_mdp_util.c
+++ b/drivers/video/msm/mdss/mdss_mdp_util.c
@@ -592,7 +592,7 @@
 		return -EINVAL;
 
 	unit = 1 << PHASE_STEP_SHIFT;
-	*out_phase = mult_frac(src, unit, dst);
+	*out_phase = mult_frac(unit, src, dst);
 
 	/* check if overflow is possible */
 	if (src > dst) {
diff --git a/drivers/video/msm/mdss/mdss_mdp_wb.c b/drivers/video/msm/mdss/mdss_mdp_wb.c
index c0e49c8..5789341 100644
--- a/drivers/video/msm/mdss/mdss_mdp_wb.c
+++ b/drivers/video/msm/mdss/mdss_mdp_wb.c
@@ -164,6 +164,16 @@
 		return -EINVAL;
 	}
 
+	if (!ctl || !ctl->mdata) {
+		pr_err("%s : ctl is NULL", __func__);
+		return -EINVAL;
+	}
+
+	if (!wb) {
+		pr_err("unable to start, writeback is not initialized\n");
+		return -ENODEV;
+	}
+
 	ctl->is_secure = enable;
 	wb->is_secure = enable;
 
@@ -508,23 +518,13 @@
 	return ret;
 }
 
-static void mdss_mdp_wb_callback(void *arg)
-{
-	if (arg)
-		complete((struct completion *) arg);
-}
-
 int mdss_mdp_wb_kickoff(struct msm_fb_data_type *mfd)
 {
 	struct mdss_mdp_wb *wb = mfd_to_wb(mfd);
 	struct mdss_mdp_ctl *ctl = mfd_to_ctl(mfd);
 	struct mdss_mdp_wb_data *node = NULL;
 	int ret = 0;
-	DECLARE_COMPLETION_ONSTACK(comp);
-	struct mdss_mdp_writeback_arg wb_args = {
-		.callback_fnc = mdss_mdp_wb_callback,
-		.priv_data = &comp,
-	};
+	struct mdss_mdp_writeback_arg wb_args;
 
 	if (!ctl->power_on)
 		return 0;
@@ -566,12 +566,6 @@
 		goto kickoff_fail;
 	}
 
-	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);
 		list_add_tail(&node->active_entry, &wb->busy_queue);
diff --git a/drivers/video/msm/mdss/mdss_panel.h b/drivers/video/msm/mdss/mdss_panel.h
index 75fc095..b859598 100644
--- a/drivers/video/msm/mdss/mdss_panel.h
+++ b/drivers/video/msm/mdss/mdss_panel.h
@@ -299,6 +299,8 @@
 	struct ion_handle *splash_ihdl;
 	u32 panel_power_on;
 
+	uint32_t panel_dead;
+
 	struct lcd_panel_info lcdc;
 	struct fbc_panel_info fbc;
 	struct mipi_panel_info mipi;
diff --git a/drivers/video/msm/mdss/mhl_sii8334.c b/drivers/video/msm/mdss/mhl_sii8334.c
index a759e86..ab01566 100644
--- a/drivers/video/msm/mdss/mhl_sii8334.c
+++ b/drivers/video/msm/mdss/mhl_sii8334.c
@@ -1463,7 +1463,7 @@
 	static struct regulator *reg_8941_l02;
 	static struct regulator *reg_8941_smps3a;
 	static struct regulator *reg_8941_vdda;
-	int rc;
+	int rc = -EINVAL;
 
 	pr_debug("%s\n", __func__);
 	if (!reg_8941_l24) {
diff --git a/include/linux/diagchar.h b/include/linux/diagchar.h
index 0739ece..d525e84 100644
--- a/include/linux/diagchar.h
+++ b/include/linux/diagchar.h
@@ -726,25 +726,27 @@
 };
 
 /* LOG CODES */
+static const uint32_t log_code_last_tbl[] = {
+	0x0,	/* EQUIP ID 0 */
+	0x182F,	/* EQUIP ID 1 */
+	0x0,	/* EQUIP ID 2 */
+	0x0,	/* EQUIP ID 3 */
+	0x4910,	/* EQUIP ID 4 */
+	0x5420,	/* EQUIP ID 5 */
+	0x0,	/* EQUIP ID 6 */
+	0x74FF,	/* EQUIP ID 7 */
+	0x0,	/* EQUIP ID 8 */
+	0x0,	/* EQUIP ID 9 */
+	0xA38A,	/* EQUIP ID 10 */
+	0xB201,	/* EQUIP ID 11 */
+	0x0,	/* EQUIP ID 12 */
+	0x0,	/* EQUIP ID 13 */
+	0x0,	/* EQUIP ID 14 */
+	0x0,	/* EQUIP ID 15 */
+};
 
-#define LOG_0	0x0
-#define LOG_1	0x1808
-#define LOG_2	0x0
-#define LOG_3	0x0
-#define LOG_4	0x4910
-#define LOG_5	0x5420
-#define LOG_6	0x0
-#define LOG_7	0x74FF
-#define LOG_8	0x0
-#define LOG_9	0x0
-#define LOG_10	0xA38A
-#define LOG_11	0xB201
-#define LOG_12	0x0
-#define LOG_13	0x0
-#define LOG_14	0x0
-#define LOG_15	0x0
-
-#define LOG_GET_ITEM_NUM(xx_code) (xx_code & 0x0FFF)
-#define LOG_GET_EQUIP_ID(xx_code) ((xx_code & 0xF000) >> 12)
+#define LOG_GET_ITEM_NUM(xx_code)	(xx_code & 0x0FFF)
+#define LOG_GET_EQUIP_ID(xx_code)	((xx_code & 0xF000) >> 12)
+#define LOG_ITEMS_TO_SIZE(num_items)	((num_items+7)/8)
 
 #endif
diff --git a/include/linux/mm.h b/include/linux/mm.h
index a5fa304..2218ac4 100644
--- a/include/linux/mm.h
+++ b/include/linux/mm.h
@@ -806,6 +806,17 @@
 	return (void *)((unsigned long)page->mapping & ~PAGE_MAPPING_FLAGS);
 }
 
+extern struct address_space *__page_file_mapping(struct page *);
+
+static inline
+struct address_space *page_file_mapping(struct page *page)
+{
+	if (unlikely(PageSwapCache(page)))
+		return __page_file_mapping(page);
+
+	return page->mapping;
+}
+
 static inline int PageAnon(struct page *page)
 {
 	return ((unsigned long)page->mapping & PAGE_MAPPING_ANON) != 0;
@@ -822,6 +833,20 @@
 	return page->index;
 }
 
+extern pgoff_t __page_file_index(struct page *page);
+
+/*
+ * Return the file index of the page. Regular pagecache pages use ->index
+ * whereas swapcache pages use swp_offset(->private)
+ */
+static inline pgoff_t page_file_index(struct page *page)
+{
+	if (unlikely(PageSwapCache(page)))
+		return __page_file_index(page);
+
+	return page->index;
+}
+
 /*
  * Return true if this page is mapped into pagetables.
  */
diff --git a/include/linux/mm_inline.h b/include/linux/mm_inline.h
index 227fd3e..9a584c0 100644
--- a/include/linux/mm_inline.h
+++ b/include/linux/mm_inline.h
@@ -2,6 +2,7 @@
 #define LINUX_MM_INLINE_H
 
 #include <linux/huge_mm.h>
+#include <linux/swap.h>
 
 /**
  * page_is_file_cache - should the page be on a file LRU or anon LRU?
diff --git a/include/linux/mmc/card.h b/include/linux/mmc/card.h
index d0ad3e4..1bcfd28 100644
--- a/include/linux/mmc/card.h
+++ b/include/linux/mmc/card.h
@@ -219,6 +219,7 @@
 	MMC_BLK_NEW_REQUEST,
 	MMC_BLK_URGENT,
 	MMC_BLK_URGENT_DONE,
+	MMC_BLK_NO_REQ_TO_STOP,
 };
 
 struct mmc_wr_pack_stats {
diff --git a/include/linux/mmzone.h b/include/linux/mmzone.h
index 7539e03..381fff5 100644
--- a/include/linux/mmzone.h
+++ b/include/linux/mmzone.h
@@ -375,7 +375,6 @@
 	 * free areas of different sizes
 	 */
 	spinlock_t		lock;
-	int                     all_unreclaimable; /* All pages pinned */
 #if defined CONFIG_COMPACTION || defined CONFIG_CMA
 	/* Set to true when the PG_migrate_skip bits should be cleared */
 	bool			compact_blockskip_flush;
diff --git a/include/linux/msm_mdp.h b/include/linux/msm_mdp.h
index de31795..3425386 100644
--- a/include/linux/msm_mdp.h
+++ b/include/linux/msm_mdp.h
@@ -156,6 +156,7 @@
 
 #define MDSS_MDP_ROT_ONLY		0x80
 #define MDSS_MDP_RIGHT_MIXER		0x100
+#define MDSS_MDP_DUAL_PIPE		0x200
 
 /* mdp_blit_req flag values */
 #define MDP_ROT_NOP 0
@@ -451,6 +452,33 @@
 	BLEND_OP_MAX,
 };
 
+#define MAX_PLANES	4
+struct mdp_scale_data {
+	uint8_t enable_pxl_ext;
+
+	int init_phase_x[MAX_PLANES];
+	int phase_step_x[MAX_PLANES];
+	int init_phase_y[MAX_PLANES];
+	int phase_step_y[MAX_PLANES];
+
+	int num_ext_pxls_left[MAX_PLANES];
+	int num_ext_pxls_right[MAX_PLANES];
+	int num_ext_pxls_top[MAX_PLANES];
+	int num_ext_pxls_btm[MAX_PLANES];
+
+	int left_ftch[MAX_PLANES];
+	int left_rpt[MAX_PLANES];
+	int right_ftch[MAX_PLANES];
+	int right_rpt[MAX_PLANES];
+
+	int top_rpt[MAX_PLANES];
+	int btm_rpt[MAX_PLANES];
+	int top_ftch[MAX_PLANES];
+	int btm_ftch[MAX_PLANES];
+
+	uint32_t roi_w[MAX_PLANES];
+};
+
 struct mdp_overlay {
 	struct msmfb_img src;
 	struct mdp_rect src_rect;
@@ -466,6 +494,7 @@
 	uint8_t horz_deci;
 	uint8_t vert_deci;
 	struct mdp_overlay_pp_params overlay_pp_cfg;
+	struct mdp_scale_data scale;
 };
 
 struct msmfb_overlay_3d {
diff --git a/include/linux/pagemap.h b/include/linux/pagemap.h
index 0844dc3..696ca39 100644
--- a/include/linux/pagemap.h
+++ b/include/linux/pagemap.h
@@ -295,6 +295,11 @@
 	return ((loff_t)page->index) << PAGE_CACHE_SHIFT;
 }
 
+static inline loff_t page_file_offset(struct page *page)
+{
+	return ((loff_t)page_file_index(page)) << PAGE_CACHE_SHIFT;
+}
+
 extern pgoff_t linear_hugepage_index(struct vm_area_struct *vma,
 				     unsigned long address);
 
diff --git a/include/linux/swap.h b/include/linux/swap.h
index d5bd6ee..c1fcf34 100644
--- a/include/linux/swap.h
+++ b/include/linux/swap.h
@@ -197,6 +197,18 @@
 	struct block_device *bdev;	/* swap device or bdev of swap file */
 	struct file *swap_file;		/* seldom referenced */
 	unsigned int old_block_size;	/* seldom referenced */
+	spinlock_t lock;		/*
+					 * protect map scan related fields like
+					 * swap_map, lowest_bit, highest_bit,
+					 * inuse_pages, cluster_next,
+					 * cluster_nr, lowest_alloc and
+					 * highest_alloc. other fields are only
+					 * changed at swapon/swapoff, so are
+					 * protected by swap_lock. changing
+					 * flags need hold this lock and
+					 * swap_lock. If both locks need hold,
+					 * hold swap_lock first.
+					 */
 };
 
 struct swap_list_t {
@@ -204,9 +216,6 @@
 	int next;	/* swapfile to be used next */
 };
 
-/* Swap 50% full? Release swapcache more aggressively.. */
-#define vm_swap_full() (nr_swap_pages*2 < total_swap_pages)
-
 /* linux/mm/page_alloc.c */
 extern unsigned long totalram_pages;
 extern unsigned long totalreserve_pages;
@@ -335,8 +344,20 @@
 			struct vm_area_struct *vma, unsigned long addr);
 
 /* linux/mm/swapfile.c */
-extern long nr_swap_pages;
+extern atomic_long_t nr_swap_pages;
 extern long total_swap_pages;
+
+/* Swap 50% full? Release swapcache more aggressively.. */
+static inline bool vm_swap_full(void)
+{
+	return atomic_long_read(&nr_swap_pages) * 2 < total_swap_pages;
+}
+
+static inline long get_nr_swap_pages(void)
+{
+	return atomic_long_read(&nr_swap_pages);
+}
+
 extern void si_swapinfo(struct sysinfo *);
 extern swp_entry_t get_swap_page(void);
 extern swp_entry_t get_swap_page_of_type(int);
@@ -351,6 +372,8 @@
 extern unsigned int count_swap_pages(int, int);
 extern sector_t map_swap_page(struct page *, struct block_device **);
 extern sector_t swapdev_block(int, pgoff_t);
+extern int page_swapcount(struct page *);
+extern struct swap_info_struct *page_swap_info(struct page *);
 extern int reuse_swap_page(struct page *);
 extern int try_to_free_swap(struct page *);
 struct backing_dev_info;
@@ -368,9 +391,10 @@
 
 #else /* CONFIG_SWAP */
 
-#define nr_swap_pages				0L
+#define get_nr_swap_pages()			0L
 #define total_swap_pages			0L
 #define total_swapcache_pages			0UL
+#define vm_swap_full()				0
 
 #define si_swapinfo(val) \
 	do { (val)->freeswap = (val)->totalswap = 0; } while (0)
diff --git a/include/linux/usb/android.h b/include/linux/usb/android.h
index e17e978..8d5e51b 100644
--- a/include/linux/usb/android.h
+++ b/include/linux/usb/android.h
@@ -19,12 +19,16 @@
 
 #include <linux/usb/composite.h>
 
+#define MAX_STREAMING_FUNCS 3
+#define FUNC_NAME_LEN 10
 struct android_usb_platform_data {
 	int (*update_pid_and_serial_num)(uint32_t, const char *);
 	u32 swfi_latency;
 	u8 usb_core_id;
 	bool cdrom;
 	bool internal_ums;
+	char streaming_func[MAX_STREAMING_FUNCS][FUNC_NAME_LEN];
+	int  streaming_func_count;
 };
 
 #ifndef CONFIG_TARGET_CORE
diff --git a/include/linux/usb/gadget.h b/include/linux/usb/gadget.h
index fea832e..3844f41 100644
--- a/include/linux/usb/gadget.h
+++ b/include/linux/usb/gadget.h
@@ -508,6 +508,7 @@
  * @dev: Driver model state for this abstract device.
  * @usb_core_id: Identifies the usb core controlled by this usb_gadget.
  *		 Used in case of more then one core operates concurrently.
+ * @streaming_enabled: Enable streaming mode with usb core.
  *
  * Gadgets have a mostly-portable "gadget driver" implementing device
  * functions, handling all usb configurations and interfaces.  Gadget
@@ -546,6 +547,7 @@
 	struct device			dev;
 	u8				usb_core_id;
 	bool				l1_supported;
+	bool				streaming_enabled;
 };
 
 static inline void set_gadget_data(struct usb_gadget *gadget, void *data)
diff --git a/include/linux/usb/msm_hsusb.h b/include/linux/usb/msm_hsusb.h
index 07f9b90..9eb9cd8 100644
--- a/include/linux/usb/msm_hsusb.h
+++ b/include/linux/usb/msm_hsusb.h
@@ -229,7 +229,9 @@
  *              between 1 to 7.
  * @l1_supported: enable link power management support.
  * @dpdm_pulldown_added: Indicates whether pull down resistors are
-		connected on data lines or not.
+ *		connected on data lines or not.
+ * @enable_ahb2ahb_bypass: Indicates whether enable AHB2AHB BYPASS
+ *		mode with controller in device mode.
  */
 struct msm_otg_platform_data {
 	int *phy_init_seq;
@@ -258,6 +260,7 @@
 	int log2_itc;
 	bool l1_supported;
 	bool dpdm_pulldown_added;
+	bool enable_ahb2ahb_bypass;
 };
 
 /* phy related flags */
@@ -462,6 +465,7 @@
 	int log2_itc;
 	void *prv_data;
 	bool l1_supported;
+	bool enable_ahb2ahb_bypass;
 };
 
 /**
diff --git a/include/linux/usb/msm_hsusb_hw.h b/include/linux/usb/msm_hsusb_hw.h
index 58ab4eb..2a5ebd4 100644
--- a/include/linux/usb/msm_hsusb_hw.h
+++ b/include/linux/usb/msm_hsusb_hw.h
@@ -49,6 +49,10 @@
 #define L1_CONFIG_PHY_LPM	BIT(10)
 #define L1_CONFIG_PLL		BIT(11)
 
+#define AHB2AHB_BYPASS		BIT(31)
+#define AHB2AHB_BYPASS_BIT_MASK	BIT(31)
+#define AHB2AHB_BYPASS_CLEAR	(0 << 31)
+
 #define PORTSC_PHCD            (1 << 23) /* phy suspend mode */
 #define PORTSC_PTS_MASK         (3 << 30)
 #define PORTSC_PTS_ULPI         (3 << 30)
diff --git a/include/linux/vmstat.h b/include/linux/vmstat.h
index 1d10474..2d59889 100644
--- a/include/linux/vmstat.h
+++ b/include/linux/vmstat.h
@@ -140,7 +140,6 @@
 }
 
 extern unsigned long global_reclaimable_pages(void);
-extern unsigned long zone_reclaimable_pages(struct zone *zone);
 
 #ifdef CONFIG_NUMA
 /*
diff --git a/include/sound/apr_audio-v2.h b/include/sound/apr_audio-v2.h
index bbda72e..b62a759 100644
--- a/include/sound/apr_audio-v2.h
+++ b/include/sound/apr_audio-v2.h
@@ -3676,6 +3676,7 @@
 } __packed;
 
 #define ASM_SESSION_CMD_PAUSE 0x00010BD3
+#define ASM_SESSION_CMD_SUSPEND 0x00010DEC
 #define ASM_SESSION_CMD_GET_SESSIONTIME_V3 0x00010D9D
 #define ASM_SESSION_CMD_REGISTER_FOR_RX_UNDERFLOW_EVENTS 0x00010BD5
 
@@ -4698,6 +4699,25 @@
 
 } __packed;
 
+
+/*
+    Indicates the number of samples per channel to be removed from the
+    beginning of the stream.
+*/
+#define ASM_DATA_CMD_REMOVE_INITIAL_SILENCE 0x00010D67
+/*
+    Indicates the number of samples per channel to be removed from
+    the end of the stream.
+*/
+#define ASM_DATA_CMD_REMOVE_TRAILING_SILENCE 0x00010D68
+struct asm_data_cmd_remove_silence {
+	struct apr_hdr hdr;
+	u32	num_samples_to_remove;
+	/**< Number of samples per channel to be removed.
+
+	   @values 0 to (2@sscr{32}-1) */
+} __packed;
+
 #define ASM_STREAM_CMD_OPEN_READ_COMPRESSED                        0x00010D95
 
 struct asm_stream_cmd_open_read_compressed {
diff --git a/include/sound/q6asm-v2.h b/include/sound/q6asm-v2.h
index 3cc476f..eb3b41a 100644
--- a/include/sound/q6asm-v2.h
+++ b/include/sound/q6asm-v2.h
@@ -54,6 +54,7 @@
 #define CMD_EOS            0x0003
 #define CMD_CLOSE          0x0004
 #define CMD_OUT_FLUSH      0x0005
+#define CMD_SUSPEND        0x0006
 
 /* bit 0:1 represents priority of stream */
 #define STREAM_PRIORITY_NORMAL	0x0000
@@ -80,6 +81,9 @@
 #define SESSION_MAX		0x08
 #define ASM_CONTROL_SESSION	0x0F
 
+#define ASM_SHIFT_GAPLESS_MODE_FLAG	31
+#define ASM_SHIFT_LAST_BUFFER_FLAG	30
+
 /* payload structure bytes */
 #define READDONE_IDX_STATUS 0
 #define READDONE_IDX_BUFADD_LSW 1
@@ -130,6 +134,7 @@
 	uint32_t      msw_ts;
 	uint32_t      flags;
 	uint32_t      metadata_len;
+	uint32_t      last_buffer;
 };
 
 struct audio_aio_read_param {
@@ -162,12 +167,14 @@
 	uint64_t	       time_stamp;
 	struct apr_svc         *apr;
 	struct apr_svc         *mmap_apr;
+	struct apr_svc         *apr2;
 	struct mutex	       cmd_lock;
 	/* idx:1 out port, 0: in port*/
 	struct audio_port_data port[2];
 	wait_queue_head_t      cmd_wait;
 	wait_queue_head_t      time_wait;
 	bool                   perf_mode;
+	int					   stream_id;
 	/* audio cache operations fptr*/
 	int (*fptr_cache_ops)(struct audio_buffer *abuff, int cache_op);
 };
@@ -203,6 +210,10 @@
 int q6asm_open_write_v2(struct audio_client *ac, uint32_t format,
 			uint16_t bits_per_sample);
 
+int q6asm_stream_open_write_v2(struct audio_client *ac, uint32_t format,
+				uint16_t bits_per_sample, int32_t stream_id,
+				bool is_gapless_mode);
+
 int q6asm_open_read_write(struct audio_client *ac,
 			uint32_t rd_format,
 			uint32_t wr_format);
@@ -239,12 +250,22 @@
 int q6asm_run_nowait(struct audio_client *ac, uint32_t flags,
 		uint32_t msw_ts, uint32_t lsw_ts);
 
+int q6asm_stream_run_nowait(struct audio_client *ac, uint32_t flags,
+		uint32_t msw_ts, uint32_t lsw_ts, uint32_t stream_id);
+
 int q6asm_reg_tx_overflow(struct audio_client *ac, uint16_t enable);
 
+int q6asm_reg_rx_underflow(struct audio_client *ac, uint16_t enable);
+
 int q6asm_cmd(struct audio_client *ac, int cmd);
 
+int q6asm_stream_cmd(struct audio_client *ac, int cmd, uint32_t stream_id);
+
 int q6asm_cmd_nowait(struct audio_client *ac, int cmd);
 
+int q6asm_stream_cmd_nowait(struct audio_client *ac, int cmd,
+			    uint32_t stream_id);
+
 void *q6asm_is_cpu_buf_avail(int dir, struct audio_client *ac,
 				uint32_t *size, uint32_t *idx);
 
@@ -316,6 +337,9 @@
 int q6asm_media_format_block_aac(struct audio_client *ac,
 			struct asm_aac_cfg *cfg);
 
+int q6asm_stream_media_format_block_aac(struct audio_client *ac,
+			struct asm_aac_cfg *cfg, int stream_id);
+
 int q6asm_media_format_block_multi_aac(struct audio_client *ac,
 			struct asm_aac_cfg *cfg);
 
@@ -363,4 +387,8 @@
 */
 int q6asm_media_format_block(struct audio_client *ac, uint32_t format);
 
+/* Send the meta data to remove initial and trailing silence */
+int q6asm_send_meta_data(struct audio_client *ac, uint32_t initial_samples,
+		uint32_t trailing_samples);
+
 #endif /* __Q6_ASM_H__ */
diff --git a/include/sound/soc-dapm.h b/include/sound/soc-dapm.h
index fed2e0a..4a606af 100644
--- a/include/sound/soc-dapm.h
+++ b/include/sound/soc-dapm.h
@@ -442,6 +442,11 @@
 	snd_soc_dapm_siggen,		/* signal generator */
 };
 
+enum snd_soc_dapm_subclass {
+	SND_SOC_DAPM_CLASS_INIT	= 0,
+	SND_SOC_DAPM_CLASS_PCM	= 1,
+};
+
 /*
  * DAPM audio route definition.
  *
diff --git a/mm/internal.h b/mm/internal.h
index 3439ef4..f5369cc 100644
--- a/mm/internal.h
+++ b/mm/internal.h
@@ -90,6 +90,8 @@
  */
 extern int isolate_lru_page(struct page *page);
 extern void putback_lru_page(struct page *page);
+extern unsigned long zone_reclaimable_pages(struct zone *zone);
+extern bool zone_reclaimable(struct zone *zone);
 
 /*
  * in mm/page_alloc.c
diff --git a/mm/mmap.c b/mm/mmap.c
index 848ef52..9932edb 100644
--- a/mm/mmap.c
+++ b/mm/mmap.c
@@ -133,7 +133,7 @@
 		 */
 		free -= global_page_state(NR_SHMEM);
 
-		free += nr_swap_pages;
+		free += get_nr_swap_pages();
 
 		/*
 		 * Any slabs which are created with the
diff --git a/mm/nommu.c b/mm/nommu.c
index bb8f4f0..6bb7042 100644
--- a/mm/nommu.c
+++ b/mm/nommu.c
@@ -1928,7 +1928,7 @@
 		 */
 		free -= global_page_state(NR_SHMEM);
 
-		free += nr_swap_pages;
+		free += get_nr_swap_pages();
 
 		/*
 		 * Any slabs which are created with the
diff --git a/mm/page-writeback.c b/mm/page-writeback.c
index 26adea8..a5e8dc2 100644
--- a/mm/page-writeback.c
+++ b/mm/page-writeback.c
@@ -34,8 +34,11 @@
 #include <linux/syscalls.h>
 #include <linux/buffer_head.h> /* __set_page_dirty_buffers */
 #include <linux/pagevec.h>
+#include <linux/mm_inline.h>
 #include <trace/events/writeback.h>
 
+#include "internal.h"
+
 /*
  * Sleep at most 200ms at a time in balance_dirty_pages().
  */
diff --git a/mm/page_alloc.c b/mm/page_alloc.c
index 46ccd2f..a1e4f77 100644
--- a/mm/page_alloc.c
+++ b/mm/page_alloc.c
@@ -57,6 +57,7 @@
 #include <linux/ftrace_event.h>
 #include <linux/memcontrol.h>
 #include <linux/prefetch.h>
+#include <linux/mm_inline.h>
 #include <linux/migrate.h>
 #include <linux/page-debug-flags.h>
 
@@ -647,7 +648,6 @@
 	int mt = 0;
 
 	spin_lock(&zone->lock);
-	zone->all_unreclaimable = 0;
 	zone->pages_scanned = 0;
 
 	while (to_free) {
@@ -693,7 +693,6 @@
 				int migratetype)
 {
 	spin_lock(&zone->lock);
-	zone->all_unreclaimable = 0;
 	zone->pages_scanned = 0;
 
 	__free_one_page(page, zone, order, migratetype);
@@ -2997,7 +2996,7 @@
 			K(zone_page_state(zone, NR_FREE_CMA_PAGES)),
 			K(zone_page_state(zone, NR_WRITEBACK_TEMP)),
 			zone->pages_scanned,
-			(zone->all_unreclaimable ? "yes" : "no")
+			(!zone_reclaimable(zone) ? "yes" : "no")
 			);
 		printk("lowmem_reserve[]:");
 		for (i = 0; i < MAX_NR_ZONES; i++)
diff --git a/mm/page_io.c b/mm/page_io.c
index dc76b4d..e60e43f 100644
--- a/mm/page_io.c
+++ b/mm/page_io.c
@@ -1,3 +1,4 @@
+
 /*
  *  linux/mm/page_io.c
  *
@@ -18,6 +19,7 @@
 #include <linux/bio.h>
 #include <linux/swapops.h>
 #include <linux/writeback.h>
+#include <linux/blkdev.h>
 #include <asm/pgtable.h>
 
 static struct bio *get_swap_bio(gfp_t gfp_flags,
@@ -78,9 +80,54 @@
 				imajor(bio->bi_bdev->bd_inode),
 				iminor(bio->bi_bdev->bd_inode),
 				(unsigned long long)bio->bi_sector);
-	} else {
-		SetPageUptodate(page);
+		goto out;
 	}
+
+	SetPageUptodate(page);
+
+	/*
+	 * There is no guarantee that the page is in swap cache - the software
+	 * suspend code (at least) uses end_swap_bio_read() against a non-
+	 * swapcache page.  So we must check PG_swapcache before proceeding with
+	 * this optimization.
+	 */
+	if (likely(PageSwapCache(page))) {
+		struct swap_info_struct *sis;
+
+		sis = page_swap_info(page);
+		if (sis->flags & SWP_BLKDEV) {
+			/*
+			 * The swap subsystem performs lazy swap slot freeing,
+			 * expecting that the page will be swapped out again.
+			 * So we can avoid an unnecessary write if the page
+			 * isn't redirtied.
+			 * This is good for real swap storage because we can
+			 * reduce unnecessary I/O and enhance wear-leveling
+			 * if an SSD is used as the as swap device.
+			 * But if in-memory swap device (eg zram) is used,
+			 * this causes a duplicated copy between uncompressed
+			 * data in VM-owned memory and compressed data in
+			 * zram-owned memory.  So let's free zram-owned memory
+			 * and make the VM-owned decompressed page *dirty*,
+			 * so the page should be swapped out somewhere again if
+			 * we again wish to reclaim it.
+			 */
+			struct gendisk *disk = sis->bdev->bd_disk;
+			if (disk->fops->swap_slot_free_notify) {
+				swp_entry_t entry;
+				unsigned long offset;
+
+				entry.val = page_private(page);
+				offset = swp_offset(entry);
+
+				SetPageDirty(page);
+				disk->fops->swap_slot_free_notify(sis->bdev,
+						offset);
+			}
+		}
+	}
+
+out:
 	unlock_page(page);
 	bio_put(bio);
 }
diff --git a/mm/swap_state.c b/mm/swap_state.c
index 4c5ff7f..eb6a79c 100644
--- a/mm/swap_state.c
+++ b/mm/swap_state.c
@@ -58,7 +58,8 @@
 	printk("Swap cache stats: add %lu, delete %lu, find %lu/%lu\n",
 		swap_cache_info.add_total, swap_cache_info.del_total,
 		swap_cache_info.find_success, swap_cache_info.find_total);
-	printk("Free swap  = %ldkB\n", nr_swap_pages << (PAGE_SHIFT - 10));
+	printk("Free swap  = %ldkB\n",
+		get_nr_swap_pages() << (PAGE_SHIFT - 10));
 	printk("Total swap = %lukB\n", total_swap_pages << (PAGE_SHIFT - 10));
 }
 
diff --git a/mm/swapfile.c b/mm/swapfile.c
index fafc26d..9ae4c8d 100644
--- a/mm/swapfile.c
+++ b/mm/swapfile.c
@@ -31,6 +31,7 @@
 #include <linux/memcontrol.h>
 #include <linux/poll.h>
 #include <linux/oom.h>
+#include <linux/export.h>
 
 #include <asm/pgtable.h>
 #include <asm/tlbflush.h>
@@ -44,9 +45,11 @@
 
 static DEFINE_SPINLOCK(swap_lock);
 static unsigned int nr_swapfiles;
-long nr_swap_pages;
+atomic_long_t nr_swap_pages;
+/* protected with swap_lock. reading in vm_swap_full() doesn't need lock */
 long total_swap_pages;
 static int least_priority;
+static atomic_t highest_priority_index = ATOMIC_INIT(-1);
 
 static const char Bad_file[] = "Bad swap file entry ";
 static const char Unused_file[] = "Unused swap file entry ";
@@ -220,7 +223,7 @@
 			si->lowest_alloc = si->max;
 			si->highest_alloc = 0;
 		}
-		spin_unlock(&swap_lock);
+		spin_unlock(&si->lock);
 
 		/*
 		 * If seek is expensive, start searching for new cluster from
@@ -239,7 +242,7 @@
 			if (si->swap_map[offset])
 				last_in_cluster = offset + SWAPFILE_CLUSTER;
 			else if (offset == last_in_cluster) {
-				spin_lock(&swap_lock);
+				spin_lock(&si->lock);
 				offset -= SWAPFILE_CLUSTER - 1;
 				si->cluster_next = offset;
 				si->cluster_nr = SWAPFILE_CLUSTER - 1;
@@ -260,7 +263,7 @@
 			if (si->swap_map[offset])
 				last_in_cluster = offset + SWAPFILE_CLUSTER;
 			else if (offset == last_in_cluster) {
-				spin_lock(&swap_lock);
+				spin_lock(&si->lock);
 				offset -= SWAPFILE_CLUSTER - 1;
 				si->cluster_next = offset;
 				si->cluster_nr = SWAPFILE_CLUSTER - 1;
@@ -274,7 +277,7 @@
 		}
 
 		offset = scan_base;
-		spin_lock(&swap_lock);
+		spin_lock(&si->lock);
 		si->cluster_nr = SWAPFILE_CLUSTER - 1;
 		si->lowest_alloc = 0;
 	}
@@ -290,9 +293,9 @@
 	/* reuse swap entry of cache-only swap if not busy. */
 	if (vm_swap_full() && si->swap_map[offset] == SWAP_HAS_CACHE) {
 		int swap_was_freed;
-		spin_unlock(&swap_lock);
+		spin_unlock(&si->lock);
 		swap_was_freed = __try_to_reclaim_swap(si, offset);
-		spin_lock(&swap_lock);
+		spin_lock(&si->lock);
 		/* entry was freed successfully, try to use this again */
 		if (swap_was_freed)
 			goto checks;
@@ -332,13 +335,13 @@
 			    si->lowest_alloc <= last_in_cluster)
 				last_in_cluster = si->lowest_alloc - 1;
 			si->flags |= SWP_DISCARDING;
-			spin_unlock(&swap_lock);
+			spin_unlock(&si->lock);
 
 			if (offset < last_in_cluster)
 				discard_swap_cluster(si, offset,
 					last_in_cluster - offset + 1);
 
-			spin_lock(&swap_lock);
+			spin_lock(&si->lock);
 			si->lowest_alloc = 0;
 			si->flags &= ~SWP_DISCARDING;
 
@@ -352,10 +355,10 @@
 			 * could defer that delay until swap_writepage,
 			 * but it's easier to keep this self-contained.
 			 */
-			spin_unlock(&swap_lock);
+			spin_unlock(&si->lock);
 			wait_on_bit(&si->flags, ilog2(SWP_DISCARDING),
 				wait_for_discard, TASK_UNINTERRUPTIBLE);
-			spin_lock(&swap_lock);
+			spin_lock(&si->lock);
 		} else {
 			/*
 			 * Note pages allocated by racing tasks while
@@ -371,14 +374,14 @@
 	return offset;
 
 scan:
-	spin_unlock(&swap_lock);
+	spin_unlock(&si->lock);
 	while (++offset <= si->highest_bit) {
 		if (!si->swap_map[offset]) {
-			spin_lock(&swap_lock);
+			spin_lock(&si->lock);
 			goto checks;
 		}
 		if (vm_swap_full() && si->swap_map[offset] == SWAP_HAS_CACHE) {
-			spin_lock(&swap_lock);
+			spin_lock(&si->lock);
 			goto checks;
 		}
 		if (unlikely(--latency_ration < 0)) {
@@ -389,11 +392,11 @@
 	offset = si->lowest_bit;
 	while (++offset < scan_base) {
 		if (!si->swap_map[offset]) {
-			spin_lock(&swap_lock);
+			spin_lock(&si->lock);
 			goto checks;
 		}
 		if (vm_swap_full() && si->swap_map[offset] == SWAP_HAS_CACHE) {
-			spin_lock(&swap_lock);
+			spin_lock(&si->lock);
 			goto checks;
 		}
 		if (unlikely(--latency_ration < 0)) {
@@ -401,7 +404,7 @@
 			latency_ration = LATENCY_LIMIT;
 		}
 	}
-	spin_lock(&swap_lock);
+	spin_lock(&si->lock);
 
 no_page:
 	si->flags -= SWP_SCANNING;
@@ -414,13 +417,34 @@
 	pgoff_t offset;
 	int type, next;
 	int wrapped = 0;
+	int hp_index;
 
 	spin_lock(&swap_lock);
-	if (nr_swap_pages <= 0)
+	if (atomic_long_read(&nr_swap_pages) <= 0)
 		goto noswap;
-	nr_swap_pages--;
+	atomic_long_dec(&nr_swap_pages);
 
 	for (type = swap_list.next; type >= 0 && wrapped < 2; type = next) {
+		hp_index = atomic_xchg(&highest_priority_index, -1);
+		/*
+		 * highest_priority_index records current highest priority swap
+		 * type which just frees swap entries. If its priority is
+		 * higher than that of swap_list.next swap type, we use it.  It
+		 * isn't protected by swap_lock, so it can be an invalid value
+		 * if the corresponding swap type is swapoff. We double check
+		 * the flags here. It's even possible the swap type is swapoff
+		 * and swapon again and its priority is changed. In such rare
+		 * case, low prority swap type might be used, but eventually
+		 * high priority swap will be used after several rounds of
+		 * swap.
+		 */
+		if (hp_index != -1 && hp_index != type &&
+		    swap_info[type]->prio < swap_info[hp_index]->prio &&
+		    (swap_info[hp_index]->flags & SWP_WRITEOK)) {
+			type = hp_index;
+			swap_list.next = type;
+		}
+
 		si = swap_info[type];
 		next = si->next;
 		if (next < 0 ||
@@ -429,22 +453,29 @@
 			wrapped++;
 		}
 
-		if (!si->highest_bit)
+		spin_lock(&si->lock);
+		if (!si->highest_bit) {
+			spin_unlock(&si->lock);
 			continue;
-		if (!(si->flags & SWP_WRITEOK))
+		}
+		if (!(si->flags & SWP_WRITEOK)) {
+			spin_unlock(&si->lock);
 			continue;
+		}
 
 		swap_list.next = next;
+
+		spin_unlock(&swap_lock);
 		/* This is called for allocating swap entry for cache */
 		offset = scan_swap_map(si, SWAP_HAS_CACHE);
-		if (offset) {
-			spin_unlock(&swap_lock);
+		spin_unlock(&si->lock);
+		if (offset)
 			return swp_entry(type, offset);
-		}
+		spin_lock(&swap_lock);
 		next = swap_list.next;
 	}
 
-	nr_swap_pages++;
+	atomic_long_inc(&nr_swap_pages);
 noswap:
 	spin_unlock(&swap_lock);
 	return (swp_entry_t) {0};
@@ -456,19 +487,19 @@
 	struct swap_info_struct *si;
 	pgoff_t offset;
 
-	spin_lock(&swap_lock);
 	si = swap_info[type];
+	spin_lock(&si->lock);
 	if (si && (si->flags & SWP_WRITEOK)) {
-		nr_swap_pages--;
+		atomic_long_dec(&nr_swap_pages);
 		/* This is called for allocating swap entry, not cache */
 		offset = scan_swap_map(si, 1);
 		if (offset) {
-			spin_unlock(&swap_lock);
+			spin_unlock(&si->lock);
 			return swp_entry(type, offset);
 		}
-		nr_swap_pages++;
+		atomic_long_inc(&nr_swap_pages);
 	}
-	spin_unlock(&swap_lock);
+	spin_unlock(&si->lock);
 	return (swp_entry_t) {0};
 }
 
@@ -490,7 +521,7 @@
 		goto bad_offset;
 	if (!p->swap_map[offset])
 		goto bad_free;
-	spin_lock(&swap_lock);
+	spin_lock(&p->lock);
 	return p;
 
 bad_free:
@@ -508,6 +539,27 @@
 	return NULL;
 }
 
+/*
+ * This swap type frees swap entry, check if it is the highest priority swap
+ * type which just frees swap entry. get_swap_page() uses
+ * highest_priority_index to search highest priority swap type. The
+ * swap_info_struct.lock can't protect us if there are multiple swap types
+ * active, so we use atomic_cmpxchg.
+ */
+static void set_highest_priority_index(int type)
+{
+	int old_hp_index, new_hp_index;
+
+	do {
+		old_hp_index = atomic_read(&highest_priority_index);
+		if (old_hp_index != -1 &&
+			swap_info[old_hp_index]->prio >= swap_info[type]->prio)
+			break;
+		new_hp_index = type;
+	} while (atomic_cmpxchg(&highest_priority_index,
+		old_hp_index, new_hp_index) != old_hp_index);
+}
+
 static unsigned char swap_entry_free(struct swap_info_struct *p,
 				     swp_entry_t entry, unsigned char usage)
 {
@@ -551,10 +603,8 @@
 			p->lowest_bit = offset;
 		if (offset > p->highest_bit)
 			p->highest_bit = offset;
-		if (swap_list.next >= 0 &&
-		    p->prio > swap_info[swap_list.next]->prio)
-			swap_list.next = p->type;
-		nr_swap_pages++;
+		set_highest_priority_index(p->type);
+		atomic_long_inc(&nr_swap_pages);
 		p->inuse_pages--;
 		if ((p->flags & SWP_BLKDEV) &&
 				disk->fops->swap_slot_free_notify)
@@ -575,7 +625,7 @@
 	p = swap_info_get(entry);
 	if (p) {
 		swap_entry_free(p, entry, 1);
-		spin_unlock(&swap_lock);
+		spin_unlock(&p->lock);
 	}
 }
 
@@ -592,7 +642,7 @@
 		count = swap_entry_free(p, entry, SWAP_HAS_CACHE);
 		if (page)
 			mem_cgroup_uncharge_swapcache(page, entry, count != 0);
-		spin_unlock(&swap_lock);
+		spin_unlock(&p->lock);
 	}
 }
 
@@ -601,7 +651,7 @@
  * This does not give an exact answer when swap count is continued,
  * but does include the high COUNT_CONTINUED flag to allow for that.
  */
-static inline int page_swapcount(struct page *page)
+int page_swapcount(struct page *page)
 {
 	int count = 0;
 	struct swap_info_struct *p;
@@ -611,7 +661,7 @@
 	p = swap_info_get(entry);
 	if (p) {
 		count = swap_count(p->swap_map[swp_offset(entry)]);
-		spin_unlock(&swap_lock);
+		spin_unlock(&p->lock);
 	}
 	return count;
 }
@@ -699,7 +749,7 @@
 				page = NULL;
 			}
 		}
-		spin_unlock(&swap_lock);
+		spin_unlock(&p->lock);
 	}
 	if (page) {
 		/*
@@ -828,11 +878,13 @@
 	if ((unsigned int)type < nr_swapfiles) {
 		struct swap_info_struct *sis = swap_info[type];
 
+		spin_lock(&sis->lock);
 		if (sis->flags & SWP_WRITEOK) {
 			n = sis->pages;
 			if (free)
 				n -= sis->inuse_pages;
 		}
+		spin_unlock(&sis->lock);
 	}
 	spin_unlock(&swap_lock);
 	return n;
@@ -1528,7 +1580,7 @@
 		p->prio = --least_priority;
 	p->swap_map = swap_map;
 	p->flags |= SWP_WRITEOK;
-	nr_swap_pages += p->pages;
+	atomic_long_add(p->pages, &nr_swap_pages);
 	total_swap_pages += p->pages;
 
 	/* insert swap space into swap_list: */
@@ -1605,14 +1657,16 @@
 		/* just pick something that's safe... */
 		swap_list.next = swap_list.head;
 	}
+	spin_lock(&p->lock);
 	if (p->prio < 0) {
 		for (i = p->next; i >= 0; i = swap_info[i]->next)
 			swap_info[i]->prio = p->prio--;
 		least_priority++;
 	}
-	nr_swap_pages -= p->pages;
+	atomic_long_sub(p->pages, &nr_swap_pages);
 	total_swap_pages -= p->pages;
 	p->flags &= ~SWP_WRITEOK;
+	spin_unlock(&p->lock);
 	spin_unlock(&swap_lock);
 
 	oom_score_adj = test_set_oom_score_adj(OOM_SCORE_ADJ_MAX);
@@ -1637,14 +1691,17 @@
 
 	mutex_lock(&swapon_mutex);
 	spin_lock(&swap_lock);
+	spin_lock(&p->lock);
 	drain_mmlist();
 
 	/* wait for anyone still in scan_swap_map */
 	p->highest_bit = 0;		/* cuts scans short */
 	while (p->flags >= SWP_SCANNING) {
+		spin_unlock(&p->lock);
 		spin_unlock(&swap_lock);
 		schedule_timeout_uninterruptible(1);
 		spin_lock(&swap_lock);
+		spin_lock(&p->lock);
 	}
 
 	swap_file = p->swap_file;
@@ -1653,6 +1710,7 @@
 	swap_map = p->swap_map;
 	p->swap_map = NULL;
 	p->flags = 0;
+	spin_unlock(&p->lock);
 	spin_unlock(&swap_lock);
 	mutex_unlock(&swapon_mutex);
 	vfree(swap_map);
@@ -1856,6 +1914,7 @@
 	p->flags = SWP_USED;
 	p->next = -1;
 	spin_unlock(&swap_lock);
+	spin_lock_init(&p->lock);
 
 	return p;
 }
@@ -2177,7 +2236,7 @@
 		if ((si->flags & SWP_USED) && !(si->flags & SWP_WRITEOK))
 			nr_to_be_unused += si->inuse_pages;
 	}
-	val->freeswap = nr_swap_pages + nr_to_be_unused;
+	val->freeswap = atomic_long_read(&nr_swap_pages) + nr_to_be_unused;
 	val->totalswap = total_swap_pages + nr_to_be_unused;
 	spin_unlock(&swap_lock);
 }
@@ -2210,7 +2269,7 @@
 	p = swap_info[type];
 	offset = swp_offset(entry);
 
-	spin_lock(&swap_lock);
+	spin_lock(&p->lock);
 	if (unlikely(offset >= p->max))
 		goto unlock_out;
 
@@ -2245,7 +2304,7 @@
 	p->swap_map[offset] = count | has_cache;
 
 unlock_out:
-	spin_unlock(&swap_lock);
+	spin_unlock(&p->lock);
 out:
 	return err;
 
@@ -2292,6 +2351,31 @@
 	return __swap_duplicate(entry, SWAP_HAS_CACHE);
 }
 
+struct swap_info_struct *page_swap_info(struct page *page)
+{
+	swp_entry_t swap = { .val = page_private(page) };
+	BUG_ON(!PageSwapCache(page));
+	return swap_info[swp_type(swap)];
+}
+
+/*
+ * out-of-line __page_file_ methods to avoid include hell.
+ */
+struct address_space *__page_file_mapping(struct page *page)
+{
+	VM_BUG_ON(!PageSwapCache(page));
+	return page_swap_info(page)->swap_file->f_mapping;
+}
+EXPORT_SYMBOL_GPL(__page_file_mapping);
+
+pgoff_t __page_file_index(struct page *page)
+{
+	swp_entry_t swap = { .val = page_private(page) };
+	VM_BUG_ON(!PageSwapCache(page));
+	return swp_offset(swap);
+}
+EXPORT_SYMBOL_GPL(__page_file_index);
+
 /*
  * add_swap_count_continuation - called when a swap count is duplicated
  * beyond SWAP_MAP_MAX, it allocates a new page and links that to the entry's
@@ -2345,7 +2429,7 @@
 	}
 
 	if (!page) {
-		spin_unlock(&swap_lock);
+		spin_unlock(&si->lock);
 		return -ENOMEM;
 	}
 
@@ -2393,7 +2477,7 @@
 	list_add_tail(&page->lru, &head->lru);
 	page = NULL;			/* now it's attached, don't free it */
 out:
-	spin_unlock(&swap_lock);
+	spin_unlock(&si->lock);
 outer:
 	if (page)
 		__free_page(page);
diff --git a/mm/vmscan.c b/mm/vmscan.c
index 1438de9..9e95109 100644
--- a/mm/vmscan.c
+++ b/mm/vmscan.c
@@ -158,8 +158,28 @@
 	return &mz->zone->reclaim_stat;
 }
 
+unsigned long zone_reclaimable_pages(struct zone *zone)
+{
+	int nr;
+
+	nr = zone_page_state(zone, NR_ACTIVE_FILE) +
+	     zone_page_state(zone, NR_INACTIVE_FILE);
+
+	if (get_nr_swap_pages() > 0)
+		nr += zone_page_state(zone, NR_ACTIVE_ANON) +
+		      zone_page_state(zone, NR_INACTIVE_ANON);
+
+	return nr;
+}
+
+bool zone_reclaimable(struct zone *zone)
+{
+	return zone->pages_scanned < zone_reclaimable_pages(zone) * 6;
+}
+
 static unsigned long zone_nr_lru_pages(struct mem_cgroup_zone *mz,
 				       enum lru_list lru)
+
 {
 	if (!mem_cgroup_disabled())
 		return mem_cgroup_zone_nr_lru_pages(mz->mem_cgroup,
@@ -1648,13 +1668,13 @@
 	 * latencies, so it's better to scan a minimum amount there as
 	 * well.
 	 */
-	if (current_is_kswapd() && mz->zone->all_unreclaimable)
+	if (current_is_kswapd() && !zone_reclaimable(mz->zone))
 		force_scan = true;
 	if (!global_reclaim(sc))
 		force_scan = true;
 
 	/* If we have no swap space, do not bother scanning anon pages. */
-	if (!sc->may_swap || (nr_swap_pages <= 0)) {
+	if (!sc->may_swap || (get_nr_swap_pages() <= 0)) {
 		noswap = 1;
 		fraction[0] = 0;
 		fraction[1] = 1;
@@ -1798,7 +1818,7 @@
 	 */
 	pages_for_compaction = (2UL << sc->order);
 	inactive_lru_pages = zone_nr_lru_pages(mz, LRU_INACTIVE_FILE);
-	if (nr_swap_pages > 0)
+	if (get_nr_swap_pages() > 0)
 		inactive_lru_pages += zone_nr_lru_pages(mz, LRU_INACTIVE_ANON);
 	if (sc->nr_reclaimed < pages_for_compaction &&
 			inactive_lru_pages > pages_for_compaction)
@@ -1995,8 +2015,8 @@
 		if (global_reclaim(sc)) {
 			if (!cpuset_zone_allowed_hardwall(zone, GFP_KERNEL))
 				continue;
-			if (zone->all_unreclaimable &&
-					sc->priority != DEF_PRIORITY)
+			if (sc->priority != DEF_PRIORITY &&
+			    !zone_reclaimable(zone))
 				continue;	/* Let kswapd poll it */
 			if (COMPACTION_BUILD) {
 				/*
@@ -2034,11 +2054,6 @@
 	return aborted_reclaim;
 }
 
-static bool zone_reclaimable(struct zone *zone)
-{
-	return zone->pages_scanned < zone_reclaimable_pages(zone) * 6;
-}
-
 /* All zones in zonelist are unreclaimable? */
 static bool all_unreclaimable(struct zonelist *zonelist,
 		struct scan_control *sc)
@@ -2052,7 +2067,7 @@
 			continue;
 		if (!cpuset_zone_allowed_hardwall(zone, GFP_KERNEL))
 			continue;
-		if (!zone->all_unreclaimable)
+		if (zone_reclaimable(zone))
 			return false;
 	}
 
@@ -2377,7 +2392,7 @@
 		 * they must be considered balanced here as well if kswapd
 		 * is to sleep
 		 */
-		if (zone->all_unreclaimable) {
+		if (!zone_reclaimable(zone)) {
 			balanced += zone->present_pages;
 			continue;
 		}
@@ -2470,8 +2485,8 @@
 			if (!populated_zone(zone))
 				continue;
 
-			if (zone->all_unreclaimable &&
-			    sc.priority != DEF_PRIORITY)
+			if (sc.priority != DEF_PRIORITY &&
+			    !zone_reclaimable(zone))
 				continue;
 
 			/*
@@ -2525,8 +2540,8 @@
 			if (!populated_zone(zone))
 				continue;
 
-			if (zone->all_unreclaimable &&
-			    sc.priority != DEF_PRIORITY)
+			if (sc.priority != DEF_PRIORITY &&
+			    !zone_reclaimable(zone))
 				continue;
 
 			sc.nr_scanned = 0;
@@ -2576,8 +2591,6 @@
 				sc.nr_reclaimed += reclaim_state->reclaimed_slab;
 				total_scanned += sc.nr_scanned;
 
-				if (nr_slab == 0 && !zone_reclaimable(zone))
-					zone->all_unreclaimable = 1;
 			}
 
 			/*
@@ -2589,7 +2602,7 @@
 			    total_scanned > sc.nr_reclaimed + sc.nr_reclaimed / 2)
 				sc.may_writepage = 1;
 
-			if (zone->all_unreclaimable) {
+			if (!zone_reclaimable(zone)) {
 				if (end_zone && end_zone == i)
 					end_zone--;
 				continue;
@@ -2912,27 +2925,13 @@
 	nr = global_page_state(NR_ACTIVE_FILE) +
 	     global_page_state(NR_INACTIVE_FILE);
 
-	if (nr_swap_pages > 0)
+	if (get_nr_swap_pages() > 0)
 		nr += global_page_state(NR_ACTIVE_ANON) +
 		      global_page_state(NR_INACTIVE_ANON);
 
 	return nr;
 }
 
-unsigned long zone_reclaimable_pages(struct zone *zone)
-{
-	int nr;
-
-	nr = zone_page_state(zone, NR_ACTIVE_FILE) +
-	     zone_page_state(zone, NR_INACTIVE_FILE);
-
-	if (nr_swap_pages > 0)
-		nr += zone_page_state(zone, NR_ACTIVE_ANON) +
-		      zone_page_state(zone, NR_INACTIVE_ANON);
-
-	return nr;
-}
-
 #ifdef CONFIG_HIBERNATION
 /*
  * Try to free `nr_to_reclaim' of memory, system-wide, and return the number of
@@ -3227,7 +3226,7 @@
 	    zone_page_state(zone, NR_SLAB_RECLAIMABLE) <= zone->min_slab_pages)
 		return ZONE_RECLAIM_FULL;
 
-	if (zone->all_unreclaimable)
+	if (!zone_reclaimable(zone))
 		return ZONE_RECLAIM_FULL;
 
 	/*
diff --git a/mm/vmstat.c b/mm/vmstat.c
index 959a558..9559032 100644
--- a/mm/vmstat.c
+++ b/mm/vmstat.c
@@ -19,6 +19,9 @@
 #include <linux/math64.h>
 #include <linux/writeback.h>
 #include <linux/compaction.h>
+#include <linux/mm_inline.h>
+
+#include "internal.h"
 
 #ifdef CONFIG_VM_EVENT_COUNTERS
 DEFINE_PER_CPU(struct vm_event_state, vm_event_states) = {{0}};
@@ -1027,7 +1030,7 @@
 		   "\n  all_unreclaimable: %u"
 		   "\n  start_pfn:         %lu"
 		   "\n  inactive_ratio:    %u",
-		   zone->all_unreclaimable,
+		   !zone_reclaimable(zone),
 		   zone->zone_start_pfn,
 		   zone->inactive_ratio);
 	seq_putc(m, '\n');
diff --git a/sound/soc/codecs/msm8x10-wcd.c b/sound/soc/codecs/msm8x10-wcd.c
index 6785fe1..52af21c 100644
--- a/sound/soc/codecs/msm8x10-wcd.c
+++ b/sound/soc/codecs/msm8x10-wcd.c
@@ -3007,10 +3007,21 @@
 
 	return NULL;
 }
+static int msm8x10_wcd_device_down(struct snd_soc_codec *codec)
+{
+	dev_dbg(codec->dev, "%s: device down!\n", __func__);
+
+	snd_soc_card_change_online_state(codec->card, 0);
+	return 0;
+}
 
 static int msm8x10_wcd_device_up(struct snd_soc_codec *codec)
 {
-	pr_debug("%s: device up!\n", __func__);
+	dev_dbg(codec->dev, "%s: device up!\n", __func__);
+
+	snd_soc_card_change_online_state(codec->card, 1);
+	/* delay is required to make sure sound card state updated */
+	usleep_range(5000, 5100);
 
 	mutex_lock(&codec->mutex);
 
@@ -3029,7 +3040,9 @@
 	bool timedout;
 	unsigned long timeout;
 
-	if (value == SUBSYS_AFTER_POWERUP) {
+	if (value == SUBSYS_BEFORE_SHUTDOWN)
+		msm8x10_wcd_device_down(registered_codec);
+	else if (value == SUBSYS_AFTER_POWERUP) {
 		pr_debug("%s: ADSP is about to power up. bring up codec\n",
 			 __func__);
 
diff --git a/sound/soc/codecs/wcd9306.c b/sound/soc/codecs/wcd9306.c
index da99254..aaa132e 100644
--- a/sound/soc/codecs/wcd9306.c
+++ b/sound/soc/codecs/wcd9306.c
@@ -3154,13 +3154,27 @@
 		struct snd_soc_dai *dai)
 {
 	struct wcd9xxx *tapan_core = dev_get_drvdata(dai->codec->dev->parent);
+	struct tapan_priv *tapan = snd_soc_codec_get_drvdata(dai->codec);
+	u32 active = 0;
+
 	dev_dbg(dai->codec->dev, "%s(): substream = %s  stream = %d\n",
 		 __func__, substream->name, substream->stream);
+
+	if (dai->id <= NUM_CODEC_DAIS) {
+		if (tapan->dai[dai->id].ch_mask) {
+			active = 1;
+			dev_dbg(dai->codec->dev, "%s(): Codec DAI: chmask[%d] = 0x%lx\n",
+				 __func__, dai->id,
+				 tapan->dai[dai->id].ch_mask);
+		}
+	}
 	if ((tapan_core != NULL) &&
 	    (tapan_core->dev != NULL) &&
-	    (tapan_core->dev->parent != NULL)) {
+	    (tapan_core->dev->parent != NULL) &&
+	    (active == 0)) {
 		pm_runtime_mark_last_busy(tapan_core->dev->parent);
 		pm_runtime_put(tapan_core->dev->parent);
+		dev_dbg(dai->codec->dev, "%s: unvote requested", __func__);
 	}
 }
 
@@ -3920,6 +3934,13 @@
 			dev_dbg(codec->dev, "%s: Disconnect RX port, ret = %d\n",
 				 __func__, ret);
 		}
+		if ((core != NULL) &&
+		    (core->dev != NULL) &&
+		    (core->dev->parent != NULL)) {
+			pm_runtime_mark_last_busy(core->dev->parent);
+			pm_runtime_put(core->dev->parent);
+			dev_dbg(codec->dev, "%s: unvote requested", __func__);
+		}
 		break;
 	}
 	return ret;
@@ -3967,6 +3988,13 @@
 			dev_dbg(codec->dev, "%s: Disconnect RX port, ret = %d\n",
 				 __func__, ret);
 		}
+		if ((core != NULL) &&
+		    (core->dev != NULL) &&
+		    (core->dev->parent != NULL)) {
+			pm_runtime_mark_last_busy(core->dev->parent);
+			pm_runtime_put(core->dev->parent);
+			dev_dbg(codec->dev, "%s: unvote requested", __func__);
+		}
 		break;
 	}
 	return ret;
diff --git a/sound/soc/codecs/wcd9310.c b/sound/soc/codecs/wcd9310.c
index 673b634..725c51f 100644
--- a/sound/soc/codecs/wcd9310.c
+++ b/sound/soc/codecs/wcd9310.c
@@ -1235,49 +1235,49 @@
 	SOC_SINGLE_TLV("HPHR Volume", TABLA_A_RX_HPH_R_GAIN, 0, 12, 1,
 		line_gain),
 
-	SOC_SINGLE_S8_TLV("RX1 Digital Volume", TABLA_A_CDC_RX1_VOL_CTL_B2_CTL,
-		-84, 40, digital_gain),
-	SOC_SINGLE_S8_TLV("RX2 Digital Volume", TABLA_A_CDC_RX2_VOL_CTL_B2_CTL,
-		-84, 40, digital_gain),
-	SOC_SINGLE_S8_TLV("RX3 Digital Volume", TABLA_A_CDC_RX3_VOL_CTL_B2_CTL,
-		-84, 40, digital_gain),
-	SOC_SINGLE_S8_TLV("RX4 Digital Volume", TABLA_A_CDC_RX4_VOL_CTL_B2_CTL,
-		-84, 40, digital_gain),
-	SOC_SINGLE_S8_TLV("RX5 Digital Volume", TABLA_A_CDC_RX5_VOL_CTL_B2_CTL,
-		-84, 40, digital_gain),
-	SOC_SINGLE_S8_TLV("RX6 Digital Volume", TABLA_A_CDC_RX6_VOL_CTL_B2_CTL,
-		-84, 40, digital_gain),
-	SOC_SINGLE_S8_TLV("RX7 Digital Volume", TABLA_A_CDC_RX7_VOL_CTL_B2_CTL,
-		-84, 40, digital_gain),
+	SOC_SINGLE_SX_TLV("RX1 Digital Volume", TABLA_A_CDC_RX1_VOL_CTL_B2_CTL,
+		0, -84, 40, digital_gain),
+	SOC_SINGLE_SX_TLV("RX2 Digital Volume", TABLA_A_CDC_RX2_VOL_CTL_B2_CTL,
+		0, -84, 40, digital_gain),
+	SOC_SINGLE_SX_TLV("RX3 Digital Volume", TABLA_A_CDC_RX3_VOL_CTL_B2_CTL,
+		0, -84, 40, digital_gain),
+	SOC_SINGLE_SX_TLV("RX4 Digital Volume", TABLA_A_CDC_RX4_VOL_CTL_B2_CTL,
+		0, -84, 40, digital_gain),
+	SOC_SINGLE_SX_TLV("RX5 Digital Volume", TABLA_A_CDC_RX5_VOL_CTL_B2_CTL,
+		0, -84, 40, digital_gain),
+	SOC_SINGLE_SX_TLV("RX6 Digital Volume", TABLA_A_CDC_RX6_VOL_CTL_B2_CTL,
+		0, -84, 40, digital_gain),
+	SOC_SINGLE_SX_TLV("RX7 Digital Volume", TABLA_A_CDC_RX7_VOL_CTL_B2_CTL,
+		0, -84, 40, digital_gain),
 
-	SOC_SINGLE_S8_TLV("DEC1 Volume", TABLA_A_CDC_TX1_VOL_CTL_GAIN, -84, 40,
-		digital_gain),
-	SOC_SINGLE_S8_TLV("DEC2 Volume", TABLA_A_CDC_TX2_VOL_CTL_GAIN, -84, 40,
-		digital_gain),
-	SOC_SINGLE_S8_TLV("DEC3 Volume", TABLA_A_CDC_TX3_VOL_CTL_GAIN, -84, 40,
-		digital_gain),
-	SOC_SINGLE_S8_TLV("DEC4 Volume", TABLA_A_CDC_TX4_VOL_CTL_GAIN, -84, 40,
-		digital_gain),
-	SOC_SINGLE_S8_TLV("DEC5 Volume", TABLA_A_CDC_TX5_VOL_CTL_GAIN, -84, 40,
-		digital_gain),
-	SOC_SINGLE_S8_TLV("DEC6 Volume", TABLA_A_CDC_TX6_VOL_CTL_GAIN, -84, 40,
-		digital_gain),
-	SOC_SINGLE_S8_TLV("DEC7 Volume", TABLA_A_CDC_TX7_VOL_CTL_GAIN, -84, 40,
-		digital_gain),
-	SOC_SINGLE_S8_TLV("DEC8 Volume", TABLA_A_CDC_TX8_VOL_CTL_GAIN, -84, 40,
-		digital_gain),
-	SOC_SINGLE_S8_TLV("DEC9 Volume", TABLA_A_CDC_TX9_VOL_CTL_GAIN, -84, 40,
-		digital_gain),
-	SOC_SINGLE_S8_TLV("DEC10 Volume", TABLA_A_CDC_TX10_VOL_CTL_GAIN, -84,
+	SOC_SINGLE_SX_TLV("DEC1 Volume", TABLA_A_CDC_TX1_VOL_CTL_GAIN, 0, -84,
 		40, digital_gain),
-	SOC_SINGLE_S8_TLV("IIR1 INP1 Volume", TABLA_A_CDC_IIR1_GAIN_B1_CTL, -84,
+	SOC_SINGLE_SX_TLV("DEC2 Volume", TABLA_A_CDC_TX2_VOL_CTL_GAIN, 0, -84,
 		40, digital_gain),
-	SOC_SINGLE_S8_TLV("IIR1 INP2 Volume", TABLA_A_CDC_IIR1_GAIN_B2_CTL, -84,
+	SOC_SINGLE_SX_TLV("DEC3 Volume", TABLA_A_CDC_TX3_VOL_CTL_GAIN, 0, -84,
 		40, digital_gain),
-	SOC_SINGLE_S8_TLV("IIR1 INP3 Volume", TABLA_A_CDC_IIR1_GAIN_B3_CTL, -84,
+	SOC_SINGLE_SX_TLV("DEC4 Volume", TABLA_A_CDC_TX4_VOL_CTL_GAIN, 0, -84,
 		40, digital_gain),
-	SOC_SINGLE_S8_TLV("IIR1 INP4 Volume", TABLA_A_CDC_IIR1_GAIN_B4_CTL, -84,
+	SOC_SINGLE_SX_TLV("DEC5 Volume", TABLA_A_CDC_TX5_VOL_CTL_GAIN, 0, -84,
 		40, digital_gain),
+	SOC_SINGLE_SX_TLV("DEC6 Volume", TABLA_A_CDC_TX6_VOL_CTL_GAIN, 0, -84,
+		40, digital_gain),
+	SOC_SINGLE_SX_TLV("DEC7 Volume", TABLA_A_CDC_TX7_VOL_CTL_GAIN, 0, -84,
+		40, digital_gain),
+	SOC_SINGLE_SX_TLV("DEC8 Volume", TABLA_A_CDC_TX8_VOL_CTL_GAIN, 0, -84,
+		40, digital_gain),
+	SOC_SINGLE_SX_TLV("DEC9 Volume", TABLA_A_CDC_TX9_VOL_CTL_GAIN, 0, -84,
+		40, digital_gain),
+	SOC_SINGLE_SX_TLV("DEC10 Volume", TABLA_A_CDC_TX10_VOL_CTL_GAIN, 0,
+		-84, 40, digital_gain),
+	SOC_SINGLE_SX_TLV("IIR1 INP1 Volume", TABLA_A_CDC_IIR1_GAIN_B1_CTL, 0,
+		-84, 40, digital_gain),
+	SOC_SINGLE_SX_TLV("IIR1 INP2 Volume", TABLA_A_CDC_IIR1_GAIN_B2_CTL, 0,
+		-84, 40, digital_gain),
+	SOC_SINGLE_SX_TLV("IIR1 INP3 Volume", TABLA_A_CDC_IIR1_GAIN_B3_CTL, 0,
+		-84, 40, digital_gain),
+	SOC_SINGLE_SX_TLV("IIR1 INP4 Volume", TABLA_A_CDC_IIR1_GAIN_B4_CTL, 0,
+		-84, 40, digital_gain),
 	SOC_SINGLE_TLV("ADC1 Volume", TABLA_A_TX_1_2_EN, 5, 3, 0, analog_gain),
 	SOC_SINGLE_TLV("ADC2 Volume", TABLA_A_TX_1_2_EN, 1, 3, 0, analog_gain),
 	SOC_SINGLE_TLV("ADC3 Volume", TABLA_A_TX_3_4_EN, 5, 3, 0, analog_gain),
@@ -2155,7 +2155,7 @@
 		goto err;
 	}
 rtn:
-	snd_soc_dapm_mux_update_power(widget, kcontrol, 1, widget->value, e);
+	snd_soc_dapm_mux_update_power(widget, kcontrol, widget->value, e);
 	mutex_unlock(&codec->mutex);
 	return 0;
 err:
diff --git a/sound/soc/codecs/wcd9320.c b/sound/soc/codecs/wcd9320.c
index 9cad1e5..6dc2ec0 100644
--- a/sound/soc/codecs/wcd9320.c
+++ b/sound/soc/codecs/wcd9320.c
@@ -4974,12 +4974,6 @@
 		/*Enable spkr VI clocks*/
 		snd_soc_update_bits(codec,
 		TAIKO_A_CDC_CLK_TX_CLK_EN_B2_CTL, 0xC, 0xC);
-		/*Enable Voltage Decimator*/
-		snd_soc_update_bits(codec,
-		TAIKO_A_CDC_CONN_TX_SB_B9_CTL, 0x1F, 0x12);
-		/*Enable Current Decimator*/
-		snd_soc_update_bits(codec,
-		TAIKO_A_CDC_CONN_TX_SB_B10_CTL, 0x1F, 0x13);
 		(void) taiko_codec_enable_slim_chmask(dai, true);
 		ret = wcd9xxx_cfg_slim_sch_tx(core, &dai->wcd9xxx_ch_list,
 					dai->rate, dai->bit_width,
@@ -4991,13 +4985,6 @@
 		if (ret)
 			pr_err("%s error in close_slim_sch_tx %d\n",
 				__func__, ret);
-		/*Disable Voltage decimator*/
-		snd_soc_update_bits(codec,
-		TAIKO_A_CDC_CONN_TX_SB_B9_CTL, 0x1F, 0x0);
-		/*Disable Current decimator*/
-		snd_soc_update_bits(codec,
-		TAIKO_A_CDC_CONN_TX_SB_B10_CTL, 0x1F, 0x0);
-		/*Disable spkr VI clocks*/
 		snd_soc_update_bits(codec, TAIKO_A_CDC_CLK_TX_CLK_EN_B2_CTL,
 				0xC, 0x0);
 		/*Disable V&I sensing*/
@@ -5988,6 +5975,10 @@
 
 	/* Set HPH Path to low power mode */
 	TAIKO_REG_VAL(TAIKO_A_RX_HPH_BIAS_PA, 0x55),
+
+	/* BUCK default */
+	TAIKO_REG_VAL(WCD9XXX_A_BUCK_CTRL_CCL_4, 0x51),
+	TAIKO_REG_VAL(WCD9XXX_A_BUCK_CTRL_CCL_1, 0x5B),
 };
 
 static const struct wcd9xxx_reg_mask_val taiko_1_0_reg_defaults[] = {
@@ -5996,13 +5987,9 @@
 	 * Taiko 2.0 will have appropriate defaults for these registers.
 	 */
 
-	/* BUCK default */
-	TAIKO_REG_VAL(WCD9XXX_A_BUCK_CTRL_CCL_4, 0x50),
-
 	/* Required defaults for class H operation */
 	TAIKO_REG_VAL(TAIKO_A_RX_HPH_CHOP_CTL, 0xF4),
 	TAIKO_REG_VAL(TAIKO_A_BIAS_CURR_CTL_2, 0x08),
-	TAIKO_REG_VAL(WCD9XXX_A_BUCK_CTRL_CCL_1, 0x5B),
 	TAIKO_REG_VAL(WCD9XXX_A_BUCK_CTRL_CCL_3, 0x60),
 
 	/* Choose max non-overlap time for NCP */
@@ -6053,7 +6040,7 @@
 	TAIKO_REG_VAL(TAIKO_A_CDC_TX_5_6_ADC_IB, 0x44),
 	TAIKO_REG_VAL(WCD9XXX_A_BUCK_MODE_3, 0xCE),
 	TAIKO_REG_VAL(WCD9XXX_A_BUCK_CTRL_VCL_1, 0x8),
-	TAIKO_REG_VAL(WCD9XXX_A_BUCK_CTRL_CCL_4, 0x51),
+	TAIKO_REG_VAL(TAIKO_A_BUCK_CTRL_CCL_4, 0x51),
 	TAIKO_REG_VAL(TAIKO_A_NCP_DTEST, 0x10),
 	TAIKO_REG_VAL(TAIKO_A_RX_HPH_CHOP_CTL, 0xA4),
 	TAIKO_REG_VAL(TAIKO_A_RX_HPH_OCP_CTL, 0x69),
@@ -6094,6 +6081,7 @@
 	TAIKO_REG_VAL(TAIKO_A_CDC_SPKR_CLIPDET_B1_CTL, 0x0),
 	TAIKO_REG_VAL(TAIKO_A_CDC_COMP0_B4_CTL, 0x37),
 	TAIKO_REG_VAL(TAIKO_A_CDC_COMP0_B5_CTL, 0x7f),
+	TAIKO_REG_VAL(TAIKO_A_CDC_COMP0_B5_CTL, 0x7f),
 };
 
 static void taiko_update_reg_defaults(struct snd_soc_codec *codec)
diff --git a/sound/soc/codecs/wcd9xxx-common.c b/sound/soc/codecs/wcd9xxx-common.c
index 05f2191..b104a6b 100644
--- a/sound/soc/codecs/wcd9xxx-common.c
+++ b/sound/soc/codecs/wcd9xxx-common.c
@@ -22,12 +22,11 @@
 #define CLSH_COMPUTE_HPH_L 0x02
 #define CLSH_COMPUTE_HPH_R 0x03
 
+#define BUCK_VREF_0P494V 0x3F
 #define BUCK_VREF_2V 0xFF
+#define BUCK_VREF_0P494V 0x3F
 #define BUCK_VREF_1P8V 0xE6
 
-#define NCP_FCLK_LEVEL_8 0x08
-#define NCP_FCLK_LEVEL_5 0x05
-
 #define BUCK_SETTLE_TIME_US 50
 #define NCP_SETTLE_TIME_US 50
 
@@ -414,12 +413,16 @@
 	{32164, 22},
 };
 
-static inline void wcd9xxx_enable_clsh_block(
-	struct snd_soc_codec *codec,
-	bool on)
+static inline void
+wcd9xxx_enable_clsh_block(struct snd_soc_codec *codec,
+			  struct wcd9xxx_clsh_cdc_data *clsh_d, bool enable)
 {
-	snd_soc_update_bits(codec, WCD9XXX_A_CDC_CLSH_B1_CTL,
-		0x01, on ? 0x01 : 0x00);
+	if ((enable && ++clsh_d->clsh_users == 1) ||
+	    (!enable && --clsh_d->clsh_users == 0))
+		snd_soc_update_bits(codec, WCD9XXX_A_CDC_CLSH_B1_CTL,
+				    0x01, enable ? 0x01 : 0x00);
+	dev_dbg(codec->dev, "%s: clsh_users %d, enable %d", __func__,
+		clsh_d->clsh_users, enable);
 }
 
 static inline void wcd9xxx_enable_anc_delay(
@@ -430,64 +433,56 @@
 		0x02, on ? 0x02 : 0x00);
 }
 
-static inline void wcd9xxx_enable_ncp(
-	struct snd_soc_codec *codec,
-	bool on)
+static inline void
+wcd9xxx_enable_buck(struct snd_soc_codec *codec,
+		    struct wcd9xxx_clsh_cdc_data *clsh_d, bool enable)
 {
-	snd_soc_update_bits(codec, WCD9XXX_A_NCP_EN,
-		0x01, on ? 0x01 : 0x00);
+	if ((enable && ++clsh_d->buck_users == 1) ||
+	    (!enable && --clsh_d->buck_users == 0))
+		snd_soc_update_bits(codec, WCD9XXX_A_BUCK_MODE_1,
+				    0x80, enable ? 0x80 : 0x00);
+	dev_dbg(codec->dev, "%s: buck_users %d, enable %d", __func__,
+		clsh_d->buck_users, enable);
 }
 
-static inline void wcd9xxx_enable_buck(
-	struct snd_soc_codec *codec,
-	bool on)
-{
-	snd_soc_update_bits(codec, WCD9XXX_A_BUCK_MODE_1,
-		0x80, on ? 0x80 : 0x00);
-}
+static void (*clsh_state_fp[NUM_CLSH_STATES])(struct snd_soc_codec *,
+					      struct wcd9xxx_clsh_cdc_data *,
+					      u8 req_state, bool req_type);
 
-static int cdc_lo_count;
-
-static void (*clsh_state_fp[NUM_CLSH_STATES])
-			(struct snd_soc_codec *,
-			 struct wcd9xxx_clsh_cdc_data *,
-			 u8 req_state, bool req_type);
-
-static const char *state_to_str(u8 state)
-{
-	if (state == WCD9XXX_CLSH_STATE_IDLE)
-		return "STATE_IDLE";
-	else if (state == WCD9XXX_CLSH_STATE_EAR)
-		return "STATE_EAR";
-	else if (state == WCD9XXX_CLSH_STATE_HPHL)
-		return "STATE_HPH_L";
-	else if (state == WCD9XXX_CLSH_STATE_HPHR)
-		return "STATE_HPH_R";
-	else if (state == (WCD9XXX_CLSH_STATE_HPHL
-				| WCD9XXX_CLSH_STATE_HPHR))
-		return "STATE_HPH_L_R";
-	else if (state == WCD9XXX_CLSH_STATE_LO)
-		return "STATE_LO";
-
-	return "UNKNOWN_STATE";
-}
-
-static void wcd9xxx_cfg_clsh_buck(
-		struct snd_soc_codec *codec)
+static const char *state_to_str(u8 state, char *buf, size_t buflen)
 {
 	int i;
-	const struct wcd9xxx_reg_mask_val reg_set[] = {
-		{WCD9XXX_A_BUCK_CTRL_CCL_4, 0x0B, 0x00},
-		{WCD9XXX_A_BUCK_CTRL_CCL_1, 0xF0, 0x50},
-		{WCD9XXX_A_BUCK_CTRL_CCL_3, 0x03, 0x00},
-		{WCD9XXX_A_BUCK_CTRL_CCL_3, 0x0B, 0x00},
+	int cnt = 0;
+	/*
+	 * This array of strings should match with enum wcd9xxx_clsh_state_bit.
+	 */
+	const char *states[] = {
+		"STATE_EAR",
+		"STATE_HPH_L",
+		"STATE_HPH_R",
+		"STATE_LO",
 	};
 
-	for (i = 0; i < ARRAY_SIZE(reg_set); i++)
-		snd_soc_update_bits(codec, reg_set[i].reg, reg_set[i].mask,
-						    reg_set[i].val);
+	if (state == WCD9XXX_CLSH_STATE_IDLE) {
+		snprintf(buf, buflen, "[STATE_IDLE]");
+		goto done;
+	}
 
-	dev_dbg(codec->dev, "%s: Programmed buck parameters", __func__);
+	buf[0] = '\0';
+	for (i = 0; i < ARRAY_SIZE(states); i++) {
+		if (!(state & (1 << i)))
+			continue;
+		cnt = snprintf(buf, buflen - cnt - 1, "%s%s%s", buf,
+			       buf[0] == '\0' ? "[" : "|",
+			       states[i]);
+	}
+	if (cnt > 0)
+		strlcat(buf + cnt, "]", buflen);
+
+done:
+	if (buf[0] == '\0')
+		snprintf(buf, buflen, "[STATE_UNKNOWN]");
+	return buf;
 }
 
 static void wcd9xxx_cfg_clsh_param_common(
@@ -515,26 +510,25 @@
 			 __func__);
 }
 
-static void wcd9xxx_chargepump_request(
-	struct snd_soc_codec *codec, bool on)
+static void wcd9xxx_chargepump_request(struct snd_soc_codec *codec, bool on)
 {
 	static int cp_count;
 
 	if (on && (++cp_count == 1)) {
 		snd_soc_update_bits(codec, WCD9XXX_A_CDC_CLK_OTHR_CTL,
-							0x01, 0x01);
+				    0x01, 0x01);
 		dev_dbg(codec->dev, "%s: Charge Pump enabled, count = %d\n",
-				__func__, cp_count);
-	}
-
-	else if (!on) {
+			__func__, cp_count);
+	} else if (!on) {
 		if (--cp_count < 0) {
-			dev_dbg(codec->dev, "%s: Unbalanced disable for charge pump\n",
+			dev_dbg(codec->dev,
+				"%s: Unbalanced disable for charge pump\n",
+				__func__);
+			if (snd_soc_read(codec, WCD9XXX_A_CDC_CLK_OTHR_CTL) &
+			    0x01) {
+				dev_dbg(codec->dev,
+					"%s: Actual chargepump is ON\n",
 					__func__);
-			if (snd_soc_read(codec, WCD9XXX_A_CDC_CLK_OTHR_CTL)
-					& 0x01) {
-				dev_dbg(codec->dev, "%s: Actual chargepump is ON\n",
-						__func__);
 			}
 			cp_count = 0;
 			WARN_ON(1);
@@ -542,9 +536,10 @@
 
 		if (cp_count == 0) {
 			snd_soc_update_bits(codec, WCD9XXX_A_CDC_CLK_OTHR_CTL,
-							0x01, 0x00);
-			dev_dbg(codec->dev, "%s: Charge pump disabled, count = %d\n",
-					__func__, cp_count);
+					    0x01, 0x00);
+			dev_dbg(codec->dev,
+				"%s: Charge pump disabled, count = %d\n",
+				__func__, cp_count);
 		}
 	}
 }
@@ -617,7 +612,6 @@
 	}
 }
 
-
 int wcd9xxx_soc_update_bits_push(struct snd_soc_codec *codec,
 					struct list_head *list,
 					uint16_t reg, uint8_t mask,
@@ -657,18 +651,15 @@
 }
 EXPORT_SYMBOL(wcd9xxx_restore_registers);
 
-static void wcd9xxx_enable_buck_mode(struct snd_soc_codec *codec,
-		u8 buck_vref)
+static void wcd9xxx_set_buck_mode(struct snd_soc_codec *codec, u8 buck_vref)
 {
 	int i;
 	const struct wcd9xxx_reg_mask_val reg_set[] = {
-		{WCD9XXX_A_BUCK_MODE_5, 0x02, 0x03},
+		{WCD9XXX_A_BUCK_MODE_5, 0x02, 0x02},
 		{WCD9XXX_A_BUCK_MODE_4, 0xFF, buck_vref},
 		{WCD9XXX_A_BUCK_MODE_1, 0x04, 0x04},
-		{WCD9XXX_A_BUCK_MODE_1, 0x08, 0x00},
 		{WCD9XXX_A_BUCK_MODE_3, 0x04, 0x00},
 		{WCD9XXX_A_BUCK_MODE_3, 0x08, 0x00},
-		{WCD9XXX_A_BUCK_MODE_1, 0x80, 0x80},
 	};
 
 	for (i = 0; i < ARRAY_SIZE(reg_set); i++)
@@ -704,25 +695,51 @@
 
 }
 
-static void wcd9xxx_set_fclk_enable_ncp(struct snd_soc_codec *codec,
-		u8 fclk_level)
+static void wcd9xxx_set_fclk_get_ncp(struct snd_soc_codec *codec,
+				     struct wcd9xxx_clsh_cdc_data *clsh_d,
+				     enum ncp_fclk_level fclk_level)
 {
-	int i;
-	const struct wcd9xxx_reg_mask_val reg_set[] = {
-		{WCD9XXX_A_NCP_STATIC, 0x20, 0x20},
-		{WCD9XXX_A_NCP_EN, 0x01, 0x01},
-	};
-	snd_soc_update_bits(codec, WCD9XXX_A_NCP_STATIC,
-						0x010, 0x00);
-	snd_soc_update_bits(codec, WCD9XXX_A_NCP_STATIC,
-						0x0F, fclk_level);
-	for (i = 0; i < ARRAY_SIZE(reg_set); i++)
-		snd_soc_update_bits(codec, reg_set[i].reg,
-					reg_set[i].mask, reg_set[i].val);
+	clsh_d->ncp_users[fclk_level]++;
 
-	usleep_range(NCP_SETTLE_TIME_US, NCP_SETTLE_TIME_US);
+	pr_debug("%s: enter ncp type %d users fclk8 %d, fclk5 %d\n", __func__,
+		 fclk_level, clsh_d->ncp_users[NCP_FCLK_LEVEL_8],
+		 clsh_d->ncp_users[NCP_FCLK_LEVEL_5]);
 
-	dev_dbg(codec->dev, "%s: set ncp done\n", __func__);
+	snd_soc_update_bits(codec, WCD9XXX_A_NCP_STATIC, 0x10, 0x00);
+	/* fclk level 8 dominates level 5 */
+	if (clsh_d->ncp_users[NCP_FCLK_LEVEL_8] > 0)
+		snd_soc_update_bits(codec, WCD9XXX_A_NCP_STATIC, 0x0F, 0x08);
+	else if (clsh_d->ncp_users[NCP_FCLK_LEVEL_5] > 0)
+		snd_soc_update_bits(codec, WCD9XXX_A_NCP_STATIC, 0x0F, 0x05);
+	else
+		WARN_ONCE(1, "Unexpected users %d,%d\n",
+			  clsh_d->ncp_users[NCP_FCLK_LEVEL_8],
+			  clsh_d->ncp_users[NCP_FCLK_LEVEL_5]);
+	snd_soc_update_bits(codec, WCD9XXX_A_NCP_STATIC, 0x20, 0x20);
+
+	/* enable NCP and wait until settles down */
+	if (snd_soc_update_bits(codec, WCD9XXX_A_NCP_EN, 0x01, 0x01))
+		usleep_range(NCP_SETTLE_TIME_US, NCP_SETTLE_TIME_US);
+	pr_debug("%s: leave\n", __func__);
+}
+
+static void wcd9xxx_set_fclk_put_ncp(struct snd_soc_codec *codec,
+				     struct wcd9xxx_clsh_cdc_data *clsh_d,
+				     enum ncp_fclk_level fclk_level)
+{
+	clsh_d->ncp_users[fclk_level]--;
+
+	pr_debug("%s: enter ncp type %d users fclk8 %d, fclk5 %d\n", __func__,
+		 fclk_level, clsh_d->ncp_users[NCP_FCLK_LEVEL_8],
+		 clsh_d->ncp_users[NCP_FCLK_LEVEL_5]);
+
+	if (clsh_d->ncp_users[NCP_FCLK_LEVEL_8] == 0 &&
+	    clsh_d->ncp_users[NCP_FCLK_LEVEL_5] == 0)
+		snd_soc_update_bits(codec, WCD9XXX_A_NCP_EN, 0x01, 0x00);
+	else if (clsh_d->ncp_users[NCP_FCLK_LEVEL_8] == 0)
+		/* if dominating level 8 has gone, switch to 5 */
+		snd_soc_update_bits(codec, WCD9XXX_A_NCP_STATIC, 0x0F, 0x05);
+	pr_debug("%s: leave\n", __func__);
 }
 
 static void wcd9xxx_cfg_clsh_param_ear(struct snd_soc_codec *codec)
@@ -790,72 +807,30 @@
 			 __func__);
 }
 
-static void wcd9xxx_clsh_turnoff_postpa
-	(struct snd_soc_codec *codec)
-{
-
-	int i;
-
-	const struct wcd9xxx_reg_mask_val reg_set[] = {
-		{WCD9XXX_A_NCP_EN, 0x01, 0x00},
-		{WCD9XXX_A_BUCK_MODE_1, 0x80, 0x00},
-		{WCD9XXX_A_CDC_CLSH_B1_CTL, 0x10, 0x00},
-	};
-
-	wcd9xxx_chargepump_request(codec, false);
-
-	for (i = 0; i < ARRAY_SIZE(reg_set); i++)
-		snd_soc_update_bits(codec, reg_set[i].reg,
-				reg_set[i].mask, reg_set[i].val);
-
-	wcd9xxx_enable_clsh_block(codec, false);
-
-	dev_dbg(codec->dev, "%s: Done\n", __func__);
-}
-
-static void wcd9xxx_clsh_state_idle(struct snd_soc_codec *codec,
-			struct wcd9xxx_clsh_cdc_data *clsh_d,
-			u8 req_state, bool is_enable)
-{
-	if (is_enable) {
-		dev_dbg(codec->dev, "%s: wrong transition, cannot enable IDLE state\n",
-			   __func__);
-	} else {
-		if (req_state == WCD9XXX_CLSH_STATE_EAR) {
-			wcd9xxx_clsh_turnoff_postpa(codec);
-		} else if (req_state == WCD9XXX_CLSH_STATE_HPHL) {
-			wcd9xxx_clsh_comp_req(codec, clsh_d, CLSH_COMPUTE_HPH_L,
-					      false);
-			wcd9xxx_clsh_turnoff_postpa(codec);
-		} else if (req_state == WCD9XXX_CLSH_STATE_HPHR) {
-			wcd9xxx_clsh_comp_req(codec, clsh_d, CLSH_COMPUTE_HPH_R,
-					      false);
-			wcd9xxx_clsh_turnoff_postpa(codec);
-		} else if (req_state == WCD9XXX_CLSH_STATE_LO) {
-			wcd9xxx_enable_ncp(codec, false);
-			wcd9xxx_enable_buck(codec, false);
-		}
-	}
-}
-
 static void wcd9xxx_clsh_state_ear(struct snd_soc_codec *codec,
 			struct wcd9xxx_clsh_cdc_data *clsh_d,
 			u8 req_state, bool is_enable)
 {
+	pr_debug("%s: enter %s\n", __func__, is_enable ? "enable" : "disable");
 	if (is_enable) {
-		wcd9xxx_cfg_clsh_buck(codec);
 		wcd9xxx_cfg_clsh_param_common(codec);
 		wcd9xxx_cfg_clsh_param_ear(codec);
-		wcd9xxx_enable_clsh_block(codec, true);
+		wcd9xxx_enable_clsh_block(codec, clsh_d, true);
 		wcd9xxx_chargepump_request(codec, true);
 		wcd9xxx_enable_anc_delay(codec, true);
 		wcd9xxx_clsh_comp_req(codec, clsh_d, CLSH_COMPUTE_EAR, true);
-		wcd9xxx_enable_buck_mode(codec, BUCK_VREF_2V);
-		wcd9xxx_set_fclk_enable_ncp(codec, NCP_FCLK_LEVEL_8);
+		wcd9xxx_set_buck_mode(codec, BUCK_VREF_2V);
+		wcd9xxx_enable_buck(codec, clsh_d, true);
+		wcd9xxx_set_fclk_get_ncp(codec, clsh_d, NCP_FCLK_LEVEL_8);
 
 		dev_dbg(codec->dev, "%s: Enabled ear mode class h\n", __func__);
 	} else {
 		dev_dbg(codec->dev, "%s: stub fallback to ear\n", __func__);
+		wcd9xxx_set_fclk_put_ncp(codec, clsh_d, NCP_FCLK_LEVEL_8);
+		wcd9xxx_enable_buck(codec, clsh_d, false);
+		wcd9xxx_clsh_comp_req(codec, clsh_d, CLSH_COMPUTE_EAR, true);
+		wcd9xxx_chargepump_request(codec, false);
+		wcd9xxx_enable_clsh_block(codec, clsh_d, false);
 	}
 }
 
@@ -863,26 +838,26 @@
 		struct wcd9xxx_clsh_cdc_data *clsh_d,
 		u8 req_state, bool is_enable)
 {
+	pr_debug("%s: enter %s\n", __func__, is_enable ? "enable" : "disable");
+
 	if (is_enable) {
-		wcd9xxx_cfg_clsh_buck(codec);
 		wcd9xxx_cfg_clsh_param_common(codec);
 		wcd9xxx_cfg_clsh_param_hph(codec);
-		wcd9xxx_enable_clsh_block(codec, true);
+		wcd9xxx_enable_clsh_block(codec, clsh_d, true);
 		wcd9xxx_chargepump_request(codec, true);
 		wcd9xxx_enable_anc_delay(codec, true);
 		wcd9xxx_clsh_comp_req(codec, clsh_d, CLSH_COMPUTE_HPH_L, true);
-		wcd9xxx_enable_buck_mode(codec, BUCK_VREF_2V);
-		wcd9xxx_set_fclk_enable_ncp(codec, NCP_FCLK_LEVEL_8);
+		wcd9xxx_set_buck_mode(codec, BUCK_VREF_0P494V);
+		wcd9xxx_enable_buck(codec, clsh_d, true);
+		wcd9xxx_set_fclk_get_ncp(codec, clsh_d, NCP_FCLK_LEVEL_8);
 
 		dev_dbg(codec->dev, "%s: Done\n", __func__);
 	} else {
-		if (req_state == WCD9XXX_CLSH_STATE_HPHR) {
-			wcd9xxx_clsh_comp_req(codec, clsh_d, CLSH_COMPUTE_HPH_R,
-					      false);
-		} else {
-			dev_dbg(codec->dev, "%s: stub fallback to hph_l\n",
-					__func__);
-		}
+		wcd9xxx_set_fclk_put_ncp(codec, clsh_d, NCP_FCLK_LEVEL_8);
+		wcd9xxx_enable_buck(codec, clsh_d, false);
+		wcd9xxx_clsh_comp_req(codec, clsh_d, CLSH_COMPUTE_HPH_L, false);
+		wcd9xxx_chargepump_request(codec, false);
+		wcd9xxx_enable_clsh_block(codec, clsh_d, false);
 	}
 }
 
@@ -890,27 +865,26 @@
 		struct wcd9xxx_clsh_cdc_data *clsh_d,
 		u8 req_state, bool is_enable)
 {
-	if (is_enable) {
+	pr_debug("%s: enter %s\n", __func__, is_enable ? "enable" : "disable");
 
-		wcd9xxx_cfg_clsh_buck(codec);
+	if (is_enable) {
 		wcd9xxx_cfg_clsh_param_common(codec);
 		wcd9xxx_cfg_clsh_param_hph(codec);
-		wcd9xxx_enable_clsh_block(codec, true);
+		wcd9xxx_enable_clsh_block(codec, clsh_d, true);
 		wcd9xxx_chargepump_request(codec, true);
 		wcd9xxx_enable_anc_delay(codec, true);
 		wcd9xxx_clsh_comp_req(codec, clsh_d, CLSH_COMPUTE_HPH_R, true);
-		wcd9xxx_enable_buck_mode(codec, BUCK_VREF_2V);
-		wcd9xxx_set_fclk_enable_ncp(codec, NCP_FCLK_LEVEL_8);
+		wcd9xxx_set_buck_mode(codec, BUCK_VREF_0P494V);
+		wcd9xxx_enable_buck(codec, clsh_d, true);
+		wcd9xxx_set_fclk_get_ncp(codec, clsh_d, NCP_FCLK_LEVEL_8);
 
 		dev_dbg(codec->dev, "%s: Done\n", __func__);
 	} else {
-		if (req_state == WCD9XXX_CLSH_STATE_HPHL) {
-			wcd9xxx_clsh_comp_req(codec, clsh_d, CLSH_COMPUTE_HPH_L,
-					      false);
-		} else {
-			dev_dbg(codec->dev, "%s: stub fallback to hph_r\n",
-					__func__);
-		}
+		wcd9xxx_set_fclk_put_ncp(codec, clsh_d, NCP_FCLK_LEVEL_8);
+		wcd9xxx_enable_buck(codec, clsh_d, false);
+		wcd9xxx_clsh_comp_req(codec, clsh_d, CLSH_COMPUTE_HPH_R, false);
+		wcd9xxx_chargepump_request(codec, false);
+		wcd9xxx_enable_clsh_block(codec, clsh_d, false);
 	}
 }
 
@@ -918,9 +892,11 @@
 		struct wcd9xxx_clsh_cdc_data *clsh_d,
 		u8 req_state, bool is_enable)
 {
+	pr_debug("%s: enter %s\n", __func__, is_enable ? "enable" : "disable");
+
 	if (is_enable) {
 		wcd9xxx_clsh_comp_req(codec, clsh_d, CLSH_COMPUTE_HPH_L, true);
-		wcd9xxx_clsh_comp_req(codec, clsh_d,  CLSH_COMPUTE_HPH_R, true);
+		wcd9xxx_clsh_comp_req(codec, clsh_d, CLSH_COMPUTE_HPH_R, true);
 	} else {
 		dev_dbg(codec->dev, "%s: stub fallback to hph_st\n", __func__);
 	}
@@ -930,38 +906,36 @@
 		struct wcd9xxx_clsh_cdc_data *clsh_d,
 		u8 req_state, bool is_enable)
 {
-	if (is_enable) {
-		if (++cdc_lo_count > 1)
-			return;
+	pr_debug("%s: enter %s, buck_mv %d\n", __func__,
+		 is_enable ? "enable" : "disable", clsh_d->buck_mv);
 
-		wcd9xxx_enable_buck_mode(codec, BUCK_VREF_1P8V);
-		wcd9xxx_set_fclk_enable_ncp(codec, NCP_FCLK_LEVEL_5);
+	if (is_enable) {
+		wcd9xxx_set_buck_mode(codec, BUCK_VREF_1P8V);
+		wcd9xxx_enable_buck(codec, clsh_d, true);
+		wcd9xxx_set_fclk_get_ncp(codec, clsh_d, NCP_FCLK_LEVEL_5);
 
 		if (clsh_d->buck_mv == WCD9XXX_CDC_BUCK_MV_1P8) {
-			wcd9xxx_enable_buck(codec, false);
+			wcd9xxx_enable_buck(codec, clsh_d, false);
 			snd_soc_update_bits(codec, WCD9XXX_A_NCP_STATIC,
-							0x20, 0x01);
-			wcd9xxx_enable_ncp(codec, true);
+					    1 << 4, 1 << 4);
 			/* NCP settle time recommended by codec specification */
 			usleep_range(NCP_SETTLE_TIME_US,
-				NCP_SETTLE_TIME_US + 10);
-
+				     NCP_SETTLE_TIME_US + 10);
 		} else {
-			snd_soc_update_bits(codec, WCD9XXX_A_NCP_EN,
-							0x40, 0x00);
-			wcd9xxx_enable_ncp(codec, true);
 			/* NCP settle time recommended by codec specification */
 			usleep_range(NCP_SETTLE_TIME_US,
-				NCP_SETTLE_TIME_US + 10);
+				     NCP_SETTLE_TIME_US + 10);
 			snd_soc_update_bits(codec, WCD9XXX_A_BUCK_MODE_5,
-							0x01, 0x01);
+					    0x01, (0x01 & 0x03));
 			snd_soc_update_bits(codec, WCD9XXX_A_BUCK_MODE_5,
-							0xFB, (0x02 << 2));
+					    0xFC, (0xFC & 0xB));
 		}
-		snd_soc_update_bits(codec, WCD9XXX_A_BUCK_MODE_1,
-							0x04, 0x00);
+		snd_soc_update_bits(codec, WCD9XXX_A_BUCK_MODE_1, 0x04, 0x00);
 	} else {
 		dev_dbg(codec->dev, "%s: stub fallback to lineout\n", __func__);
+		wcd9xxx_set_fclk_put_ncp(codec, clsh_d, NCP_FCLK_LEVEL_5);
+		if (clsh_d->buck_mv != WCD9XXX_CDC_BUCK_MV_1P8)
+			wcd9xxx_enable_buck(codec, clsh_d, false);
 	}
 }
 
@@ -969,9 +943,12 @@
 		struct wcd9xxx_clsh_cdc_data *clsh_d,
 		u8 req_state, bool is_enable)
 {
-	dev_dbg(codec->dev, "%s Wrong request for class H state machine requested to %s %s"
-			, __func__, is_enable ? "enable" : "disable",
-			state_to_str(req_state));
+	char msg[128];
+
+	dev_dbg(codec->dev,
+		"%s Wrong request for class H state machine requested to %s %s",
+		__func__, is_enable ? "enable" : "disable",
+		state_to_str(req_state, msg, sizeof(msg)));
 	WARN_ON(1);
 }
 
@@ -980,51 +957,45 @@
 		u8 req_state, bool req_type, u8 clsh_event)
 {
 	u8 old_state, new_state;
+	char msg0[128], msg1[128];
 
 	switch (clsh_event) {
-
 	case WCD9XXX_CLSH_EVENT_PRE_DAC:
-
 		/* PRE_DAC event should be used only for Enable */
 		BUG_ON(req_type != WCD9XXX_CLSH_REQ_ENABLE);
 
 		old_state = cdc_clsh_d->state;
 		new_state = old_state | req_state;
 
-		(*clsh_state_fp[new_state]) (codec, cdc_clsh_d,
-							req_state, req_type);
+		(*clsh_state_fp[req_state]) (codec, cdc_clsh_d, req_state,
+					     req_type);
 		cdc_clsh_d->state = new_state;
 		dev_dbg(codec->dev, "%s: ClassH state transition from %s to %s\n",
-			__func__, state_to_str(old_state),
-			state_to_str(cdc_clsh_d->state));
+			__func__, state_to_str(old_state, msg0, sizeof(msg0)),
+			state_to_str(cdc_clsh_d->state, msg1, sizeof(msg1)));
 
 		break;
-
 	case WCD9XXX_CLSH_EVENT_POST_PA:
-
 		if (req_type == WCD9XXX_CLSH_REQ_DISABLE) {
-			if (req_state == WCD9XXX_CLSH_STATE_LO
-					&& --cdc_lo_count > 0)
-				break;
-
 			old_state = cdc_clsh_d->state;
 			new_state = old_state & (~req_state);
 
 			if (new_state < NUM_CLSH_STATES) {
-				(*clsh_state_fp[new_state]) (codec, cdc_clsh_d,
-							req_state, req_type);
+				(*clsh_state_fp[req_state]) (codec, cdc_clsh_d,
+							     req_state,
+							     req_type);
 				cdc_clsh_d->state = new_state;
 				dev_dbg(codec->dev, "%s: ClassH state transition from %s to %s\n",
-					__func__, state_to_str(old_state),
-					state_to_str(cdc_clsh_d->state));
+					__func__, state_to_str(old_state, msg0,
+							       sizeof(msg0)),
+					state_to_str(cdc_clsh_d->state, msg1,
+						     sizeof(msg1)));
 
 			} else {
 				dev_dbg(codec->dev, "%s: wrong new state = %x\n",
 						__func__, new_state);
 			}
-
-
-		} else if (req_state != WCD9XXX_CLSH_STATE_LO) {
+		} else if (!(cdc_clsh_d->state & WCD9XXX_CLSH_STATE_LO)) {
 			wcd9xxx_clsh_enable_post_pa(codec, cdc_clsh_d);
 		}
 
@@ -1044,7 +1015,6 @@
 	for (i = 0; i < NUM_CLSH_STATES; i++)
 		clsh_state_fp[i] = wcd9xxx_clsh_state_err;
 
-	clsh_state_fp[WCD9XXX_CLSH_STATE_IDLE] = wcd9xxx_clsh_state_idle;
 	clsh_state_fp[WCD9XXX_CLSH_STATE_EAR] = wcd9xxx_clsh_state_ear;
 	clsh_state_fp[WCD9XXX_CLSH_STATE_HPHL] =
 						wcd9xxx_clsh_state_hph_l;
diff --git a/sound/soc/codecs/wcd9xxx-common.h b/sound/soc/codecs/wcd9xxx-common.h
index 0239c86..324f6e9 100644
--- a/sound/soc/codecs/wcd9xxx-common.h
+++ b/sound/soc/codecs/wcd9xxx-common.h
@@ -63,11 +63,20 @@
 	u8	val;
 };
 
+enum ncp_fclk_level {
+	NCP_FCLK_LEVEL_8,
+	NCP_FCLK_LEVEL_5,
+	NCP_FCLK_LEVEL_MAX,
+};
+
 /* Class H data that the codec driver will maintain */
 struct wcd9xxx_clsh_cdc_data {
 	u8 state;
 	int buck_mv;
 	bool is_dynamic_vdd_cp;
+	int clsh_users;
+	int buck_users;
+	int ncp_users[NCP_FCLK_LEVEL_MAX];
 	struct wcd9xxx_resmgr *resmgr;
 };
 
diff --git a/sound/soc/codecs/wcd9xxx-mbhc.c b/sound/soc/codecs/wcd9xxx-mbhc.c
index 8d6c4bc..ec99c5f 100644
--- a/sound/soc/codecs/wcd9xxx-mbhc.c
+++ b/sound/soc/codecs/wcd9xxx-mbhc.c
@@ -222,6 +222,19 @@
 		pr_debug("Polling is not active, do not start polling\n");
 		return;
 	}
+
+	/*
+	 * setup internal micbias if codec uses internal micbias for
+	 * headset detection
+	 */
+	if (mbhc->mbhc_cfg->use_int_rbias && !mbhc->int_rbias_on) {
+		if (mbhc->mbhc_cb && mbhc->mbhc_cb->setup_int_rbias)
+			mbhc->mbhc_cb->setup_int_rbias(codec, true);
+		else
+			pr_err("%s: internal bias requested but codec did not provide callback\n",
+				__func__);
+	}
+
 	snd_soc_write(codec, WCD9XXX_A_MBHC_SCALING_MUX_1, 0x04);
 	if (mbhc->mbhc_cb && mbhc->mbhc_cb->enable_mux_bias_block)
 		mbhc->mbhc_cb->enable_mux_bias_block(codec);
@@ -1090,12 +1103,12 @@
 	 * setup internal micbias if codec uses internal micbias for
 	 * headset detection
 	 */
-	if (mbhc->mbhc_cfg->use_int_rbias) {
+	if (mbhc->mbhc_cfg->use_int_rbias && !mbhc->int_rbias_on) {
 		if (mbhc->mbhc_cb && mbhc->mbhc_cb->setup_int_rbias)
 			mbhc->mbhc_cb->setup_int_rbias(codec, true);
 	else
-		pr_err("%s: internal bias is requested but codec did not provide callback\n",
-			 __func__);
+		pr_err("%s: internal bias requested but codec did not provide callback\n",
+			__func__);
 	}
 
 	snd_soc_update_bits(codec, WCD9XXX_A_CLK_BUFF_EN1, 0x05, 0x01);
@@ -1289,6 +1302,7 @@
 	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;
+	int highhph_cnt = 0;
 
 	pr_debug("%s: enter\n", __func__);
 	pr_debug("%s: event_state 0x%lx\n", __func__, event_state);
@@ -1313,9 +1327,10 @@
 		d->_vdces = vdce;
 		if (d->_vdces < no_mic)
 			d->_type = PLUG_TYPE_HEADPHONE;
-		else if (d->_vdces >= hs_max)
+		else if (d->_vdces >= hs_max) {
 			d->_type = PLUG_TYPE_HIGH_HPH;
-		else
+			highhph_cnt++;
+		} else
 			d->_type = PLUG_TYPE_HEADSET;
 
 		pr_debug("%s: DCE #%d, %04x, V %04d(%04d), HPHL %d TYPE %d\n",
@@ -1350,7 +1365,8 @@
 		goto exit;
 	}
 
-	delta_thr = highhph ? WCD9XXX_MB_MEAS_DELTA_MAX_MV :
+	delta_thr = ((highhph_cnt == sz) || highhph) ?
+			      WCD9XXX_MB_MEAS_DELTA_MAX_MV :
 			      WCD9XXX_CS_MEAS_DELTA_MAX_MV;
 
 	for (i = 0, d = dt; i < sz; i++, d++) {
@@ -2842,6 +2858,10 @@
 	if (wcd9xxx_cancel_btn_work(mbhc))
 		pr_debug("%s: button press is canceled\n", __func__);
 
+	/* cancel detect plug */
+	wcd9xxx_cancel_hs_detect_plug(mbhc,
+				      &mbhc->correct_plug_swch);
+
 	insert = !wcd9xxx_swch_level_remove(mbhc);
 	pr_debug("%s: Current plug type %d, insert %d\n", __func__,
 		 mbhc->current_plug, insert);
@@ -2849,9 +2869,6 @@
 		mbhc->lpi_enabled = false;
 		wmb();
 
-		/* cancel detect plug */
-		wcd9xxx_cancel_hs_detect_plug(mbhc,
-					      &mbhc->correct_plug_swch);
 		if ((mbhc->current_plug != PLUG_TYPE_NONE) &&
 		    !(snd_soc_read(codec, WCD9XXX_A_MBHC_INSERT_DETECT) &
 				   (1 << 1)))
@@ -2866,10 +2883,6 @@
 		mbhc->lpi_enabled = false;
 		wmb();
 
-		/* cancel detect plug */
-		wcd9xxx_cancel_hs_detect_plug(mbhc,
-					      &mbhc->correct_plug_swch);
-
 		if (mbhc->current_plug == PLUG_TYPE_HEADPHONE) {
 			wcd9xxx_report_plug(mbhc, 0, SND_JACK_HEADPHONE);
 			is_removed = true;
@@ -3171,6 +3184,19 @@
 		goto done;
 	}
 
+	/*
+	 * setup internal micbias if codec uses internal micbias for
+	 * headset detection
+	 */
+	if (mbhc->mbhc_cfg->use_int_rbias && !mbhc->int_rbias_on) {
+		if (mbhc->mbhc_cb && mbhc->mbhc_cb->setup_int_rbias)
+			mbhc->mbhc_cb->setup_int_rbias(codec, true);
+		else
+			pr_err("%s: internal bias requested but codec did not provide callback\n",
+				__func__);
+	}
+
+
 	/* Measure scaled HW DCE */
 	vddio = (mbhc->mbhc_data.micb_mv != VDDIO_MICBIAS_MV &&
 		 mbhc->mbhc_micbias_switched);
@@ -3991,11 +4017,13 @@
 	 * headset detection
 	 */
 	if (mbhc->mbhc_cfg->use_int_rbias) {
-		if (mbhc->mbhc_cb && mbhc->mbhc_cb->setup_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",
+			mbhc->int_rbias_on = true;
+		} else {
+			pr_info("%s: internal bias requested but codec did not provide callback\n",
 				__func__);
+		}
 	}
 
 	/*
@@ -4150,6 +4178,7 @@
 	case WCD9XXX_EVENT_PRE_MICBIAS_2_ON:
 	case WCD9XXX_EVENT_PRE_MICBIAS_3_ON:
 	case WCD9XXX_EVENT_PRE_MICBIAS_4_ON:
+		mbhc->int_rbias_on = true;
 		if (mbhc->mbhc_cfg && mbhc->mbhc_cfg->micbias ==
 		    wcd9xxx_event_to_micbias(event)) {
 			wcd9xxx_switch_micbias(mbhc, 0);
@@ -4177,6 +4206,7 @@
 	case WCD9XXX_EVENT_POST_MICBIAS_2_OFF:
 	case WCD9XXX_EVENT_POST_MICBIAS_3_OFF:
 	case WCD9XXX_EVENT_POST_MICBIAS_4_OFF:
+		mbhc->int_rbias_on = false;
 		if (mbhc->mbhc_cfg && mbhc->mbhc_cfg->micbias ==
 		    wcd9xxx_event_to_micbias(event)) {
 			if (mbhc->event_state &
@@ -4472,6 +4502,7 @@
 	mbhc->mbhc_cb = mbhc_cb;
 	mbhc->intr_ids = mbhc_cdc_intr_ids;
 	mbhc->impedance_detect = impedance_det_en;
+	mbhc->int_rbias_on = false;
 
 	if (mbhc->intr_ids == NULL) {
 		pr_err("%s: Interrupt mapping not provided\n", __func__);
diff --git a/sound/soc/codecs/wcd9xxx-mbhc.h b/sound/soc/codecs/wcd9xxx-mbhc.h
index 9d0afe9..7fe9538 100644
--- a/sound/soc/codecs/wcd9xxx-mbhc.h
+++ b/sound/soc/codecs/wcd9xxx-mbhc.h
@@ -336,7 +336,7 @@
 	u32 rco_clk_rate;
 
 	bool update_z;
-
+	bool int_rbias_on;
 	/* Holds codec specific interrupt mapping */
 	const struct wcd9xxx_mbhc_intr *intr_ids;
 
diff --git a/sound/soc/msm/msm-pcm-host-voice.c b/sound/soc/msm/msm-pcm-host-voice.c
index 2eafc1d..1b68bcf 100644
--- a/sound/soc/msm/msm-pcm-host-voice.c
+++ b/sound/soc/msm/msm-pcm-host-voice.c
@@ -989,7 +989,7 @@
 			spin_unlock_irqrestore(&dai_data->dsp_lock, dsp_flags);
 			ret = copy_to_user(buf,
 					   &buf_node->frame.voc_pkt,
-					   count);
+					   buf_node->frame.len);
 			if (ret) {
 				pr_err("%s: Copy to user retuned %d\n",
 					__func__, ret);
diff --git a/sound/soc/msm/msm8974.c b/sound/soc/msm/msm8974.c
index 01b7956..99f196c 100644
--- a/sound/soc/msm/msm8974.c
+++ b/sound/soc/msm/msm8974.c
@@ -58,16 +58,9 @@
 #define LO_2_SPK_AMP	0x4
 #define LO_4_SPK_AMP	0x8
 
-#define LPAIF_OFFSET 0xFE000000
-#define LPAIF_PRI_MODE_MUXSEL (LPAIF_OFFSET + 0x2B000)
-#define LPAIF_SEC_MODE_MUXSEL (LPAIF_OFFSET + 0x2C000)
-#define LPAIF_TER_MODE_MUXSEL (LPAIF_OFFSET + 0x2D000)
-#define LPAIF_QUAD_MODE_MUXSEL (LPAIF_OFFSET + 0x2E000)
-
 #define I2S_PCM_SEL 1
 #define I2S_PCM_SEL_OFFSET 1
 
-
 #define WCD9XXX_MBHC_DEF_BUTTONS 8
 #define WCD9XXX_MBHC_DEF_RLOADS 5
 #define TAIKO_EXT_CLK_RATE 9600000
@@ -146,6 +139,7 @@
 struct msm_auxpcm_ctrl {
 	struct msm_auxpcm_gpio *pin_data;
 	u32 cnt;
+	void __iomem *mux;
 };
 
 struct msm8974_asoc_mach_data {
@@ -173,9 +167,6 @@
 	{"SEC_AUXPCM_DOUT",      "qcom,sec-auxpcm-gpio-dout"},
 };
 
-void *lpaif_pri_muxsel_virt_addr;
-void *lpaif_sec_muxsel_virt_addr;
-
 struct msm8974_liquid_dock_dev {
 	int dock_plug_gpio;
 	int dock_plug_irq;
@@ -1192,12 +1183,14 @@
 		goto err;
 	}
 	if (atomic_inc_return(&prim_auxpcm_rsc_ref) == 1) {
-		if (lpaif_pri_muxsel_virt_addr != NULL)
+		if (auxpcm_ctrl->mux != NULL) {
 			iowrite32(I2S_PCM_SEL << I2S_PCM_SEL_OFFSET,
-				lpaif_pri_muxsel_virt_addr);
-		else
-			pr_err("%s lpaif_pri_muxsel_virt_addr is NULL\n",
-				 __func__);
+				  auxpcm_ctrl->mux);
+		} else {
+			pr_err("%s: Pri AUXPCM MUX addr is NULL\n", __func__);
+			ret = -EINVAL;
+			goto err;
+		}
 		ret = msm_aux_pcm_get_gpios(auxpcm_ctrl);
 	}
 	if (ret < 0) {
@@ -1247,12 +1240,14 @@
 		goto err;
 	}
 	if (atomic_inc_return(&sec_auxpcm_rsc_ref) == 1) {
-		if (lpaif_sec_muxsel_virt_addr != NULL)
+		if (auxpcm_ctrl->mux != NULL) {
 			iowrite32(I2S_PCM_SEL << I2S_PCM_SEL_OFFSET,
-				lpaif_sec_muxsel_virt_addr);
-		else
-			pr_err("%s lpaif_sec_muxsel_virt_addr is NULL\n",
-				 __func__);
+				  auxpcm_ctrl->mux);
+		} else {
+			pr_err("%s Sec AUXPCM MUX addr is NULL\n", __func__);
+			ret = -EINVAL;
+			goto err;
+		}
 		ret = msm_aux_pcm_get_gpios(auxpcm_ctrl);
 	}
 	if (ret < 0) {
@@ -2667,6 +2662,8 @@
 	int ret;
 	const char *auxpcm_pri_gpio_set = NULL;
 	const char *prop_name_ult_lo_gpio = "qcom,ext-ult-lo-amp-gpio";
+	struct resource	*pri_muxsel;
+	struct resource	*sec_muxsel;
 
 	if (!pdev->dev.of_node) {
 		dev_err(&pdev->dev, "No platform supplied from device tree\n");
@@ -2794,7 +2791,6 @@
 		}
 	}
 
-
 	pdata->us_euro_gpio = of_get_named_gpio(pdev->dev.of_node,
 				"qcom,us-euro-gpios", 0);
 	if (pdata->us_euro_gpio < 0) {
@@ -2821,28 +2817,49 @@
 		goto err1;
 	}
 	if (!strcmp(auxpcm_pri_gpio_set, "prim-gpio-prim")) {
-		lpaif_pri_muxsel_virt_addr = ioremap(LPAIF_PRI_MODE_MUXSEL, 4);
+		pri_muxsel = platform_get_resource_byname(pdev, IORESOURCE_MEM,
+						"lpaif_pri_mode_muxsel");
 	} else if (!strcmp(auxpcm_pri_gpio_set, "prim-gpio-tert")) {
-		lpaif_pri_muxsel_virt_addr = ioremap(LPAIF_TER_MODE_MUXSEL, 4);
+		pri_muxsel = platform_get_resource_byname(pdev, IORESOURCE_MEM,
+						"lpaif_tert_mode_muxsel");
 	} else {
 		dev_err(&pdev->dev, "Invalid value %s for AUXPCM GPIO set\n",
 			auxpcm_pri_gpio_set);
 		ret = -EINVAL;
 		goto err1;
 	}
-	if (lpaif_pri_muxsel_virt_addr == NULL) {
-		pr_err("%s Pri muxsel virt addr is null\n", __func__);
-		ret = -EINVAL;
-		goto err1;
+	if (!pri_muxsel) {
+		dev_err(&pdev->dev, "MUX addr invalid for primary AUXPCM\n");
+			ret = -ENODEV;
+			goto err1;
+	} else {
+		pdata->pri_auxpcm_ctrl->mux = ioremap(pri_muxsel->start,
+						    resource_size(pri_muxsel));
+		if (pdata->pri_auxpcm_ctrl->mux == NULL) {
+			pr_err("%s Pri muxsel virt addr is null\n", __func__);
+			ret = -EINVAL;
+			goto err1;
+		}
 	}
-	lpaif_sec_muxsel_virt_addr = ioremap(LPAIF_SEC_MODE_MUXSEL, 4);
-	if (lpaif_sec_muxsel_virt_addr == NULL) {
+
+	sec_muxsel = platform_get_resource_byname(pdev, IORESOURCE_MEM,
+						"lpaif_sec_mode_muxsel");
+	if (!sec_muxsel) {
+		dev_err(&pdev->dev, "MUX addr invalid for secondary AUXPCM\n");
+		ret = -ENODEV;
+		goto err2;
+	}
+	pdata->sec_auxpcm_ctrl->mux = ioremap(sec_muxsel->start,
+					     resource_size(sec_muxsel));
+	if (pdata->sec_auxpcm_ctrl->mux == NULL) {
 		pr_err("%s Sec muxsel virt addr is null\n", __func__);
 		ret = -EINVAL;
-		goto err1;
+		goto err2;
 	}
 	return 0;
 
+err2:
+	iounmap(pdata->pri_auxpcm_ctrl->mux);
 err1:
 	if (ext_ult_lo_amp_gpio >= 0)
 		gpio_free(ext_ult_lo_amp_gpio);
@@ -2896,8 +2913,8 @@
 		msm8974_liquid_dock_dev = NULL;
 	}
 
-	iounmap(lpaif_pri_muxsel_virt_addr);
-	iounmap(lpaif_sec_muxsel_virt_addr);
+	iounmap(pdata->pri_auxpcm_ctrl->mux);
+	iounmap(pdata->sec_auxpcm_ctrl->mux);
 	snd_soc_unregister_card(card);
 
 	return 0;
diff --git a/sound/soc/msm/qdsp6v2/audio_acdb.c b/sound/soc/msm/qdsp6v2/audio_acdb.c
index 01422cf..8187616 100644
--- a/sound/soc/msm/qdsp6v2/audio_acdb.c
+++ b/sound/soc/msm/qdsp6v2/audio_acdb.c
@@ -38,64 +38,60 @@
 
 #define MAX_HW_DELAY_ENTRIES	25
 
-struct sidetone_atomic_cal {
-	atomic_t	enable;
-	atomic_t	gain;
-};
-
-
 struct acdb_data {
+	uint32_t		usage_count;
+
 	struct mutex		acdb_mutex;
 
 	/* ANC Cal */
-	struct acdb_atomic_cal_block	anc_cal;
+	struct acdb_cal_block		anc_cal;
 
 	/* AANC Cal */
-	struct acdb_atomic_cal_block    aanc_cal;
+	struct acdb_cal_block		aanc_cal;
 
 	/* LSM Cal */
-	struct acdb_atomic_cal_block	lsm_cal;
+	struct acdb_cal_block		lsm_cal;
 
 	/* AudProc Cal */
-	atomic_t			asm_topology;
-	atomic_t			adm_topology[MAX_AUDPROC_TYPES];
-	struct acdb_atomic_cal_block	audproc_cal[MAX_AUDPROC_TYPES];
-	struct acdb_atomic_cal_block	audstrm_cal[MAX_AUDPROC_TYPES];
-	struct acdb_atomic_cal_block	audvol_cal[MAX_AUDPROC_TYPES];
+	uint32_t			asm_topology;
+	uint32_t			adm_topology[MAX_AUDPROC_TYPES];
+	struct acdb_cal_block		audproc_cal[MAX_AUDPROC_TYPES];
+	struct acdb_cal_block		audstrm_cal[MAX_AUDPROC_TYPES];
+	struct acdb_cal_block		audvol_cal[MAX_AUDPROC_TYPES];
 
 	/* VocProc Cal */
-	atomic_t			voice_rx_topology;
-	atomic_t			voice_tx_topology;
-	struct acdb_atomic_cal_block	vocproc_cal;
-	struct acdb_atomic_cal_block	vocstrm_cal;
-	struct acdb_atomic_cal_block	vocvol_cal;
+	uint32_t			voice_rx_topology;
+	uint32_t			voice_tx_topology;
+	struct acdb_cal_block		vocproc_cal;
+	struct acdb_cal_block		vocstrm_cal;
+	struct acdb_cal_block		vocvol_cal;
 
 	/* Voice Column data */
-	struct acdb_atomic_cal_block	vocproc_col_cal[MAX_VOCPROC_TYPES];
+	struct acdb_cal_block		vocproc_col_cal[MAX_VOCPROC_TYPES];
 	uint32_t			*col_data[MAX_VOCPROC_TYPES];
 
 	/* VocProc dev cfg cal*/
-	struct acdb_atomic_cal_block	vocproc_dev_cal;
+	struct acdb_cal_block		vocproc_dev_cal;
 
 	/* Custom topology */
-	struct acdb_atomic_cal_block	adm_custom_topology;
-	struct acdb_atomic_cal_block	asm_custom_topology;
-	atomic_t			valid_adm_custom_top;
-	atomic_t			valid_asm_custom_top;
+	struct acdb_cal_block		adm_custom_topology;
+	struct acdb_cal_block		asm_custom_topology;
+	uint32_t			valid_adm_custom_top;
+	uint32_t			valid_asm_custom_top;
 
 	/* AFE cal */
-	struct acdb_atomic_cal_block	afe_cal[MAX_AUDPROC_TYPES];
+	struct acdb_cal_block		afe_cal[MAX_AUDPROC_TYPES];
 
 	/* Sidetone Cal */
-	struct sidetone_atomic_cal	sidetone_cal;
+	struct sidetone_cal		sidetone_cal;
 
 	/* Allocation information */
 	struct ion_client		*ion_client;
 	struct ion_handle		*ion_handle;
-	atomic_t			map_handle;
-	atomic64_t			paddr;
-	atomic64_t			kvaddr;
-	atomic64_t			mem_len;
+	uint32_t			map_handle;
+	uint64_t			paddr;
+	uint64_t			kvaddr;
+	uint64_t			mem_len;
 
 	/* Speaker protection */
 	struct msm_spk_prot_cfg spk_prot_cfg;
@@ -106,62 +102,63 @@
 };
 
 static struct acdb_data		acdb_data;
-static atomic_t usage_count;
 
 uint32_t get_voice_rx_topology(void)
 {
-	return atomic_read(&acdb_data.voice_rx_topology);
+	return acdb_data.voice_rx_topology;
 }
 
 void store_voice_rx_topology(uint32_t topology)
 {
-	atomic_set(&acdb_data.voice_rx_topology, topology);
+	acdb_data.voice_rx_topology = topology;
 }
 
 uint32_t get_voice_tx_topology(void)
 {
-	return atomic_read(&acdb_data.voice_tx_topology);
+	return acdb_data.voice_tx_topology;
 }
 
 void store_voice_tx_topology(uint32_t topology)
 {
-	atomic_set(&acdb_data.voice_tx_topology, topology);
+	acdb_data.voice_tx_topology = topology;
 }
 
 uint32_t get_adm_rx_topology(void)
 {
-	return atomic_read(&acdb_data.adm_topology[RX_CAL]);
+	return acdb_data.adm_topology[RX_CAL];
 }
 
 void store_adm_rx_topology(uint32_t topology)
 {
-	atomic_set(&acdb_data.adm_topology[RX_CAL], topology);
+	acdb_data.adm_topology[RX_CAL] = topology;
 }
 
 uint32_t get_adm_tx_topology(void)
 {
-	return atomic_read(&acdb_data.adm_topology[TX_CAL]);
+	return acdb_data.adm_topology[TX_CAL];
 }
 
 void store_adm_tx_topology(uint32_t topology)
 {
-	atomic_set(&acdb_data.adm_topology[TX_CAL], topology);
+	acdb_data.adm_topology[TX_CAL] = topology;
 }
 
 uint32_t get_asm_topology(void)
 {
-	return atomic_read(&acdb_data.asm_topology);
+	return acdb_data.asm_topology;
 }
 
 void store_asm_topology(uint32_t topology)
 {
-	atomic_set(&acdb_data.asm_topology, topology);
+	acdb_data.asm_topology = topology;
 }
 
 void reset_custom_topology_flags(void)
 {
-	atomic_set(&acdb_data.valid_adm_custom_top, 1);
-	atomic_set(&acdb_data.valid_asm_custom_top, 1);
+	mutex_lock(&acdb_data.acdb_mutex);
+	acdb_data.valid_adm_custom_top = 1;
+	acdb_data.valid_asm_custom_top = 1;
+	mutex_unlock(&acdb_data.acdb_mutex);
 }
 
 int get_adm_custom_topology(struct acdb_cal_block *cal_block)
@@ -175,19 +172,19 @@
 		goto done;
 	}
 
+	mutex_lock(&acdb_data.acdb_mutex);
 	/* Only return allow one access after memory registered */
-	if (atomic_read(&acdb_data.valid_adm_custom_top) == 0) {
+	if (acdb_data.valid_adm_custom_top == 0) {
 		cal_block->cal_size = 0;
-		goto done;
+		goto unlock;
 	}
-	atomic_set(&acdb_data.valid_adm_custom_top, 0);
+	acdb_data.valid_adm_custom_top = 0;
 
-	cal_block->cal_size =
-		atomic_read(&acdb_data.adm_custom_topology.cal_size);
-	cal_block->cal_paddr =
-		atomic_read(&acdb_data.adm_custom_topology.cal_paddr);
-	cal_block->cal_kvaddr =
-		atomic_read(&acdb_data.adm_custom_topology.cal_kvaddr);
+	cal_block->cal_size = acdb_data.adm_custom_topology.cal_size;
+	cal_block->cal_paddr = acdb_data.adm_custom_topology.cal_paddr;
+	cal_block->cal_kvaddr = acdb_data.adm_custom_topology.cal_kvaddr;
+unlock:
+	mutex_unlock(&acdb_data.acdb_mutex);
 done:
 	return result;
 }
@@ -197,21 +194,18 @@
 	int result = 0;
 	pr_debug("%s,\n", __func__);
 
-	if (cal_block->cal_offset > atomic64_read(&acdb_data.mem_len)) {
-		pr_err("%s: offset %d is > mem_len %ld\n",
-			__func__, cal_block->cal_offset,
-			(long)atomic64_read(&acdb_data.mem_len));
+	if (cal_block->cal_offset > acdb_data.mem_len) {
+		pr_err("%s: offset %d is > mem_len %llu\n",
+			__func__, cal_block->cal_offset, acdb_data.mem_len);
 		result = -EINVAL;
 		goto done;
 	}
 
-	atomic_set(&acdb_data.adm_custom_topology.cal_size,
-		cal_block->cal_size);
-	atomic_set(&acdb_data.adm_custom_topology.cal_paddr,
-		cal_block->cal_offset + atomic64_read(&acdb_data.paddr));
-	atomic_set(&acdb_data.adm_custom_topology.cal_kvaddr,
-		cal_block->cal_offset +
-		atomic64_read(&acdb_data.kvaddr));
+	acdb_data.adm_custom_topology.cal_size = cal_block->cal_size;
+	acdb_data.adm_custom_topology.cal_paddr =
+		cal_block->cal_offset + acdb_data.paddr;
+	acdb_data.adm_custom_topology.cal_kvaddr =
+		cal_block->cal_offset + acdb_data.kvaddr;
 done:
 	return result;
 }
@@ -227,19 +221,19 @@
 		goto done;
 	}
 
+	mutex_lock(&acdb_data.acdb_mutex);
 	/* Only return allow one access after memory registered */
-	if (atomic_read(&acdb_data.valid_asm_custom_top) == 0) {
+	if (acdb_data.valid_asm_custom_top == 0) {
 		cal_block->cal_size = 0;
-		goto done;
+		goto unlock;
 	}
-	atomic_set(&acdb_data.valid_asm_custom_top, 0);
+	acdb_data.valid_asm_custom_top = 0;
 
-	cal_block->cal_size =
-		atomic_read(&acdb_data.asm_custom_topology.cal_size);
-	cal_block->cal_paddr =
-		atomic_read(&acdb_data.asm_custom_topology.cal_paddr);
-	cal_block->cal_kvaddr =
-		atomic_read(&acdb_data.asm_custom_topology.cal_kvaddr);
+	cal_block->cal_size = acdb_data.asm_custom_topology.cal_size;
+	cal_block->cal_paddr = acdb_data.asm_custom_topology.cal_paddr;
+	cal_block->cal_kvaddr = acdb_data.asm_custom_topology.cal_kvaddr;
+unlock:
+	mutex_unlock(&acdb_data.acdb_mutex);
 done:
 	return result;
 }
@@ -249,21 +243,18 @@
 	int result = 0;
 	pr_debug("%s,\n", __func__);
 
-	if (cal_block->cal_offset > atomic64_read(&acdb_data.mem_len)) {
-		pr_err("%s: offset %d is > mem_len %ld\n",
-			__func__, cal_block->cal_offset,
-			(long)atomic64_read(&acdb_data.mem_len));
+	if (cal_block->cal_offset > acdb_data.mem_len) {
+		pr_err("%s: offset %d is > mem_len %llu\n",
+			__func__, cal_block->cal_offset, acdb_data.mem_len);
 		result = -EINVAL;
 		goto done;
 	}
 
-	atomic_set(&acdb_data.asm_custom_topology.cal_size,
-		cal_block->cal_size);
-	atomic_set(&acdb_data.asm_custom_topology.cal_paddr,
-		cal_block->cal_offset + atomic64_read(&acdb_data.paddr));
-	atomic_set(&acdb_data.asm_custom_topology.cal_kvaddr,
-		cal_block->cal_offset +
-		atomic64_read(&acdb_data.kvaddr));
+	acdb_data.asm_custom_topology.cal_size = cal_block->cal_size;
+	acdb_data.asm_custom_topology.cal_paddr =
+		cal_block->cal_offset + acdb_data.paddr;
+	acdb_data.asm_custom_topology.cal_kvaddr =
+		cal_block->cal_offset + acdb_data.kvaddr;
 done:
 	return result;
 }
@@ -280,10 +271,8 @@
 	}
 
 	cal_block->cal_size = ACDB_TOTAL_VOICE_ALLOCATION;
-	cal_block->cal_paddr =
-		atomic_read(&acdb_data.vocproc_cal.cal_paddr);
-	cal_block->cal_kvaddr =
-		atomic_read(&acdb_data.vocproc_cal.cal_kvaddr);
+	cal_block->cal_paddr = acdb_data.vocproc_cal.cal_paddr;
+	cal_block->cal_kvaddr = acdb_data.vocproc_cal.cal_kvaddr;
 done:
 	return result;
 }
@@ -299,12 +288,9 @@
 		goto done;
 	}
 
-	cal_block->cal_size =
-		atomic_read(&acdb_data.aanc_cal.cal_size);
-	cal_block->cal_paddr =
-		atomic_read(&acdb_data.aanc_cal.cal_paddr);
-	cal_block->cal_kvaddr =
-		atomic_read(&acdb_data.aanc_cal.cal_kvaddr);
+	cal_block->cal_size = acdb_data.aanc_cal.cal_size;
+	cal_block->cal_paddr = acdb_data.aanc_cal.cal_paddr;
+	cal_block->cal_kvaddr = acdb_data.aanc_cal.cal_kvaddr;
 done:
 	return result;
 }
@@ -314,20 +300,18 @@
 	int result = 0;
 	pr_debug("%s,\n", __func__);
 
-	if (cal_block->cal_offset > atomic64_read(&acdb_data.mem_len)) {
-		pr_err("%s: offset %d is > mem_len %ld\n",
-		 __func__, cal_block->cal_offset,
-		(long)atomic64_read(&acdb_data.mem_len));
+	if (cal_block->cal_offset > acdb_data.mem_len) {
+		pr_err("%s: offset %d is > mem_len %llu\n",
+		 __func__, cal_block->cal_offset, acdb_data.mem_len);
 		result = -EINVAL;
 		goto done;
 	}
 
-	atomic_set(&acdb_data.aanc_cal.cal_size,
-		cal_block->cal_size);
-	atomic_set(&acdb_data.aanc_cal.cal_paddr,
-		cal_block->cal_offset + atomic64_read(&acdb_data.paddr));
-	atomic_set(&acdb_data.aanc_cal.cal_kvaddr,
-		cal_block->cal_offset + atomic64_read(&acdb_data.kvaddr));
+	acdb_data.aanc_cal.cal_size = cal_block->cal_size;
+	acdb_data.aanc_cal.cal_paddr =
+		cal_block->cal_offset + acdb_data.paddr;
+	acdb_data.aanc_cal.cal_kvaddr =
+		cal_block->cal_offset + acdb_data.kvaddr;
 done:
 	return result;
 }
@@ -343,12 +327,9 @@
 		goto done;
 	}
 
-	cal_block->cal_size =
-		atomic_read(&acdb_data.lsm_cal.cal_size);
-	cal_block->cal_paddr =
-		atomic_read(&acdb_data.lsm_cal.cal_paddr);
-	cal_block->cal_kvaddr =
-		atomic_read(&acdb_data.lsm_cal.cal_kvaddr);
+	cal_block->cal_size = acdb_data.lsm_cal.cal_size;
+	cal_block->cal_paddr = acdb_data.lsm_cal.cal_paddr;
+	cal_block->cal_kvaddr = acdb_data.lsm_cal.cal_kvaddr;
 done:
 	return result;
 }
@@ -358,20 +339,18 @@
 	int result = 0;
 	pr_debug("%s,\n", __func__);
 
-	if (cal_block->cal_offset > atomic64_read(&acdb_data.mem_len)) {
-		pr_err("%s: offset %d is > mem_len %ld\n",
-			__func__, cal_block->cal_offset,
-			(long)atomic64_read(&acdb_data.mem_len));
+	if (cal_block->cal_offset > acdb_data.mem_len) {
+		pr_err("%s: offset %d is > mem_len %llu\n",
+			__func__, cal_block->cal_offset, acdb_data.mem_len);
 		result = -EINVAL;
 		goto done;
 	}
 
-	atomic_set(&acdb_data.lsm_cal.cal_size,
-		cal_block->cal_size);
-	atomic_set(&acdb_data.lsm_cal.cal_paddr,
-		cal_block->cal_offset + atomic64_read(&acdb_data.paddr));
-	atomic_set(&acdb_data.lsm_cal.cal_kvaddr,
-		cal_block->cal_offset + atomic64_read(&acdb_data.kvaddr));
+	acdb_data.lsm_cal.cal_size = cal_block->cal_size;
+	acdb_data.lsm_cal.cal_paddr =
+		cal_block->cal_offset + acdb_data.paddr;
+	acdb_data.lsm_cal.cal_kvaddr =
+		cal_block->cal_offset + acdb_data.kvaddr;
 done:
 	return result;
 }
@@ -470,7 +449,6 @@
 	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)
@@ -487,7 +465,6 @@
 		       __func__, result, path);
 		result = -EFAULT;
 	}
-	mutex_unlock(&acdb_data.acdb_mutex);
 done:
 	return result;
 }
@@ -503,12 +480,9 @@
 		goto done;
 	}
 
-	cal_block->cal_size =
-		atomic_read(&acdb_data.anc_cal.cal_size);
-	cal_block->cal_paddr =
-		atomic_read(&acdb_data.anc_cal.cal_paddr);
-	cal_block->cal_kvaddr =
-		atomic_read(&acdb_data.anc_cal.cal_kvaddr);
+	cal_block->cal_size = acdb_data.anc_cal.cal_size;
+	cal_block->cal_paddr = acdb_data.anc_cal.cal_paddr;
+	cal_block->cal_kvaddr = acdb_data.anc_cal.cal_kvaddr;
 done:
 	return result;
 }
@@ -518,20 +492,18 @@
 	int result = 0;
 	pr_debug("%s,\n", __func__);
 
-	if (cal_block->cal_offset > atomic64_read(&acdb_data.mem_len)) {
-		pr_err("%s: offset %d is > mem_len %ld\n",
-			__func__, cal_block->cal_offset,
-			(long)atomic64_read(&acdb_data.mem_len));
+	if (cal_block->cal_offset > acdb_data.mem_len) {
+		pr_err("%s: offset %d is > mem_len %llu\n",
+			__func__, cal_block->cal_offset, acdb_data.mem_len);
 		result = -EINVAL;
 		goto done;
 	}
 
-	atomic_set(&acdb_data.anc_cal.cal_size,
-		cal_block->cal_size);
-	atomic_set(&acdb_data.anc_cal.cal_paddr,
-		cal_block->cal_offset + atomic64_read(&acdb_data.paddr));
-	atomic_set(&acdb_data.anc_cal.cal_kvaddr,
-		cal_block->cal_offset + atomic64_read(&acdb_data.kvaddr));
+	acdb_data.anc_cal.cal_size = cal_block->cal_size;
+	acdb_data.anc_cal.cal_paddr =
+		cal_block->cal_offset + acdb_data.paddr;
+	acdb_data.anc_cal.cal_kvaddr =
+		cal_block->cal_offset + acdb_data.kvaddr;
 done:
 	return result;
 }
@@ -541,10 +513,9 @@
 	int result = 0;
 	pr_debug("%s, path = %d\n", __func__, path);
 
-	if (cal_block->cal_offset > atomic64_read(&acdb_data.mem_len)) {
-		pr_err("%s: offset %d is > mem_len %ld\n",
-			__func__, cal_block->cal_offset,
-			(long)atomic64_read(&acdb_data.mem_len));
+	if (cal_block->cal_offset > acdb_data.mem_len) {
+		pr_err("%s: offset %d is > mem_len %llu\n",
+			__func__, cal_block->cal_offset, acdb_data.mem_len);
 		result = -EINVAL;
 		goto done;
 	}
@@ -555,12 +526,11 @@
 		goto done;
 	}
 
-	atomic_set(&acdb_data.afe_cal[path].cal_size,
-		cal_block->cal_size);
-	atomic_set(&acdb_data.afe_cal[path].cal_paddr,
-		cal_block->cal_offset + atomic64_read(&acdb_data.paddr));
-	atomic_set(&acdb_data.afe_cal[path].cal_kvaddr,
-		cal_block->cal_offset + atomic64_read(&acdb_data.kvaddr));
+	acdb_data.afe_cal[path].cal_size = cal_block->cal_size;
+	acdb_data.afe_cal[path].cal_paddr =
+		cal_block->cal_offset + acdb_data.paddr;
+	acdb_data.afe_cal[path].cal_kvaddr =
+		cal_block->cal_offset + acdb_data.kvaddr;
 done:
 	return result;
 }
@@ -582,12 +552,9 @@
 		goto done;
 	}
 
-	cal_block->cal_size =
-		atomic_read(&acdb_data.afe_cal[path].cal_size);
-	cal_block->cal_paddr =
-		atomic_read(&acdb_data.afe_cal[path].cal_paddr);
-	cal_block->cal_kvaddr =
-		atomic_read(&acdb_data.afe_cal[path].cal_kvaddr);
+	cal_block->cal_size = acdb_data.afe_cal[path].cal_size;
+	cal_block->cal_paddr = acdb_data.afe_cal[path].cal_paddr;
+	cal_block->cal_kvaddr = acdb_data.afe_cal[path].cal_kvaddr;
 done:
 	return result;
 }
@@ -597,10 +564,9 @@
 	int result = 0;
 	pr_debug("%s, path = %d\n", __func__, path);
 
-	if (cal_block->cal_offset > atomic64_read(&acdb_data.mem_len)) {
-		pr_err("%s: offset %d is > mem_len %ld\n",
-			__func__, cal_block->cal_offset,
-			(long)atomic64_read(&acdb_data.mem_len));
+	if (cal_block->cal_offset > acdb_data.mem_len) {
+		pr_err("%s: offset %d is > mem_len %llu\n",
+			__func__, cal_block->cal_offset, acdb_data.mem_len);
 		result = -EINVAL;
 		goto done;
 	}
@@ -611,12 +577,11 @@
 		goto done;
 	}
 
-	atomic_set(&acdb_data.audproc_cal[path].cal_size,
-		cal_block->cal_size);
-	atomic_set(&acdb_data.audproc_cal[path].cal_paddr,
-		cal_block->cal_offset + atomic64_read(&acdb_data.paddr));
-	atomic_set(&acdb_data.audproc_cal[path].cal_kvaddr,
-		cal_block->cal_offset + atomic64_read(&acdb_data.kvaddr));
+	acdb_data.audproc_cal[path].cal_size = cal_block->cal_size;
+	acdb_data.audproc_cal[path].cal_paddr =
+		cal_block->cal_offset + acdb_data.paddr;
+	acdb_data.audproc_cal[path].cal_kvaddr =
+		cal_block->cal_offset + acdb_data.kvaddr;
 done:
 	return result;
 }
@@ -638,12 +603,9 @@
 		goto done;
 	}
 
-	cal_block->cal_size =
-		atomic_read(&acdb_data.audproc_cal[path].cal_size);
-	cal_block->cal_paddr =
-		atomic_read(&acdb_data.audproc_cal[path].cal_paddr);
-	cal_block->cal_kvaddr =
-		atomic_read(&acdb_data.audproc_cal[path].cal_kvaddr);
+	cal_block->cal_size = acdb_data.audproc_cal[path].cal_size;
+	cal_block->cal_paddr = acdb_data.audproc_cal[path].cal_paddr;
+	cal_block->cal_kvaddr = acdb_data.audproc_cal[path].cal_kvaddr;
 done:
 	return result;
 }
@@ -653,10 +615,9 @@
 	int result = 0;
 	pr_debug("%s, path = %d\n", __func__, path);
 
-	if (cal_block->cal_offset > atomic64_read(&acdb_data.mem_len)) {
-		pr_err("%s: offset %d is > mem_len %ld\n",
-			__func__, cal_block->cal_offset,
-			(long)atomic64_read(&acdb_data.mem_len));
+	if (cal_block->cal_offset > acdb_data.mem_len) {
+		pr_err("%s: offset %d is > mem_len %llu\n",
+			__func__, cal_block->cal_offset, acdb_data.mem_len);
 		result = -EINVAL;
 		goto done;
 	}
@@ -667,12 +628,11 @@
 		goto done;
 	}
 
-	atomic_set(&acdb_data.audstrm_cal[path].cal_size,
-		cal_block->cal_size);
-	atomic_set(&acdb_data.audstrm_cal[path].cal_paddr,
-		cal_block->cal_offset + atomic64_read(&acdb_data.paddr));
-	atomic_set(&acdb_data.audstrm_cal[path].cal_kvaddr,
-		cal_block->cal_offset + atomic64_read(&acdb_data.kvaddr));
+	acdb_data.audstrm_cal[path].cal_size = cal_block->cal_size;
+	acdb_data.audstrm_cal[path].cal_paddr =
+		cal_block->cal_offset + acdb_data.paddr;
+	acdb_data.audstrm_cal[path].cal_kvaddr =
+		cal_block->cal_offset + acdb_data.kvaddr;
 done:
 	return result;
 }
@@ -694,12 +654,9 @@
 		goto done;
 	}
 
-	cal_block->cal_size =
-		atomic_read(&acdb_data.audstrm_cal[path].cal_size);
-	cal_block->cal_paddr =
-		atomic_read(&acdb_data.audstrm_cal[path].cal_paddr);
-	cal_block->cal_kvaddr =
-		atomic_read(&acdb_data.audstrm_cal[path].cal_kvaddr);
+	cal_block->cal_size = acdb_data.audstrm_cal[path].cal_size;
+	cal_block->cal_paddr = acdb_data.audstrm_cal[path].cal_paddr;
+	cal_block->cal_kvaddr = acdb_data.audstrm_cal[path].cal_kvaddr;
 done:
 	return result;
 }
@@ -709,10 +666,9 @@
 	int result = 0;
 	pr_debug("%s, path = %d\n", __func__, path);
 
-	if (cal_block->cal_offset > atomic64_read(&acdb_data.mem_len)) {
-		pr_err("%s: offset %d is > mem_len %ld\n",
-			__func__, cal_block->cal_offset,
-			(long)atomic64_read(&acdb_data.mem_len));
+	if (cal_block->cal_offset > acdb_data.mem_len) {
+		pr_err("%s: offset %d is > mem_len %llu\n",
+			__func__, cal_block->cal_offset, acdb_data.mem_len);
 		result = -EINVAL;
 		goto done;
 	}
@@ -723,12 +679,11 @@
 		goto done;
 	}
 
-	atomic_set(&acdb_data.audvol_cal[path].cal_size,
-		cal_block->cal_size);
-	atomic_set(&acdb_data.audvol_cal[path].cal_paddr,
-		cal_block->cal_offset + atomic64_read(&acdb_data.paddr));
-	atomic_set(&acdb_data.audvol_cal[path].cal_kvaddr,
-		cal_block->cal_offset + atomic64_read(&acdb_data.kvaddr));
+	acdb_data.audvol_cal[path].cal_size = cal_block->cal_size;
+	acdb_data.audvol_cal[path].cal_paddr =
+		cal_block->cal_offset + acdb_data.paddr;
+	acdb_data.audvol_cal[path].cal_kvaddr =
+		cal_block->cal_offset + acdb_data.kvaddr;
 done:
 	return result;
 }
@@ -750,12 +705,9 @@
 		goto done;
 	}
 
-	cal_block->cal_size =
-		atomic_read(&acdb_data.audvol_cal[path].cal_size);
-	cal_block->cal_paddr =
-		atomic_read(&acdb_data.audvol_cal[path].cal_paddr);
-	cal_block->cal_kvaddr =
-		atomic_read(&acdb_data.audvol_cal[path].cal_kvaddr);
+	cal_block->cal_size = acdb_data.audvol_cal[path].cal_size;
+	cal_block->cal_paddr = acdb_data.audvol_cal[path].cal_paddr;
+	cal_block->cal_kvaddr = acdb_data.audvol_cal[path].cal_kvaddr;
 done:
 	return result;
 }
@@ -767,21 +719,18 @@
 	pr_debug("%s,\n", __func__);
 
 	if (cal_size > MAX_COL_SIZE) {
-		pr_err("%s: col size is to big %d\n", __func__,
-				cal_size);
+		pr_err("%s: col size is to big %d\n", __func__, cal_size);
 		result = -EINVAL;
 		goto done;
 	}
 	if (copy_from_user(acdb_data.col_data[vocproc_type],
 			(void *)((uint8_t *)cal_block + sizeof(cal_size)),
 			cal_size)) {
-		pr_err("%s: fail to copy col size %d\n",
-			__func__, cal_size);
+		pr_err("%s: fail to copy col size %d\n", __func__, cal_size);
 		result = -EINVAL;
 		goto done;
 	}
-	atomic_set(&acdb_data.vocproc_col_cal[vocproc_type].cal_size,
-		cal_size);
+	acdb_data.vocproc_col_cal[vocproc_type].cal_size = cal_size;
 done:
 	return result;
 }
@@ -798,12 +747,12 @@
 		goto done;
 	}
 
-	cal_block->cal_size = atomic_read(&acdb_data.
-				vocproc_col_cal[vocproc_type].cal_size);
-	cal_block->cal_paddr = atomic_read(&acdb_data.
-				vocproc_col_cal[vocproc_type].cal_paddr);
-	cal_block->cal_kvaddr = atomic_read(&acdb_data.
-				vocproc_col_cal[vocproc_type].cal_kvaddr);
+	cal_block->cal_size = acdb_data.
+		vocproc_col_cal[vocproc_type].cal_size;
+	cal_block->cal_paddr = acdb_data.
+		vocproc_col_cal[vocproc_type].cal_paddr;
+	cal_block->cal_kvaddr = acdb_data.
+		vocproc_col_cal[vocproc_type].cal_kvaddr;
 done:
 	return result;
 }
@@ -815,24 +764,19 @@
 
 
 	if (cal_block->cal_offset >
-				atomic64_read(&acdb_data.mem_len)) {
-		pr_err("%s: offset %d is > mem_len %ld\n",
-			__func__, cal_block->cal_offset,
-			(long)atomic64_read(&acdb_data.mem_len));
-		atomic_set(&acdb_data.vocproc_dev_cal.cal_size, 0);
+				acdb_data.mem_len) {
+		pr_err("%s: offset %d is > mem_len %llu\n",
+			__func__, cal_block->cal_offset, acdb_data.mem_len);
+		acdb_data.vocproc_dev_cal.cal_size = 0;
 		result = -EINVAL;
 		goto done;
 	}
 
-	atomic_set(&acdb_data.vocproc_dev_cal.cal_size,
-		cal_block->cal_size);
-	atomic_set(&acdb_data.vocproc_dev_cal.cal_paddr,
-		cal_block->cal_offset +
-	atomic64_read(&acdb_data.paddr));
-			atomic_set(&acdb_data.vocproc_dev_cal.cal_kvaddr,
-			cal_block->cal_offset +
-			atomic64_read(&acdb_data.kvaddr));
-
+	acdb_data.vocproc_dev_cal.cal_size = cal_block->cal_size;
+	acdb_data.vocproc_dev_cal.cal_paddr =
+		cal_block->cal_offset + acdb_data.paddr;
+	acdb_data.vocproc_dev_cal.cal_kvaddr =
+		cal_block->cal_offset + acdb_data.kvaddr;
 done:
 	return result;
 }
@@ -848,12 +792,9 @@
 		goto done;
 	}
 
-	cal_block->cal_size =
-		atomic_read(&acdb_data.vocproc_dev_cal.cal_size);
-	cal_block->cal_paddr =
-		atomic_read(&acdb_data.vocproc_dev_cal.cal_paddr);
-	cal_block->cal_kvaddr =
-		atomic_read(&acdb_data.vocproc_dev_cal.cal_kvaddr);
+	cal_block->cal_size = acdb_data.vocproc_dev_cal.cal_size;
+	cal_block->cal_paddr = acdb_data.vocproc_dev_cal.cal_paddr;
+	cal_block->cal_kvaddr = acdb_data.vocproc_dev_cal.cal_kvaddr;
 done:
 	return result;
 }
@@ -866,24 +807,19 @@
 	pr_debug("%s,\n", __func__);
 
 	if (cal_block->cal_offset >
-				atomic64_read(&acdb_data.mem_len)) {
-		pr_err("%s: offset %d is > mem_len %ld\n",
-			__func__, cal_block->cal_offset,
-			(long)atomic64_read(&acdb_data.mem_len));
-		atomic_set(&acdb_data.vocproc_cal.cal_size, 0);
+				acdb_data.mem_len) {
+		pr_err("%s: offset %d is > mem_len %llu\n",
+			__func__, cal_block->cal_offset, acdb_data.mem_len);
+		acdb_data.vocproc_cal.cal_size = 0;
 		result = -EINVAL;
 		goto done;
 	}
 
-	atomic_set(&acdb_data.vocproc_cal.cal_size,
-		cal_block->cal_size);
-	atomic_set(&acdb_data.vocproc_cal.cal_paddr,
-		cal_block->cal_offset +
-		atomic64_read(&acdb_data.paddr));
-	atomic_set(&acdb_data.vocproc_cal.cal_kvaddr,
-		cal_block->cal_offset +
-		atomic64_read(&acdb_data.kvaddr));
-
+	acdb_data.vocproc_cal.cal_size = cal_block->cal_size;
+	acdb_data.vocproc_cal.cal_paddr =
+		cal_block->cal_offset + acdb_data.paddr;
+	acdb_data.vocproc_cal.cal_kvaddr =
+		cal_block->cal_offset + acdb_data.kvaddr;
 done:
 	return result;
 }
@@ -899,12 +835,9 @@
 		goto done;
 	}
 
-	cal_block->cal_size =
-		atomic_read(&acdb_data.vocproc_cal.cal_size);
-	cal_block->cal_paddr =
-		atomic_read(&acdb_data.vocproc_cal.cal_paddr);
-	cal_block->cal_kvaddr =
-		atomic_read(&acdb_data.vocproc_cal.cal_kvaddr);
+	cal_block->cal_size = acdb_data.vocproc_cal.cal_size;
+	cal_block->cal_paddr = acdb_data.vocproc_cal.cal_paddr;
+	cal_block->cal_kvaddr = acdb_data.vocproc_cal.cal_kvaddr;
 done:
 	return result;
 }
@@ -915,24 +848,19 @@
 	pr_debug("%s,\n", __func__);
 
 	if (cal_block->cal_offset >
-			atomic64_read(&acdb_data.mem_len)) {
-		pr_err("%s: offset %d is > mem_len %ld\n",
-			__func__, cal_block->cal_offset,
-			(long)atomic64_read(&acdb_data.mem_len));
-		atomic_set(&acdb_data.vocstrm_cal.cal_size, 0);
+			acdb_data.mem_len) {
+		pr_err("%s: offset %d is > mem_len %llu\n",
+			__func__, cal_block->cal_offset, acdb_data.mem_len);
+		acdb_data.vocstrm_cal.cal_size = 0;
 		result = -EINVAL;
 		goto done;
 	}
 
-	atomic_set(&acdb_data.vocstrm_cal.cal_size,
-		cal_block->cal_size);
-	atomic_set(&acdb_data.vocstrm_cal.cal_paddr,
-		cal_block->cal_offset +
-		atomic64_read(&acdb_data.paddr));
-	atomic_set(&acdb_data.vocstrm_cal.cal_kvaddr,
-		cal_block->cal_offset +
-		atomic64_read(&acdb_data.kvaddr));
-
+	acdb_data.vocstrm_cal.cal_size = cal_block->cal_size;
+	acdb_data.vocstrm_cal.cal_paddr =
+		cal_block->cal_offset + acdb_data.paddr;
+	acdb_data.vocstrm_cal.cal_kvaddr =
+		cal_block->cal_offset + acdb_data.kvaddr;
 done:
 	return result;
 }
@@ -948,12 +876,9 @@
 		goto done;
 	}
 
-	cal_block->cal_size =
-		atomic_read(&acdb_data.vocstrm_cal.cal_size);
-	cal_block->cal_paddr =
-		atomic_read(&acdb_data.vocstrm_cal.cal_paddr);
-	cal_block->cal_kvaddr =
-		atomic_read(&acdb_data.vocstrm_cal.cal_kvaddr);
+	cal_block->cal_size = acdb_data.vocstrm_cal.cal_size;
+	cal_block->cal_paddr = acdb_data.vocstrm_cal.cal_paddr;
+	cal_block->cal_kvaddr = acdb_data.vocstrm_cal.cal_kvaddr;
 done:
 	return result;
 }
@@ -963,25 +888,19 @@
 	int result = 0;
 	pr_debug("%s,\n", __func__);
 
-	if (cal_block->cal_offset >
-			atomic64_read(&acdb_data.mem_len)) {
-		pr_err("%s: offset %d is > mem_len %ld\n",
-			__func__, cal_block->cal_offset,
-			(long)atomic64_read(&acdb_data.mem_len));
-		atomic_set(&acdb_data.vocvol_cal.cal_size, 0);
+	if (cal_block->cal_offset > acdb_data.mem_len) {
+		pr_err("%s: offset %d is > mem_len %llu\n",
+			__func__, cal_block->cal_offset, acdb_data.mem_len);
+		acdb_data.vocvol_cal.cal_size = 0;
 		result = -EINVAL;
 		goto done;
 	}
 
-	atomic_set(&acdb_data.vocvol_cal.cal_size,
-		cal_block->cal_size);
-	atomic_set(&acdb_data.vocvol_cal.cal_paddr,
-		cal_block->cal_offset +
-		atomic64_read(&acdb_data.paddr));
-	atomic_set(&acdb_data.vocvol_cal.cal_kvaddr,
-		cal_block->cal_offset +
-		atomic64_read(&acdb_data.kvaddr));
-
+	acdb_data.vocvol_cal.cal_size = cal_block->cal_size;
+	acdb_data.vocvol_cal.cal_paddr =
+		cal_block->cal_offset + acdb_data.paddr;
+	acdb_data.vocvol_cal.cal_kvaddr =
+		cal_block->cal_offset + acdb_data.kvaddr;
 done:
 	return result;
 }
@@ -997,12 +916,9 @@
 		goto done;
 	}
 
-	cal_block->cal_size =
-		atomic_read(&acdb_data.vocvol_cal.cal_size);
-	cal_block->cal_paddr =
-		atomic_read(&acdb_data.vocvol_cal.cal_paddr);
-	cal_block->cal_kvaddr =
-		atomic_read(&acdb_data.vocvol_cal.cal_kvaddr);
+	cal_block->cal_size = acdb_data.vocvol_cal.cal_size;
+	cal_block->cal_paddr = acdb_data.vocvol_cal.cal_paddr;
+	cal_block->cal_kvaddr = acdb_data.vocvol_cal.cal_kvaddr;
 done:
 	return result;
 }
@@ -1011,8 +927,8 @@
 {
 	pr_debug("%s,\n", __func__);
 
-	atomic_set(&acdb_data.sidetone_cal.enable, cal_data->enable);
-	atomic_set(&acdb_data.sidetone_cal.gain, cal_data->gain);
+	acdb_data.sidetone_cal.enable = cal_data->enable;
+	acdb_data.sidetone_cal.gain = cal_data->gain;
 }
 
 int get_sidetone_cal(struct sidetone_cal *cal_data)
@@ -1026,8 +942,10 @@
 		goto done;
 	}
 
-	cal_data->enable = atomic_read(&acdb_data.sidetone_cal.enable);
-	cal_data->gain = atomic_read(&acdb_data.sidetone_cal.gain);
+	mutex_lock(&acdb_data.acdb_mutex);
+	cal_data->enable = acdb_data.sidetone_cal.enable;
+	cal_data->gain = acdb_data.sidetone_cal.gain;
+	mutex_unlock(&acdb_data.acdb_mutex);
 done:
 	return result;
 }
@@ -1111,14 +1029,15 @@
 	s32 result = 0;
 	pr_debug("%s\n", __func__);
 
-	if (atomic64_read(&acdb_data.mem_len)) {
+	mutex_lock(&acdb_data.acdb_mutex);
+	if (acdb_data.mem_len)
 		pr_debug("%s: ACDB opened but memory allocated, using existing allocation!\n",
 			__func__);
-	}
 
-	atomic_set(&acdb_data.valid_adm_custom_top, 1);
-	atomic_set(&acdb_data.valid_asm_custom_top, 1);
-	atomic_inc(&usage_count);
+	acdb_data.valid_adm_custom_top = 1;
+	acdb_data.valid_asm_custom_top = 1;
+	acdb_data.usage_count++;
+	mutex_unlock(&acdb_data.acdb_mutex);
 
 	return result;
 }
@@ -1195,30 +1114,31 @@
 	int	i;
 	pr_debug("%s\n", __func__);
 
-	mutex_lock(&acdb_data.acdb_mutex);
+	if (acdb_data.mem_len == 0)
+		goto done;
+
+	pr_debug("Remove existing memory\n");
+	acdb_data.mem_len = 0;
+
+	/* unmap all cal data */
+	result = unmap_cal_tables();
+	if (result < 0)
+		pr_err("%s: unmap_cal_tables failed, err = %d\n",
+			__func__, result);
+
+	msm_audio_ion_free(acdb_data.ion_client, acdb_data.ion_handle);
+	acdb_data.ion_client = NULL;
+	acdb_data.ion_handle = NULL;
+
+	for (i = 0; i < MAX_VOCPROC_TYPES; i++) {
+		kfree(acdb_data.col_data[i]);
+		acdb_data.col_data[i] = NULL;
+	}
+
 	kfree(acdb_data.hw_delay_tx.delay_info);
 	kfree(acdb_data.hw_delay_rx.delay_info);
-
-	if (atomic64_read(&acdb_data.mem_len)) {
-		/* 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++) {
-			kfree(acdb_data.col_data[i]);
-			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);
-	}
-	mutex_unlock(&acdb_data.acdb_mutex);
-	return 0;
+done:
+	return result;
 }
 
 static int register_memory(void)
@@ -1231,42 +1151,38 @@
 	unsigned long		mem_len;
 	pr_debug("%s\n", __func__);
 
-	mutex_lock(&acdb_data.acdb_mutex);
-	allocate_hw_delay_entries();
-	for (i = 0; i < MAX_VOCPROC_TYPES; i++) {
-		acdb_data.col_data[i] = kmalloc(MAX_COL_SIZE, GFP_KERNEL);
-		atomic_set(&acdb_data.vocproc_col_cal[i].cal_kvaddr,
-			(uint32_t)acdb_data.col_data[i]);
-	}
-
 	result = msm_audio_ion_import("audio_acdb_client",
 				&acdb_data.ion_client,
 				&acdb_data.ion_handle,
-				atomic_read(&acdb_data.map_handle),
+				acdb_data.map_handle,
 				NULL, 0,
 				&paddr, (size_t *)&mem_len, &kvptr);
 	if (result) {
 		pr_err("%s: audio ION alloc failed, rc = %d\n",
 			__func__, result);
-		result = PTR_ERR(acdb_data.ion_client);
 		goto err_ion_handle;
 	}
-	kvaddr = (unsigned long)kvptr;
-	atomic64_set(&acdb_data.paddr, paddr);
-	atomic64_set(&acdb_data.kvaddr, kvaddr);
-	atomic64_set(&acdb_data.mem_len, mem_len);
-	mutex_unlock(&acdb_data.acdb_mutex);
 
-	pr_debug("%s done! paddr = 0x%lx, kvaddr = 0x%lx, len = x%lx\n",
-		 __func__,
-		(long)atomic64_read(&acdb_data.paddr),
-		(long)atomic64_read(&acdb_data.kvaddr),
-		(long)atomic64_read(&acdb_data.mem_len));
+	allocate_hw_delay_entries();
+
+	for (i = 0; i < MAX_VOCPROC_TYPES; i++) {
+		acdb_data.col_data[i] = kmalloc(MAX_COL_SIZE, GFP_KERNEL);
+		acdb_data.vocproc_col_cal[i].cal_kvaddr =
+			(uint32_t)acdb_data.col_data[i];
+	}
+
+	kvaddr = (unsigned long)kvptr;
+	acdb_data.paddr = paddr;
+	acdb_data.kvaddr = kvaddr;
+	acdb_data.mem_len = mem_len;
+
+	pr_debug("%s done! paddr = 0x%llx, kvaddr = 0x%llx, len = 0x%llx\n",
+		 __func__, acdb_data.paddr, acdb_data.kvaddr,
+		 acdb_data.mem_len);
 
 	return result;
 err_ion_handle:
-	atomic64_set(&acdb_data.mem_len, 0);
-	mutex_unlock(&acdb_data.acdb_mutex);
+	acdb_data.mem_len = 0;
 	return result;
 }
 static long acdb_ioctl(struct file *f,
@@ -1281,26 +1197,26 @@
 	struct msm_spk_prot_status acdb_spk_status;
 	pr_debug("%s\n", __func__);
 
+	mutex_lock(&acdb_data.acdb_mutex);
 	switch (cmd) {
 	case AUDIO_REGISTER_PMEM:
 		pr_debug("AUDIO_REGISTER_PMEM\n");
-		if (atomic_read(&acdb_data.mem_len)) {
-			deregister_memory();
-			pr_debug("Remove the existing memory\n");
-		}
+		result = deregister_memory();
+		if (result < 0)
+			pr_err("%s: deregister_memory failed returned %d!\n",
+				__func__, result);
 
 		if (copy_from_user(&map_fd, (void *)arg, sizeof(map_fd))) {
 			pr_err("%s: fail to copy memory handle!\n", __func__);
 			result = -EFAULT;
 		} else {
-			atomic_set(&acdb_data.map_handle, map_fd);
+			acdb_data.map_handle = map_fd;
 			result = register_memory();
 		}
 		goto done;
-
 	case AUDIO_DEREGISTER_PMEM:
 		pr_debug("AUDIO_DEREGISTER_PMEM\n");
-		deregister_memory();
+		result = deregister_memory();
 		goto done;
 	case AUDIO_SET_VOICE_RX_TOPOLOGY:
 		if (copy_from_user(&topology, (void *)arg,
@@ -1343,16 +1259,13 @@
 		store_asm_topology(topology);
 		goto done;
 	case AUDIO_SET_SPEAKER_PROT:
-		mutex_lock(&acdb_data.acdb_mutex);
 		if (copy_from_user(&acdb_data.spk_prot_cfg, (void *)arg,
 				sizeof(acdb_data.spk_prot_cfg))) {
 			pr_err("%s fail to copy spk_prot_cfg\n", __func__);
 			result = -EFAULT;
 		}
-		mutex_unlock(&acdb_data.acdb_mutex);
 		goto done;
 	case AUDIO_GET_SPEAKER_PROT:
-		mutex_lock(&acdb_data.acdb_mutex);
 		/*Indicates calibration was succesfull*/
 		if (acdb_data.spk_prot_cfg.mode == MSM_SPKR_PROT_CALIBRATED) {
 			prot_status.r0 = acdb_data.spk_prot_cfg.r0;
@@ -1379,7 +1292,6 @@
 			sizeof(prot_status))) {
 			pr_err("%s: Failed to update prot_status\n", __func__);
 		}
-		mutex_unlock(&acdb_data.acdb_mutex);
 		goto done;
 	case AUDIO_REGISTER_VOCPROC_VOL_TABLE:
 		result = register_vocvol_table();
@@ -1502,23 +1414,25 @@
 	}
 
 done:
+	mutex_unlock(&acdb_data.acdb_mutex);
 	return result;
 }
 
 static int acdb_mmap(struct file *file, struct vm_area_struct *vma)
 {
 	int result = 0;
-	uint32_t size = vma->vm_end - vma->vm_start;
+	size_t size = vma->vm_end - vma->vm_start;
 
 	pr_debug("%s\n", __func__);
 
-	if (atomic64_read(&acdb_data.mem_len)) {
-		if (size <= atomic64_read(&acdb_data.mem_len)) {
+	mutex_lock(&acdb_data.acdb_mutex);
+	if (acdb_data.mem_len) {
+		if (size <= acdb_data.mem_len) {
 			vma->vm_page_prot = pgprot_noncached(
 						vma->vm_page_prot);
 			result = remap_pfn_range(vma,
 				vma->vm_start,
-				atomic64_read(&acdb_data.paddr) >> PAGE_SHIFT,
+				acdb_data.paddr >> PAGE_SHIFT,
 				size,
 				vma->vm_page_prot);
 		} else {
@@ -1529,25 +1443,29 @@
 		pr_err("%s: memory is not allocated, yet!\n", __func__);
 		result = -ENODEV;
 	}
+	mutex_unlock(&acdb_data.acdb_mutex);
 
 	return result;
 }
 
 static int acdb_release(struct inode *inode, struct file *f)
 {
-	s32 result = 0;
+	int result = 0;
+	pr_debug("%s\n", __func__);
 
-	atomic_dec(&usage_count);
-	atomic_read(&usage_count);
+	mutex_lock(&acdb_data.acdb_mutex);
+	acdb_data.usage_count--;
 
-	pr_debug("%s: ref count %d!\n", __func__,
-		atomic_read(&usage_count));
+	pr_debug("%s: ref count %d!\n", __func__, acdb_data.usage_count);
 
-	if (atomic_read(&usage_count) >= 1)
+	if (acdb_data.usage_count > 0) {
 		result = -EBUSY;
-	else
-		result = deregister_memory();
+		goto done;
+	}
 
+	result = deregister_memory();
+done:
+	mutex_unlock(&acdb_data.acdb_mutex);
 	return result;
 }
 
@@ -1571,9 +1489,9 @@
 	/*Speaker protection disabled*/
 	acdb_data.spk_prot_cfg.mode = MSM_SPKR_PROT_DISABLED;
 	mutex_init(&acdb_data.acdb_mutex);
-	atomic_set(&usage_count, 0);
-	atomic_set(&acdb_data.valid_adm_custom_top, 1);
-	atomic_set(&acdb_data.valid_asm_custom_top, 1);
+	acdb_data.usage_count = 0;
+	acdb_data.valid_adm_custom_top = 1;
+	acdb_data.valid_asm_custom_top = 1;
 
 	return misc_register(&acdb_misc);
 }
diff --git a/sound/soc/msm/qdsp6v2/audio_acdb.h b/sound/soc/msm/qdsp6v2/audio_acdb.h
index e2ca395..45a83f6 100644
--- a/sound/soc/msm/qdsp6v2/audio_acdb.h
+++ b/sound/soc/msm/qdsp6v2/audio_acdb.h
@@ -35,12 +35,6 @@
 	uint32_t		cal_paddr;
 };
 
-struct acdb_atomic_cal_block {
-	atomic_t		cal_size;
-	atomic_t		cal_kvaddr;
-	atomic_t		cal_paddr;
-};
-
 struct hw_delay_entry {
 	uint32_t sample_rate;
 	uint32_t delay_usec;
diff --git a/sound/soc/msm/qdsp6v2/audio_ocmem.c b/sound/soc/msm/qdsp6v2/audio_ocmem.c
index 93b3597..4a25606 100644
--- a/sound/soc/msm/qdsp6v2/audio_ocmem.c
+++ b/sound/soc/msm/qdsp6v2/audio_ocmem.c
@@ -879,6 +879,15 @@
 
 	pr_debug("%s\n", __func__);
 
+	audio_ocmem_lcl.audio_hdl = ocmem_notifier_register(OCMEM_LP_AUDIO,
+						&audio_ocmem_client_nb);
+	if (PTR_RET(audio_ocmem_lcl.audio_hdl) == -EPROBE_DEFER)
+		return -EPROBE_DEFER;
+	else if (!audio_ocmem_lcl.audio_hdl) {
+		pr_err("%s: Failed to get ocmem handle %d\n", __func__,
+						OCMEM_LP_AUDIO);
+		return -ENODEV;
+	}
 	subsys_notif_register_notifier("adsp", &anb);
 
 	audio_ocmem_lcl.ocmem_dump_addr =
@@ -944,12 +953,6 @@
 		ret = -EFAULT;
 		goto destroy_voice_wq;
 	}
-	audio_ocmem_lcl.audio_hdl = ocmem_notifier_register(OCMEM_LP_AUDIO,
-						&audio_ocmem_client_nb);
-	if (audio_ocmem_lcl.audio_hdl == NULL) {
-		pr_err("%s: Failed to get ocmem handle %d\n", __func__,
-						OCMEM_LP_AUDIO);
-	}
 	audio_ocmem_lcl.lp_memseg_ptr = NULL;
 	return 0;
 destroy_voice_wq:
diff --git a/sound/soc/msm/qdsp6v2/msm-compr-q6-v2.c b/sound/soc/msm/qdsp6v2/msm-compr-q6-v2.c
index fb362a1..b626fa4 100755
--- a/sound/soc/msm/qdsp6v2/msm-compr-q6-v2.c
+++ b/sound/soc/msm/qdsp6v2/msm-compr-q6-v2.c
@@ -987,7 +987,7 @@
 			struct snd_dec_ddp *ddp =
 				&compr->info.codec_param.codec.options.ddp;
 			uint32_t params_length = ddp->params_length*sizeof(int);
-			if(params_length > MAX_AC3_PARAM_SIZE) {
+			if (params_length > MAX_AC3_PARAM_SIZE) {
 				/*MAX is 36*sizeof(int) this should not happen*/
 				pr_err("params_length(%d) is greater than %d",
 				params_length, MAX_AC3_PARAM_SIZE);
@@ -1024,7 +1024,7 @@
 			struct snd_dec_ddp *ddp =
 				&compr->info.codec_param.codec.options.ddp;
 			uint32_t params_length = ddp->params_length*sizeof(int);
-			if(params_length > MAX_AC3_PARAM_SIZE) {
+			if (params_length > MAX_AC3_PARAM_SIZE) {
 				/*MAX is 36*sizeof(int) this should not happen*/
 				pr_err("params_length(%d) is greater than %d",
 				params_length, MAX_AC3_PARAM_SIZE);
diff --git a/sound/soc/msm/qdsp6v2/msm-compress-q6-v2.c b/sound/soc/msm/qdsp6v2/msm-compress-q6-v2.c
index da36f7f..79f0a97 100644
--- a/sound/soc/msm/qdsp6v2/msm-compress-q6-v2.c
+++ b/sound/soc/msm/qdsp6v2/msm-compress-q6-v2.c
@@ -44,6 +44,12 @@
 #include "msm-pcm-routing-v2.h"
 #include "audio_ocmem.h"
 
+#define DSP_PP_BUFFERING_IN_MSEC	25
+#define PARTIAL_DRAIN_ACK_EARLY_BY_MSEC	150
+#define MP3_OUTPUT_FRAME_SZ		1152
+#define AAC_OUTPUT_FRAME_SZ		1024
+#define DSP_NUM_OUTPUT_FRAME_BUFFERED	2
+
 /* Default values used if user space does not set */
 #define COMPR_PLAYBACK_MIN_FRAGMENT_SIZE (8 * 1024)
 #define COMPR_PLAYBACK_MAX_FRAGMENT_SIZE (128 * 1024)
@@ -54,6 +60,13 @@
 const DECLARE_TLV_DB_LINEAR(msm_compr_vol_gain, 0,
 				COMPRESSED_LR_VOL_MAX_STEPS);
 
+struct msm_compr_gapless_state {
+	bool set_next_stream_id;
+	int32_t stream_opened[2];
+	uint32_t initial_samples_drop;
+	uint32_t trailing_samples_drop;
+};
+
 struct msm_compr_pdata {
 	atomic_t audio_ocmem_req;
 	struct snd_compr_stream *cstream[MSM_FRONTEND_DAI_MAX];
@@ -75,6 +88,9 @@
 	uint32_t byte_offset;
 	uint32_t copied_total;
 	uint32_t bytes_received;
+	int32_t first_buffer;
+	int32_t last_buffer;
+	int32_t partial_drain_delay;
 
 	uint16_t session_id;
 
@@ -85,14 +101,19 @@
 	uint32_t cmd_interrupt;
 	uint32_t drain_ready;
 
+	struct msm_compr_gapless_state gapless_state;
+
 	atomic_t start;
 	atomic_t eos;
 	atomic_t drain;
 	atomic_t xrun;
+	atomic_t close;
+	atomic_t wait_on_close;
 
 	wait_queue_head_t eos_wait;
 	wait_queue_head_t drain_wait;
 	wait_queue_head_t flush_wait;
+	wait_queue_head_t close_wait;
 
 	spinlock_t lock;
 };
@@ -143,6 +164,17 @@
 
 	pr_debug("%s: bytes_received = %d copied_total = %d\n",
 		__func__, prtd->bytes_received, prtd->copied_total);
+	/*
+	 * FIXME: Initial and trailing silence removal API call to DSP results
+	 *	to a glitch during the stream transition for gapless playback.
+	 *	Add this when the issue is fixed from DSP.
+	 */
+/*
+	if (prtd->first_buffer)
+		q6asm_send_meta_data(prtd->audio_client,
+				prtd->gapless_state.initial_samples_drop,
+				prtd->gapless_state.trailing_samples_drop);
+*/
 	buffer_length = prtd->codec_param.buffer.fragment_size;
 	bytes_available = prtd->bytes_received - prtd->copied_total;
 	if (bytes_available < prtd->codec_param.buffer.fragment_size)
@@ -153,7 +185,10 @@
 		pr_debug("wrap around situation, send partial data %d now", buffer_length);
 	}
 
-	param.paddr	= prtd->buffer_paddr + prtd->byte_offset;
+	if (buffer_length)
+		param.paddr	= prtd->buffer_paddr + prtd->byte_offset;
+	else
+		param.paddr	= prtd->buffer_paddr;
 	WARN(param.paddr % 32 != 0, "param.paddr %lx not multiple of 32", param.paddr);
 
 	param.len	= buffer_length;
@@ -162,11 +197,16 @@
 	param.flags	= NO_TIMESTAMP;
 	param.uid	= buffer_length;
 	param.metadata_len = 0;
+	param.last_buffer = prtd->last_buffer;
 
 	pr_debug("%s: sending %d bytes to DSP byte_offset = %d\n",
 		__func__, buffer_length, prtd->byte_offset);
-	if (q6asm_async_write(prtd->audio_client, &param) < 0)
+	if (q6asm_async_write(prtd->audio_client, &param) < 0) {
 		pr_err("%s:q6asm_async_write failed\n", __func__);
+	} else {
+		if (prtd->first_buffer)
+			prtd->first_buffer = 0;
+	}
 
 	return 0;
 }
@@ -176,9 +216,10 @@
 {
 	struct msm_compr_audio *prtd = priv;
 	struct snd_compr_stream *cstream = prtd->cstream;
+	struct audio_client *ac = prtd->audio_client;
 	uint32_t chan_mode = 0;
 	uint32_t sample_rate = 0;
-	int bytes_available;
+	int bytes_available, stream_id;
 
 	pr_debug("%s opcode =%08x\n", __func__, opcode);
 	switch (opcode) {
@@ -217,12 +258,19 @@
 			pr_debug("WRITE_DONE Insufficient data to send. break out\n");
 			atomic_set(&prtd->xrun, 1);
 
+			if (prtd->last_buffer)
+				prtd->last_buffer = 0;
 			if (atomic_read(&prtd->drain)) {
-				pr_debug("wake up on drain");
+				pr_debug("wake up on drain\n");
 				prtd->drain_ready = 1;
 				wake_up(&prtd->drain_wait);
 				atomic_set(&prtd->drain, 0);
 			}
+		} else if ((bytes_available == cstream->runtime->fragment_size)
+			   && atomic_read(&prtd->drain)) {
+			prtd->last_buffer = 1;
+			msm_compr_send_buffer(prtd);
+			prtd->last_buffer = 0;
 		} else
 			msm_compr_send_buffer(prtd);
 
@@ -230,12 +278,24 @@
 		break;
 	case ASM_DATA_EVENT_RENDERED_EOS:
 		pr_debug("ASM_DATA_CMDRSP_EOS\n");
-		if (atomic_read(&prtd->eos)) {
+		spin_lock(&prtd->lock);
+		if (atomic_read(&prtd->eos) &&
+		    !prtd->gapless_state.set_next_stream_id) {
 			pr_debug("ASM_DATA_CMDRSP_EOS wake up\n");
 			prtd->cmd_ack = 1;
 			wake_up(&prtd->eos_wait);
-			atomic_set(&prtd->eos, 0);
 		}
+		atomic_set(&prtd->eos, 0);
+		stream_id = ac->stream_id^1; /*prev stream */
+		if (prtd->gapless_state.set_next_stream_id &&
+		    prtd->gapless_state.stream_opened[stream_id]) {
+			q6asm_stream_cmd_nowait(prtd->audio_client,
+						CMD_CLOSE, stream_id);
+			atomic_set(&prtd->close, 1);
+			prtd->gapless_state.stream_opened[stream_id] = 0;
+			prtd->gapless_state.set_next_stream_id = false;
+		}
+		spin_unlock(&prtd->lock);
 		break;
 	case ASM_DATA_EVENT_SR_CM_CHANGE_NOTIFY:
 	case ASM_DATA_EVENT_ENC_SR_CM_CHANGE_NOTIFY: {
@@ -271,6 +331,21 @@
 			prtd->cmd_ack = 1;
 			wake_up(&prtd->flush_wait);
 			break;
+		case ASM_DATA_CMD_REMOVE_INITIAL_SILENCE:
+			pr_debug("ASM_DATA_CMD_REMOVE_INITIAL_SILENCE\n");
+			break;
+		case ASM_DATA_CMD_REMOVE_TRAILING_SILENCE:
+			pr_debug("ASM_DATA_CMD_REMOVE_TRAILING_SILENCE\n");
+			break;
+		case ASM_STREAM_CMD_CLOSE:
+			pr_debug("ASM_DATA_CMD_CLOSE\n");
+			if (atomic_read(&prtd->close) &&
+			    atomic_read(&prtd->wait_on_close)) {
+				prtd->cmd_ack = 1;
+				wake_up(&prtd->close_wait);
+			}
+			atomic_set(&prtd->close, 0);
+			break;
 		default:
 			break;
 		}
@@ -302,7 +377,8 @@
 	prtd->compr_cap.codecs[1] = SND_AUDIOCODEC_AAC;
 }
 
-static int msm_compr_send_media_format_block(struct snd_compr_stream *cstream)
+static int msm_compr_send_media_format_block(struct snd_compr_stream *cstream,
+					     int stream_id)
 {
 	struct snd_compr_runtime *runtime = cstream->runtime;
 	struct msm_compr_audio *prtd = runtime->private_data;
@@ -319,8 +395,8 @@
 		aac_cfg.format = 0x03;
 		aac_cfg.ch_cfg = prtd->num_channels;
 		aac_cfg.sample_rate = prtd->sample_rate;
-		ret = q6asm_media_format_block_aac(prtd->audio_client,
-						&aac_cfg);
+		ret = q6asm_stream_media_format_block_aac(prtd->audio_client,
+							  &aac_cfg, stream_id);
 		if (ret < 0)
 			pr_err("%s: CMD Format block failed\n", __func__);
 		break;
@@ -338,6 +414,7 @@
 	struct snd_soc_pcm_runtime *soc_prtd = cstream->private_data;
 	uint16_t bits_per_sample = 16;
 	int dir = IN, ret = 0;
+	struct audio_client *ac = prtd->audio_client;
 	struct asm_softpause_params softpause = {
 		.enable = SOFT_PAUSE_ENABLE,
 		.period = SOFT_PAUSE_PERIOD,
@@ -351,16 +428,18 @@
 	};
 
 	pr_debug("%s\n", __func__);
-	ret = q6asm_open_write_v2(prtd->audio_client,
-				prtd->codec, bits_per_sample);
+	ret = q6asm_stream_open_write_v2(ac,
+				prtd->codec, bits_per_sample,
+				ac->stream_id, true/*gapless*/);
 	if (ret < 0) {
 		pr_err("%s: Session out open failed\n", __func__);
 		 return -ENOMEM;
 	}
 
+	prtd->gapless_state.stream_opened[ac->stream_id] = 1;
 	pr_debug("%s be_id %d\n", __func__, soc_prtd->dai_link->be_id);
 	msm_pcm_routing_reg_phy_stream(soc_prtd->dai_link->be_id,
-				prtd->audio_client->perf_mode,
+				ac->perf_mode,
 				prtd->session_id,
 				SNDRV_PCM_STREAM_PLAYBACK);
 
@@ -368,19 +447,17 @@
 	if (ret < 0)
 		pr_err("%s : Set Volume failed : %d", __func__, ret);
 
-	ret = q6asm_set_softpause(prtd->audio_client,
-					&softpause);
+	ret = q6asm_set_softpause(ac, &softpause);
 	if (ret < 0)
 		pr_err("%s: Send SoftPause Param failed ret=%d\n",
 			__func__, ret);
 
-	ret = q6asm_set_softvolume(prtd->audio_client, &softvol);
+	ret = q6asm_set_softvolume(ac, &softvol);
 	if (ret < 0)
 		pr_err("%s: Send SoftVolume Param failed ret=%d\n",
 			__func__, ret);
 
-	ret = q6asm_set_io_mode(prtd->audio_client,
-				(COMPRESSED_IO | ASYNC_IO_MODE));
+	ret = q6asm_set_io_mode(ac, (COMPRESSED_IO | ASYNC_IO_MODE));
 	if (ret < 0) {
 		pr_err("%s: Set IO mode failed\n", __func__);
 		return -EINVAL;
@@ -391,8 +468,7 @@
 	pr_debug("allocate %d buffers each of size %d\n",
 			runtime->fragments,
 			runtime->fragment_size);
-	ret = q6asm_audio_client_buf_alloc_contiguous(dir,
-					prtd->audio_client,
+	ret = q6asm_audio_client_buf_alloc_contiguous(dir, ac,
 					runtime->fragment_size,
 					runtime->fragments);
 	if (ret < 0) {
@@ -404,15 +480,13 @@
 	prtd->copied_total = 0;
 	prtd->app_pointer  = 0;
 	prtd->bytes_received = 0;
-	prtd->buffer       = prtd->audio_client->port[dir].buf[0].data;
-	prtd->buffer_paddr = prtd->audio_client->port[dir].buf[0].phys;
+	prtd->buffer       = ac->port[dir].buf[0].data;
+	prtd->buffer_paddr = ac->port[dir].buf[0].phys;
 	prtd->buffer_size  = runtime->fragments * runtime->fragment_size;
 
-	ret = msm_compr_send_media_format_block(cstream);
-
-	if (ret < 0) {
+	ret = msm_compr_send_media_format_block(cstream, ac->stream_id);
+	if (ret < 0)
 		pr_err("%s, failed to send media format block\n", __func__);
-	}
 
 	return ret;
 }
@@ -452,6 +526,10 @@
 	prtd->sample_rate = 44100;
 	prtd->num_channels = 2;
 	prtd->drain_ready = 0;
+	prtd->last_buffer = 0;
+	prtd->first_buffer = 1;
+	prtd->partial_drain_delay = 0;
+	memset(&prtd->gapless_state, 0, sizeof(struct msm_compr_gapless_state));
 
 	spin_lock_init(&prtd->lock);
 
@@ -459,10 +537,13 @@
 	atomic_set(&prtd->start, 0);
 	atomic_set(&prtd->drain, 0);
 	atomic_set(&prtd->xrun, 0);
+	atomic_set(&prtd->close, 0);
+	atomic_set(&prtd->wait_on_close, 0);
 
 	init_waitqueue_head(&prtd->eos_wait);
 	init_waitqueue_head(&prtd->drain_wait);
 	init_waitqueue_head(&prtd->flush_wait);
+	init_waitqueue_head(&prtd->close_wait);
 
 	runtime->private_data = prtd;
 	populate_codec_list(prtd);
@@ -488,7 +569,9 @@
 	struct snd_soc_pcm_runtime *soc_prtd = cstream->private_data;
 	struct msm_compr_pdata *pdata =
 			snd_soc_platform_get_drvdata(soc_prtd->platform);
-	int dir = IN, ret = 0;
+	struct audio_client *ac = prtd->audio_client;
+	int dir = IN, ret = 0, stream_id;
+	unsigned long flags;
 
 	pr_debug("%s\n", __func__);
 	pdata->cstream[soc_prtd->dai_link->be_id] = NULL;
@@ -511,13 +594,34 @@
 		if (!ret)
 			pr_err("%s: CMD_EOS failed\n", __func__);
 	}
+	if (atomic_read(&prtd->close)) {
+		prtd->cmd_ack = 0;
+		atomic_set(&prtd->wait_on_close, 1);
+		ret = wait_event_timeout(prtd->close_wait,
+					prtd->cmd_ack, 5 * HZ);
+		if (!ret)
+			pr_err("%s: CMD_CLOSE failed\n", __func__);
+	}
 
-	q6asm_cmd(prtd->audio_client, CMD_CLOSE);
+	spin_lock_irqsave(&prtd->lock, flags);
+	stream_id = ac->stream_id;
+	if (prtd->gapless_state.stream_opened[stream_id^1]) {
+		spin_unlock_irqrestore(&prtd->lock, flags);
+		q6asm_stream_cmd(ac, CMD_CLOSE, stream_id^1);
+		spin_lock_irqsave(&prtd->lock, flags);
+	}
+	if (prtd->gapless_state.stream_opened[stream_id]) {
+		spin_unlock_irqrestore(&prtd->lock, flags);
+		q6asm_stream_cmd(ac, CMD_CLOSE, stream_id);
+		spin_lock_irqsave(&prtd->lock, flags);
+	}
+	spin_unlock_irqrestore(&prtd->lock, flags);
 
-	q6asm_audio_client_buf_free_contiguous(dir,
-					prtd->audio_client);
+	/* client buf alloc was with stream id 0, so free with the same */
+	ac->stream_id = 0;
+	q6asm_audio_client_buf_free_contiguous(dir, ac);
 
-	q6asm_audio_client_free(prtd->audio_client);
+	q6asm_audio_client_free(ac);
 
 	kfree(prtd);
 
@@ -530,7 +634,7 @@
 {
 	struct snd_compr_runtime *runtime = cstream->runtime;
 	struct msm_compr_audio *prtd = runtime->private_data;
-	int ret = 0;
+	int ret = 0, frame_sz = 0, delay_time_ms = 0;
 
 	pr_debug("%s\n", __func__);
 
@@ -570,12 +674,14 @@
 	case SND_AUDIOCODEC_MP3: {
 		pr_debug("SND_AUDIOCODEC_MP3\n");
 		prtd->codec = FORMAT_MP3;
+		frame_sz = MP3_OUTPUT_FRAME_SZ;
 		break;
 	}
 
 	case SND_AUDIOCODEC_AAC: {
 		pr_debug("SND_AUDIOCODEC_AAC\n");
 		prtd->codec = FORMAT_MPEG4_AAC;
+		frame_sz = AAC_OUTPUT_FRAME_SZ;
 		break;
 	}
 
@@ -584,11 +690,40 @@
 		return -EINVAL;
 	}
 
+	delay_time_ms = ((DSP_NUM_OUTPUT_FRAME_BUFFERED * frame_sz * 1000) /
+			prtd->sample_rate) + DSP_PP_BUFFERING_IN_MSEC;
+	delay_time_ms = delay_time_ms > PARTIAL_DRAIN_ACK_EARLY_BY_MSEC ?
+			delay_time_ms - PARTIAL_DRAIN_ACK_EARLY_BY_MSEC : 0;
+	prtd->partial_drain_delay = delay_time_ms;
+
 	ret = msm_compr_configure_dsp(cstream);
 
 	return ret;
 }
 
+static int msm_compr_drain_buffer(struct msm_compr_audio *prtd,
+				  unsigned long *flags)
+{
+	int rc = 0;
+
+	atomic_set(&prtd->drain, 1);
+	prtd->drain_ready = 0;
+	spin_unlock_irqrestore(&prtd->lock, *flags);
+	pr_debug("%s: wait for buffer to be drained\n",  __func__);
+	rc = wait_event_interruptible(prtd->drain_wait,
+					prtd->drain_ready ||
+					prtd->cmd_interrupt ||
+					atomic_read(&prtd->xrun));
+	pr_debug("%s: out of buffer drain wait\n", __func__);
+	spin_lock_irqsave(&prtd->lock, *flags);
+	if (prtd->cmd_interrupt) {
+		pr_debug("%s: buffer drain interrupted by flush)\n", __func__);
+		rc = -EINTR;
+		prtd->cmd_interrupt = 0;
+	}
+	return rc;
+}
+
 static int msm_compr_trigger(struct snd_compr_stream *cstream, int cmd)
 {
 	struct snd_compr_runtime *runtime = cstream->runtime;
@@ -597,9 +732,11 @@
 	struct msm_compr_pdata *pdata =
 			snd_soc_platform_get_drvdata(rtd->platform);
 	uint32_t *volume = pdata->volume[rtd->dai_link->be_id];
+	struct audio_client *ac = prtd->audio_client;
 	int rc = 0;
 	int bytes_to_write;
 	unsigned long flags;
+	int stream_id;
 
 	if (cstream->direction != SND_COMPRESS_PLAYBACK) {
 		pr_err("%s: Unsupported stream type\n", __func__);
@@ -621,20 +758,37 @@
 		pr_debug("%s: SNDRV_PCM_TRIGGER_STOP\n", __func__);
 		spin_lock_irqsave(&prtd->lock, flags);
 
+		stream_id = ac->stream_id;
+		if (prtd->gapless_state.set_next_stream_id &&
+		    prtd->first_buffer) {
+			/*
+			 * Stream just switched for gapless, no buffers sent.
+			 * So seek needs to be applied to previous stream
+			 */
+			pr_debug("Seek previous stream as next stream hasn't started\n");
+			stream_id = stream_id^1;
+			ac->stream_id = stream_id;
+			prtd->first_buffer = 0;
+		}
 		atomic_set(&prtd->start, 0);
 		if (atomic_read(&prtd->eos)) {
-			pr_debug("%s: interrupt drain and eos wait queues", __func__);
+			pr_debug("%s: interrupt eos wait queues", __func__);
 			prtd->cmd_interrupt = 1;
-			prtd->drain_ready = 1;
-			wake_up(&prtd->drain_wait);
 			wake_up(&prtd->eos_wait);
 			atomic_set(&prtd->eos, 0);
 		}
-
-		pr_debug("issue CMD_FLUSH \n");
+		if (atomic_read(&prtd->drain)) {
+			pr_debug("%s: interrupt drain wait queues", __func__);
+			prtd->cmd_interrupt = 1;
+			prtd->drain_ready = 1;
+			wake_up(&prtd->drain_wait);
+			atomic_set(&prtd->drain, 0);
+		}
+		prtd->last_buffer = 0;
+		pr_debug("issue CMD_FLUSH\n");
 		prtd->cmd_ack = 0;
 		spin_unlock_irqrestore(&prtd->lock, flags);
-		rc = q6asm_cmd(prtd->audio_client, CMD_FLUSH);
+		rc = q6asm_stream_cmd(prtd->audio_client, CMD_FLUSH, stream_id);
 		if (rc < 0) {
 			pr_err("%s: flush cmd failed rc=%d\n",
 			       __func__, rc);
@@ -681,15 +835,15 @@
 			spin_unlock_irqrestore(&prtd->lock, flags);
 			break;
 		}
-		atomic_set(&prtd->eos, 1);
-
 		if (prtd->bytes_received > prtd->copied_total) {
-			atomic_set(&prtd->drain, 1);
-			prtd->drain_ready = 0;
-			spin_unlock_irqrestore(&prtd->lock, flags);
 			pr_debug("%s: wait till all the data is sent to dsp\n",
 				__func__);
-
+			rc = msm_compr_drain_buffer(prtd, &flags);
+			if (rc || !atomic_read(&prtd->start)) {
+				rc = -EINTR;
+				spin_unlock_irqrestore(&prtd->lock, flags);
+				break;
+			}
 			/*
 			 * FIXME: Bug.
 			 * Write(32767)
@@ -698,47 +852,107 @@
 			 * sol1 : if (prtd->copied_total) then wait?
 			 * sol2 : prtd->cmd_interrupt || prtd->drain_ready || atomic_read(xrun)
 			 */
-			rc = wait_event_interruptible(prtd->drain_wait,
-						      prtd->cmd_interrupt || prtd->drain_ready ||
-						      atomic_read(&prtd->xrun));
+			bytes_to_write = prtd->bytes_received - prtd->copied_total;
+			WARN(bytes_to_write > runtime->fragment_size,
+			     "last write %d cannot be > than fragment_size",
+			     bytes_to_write);
 
-			spin_lock_irqsave(&prtd->lock, flags);
-			if (!prtd->cmd_interrupt) {
-				bytes_to_write = prtd->bytes_received - prtd->copied_total;
-				WARN(bytes_to_write > runtime->fragment_size,
-				     "last write %d cannot be > than fragment_size",
-				     bytes_to_write);
-
-				if (bytes_to_write > 0) {
-					pr_debug("%s: send %d partial bytes at the end",
-					       __func__, bytes_to_write);
-					atomic_set(&prtd->xrun, 0);
-					msm_compr_send_buffer(prtd);
-				}
+			if (bytes_to_write > 0) {
+				pr_debug("%s: send %d partial bytes at the end",
+				       __func__, bytes_to_write);
+				atomic_set(&prtd->xrun, 0);
+				prtd->last_buffer = 1;
+				msm_compr_send_buffer(prtd);
 			}
 		}
 
-		if (!atomic_read(&prtd->start) || prtd->cmd_interrupt) {
-			pr_debug("%s: stream is not started (interrupted by flush?)\n", __func__);
-			rc = -EINTR;
-			prtd->cmd_interrupt = 0;
+		if ((cmd == SND_COMPR_TRIGGER_PARTIAL_DRAIN) &&
+		    (prtd->gapless_state.set_next_stream_id)) {
+			/* wait for the last buffer to be returned */
+			if (prtd->last_buffer) {
+				pr_debug("%s: last buffer drain\n", __func__);
+				rc = msm_compr_drain_buffer(prtd, &flags);
+				if (rc) {
+					spin_unlock_irqrestore(&prtd->lock, flags);
+					break;
+				}
+			}
+
+			/* send EOS */
+			prtd->cmd_ack = 0;
+			atomic_set(&prtd->eos, 1);
+			q6asm_cmd_nowait(prtd->audio_client, CMD_EOS);
+			pr_info("PARTIAL DRAIN, do not wait for EOS ack\n");
+
+			/* send a zero length buffer */
+			atomic_set(&prtd->xrun, 0);
+			msm_compr_send_buffer(prtd);
+
+			/* wait for the zero length buffer to be returned */
+			pr_debug("%s: zero length buffer drain\n", __func__);
+			rc = msm_compr_drain_buffer(prtd, &flags);
+			if (rc) {
+				spin_unlock_irqrestore(&prtd->lock, flags);
+				break;
+			}
+
+			/* sleep for additional duration partial drain */
+			atomic_set(&prtd->drain, 1);
+			prtd->drain_ready = 0;
+			pr_debug("%s, additional sleep: %d\n", __func__,
+				 prtd->partial_drain_delay);
+			spin_unlock_irqrestore(&prtd->lock, flags);
+			rc = wait_event_timeout(prtd->drain_wait,
+				prtd->drain_ready || prtd->cmd_interrupt,
+				msecs_to_jiffies(prtd->partial_drain_delay));
+			pr_debug("%s: out of additional wait for low sample rate\n",
+				 __func__);
+			spin_lock_irqsave(&prtd->lock, flags);
+			if (prtd->cmd_interrupt) {
+				pr_debug("%s: additional wait interrupted by flush)\n",
+					 __func__);
+				rc = -EINTR;
+				prtd->cmd_interrupt = 0;
+				spin_unlock_irqrestore(&prtd->lock, flags);
+				break;
+			}
+
+			/* move to next stream and reset vars */
+			pr_debug("%s: Moving to next stream in gapless\n", __func__);
+			ac->stream_id ^= 1;
+			prtd->byte_offset = 0;
+			prtd->app_pointer  = 0;
+			prtd->first_buffer = 1;
+			prtd->last_buffer = 0;
+			/*
+			Don't reset these as these vars map to
+			total_bytes_transferred and total_bytes_available
+			directly, only total_bytes_transferred will be updated
+			in the next avail() ioctl
+				prtd->copied_total = 0;
+				prtd->bytes_received = 0;
+			*/
+			atomic_set(&prtd->drain, 0);
+			atomic_set(&prtd->xrun, 1);
+			pr_debug("%s: issue CMD_RUN", __func__);
+			q6asm_run_nowait(prtd->audio_client, 0, 0, 0);
 			spin_unlock_irqrestore(&prtd->lock, flags);
 			break;
 		}
-
+		/*
+		   moving to next stream failed, so reset the gapless state
+		   set next stream id for the same session so that the same
+		   stream can be used for gapless playback
+		*/
+		prtd->gapless_state.set_next_stream_id = false;
 		pr_debug("%s: CMD_EOS\n", __func__);
 
 		prtd->cmd_ack = 0;
+		atomic_set(&prtd->eos, 1);
 		q6asm_cmd_nowait(prtd->audio_client, CMD_EOS);
 
 		spin_unlock_irqrestore(&prtd->lock, flags);
 
-/*
-		if (cmd == SND_COMPR_TRIGGER_PARTIAL_DRAIN) {
-			pr_err("PARTIAL DRAIN, do not wait for EOS ack");
-			break;
-		}
-*/
 
 		/* Wait indefinitely for  DRAIN. Flush can also signal this*/
 		rc = wait_event_interruptible(prtd->eos_wait,
@@ -754,6 +968,10 @@
 
 		/*FIXME : what if a flush comes while PC is here */
 		if (rc == 0 && (cmd == SND_COMPR_TRIGGER_PARTIAL_DRAIN)) {
+			/*
+			 * Failed to open second stream in DSP for gapless
+			 * so prepare the current stream in session for gapless playback
+			 */
 			spin_lock_irqsave(&prtd->lock, flags);
 			pr_debug("%s: issue CMD_PAUSE ", __func__);
 			q6asm_cmd_nowait(prtd->audio_client, CMD_PAUSE);
@@ -765,27 +983,55 @@
 					   prtd->cmd_ack, 1 * HZ / 4);
 
 			spin_lock_irqsave(&prtd->lock, flags);
+			/*
+			Don't reset these as these vars map to
+			total_bytes_transferred and total_bytes_available
+			directly, only total_bytes_transferred will be updated
+			in the next avail() ioctl
+			prtd->copied_total = 0;
+			prtd->bytes_received = 0;
+			*/
 			prtd->byte_offset = 0;
 			prtd->app_pointer  = 0;
-			/* Don't reset these as these vars map
-			   to total_bytes_transferred and total_bytes_available directly,
-			   only total_bytes_transferred will be updated in the next avail()
-			   ioctl
-			   prtd->copied_total = 0;
-			   prtd->bytes_received = 0;
-			*/
+			prtd->first_buffer = 1;
+			prtd->last_buffer = 0;
 			atomic_set(&prtd->drain, 0);
 			atomic_set(&prtd->xrun, 1);
-			pr_debug("%s: issue CMD_RESUME", __func__);
 			q6asm_run_nowait(prtd->audio_client, 0, 0, 0);
 			spin_unlock_irqrestore(&prtd->lock, flags);
 		}
-		pr_debug("%s: out of drain", __func__);
-
 		prtd->cmd_interrupt = 0;
 		break;
 	case SND_COMPR_TRIGGER_NEXT_TRACK:
 		pr_debug("%s: SND_COMPR_TRIGGER_NEXT_TRACK\n", __func__);
+		spin_lock_irqsave(&prtd->lock, flags);
+		rc = 0;
+		stream_id = ac->stream_id^1; /*next stream in gapless*/
+		if (prtd->gapless_state.stream_opened[stream_id]) {
+			pr_debug("next session is already in opened state\n");
+			spin_unlock_irqrestore(&prtd->lock, flags);
+			break;
+		}
+		spin_unlock_irqrestore(&prtd->lock, flags);
+		rc = q6asm_stream_open_write_v2(prtd->audio_client,
+						prtd->codec, 16,
+						stream_id,
+						true /*gapless*/);
+		if (rc < 0) {
+			pr_err("%s: Session out open failed for gapless\n",
+				 __func__);
+			break;
+		}
+		rc = msm_compr_send_media_format_block(cstream, stream_id);
+		if (rc < 0) {
+			 pr_err("%s, failed to send media format block\n",
+				__func__);
+			break;
+		}
+		spin_lock_irqsave(&prtd->lock, flags);
+		prtd->gapless_state.stream_opened[stream_id] = 1;
+		prtd->gapless_state.set_next_stream_id = true;
+		spin_unlock_irqrestore(&prtd->lock, flags);
 		break;
 	}
 
@@ -799,7 +1045,7 @@
 	struct msm_compr_audio *prtd = runtime->private_data;
 	struct snd_compr_tstamp tstamp;
 	uint64_t timestamp = 0;
-	int rc = 0;
+	int rc = 0, first_buffer;
 	unsigned long flags;
 
 	pr_debug("%s\n", __func__);
@@ -809,13 +1055,14 @@
 	tstamp.sampling_rate = prtd->sample_rate;
 	tstamp.byte_offset = prtd->byte_offset;
 	tstamp.copied_total = prtd->copied_total;
+	first_buffer = prtd->first_buffer;
 	spin_unlock_irqrestore(&prtd->lock, flags);
 
 	/*
 	 Query timestamp from DSP if some data is with it.
 	 This prevents timeouts.
 	*/
-	if (prtd->copied_total) {
+	if (!first_buffer) {
 		rc = q6asm_get_session_time(prtd->audio_client, &timestamp);
 		if (rc < 0) {
 			pr_err("%s: Get Session Time return value =%lld\n",
@@ -991,15 +1238,24 @@
 static int msm_compr_set_metadata(struct snd_compr_stream *cstream,
 				struct snd_compr_metadata *metadata)
 {
+	struct msm_compr_audio *prtd;
+	struct audio_client *ac;
 	pr_debug("%s\n", __func__);
 
 	if (!metadata || !cstream)
 		return -EINVAL;
 
+	prtd = cstream->runtime->private_data;
+	if (!prtd && !prtd->audio_client)
+		return -EINVAL;
+
+	ac = prtd->audio_client;
 	if (metadata->key == SNDRV_COMPRESS_ENCODER_PADDING) {
 		pr_debug("%s, got encoder padding %u", __func__, metadata->value[0]);
+		prtd->gapless_state.trailing_samples_drop = metadata->value[0];
 	} else if (metadata->key == SNDRV_COMPRESS_ENCODER_DELAY) {
 		pr_debug("%s, got encoder delay %u", __func__, metadata->value[0]);
+		prtd->gapless_state.initial_samples_drop = metadata->value[0];
 	}
 
 	return 0;
diff --git a/sound/soc/msm/qdsp6v2/msm-pcm-afe-v2.c b/sound/soc/msm/qdsp6v2/msm-pcm-afe-v2.c
index d80ca19..0612805 100644
--- a/sound/soc/msm/qdsp6v2/msm-pcm-afe-v2.c
+++ b/sound/soc/msm/qdsp6v2/msm-pcm-afe-v2.c
@@ -40,8 +40,8 @@
 
 #define MIN_CAPTURE_PERIOD_SIZE (128 * 2 * 4)
 #define MAX_CAPTURE_PERIOD_SIZE (128 * 2 * 2 * 6 * 4)
-#define MIN_CAPTURE_NUM_PERIODS (32)
-#define MAX_CAPTURE_NUM_PERIODS (384)
+#define MIN_CAPTURE_NUM_PERIODS (32 * 4)
+#define MAX_CAPTURE_NUM_PERIODS (384 * 4)
 
 static struct snd_pcm_hardware msm_afe_hardware_playback = {
 	.info =                 (SNDRV_PCM_INFO_MMAP |
diff --git a/sound/soc/msm/qdsp6v2/msm-pcm-voip-v2.c b/sound/soc/msm/qdsp6v2/msm-pcm-voip-v2.c
index af25454..97c7b5d 100644
--- a/sound/soc/msm/qdsp6v2/msm-pcm-voip-v2.c
+++ b/sound/soc/msm/qdsp6v2/msm-pcm-voip-v2.c
@@ -48,6 +48,9 @@
 #define MODE_PCM		0xC
 #define MODE_4GV_NW		0xE
 
+#define VOIP_MODE_MAX		MODE_4GV_NW
+#define VOIP_RATE_MAX		23850
+
 enum format {
 	FORMAT_S16_LE = 2,
 	FORMAT_SPECIAL = 31,
@@ -153,10 +156,14 @@
 				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_mode_config_put(struct snd_kcontrol *kcontrol,
+				    struct snd_ctl_elem_value *ucontrol);
+static int msm_voip_mode_config_get(struct snd_kcontrol *kcontrol,
+				    struct snd_ctl_elem_value *ucontrol);
+static int msm_voip_rate_config_put(struct snd_kcontrol *kcontrol,
+				    struct snd_ctl_elem_value *ucontrol);
+static int msm_voip_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,
@@ -267,11 +274,12 @@
 	SOC_SINGLE_MULTI_EXT("Voip Rx Gain", SND_SOC_NOPM, 0,
 			     MAX_RAMP_DURATION,
 			     0, 2, NULL, msm_voip_gain_put),
-	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_EXT("Voip Mode Config", SND_SOC_NOPM, 0, VOIP_MODE_MAX, 0,
+		       msm_voip_mode_config_get, msm_voip_mode_config_put),
+	SOC_SINGLE_EXT("Voip Rate Config", SND_SOC_NOPM, 0, VOIP_RATE_MAX, 0,
+		       msm_voip_rate_config_get, msm_voip_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,
+			     0, VOC_1_RATE, 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),
@@ -439,6 +447,8 @@
 			list_add_tail(&buf_node->list, &prtd->free_in_queue);
 		}
 		}
+		pr_debug("%s: frame.pktlen=%d\n", __func__, buf_node->frame.pktlen);
+
 		prtd->pcm_playback_irq_pos += prtd->pcm_count;
 		spin_unlock_irqrestore(&prtd->dsp_lock, dsp_flags);
 		snd_pcm_period_elapsed(prtd->playback_substream);
@@ -800,26 +810,20 @@
 	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) ||
+        pr_debug("%s(): mode=%d, playback sample rate=%d, capture sample rate=%d\n",
+                  __func__, prtd->mode, prtd->play_samp_rate, prtd->cap_samp_rate);
+
+	if ((runtime->format != FORMAT_S16_LE) && ((prtd->mode == MODE_PCM) ||
+	    (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",
+		pr_err("%s(): mode:%d and format:%u are not matched\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);
@@ -1057,29 +1061,52 @@
 	return 0;
 }
 
-static int msm_voip_mode_rate_config_get(struct snd_kcontrol *kcontrol,
-					struct snd_ctl_elem_value *ucontrol)
+static int msm_voip_mode_config_get(struct snd_kcontrol *kcontrol,
+				    struct snd_ctl_elem_value *ucontrol)
 {
 	mutex_lock(&voip_info.lock);
 
 	ucontrol->value.integer.value[0] = voip_info.mode;
-	ucontrol->value.integer.value[1] = voip_info.rate;
 
 	mutex_unlock(&voip_info.lock);
 
 	return 0;
 }
 
-static int msm_voip_mode_rate_config_put(struct snd_kcontrol *kcontrol,
-					struct snd_ctl_elem_value *ucontrol)
+static int msm_voip_mode_config_put(struct snd_kcontrol *kcontrol,
+				    struct snd_ctl_elem_value *ucontrol)
 {
 	mutex_lock(&voip_info.lock);
 
 	voip_info.mode = ucontrol->value.integer.value[0];
-	voip_info.rate = ucontrol->value.integer.value[1];
 
-	pr_debug("%s: mode=%d,rate=%d\n", __func__, voip_info.mode,
-		voip_info.rate);
+	pr_debug("%s: mode=%d\n", __func__, voip_info.mode);
+
+	mutex_unlock(&voip_info.lock);
+
+	return 0;
+}
+
+static int msm_voip_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.rate;
+
+	mutex_unlock(&voip_info.lock);
+
+	return 0;
+}
+
+static int msm_voip_rate_config_put(struct snd_kcontrol *kcontrol,
+				    struct snd_ctl_elem_value *ucontrol)
+{
+	mutex_lock(&voip_info.lock);
+
+	voip_info.rate = ucontrol->value.integer.value[0];
+
+	pr_debug("%s: rate=%d\n", __func__, voip_info.rate);
 
 	mutex_unlock(&voip_info.lock);
 
diff --git a/sound/soc/msm/qdsp6v2/q6asm.c b/sound/soc/msm/qdsp6v2/q6asm.c
index 3785a3e..3ae5221 100644
--- a/sound/soc/msm/qdsp6v2/q6asm.c
+++ b/sound/soc/msm/qdsp6v2/q6asm.c
@@ -811,6 +811,10 @@
 				(apr_fn)q6asm_callback,\
 				((ac->session) << 8 | 0x0001),\
 				ac);
+	ac->apr2 = apr_register("ADSP", "ASM", \
+				(apr_fn)q6asm_callback,\
+				((ac->session) << 8 | 0x0002),\
+				ac);
 
 	if (ac->apr == NULL) {
 		pr_err("%s Registration with APR failed\n", __func__);
@@ -1210,7 +1214,8 @@
 		data->token, data->payload_size, data->src_port,
 		data->dest_port);
 	if ((data->opcode != ASM_DATA_EVENT_RENDERED_EOS) &&
-			(data->opcode != ASM_DATA_EVENT_EOS))
+	    (data->opcode != ASM_DATA_EVENT_EOS) &&
+	    (data->opcode != ASM_SESSION_EVENT_RX_UNDERFLOW))
 		pr_debug("%s:Payload = [0x%x] status[0x%x]\n",
 			__func__, payload[0], payload[1]);
 	if (data->opcode == APR_BASIC_RSP_RESULT) {
@@ -1225,6 +1230,7 @@
 					data->payload_size))
 				break;
 		case ASM_SESSION_CMD_PAUSE:
+		case ASM_SESSION_CMD_SUSPEND:
 		case ASM_DATA_CMD_EOS:
 		case ASM_STREAM_CMD_CLOSE:
 		case ASM_STREAM_CMD_FLUSH:
@@ -1243,6 +1249,9 @@
 		case ASM_DATA_CMD_MEDIA_FMT_UPDATE_V2:
 		case ASM_STREAM_CMD_SET_ENCDEC_PARAM:
 		case ASM_CMD_ADD_TOPOLOGIES:
+		case ASM_DATA_CMD_REMOVE_INITIAL_SILENCE:
+		case ASM_DATA_CMD_REMOVE_TRAILING_SILENCE:
+		case ASM_SESSION_CMD_REGISTER_FOR_RX_UNDERFLOW_EVENTS:
 		pr_debug("%s:Payload = [0x%x]stat[0x%x]\n",
 				__func__, payload[0], payload[1]);
 			if (atomic_read(&ac->cmd_state) && wakeup_flag) {
@@ -1366,7 +1375,10 @@
 				  __func__, data->opcode);
 		break;
 	case ASM_SESSION_EVENTX_OVERFLOW:
-		pr_err("ASM_SESSION_EVENTX_OVERFLOW\n");
+		pr_debug("ASM_SESSION_EVENTX_OVERFLOW\n");
+		break;
+	case ASM_SESSION_EVENT_RX_UNDERFLOW:
+		pr_debug("ASM_SESSION_EVENT_RX_UNDERFLOW\n");
 		break;
 	case ASM_SESSION_CMDRSP_GET_SESSIONTIME_V3:
 		pr_debug("%s: ASM_SESSION_CMDRSP_GET_SESSIONTIME_V3, payload[0] = %d, payload[1] = %d, payload[2] = %d\n",
@@ -1518,11 +1530,11 @@
 	return ret;
 }
 
-static void q6asm_add_hdr(struct audio_client *ac, struct apr_hdr *hdr,
-			uint32_t pkt_size, uint32_t cmd_flg)
+static void __q6asm_add_hdr(struct audio_client *ac, struct apr_hdr *hdr,
+			uint32_t pkt_size, uint32_t cmd_flg, uint32_t stream_id)
 {
-	pr_debug("%s:pkt_size=%d cmd_flg=%d session=%d\n", __func__, pkt_size,
-		cmd_flg, ac->session);
+	pr_debug("%s:pkt_size=%d cmd_flg=%d session=%d stream_id=%d\n",
+		 __func__, pkt_size, cmd_flg, ac->session, stream_id);
 	if (ac->apr == NULL) {
 		pr_err("%s: ac->apr is NULL", __func__);
 		return;
@@ -1536,8 +1548,8 @@
 	hdr->src_domain = APR_DOMAIN_APPS;
 	hdr->dest_svc = APR_SVC_ASM;
 	hdr->dest_domain = APR_DOMAIN_ADSP;
-	hdr->src_port = ((ac->session << 8) & 0xFF00) | 0x01;
-	hdr->dest_port = ((ac->session << 8) & 0xFF00) | 0x01;
+	hdr->src_port = ((ac->session << 8) & 0xFF00) | (stream_id+1);
+	hdr->dest_port = ((ac->session << 8) & 0xFF00) | (stream_id+1);
 	if (cmd_flg) {
 		hdr->token = ac->session;
 		atomic_set(&ac->cmd_state, 1);
@@ -1547,11 +1559,25 @@
 	return;
 }
 
-static void q6asm_add_hdr_async(struct audio_client *ac, struct apr_hdr *hdr,
+static void q6asm_add_hdr(struct audio_client *ac, struct apr_hdr *hdr,
 			uint32_t pkt_size, uint32_t cmd_flg)
 {
-	pr_debug("pkt_size = %d, cmd_flg = %d, session = %d\n",
-			pkt_size, cmd_flg, ac->session);
+	__q6asm_add_hdr(ac, hdr, pkt_size, cmd_flg, ac->stream_id);
+	return;
+}
+
+static void q6asm_stream_add_hdr(struct audio_client *ac, struct apr_hdr *hdr,
+			uint32_t pkt_size, uint32_t cmd_flg, int32_t stream_id)
+{
+	__q6asm_add_hdr(ac, hdr, pkt_size, cmd_flg, stream_id);
+	return;
+}
+
+static void __q6asm_add_hdr_async(struct audio_client *ac, struct apr_hdr *hdr,
+			uint32_t pkt_size, uint32_t cmd_flg, uint32_t stream_id)
+{
+	pr_debug("%s pkt_size = %d, cmd_flg = %d, session = %d stream_id=%d\n",
+		__func__, pkt_size, cmd_flg, ac->session, stream_id);
 	hdr->hdr_field = APR_HDR_FIELD(APR_MSG_TYPE_SEQ_CMD, \
 				APR_HDR_LEN(sizeof(struct apr_hdr)),\
 				APR_PKT_VER);
@@ -1563,8 +1589,8 @@
 	hdr->src_domain = APR_DOMAIN_APPS;
 	hdr->dest_svc = APR_SVC_ASM;
 	hdr->dest_domain = APR_DOMAIN_ADSP;
-	hdr->src_port = ((ac->session << 8) & 0xFF00) | 0x01;
-	hdr->dest_port = ((ac->session << 8) & 0xFF00) | 0x01;
+	hdr->src_port = ((ac->session << 8) & 0xFF00) | (stream_id+1);
+	hdr->dest_port = ((ac->session << 8) & 0xFF00) | (stream_id+1);
 	if (cmd_flg) {
 		hdr->token = ac->session;
 		atomic_set(&ac->cmd_state, 1);
@@ -1573,6 +1599,21 @@
 	return;
 }
 
+static void q6asm_add_hdr_async(struct audio_client *ac, struct apr_hdr *hdr,
+				uint32_t pkt_size, uint32_t cmd_flg)
+{
+	__q6asm_add_hdr_async(ac, hdr, pkt_size, cmd_flg, ac->stream_id);
+	return;
+}
+
+static void q6asm_stream_add_hdr_async(struct audio_client *ac,
+					struct apr_hdr *hdr, uint32_t pkt_size,
+					uint32_t cmd_flg, int32_t stream_id)
+{
+	__q6asm_add_hdr_async(ac, hdr, pkt_size, cmd_flg, stream_id);
+	return;
+}
+
 static void q6asm_add_mmaphdr(struct audio_client *ac, struct apr_hdr *hdr,
 			u32 pkt_size, u32 cmd_flg, u32 token)
 {
@@ -1681,7 +1722,8 @@
 }
 
 static int __q6asm_open_write(struct audio_client *ac, uint32_t format,
-		uint16_t bits_per_sample)
+				uint16_t bits_per_sample, uint32_t stream_id,
+				bool is_gapless_mode)
 {
 	int rc = 0x00;
 	struct asm_stream_cmd_open_write_v3 open;
@@ -1693,14 +1735,17 @@
 	pr_debug("%s: session[%d] wr_format[0x%x]", __func__, ac->session,
 		format);
 
-	q6asm_add_hdr(ac, &open.hdr, sizeof(open), TRUE);
+	q6asm_stream_add_hdr(ac, &open.hdr, sizeof(open), TRUE, stream_id);
 
 	open.hdr.opcode = ASM_STREAM_CMD_OPEN_WRITE_V3;
 	open.mode_flags = 0x00;
 	if (ac->perf_mode)
 		open.mode_flags |= ASM_ULTRA_LOW_LATENCY_STREAM_SESSION;
-	else
+	else {
 		open.mode_flags |= ASM_LEGACY_STREAM_SESSION;
+		if (is_gapless_mode)
+			open.mode_flags |= 1 << ASM_SHIFT_GAPLESS_MODE_FLAG;
+	}
 
 	/* source endpoint : matrix */
 	open.sink_endpointype = ASM_END_POINT_DEVICE_MATRIX;
@@ -1759,13 +1804,23 @@
 
 int q6asm_open_write(struct audio_client *ac, uint32_t format)
 {
-	return __q6asm_open_write(ac, format, 16);
+	return __q6asm_open_write(ac, format, 16, ac->stream_id,
+					 false /*gapless*/);
 }
 
 int q6asm_open_write_v2(struct audio_client *ac, uint32_t format,
 		uint16_t bits_per_sample)
 {
-	return __q6asm_open_write(ac, format, bits_per_sample);
+	return __q6asm_open_write(ac, format, bits_per_sample,
+					 ac->stream_id, false /*gapless*/);
+}
+
+int q6asm_stream_open_write_v2(struct audio_client *ac, uint32_t format,
+				uint16_t bits_per_sample, int32_t stream_id,
+				bool is_gapless_mode)
+{
+	return __q6asm_open_write(ac, format, bits_per_sample,
+					 stream_id, is_gapless_mode);
 }
 
 int q6asm_open_read_write(struct audio_client *ac,
@@ -1919,8 +1974,8 @@
 	return -EINVAL;
 }
 
-int q6asm_run_nowait(struct audio_client *ac, uint32_t flags,
-		uint32_t msw_ts, uint32_t lsw_ts)
+static int __q6asm_run_nowait(struct audio_client *ac, uint32_t flags,
+		uint32_t msw_ts, uint32_t lsw_ts, uint32_t stream_id)
 {
 	struct asm_session_cmd_run_v2 run;
 	int rc;
@@ -1929,7 +1984,7 @@
 		return -EINVAL;
 	}
 	pr_debug("session[%d]", ac->session);
-	q6asm_add_hdr_async(ac, &run.hdr, sizeof(run), TRUE);
+	q6asm_stream_add_hdr_async(ac, &run.hdr, sizeof(run), TRUE, stream_id);
 
 	run.hdr.opcode = ASM_SESSION_CMD_RUN_V2;
 	run.flags    = flags;
@@ -1947,6 +2002,17 @@
 	return 0;
 }
 
+int q6asm_run_nowait(struct audio_client *ac, uint32_t flags,
+			uint32_t msw_ts, uint32_t lsw_ts)
+{
+	return __q6asm_run_nowait(ac, flags, msw_ts, lsw_ts, ac->stream_id);
+}
+
+int q6asm_stream_run_nowait(struct audio_client *ac, uint32_t flags,
+			uint32_t msw_ts, uint32_t lsw_ts, uint32_t stream_id)
+{
+	return __q6asm_run_nowait(ac, flags, msw_ts, lsw_ts, stream_id);
+}
 
 int q6asm_enc_cfg_blk_aac(struct audio_client *ac,
 			 uint32_t frames_per_buf,
@@ -2439,12 +2505,6 @@
 }
 
 
-int q6asm_media_format_block_aac(struct audio_client *ac,
-			struct asm_aac_cfg *cfg)
-{
-	return q6asm_media_format_block_multi_aac(ac, cfg);
-}
-
 static int __q6asm_media_format_block_pcm(struct audio_client *ac,
 				uint32_t rate, uint32_t channels,
 				uint16_t bits_per_sample)
@@ -2575,8 +2635,8 @@
 			bits_per_sample);
 }
 
-int q6asm_media_format_block_multi_aac(struct audio_client *ac,
-				struct asm_aac_cfg *cfg)
+static int __q6asm_media_format_block_multi_aac(struct audio_client *ac,
+				struct asm_aac_cfg *cfg, int stream_id)
 {
 	struct asm_aac_fmt_blk_v2 fmt;
 	int rc = 0;
@@ -2584,7 +2644,7 @@
 	pr_debug("%s:session[%d]rate[%d]ch[%d]\n", __func__, ac->session,
 		cfg->sample_rate, cfg->ch_cfg);
 
-	q6asm_add_hdr(ac, &fmt.hdr, sizeof(fmt), TRUE);
+	q6asm_stream_add_hdr(ac, &fmt.hdr, sizeof(fmt), TRUE, stream_id);
 
 	fmt.hdr.opcode = ASM_DATA_CMD_MEDIA_FMT_UPDATE_V2;
 	fmt.fmt_blk.fmt_blk_size = sizeof(fmt) - sizeof(fmt.hdr) -
@@ -2618,6 +2678,24 @@
 	return -EINVAL;
 }
 
+int q6asm_media_format_block_multi_aac(struct audio_client *ac,
+				struct asm_aac_cfg *cfg)
+{
+	return __q6asm_media_format_block_multi_aac(ac, cfg, ac->stream_id);
+}
+
+int q6asm_media_format_block_aac(struct audio_client *ac,
+			struct asm_aac_cfg *cfg)
+{
+	return __q6asm_media_format_block_multi_aac(ac, cfg, ac->stream_id);
+}
+
+int q6asm_stream_media_format_block_aac(struct audio_client *ac,
+			struct asm_aac_cfg *cfg, int stream_id)
+{
+	return __q6asm_media_format_block_multi_aac(ac, cfg, stream_id);
+}
+
 int q6asm_media_format_block_wma(struct audio_client *ac,
 				void *cfg)
 {
@@ -3602,7 +3680,7 @@
 		write.flags = (0x00000000 | (param->flags & 0x800000FF));
 	else
 		write.flags = (0x80000000 | param->flags);
-
+	write.flags |= param->last_buffer << ASM_SHIFT_LAST_BUFFER_FLAG;
 	write.seq_id = param->uid;
 	list_for_each_safe(ptr, next, &ac->port[IN].mem_map_handle) {
 		buf_node = list_entry(ptr, struct asm_buffer_node,
@@ -3852,7 +3930,7 @@
 	return -EINVAL;
 }
 
-int q6asm_cmd(struct audio_client *ac, int cmd)
+static int __q6asm_cmd(struct audio_client *ac, int cmd, uint32_t stream_id)
 {
 	struct apr_hdr hdr;
 	int rc;
@@ -3863,13 +3941,18 @@
 		pr_err("APR handle NULL\n");
 		return -EINVAL;
 	}
-	q6asm_add_hdr(ac, &hdr, sizeof(hdr), TRUE);
+	q6asm_stream_add_hdr(ac, &hdr, sizeof(hdr), TRUE, stream_id);
 	switch (cmd) {
 	case CMD_PAUSE:
 		pr_debug("%s:CMD_PAUSE\n", __func__);
 		hdr.opcode = ASM_SESSION_CMD_PAUSE;
 		state = &ac->cmd_state;
 		break;
+	case CMD_SUSPEND:
+		pr_debug("%s:CMD_SUSPEND\n", __func__);
+		hdr.opcode = ASM_SESSION_CMD_SUSPEND;
+		state = &ac->cmd_state;
+		break;
 	case CMD_FLUSH:
 		pr_debug("%s:CMD_FLUSH\n", __func__);
 		hdr.opcode = ASM_STREAM_CMD_FLUSH;
@@ -3936,7 +4019,18 @@
 	return -EINVAL;
 }
 
-int q6asm_cmd_nowait(struct audio_client *ac, int cmd)
+int q6asm_cmd(struct audio_client *ac, int cmd)
+{
+	return __q6asm_cmd(ac, cmd, ac->stream_id);
+}
+
+int q6asm_stream_cmd(struct audio_client *ac, int cmd, uint32_t stream_id)
+{
+	return __q6asm_cmd(ac, cmd, stream_id);
+}
+
+static int __q6asm_cmd_nowait(struct audio_client *ac, int cmd,
+			      uint32_t stream_id)
 {
 	struct apr_hdr hdr;
 	int rc;
@@ -3945,7 +4039,7 @@
 		pr_err("%s:APR handle NULL\n", __func__);
 		return -EINVAL;
 	}
-	q6asm_add_hdr_async(ac, &hdr, sizeof(hdr), TRUE);
+	q6asm_stream_add_hdr_async(ac, &hdr, sizeof(hdr), TRUE, stream_id);
 	switch (cmd) {
 	case CMD_PAUSE:
 		pr_debug("%s:CMD_PAUSE\n", __func__);
@@ -3955,6 +4049,10 @@
 		pr_debug("%s:CMD_EOS\n", __func__);
 		hdr.opcode = ASM_DATA_CMD_EOS;
 		break;
+	case CMD_CLOSE:
+		pr_debug("%s:CMD_CLOSE\n", __func__);
+		hdr.opcode = ASM_STREAM_CMD_CLOSE;
+		break;
 	default:
 		pr_err("%s:Invalid format[%d]\n", __func__, cmd);
 		goto fail_cmd;
@@ -3975,6 +4073,54 @@
 	return -EINVAL;
 }
 
+int q6asm_cmd_nowait(struct audio_client *ac, int cmd)
+{
+	pr_debug("%s: stream_id: %d\n", __func__, ac->stream_id);
+	return __q6asm_cmd_nowait(ac, cmd, ac->stream_id);
+}
+
+int q6asm_stream_cmd_nowait(struct audio_client *ac, int cmd,
+			    uint32_t stream_id)
+{
+	pr_debug("%s: stream_id: %d\n", __func__, stream_id);
+	return __q6asm_cmd_nowait(ac, cmd, stream_id);
+}
+
+int q6asm_send_meta_data(struct audio_client *ac, uint32_t initial_samples,
+		uint32_t trailing_samples)
+{
+	struct asm_data_cmd_remove_silence silence;
+	int rc = 0;
+	if (!ac || ac->apr == NULL) {
+		pr_err("APR handle NULL\n");
+		return -EINVAL;
+	}
+	pr_debug("%s session[%d]", __func__, ac->session);
+	q6asm_add_hdr_async(ac, &silence.hdr, sizeof(silence), FALSE);
+
+	silence.hdr.opcode = ASM_DATA_CMD_REMOVE_INITIAL_SILENCE;
+	silence.num_samples_to_remove    = initial_samples;
+
+	rc = apr_send_pkt(ac->apr, (uint32_t *) &silence);
+	if (rc < 0) {
+		pr_err("Commmand silence failed[%d]", rc);
+		goto fail_cmd;
+	}
+
+	silence.hdr.opcode = ASM_DATA_CMD_REMOVE_TRAILING_SILENCE;
+	silence.num_samples_to_remove    = trailing_samples;
+
+	rc = apr_send_pkt(ac->apr, (uint32_t *) &silence);
+	if (rc < 0) {
+		pr_err("Commmand silence failed[%d]", rc);
+		goto fail_cmd;
+	}
+
+	return 0;
+fail_cmd:
+	return -EINVAL;
+}
+
 static void q6asm_reset_buf_state(struct audio_client *ac)
 {
 	int cnt = 0;
@@ -4034,6 +4180,35 @@
 	return -EINVAL;
 }
 
+int q6asm_reg_rx_underflow(struct audio_client *ac, uint16_t enable)
+{
+	struct asm_session_cmd_rgstr_rx_underflow rx_underflow;
+	int rc;
+
+	if (!ac || ac->apr == NULL) {
+		pr_err("APR handle NULL\n");
+		return -EINVAL;
+	}
+	pr_debug("%s:session[%d]enable[%d]\n", __func__,
+						ac->session, enable);
+	q6asm_add_hdr_async(ac, &rx_underflow.hdr, sizeof(rx_underflow), FALSE);
+
+	rx_underflow.hdr.opcode = \
+			ASM_SESSION_CMD_REGISTER_FOR_RX_UNDERFLOW_EVENTS;
+	/* tx overflow event: enable */
+	rx_underflow.enable_flag = enable;
+
+	rc = apr_send_pkt(ac->apr, (uint32_t *) &rx_underflow);
+	if (rc < 0) {
+		pr_err("tx overflow op[0x%x]rc[%d]\n", \
+						rx_underflow.hdr.opcode, rc);
+		goto fail_cmd;
+	}
+	return 0;
+fail_cmd:
+	return -EINVAL;
+}
+
 int q6asm_get_apr_service_id(int session_id)
 {
 	pr_debug("%s\n", __func__);
diff --git a/sound/soc/soc-core.c b/sound/soc/soc-core.c
index 2cb3576..021d731 100644
--- a/sound/soc/soc-core.c
+++ b/sound/soc/soc-core.c
@@ -3240,7 +3240,7 @@
 	mutex_init(&card->mutex);
 	mutex_init(&card->dpcm_mutex);
 	mutex_init(&card->dapm_power_mutex);
-
+	mutex_init(&card->dapm_mutex);
 	ret = snd_soc_instantiate_card(card);
 	if (ret != 0) {
 		soc_cleanup_card_debugfs(card);
diff --git a/sound/soc/soc-dapm.c b/sound/soc/soc-dapm.c
index 99047178..bc3f6a7 100644
--- a/sound/soc/soc-dapm.c
+++ b/sound/soc/soc-dapm.c
@@ -1866,7 +1866,7 @@
 #endif
 
 /* test and update the power status of a mux widget */
-int snd_soc_dapm_mux_update_power(struct snd_soc_dapm_widget *widget,
+static int soc_dapm_mux_update_power(struct snd_soc_dapm_widget *widget,
 				 struct snd_kcontrol *kcontrol, int change,
 				 int mux, struct soc_enum *e)
 {
@@ -1915,10 +1915,22 @@
 
 	return 0;
 }
+
+int snd_soc_dapm_mux_update_power(struct snd_soc_dapm_widget *widget,
+				 struct snd_kcontrol *kcontrol, int change,
+				 int mux, struct soc_enum *e)
+{
+	struct snd_soc_card *card = widget->dapm->card;
+	int ret;
+	mutex_lock_nested(&card->dapm_mutex, SND_SOC_DAPM_CLASS_RUNTIME);
+	ret = soc_dapm_mux_update_power(widget, kcontrol, change, mux, e);
+	mutex_unlock(&card->dapm_mutex);
+	return ret;
+}
 EXPORT_SYMBOL_GPL(snd_soc_dapm_mux_update_power);
 
 /* test and update the power status of a mixer or switch widget */
-int snd_soc_dapm_mixer_update_power(struct snd_soc_dapm_widget *widget,
+static int soc_dapm_mixer_update_power(struct snd_soc_dapm_widget *widget,
 				   struct snd_kcontrol *kcontrol, int connect)
 {
 	struct snd_soc_dapm_path *path;
@@ -1952,6 +1964,17 @@
 
 	return 0;
 }
+
+int snd_soc_dapm_mixer_update_power(struct snd_soc_dapm_widget *widget,
+				   struct snd_kcontrol *kcontrol, int connect)
+{
+	struct snd_soc_card *card = widget->dapm->card;
+	int ret;
+	mutex_lock_nested(&card->dapm_mutex, SND_SOC_DAPM_CLASS_RUNTIME);
+	ret = soc_dapm_mixer_update_power(widget, kcontrol, connect);
+	mutex_unlock(&card->dapm_mutex);
+	return ret;
+}
 EXPORT_SYMBOL_GPL(snd_soc_dapm_mixer_update_power);
 
 /* show dapm widget status in sys fs */
@@ -2108,6 +2131,8 @@
  */
 int snd_soc_dapm_sync(struct snd_soc_dapm_context *dapm)
 {
+	int ret;
+
 	/*
 	 * Suppress early reports (eg, jacks syncing their state) to avoid
 	 * silly DAPM runs during card startup.
@@ -2115,7 +2140,10 @@
 	if (!dapm->card || !dapm->card->instantiated)
 		return 0;
 
-	return dapm_power_widgets(dapm, SND_SOC_DAPM_STREAM_NOP);
+	mutex_lock_nested(&dapm->card->dapm_mutex, SND_SOC_DAPM_CLASS_PCM);
+	ret = dapm_power_widgets(dapm, SND_SOC_DAPM_STREAM_NOP);
+	mutex_unlock(&dapm->card->dapm_mutex);
+	return ret;
 }
 EXPORT_SYMBOL_GPL(snd_soc_dapm_sync);
 
@@ -2279,6 +2307,7 @@
 {
 	int i, ret;
 
+	mutex_lock_nested(&dapm->card->dapm_mutex, SND_SOC_DAPM_CLASS_INIT);
 	for (i = 0; i < num; i++) {
 		ret = snd_soc_dapm_add_route(dapm, route);
 		if (ret < 0) {
@@ -2288,6 +2317,7 @@
 		}
 		route++;
 	}
+	mutex_unlock(&dapm->card->dapm_mutex);
 
 	return 0;
 }
@@ -2360,12 +2390,14 @@
 	int i, err;
 	int ret = 0;
 
+	mutex_lock_nested(&dapm->card->dapm_mutex, SND_SOC_DAPM_CLASS_INIT);
 	for (i = 0; i < num; i++) {
 		err = snd_soc_dapm_weak_route(dapm, route);
 		if (err)
 			ret = err;
 		route++;
 	}
+	mutex_unlock(&dapm->card->dapm_mutex);
 
 	return ret;
 }
@@ -2384,6 +2416,8 @@
 	struct snd_soc_dapm_widget *w;
 	unsigned int val;
 
+	mutex_lock_nested(&dapm->card->dapm_mutex, SND_SOC_DAPM_CLASS_INIT);
+
 	list_for_each_entry(w, &dapm->card->widgets, list)
 	{
 		if (w->new)
@@ -2393,8 +2427,10 @@
 			w->kcontrols = kzalloc(w->num_kcontrols *
 						sizeof(struct snd_kcontrol *),
 						GFP_KERNEL);
-			if (!w->kcontrols)
+			if (!w->kcontrols) {
+				mutex_unlock(&dapm->card->dapm_mutex);
 				return -ENOMEM;
+			}
 		}
 
 		switch(w->id) {
@@ -2434,6 +2470,7 @@
 	}
 
 	dapm_power_widgets(dapm, SND_SOC_DAPM_STREAM_NOP);
+	mutex_unlock(&dapm->card->dapm_mutex);
 	return 0;
 }
 EXPORT_SYMBOL_GPL(snd_soc_dapm_new_widgets);
@@ -2493,6 +2530,7 @@
 	struct snd_soc_dapm_widget_list *wlist = snd_kcontrol_chip(kcontrol);
 	struct snd_soc_dapm_widget *widget = wlist->widgets[0];
 	struct snd_soc_codec *codec = widget->codec;
+	struct snd_soc_card *card = codec->card;
 	struct soc_mixer_control *mc =
 		(struct soc_mixer_control *)kcontrol->private_value;
 	unsigned int reg = mc->reg;
@@ -2519,7 +2557,7 @@
 		/* old connection must be powered down */
 		connect = invert ? 1 : 0;
 
-	mutex_lock(&codec->mutex);
+	mutex_lock_nested(&card->dapm_mutex, SND_SOC_DAPM_CLASS_PCM);
 
 	change = snd_soc_test_bits(widget->codec, reg, mask, val);
 	if (change) {
@@ -2535,13 +2573,13 @@
 			update.val = val;
 			widget->dapm->update = &update;
 
-			snd_soc_dapm_mixer_update_power(widget, kcontrol, connect);
+			soc_dapm_mixer_update_power(widget, kcontrol, connect);
 
 			widget->dapm->update = NULL;
 		}
 	}
 
-	mutex_unlock(&codec->mutex);
+	mutex_unlock(&card->dapm_mutex);
 	return 0;
 }
 EXPORT_SYMBOL_GPL(snd_soc_dapm_put_volsw);
@@ -2590,6 +2628,7 @@
 	struct snd_soc_dapm_widget_list *wlist = snd_kcontrol_chip(kcontrol);
 	struct snd_soc_dapm_widget *widget = wlist->widgets[0];
 	struct snd_soc_codec *codec = widget->codec;
+	struct snd_soc_card *card = codec->card;
 	struct soc_enum *e = (struct soc_enum *)kcontrol->private_value;
 	unsigned int val, mux, change;
 	unsigned int mask, bitmask;
@@ -2610,7 +2649,7 @@
 		mask |= (bitmask - 1) << e->shift_r;
 	}
 
-	mutex_lock(&codec->mutex);
+	mutex_lock_nested(&card->dapm_mutex, SND_SOC_DAPM_CLASS_PCM);
 
 	change = snd_soc_test_bits(widget->codec, e->reg, mask, val);
 	if (change) {
@@ -2626,13 +2665,13 @@
 			update.val = val;
 			widget->dapm->update = &update;
 
-			snd_soc_dapm_mux_update_power(widget, kcontrol, change, mux, e);
+			soc_dapm_mux_update_power(widget, kcontrol, change, mux, e);
 
 			widget->dapm->update = NULL;
 		}
 	}
 
-	mutex_unlock(&codec->mutex);
+	mutex_unlock(&card->dapm_mutex);
 	return change;
 }
 EXPORT_SYMBOL_GPL(snd_soc_dapm_put_enum_double);
@@ -2669,6 +2708,7 @@
 	struct snd_soc_dapm_widget_list *wlist = snd_kcontrol_chip(kcontrol);
 	struct snd_soc_dapm_widget *widget = wlist->widgets[0];
 	struct snd_soc_codec *codec = widget->codec;
+	struct snd_soc_card *card = codec->card;
 	struct soc_enum *e =
 		(struct soc_enum *)kcontrol->private_value;
 	int change;
@@ -2678,7 +2718,7 @@
 	if (ucontrol->value.enumerated.item[0] >= e->max)
 		return -EINVAL;
 
-	mutex_lock(&codec->mutex);
+	mutex_lock_nested(&card->dapm_mutex, SND_SOC_DAPM_CLASS_PCM);
 
 	change = widget->value != ucontrol->value.enumerated.item[0];
 	if (change) {
@@ -2687,12 +2727,12 @@
 
 			widget->value = ucontrol->value.enumerated.item[0];
 
-			snd_soc_dapm_mux_update_power(widget, kcontrol, change,
+			soc_dapm_mux_update_power(widget, kcontrol, change,
 					widget->value, e);
 		}
 	}
 
-	mutex_unlock(&codec->mutex);
+	mutex_unlock(&card->dapm_mutex);
 	return ret;
 }
 EXPORT_SYMBOL_GPL(snd_soc_dapm_put_enum_virt);
@@ -2757,6 +2797,7 @@
 	struct snd_soc_dapm_widget_list *wlist = snd_kcontrol_chip(kcontrol);
 	struct snd_soc_dapm_widget *widget = wlist->widgets[0];
 	struct snd_soc_codec *codec = widget->codec;
+	struct snd_soc_card *card = codec->card;
 	struct soc_enum *e = (struct soc_enum *)kcontrol->private_value;
 	unsigned int val, mux, change;
 	unsigned int mask;
@@ -2775,7 +2816,7 @@
 		mask |= e->mask << e->shift_r;
 	}
 
-	mutex_lock(&codec->mutex);
+	mutex_lock_nested(&card->dapm_mutex, SND_SOC_DAPM_CLASS_PCM);
 
 	change = snd_soc_test_bits(widget->codec, e->reg, mask, val);
 	if (change) {
@@ -2791,13 +2832,13 @@
 			update.val = val;
 			widget->dapm->update = &update;
 
-			snd_soc_dapm_mux_update_power(widget, kcontrol, change, mux, e);
+			soc_dapm_mux_update_power(widget, kcontrol, change, mux, e);
 
 			widget->dapm->update = NULL;
 		}
 	}
 
-	mutex_unlock(&codec->mutex);
+	mutex_unlock(&card->dapm_mutex);
 	return change;
 }
 EXPORT_SYMBOL_GPL(snd_soc_dapm_put_value_enum_double);
@@ -2831,15 +2872,15 @@
 int snd_soc_dapm_get_pin_switch(struct snd_kcontrol *kcontrol,
 				struct snd_ctl_elem_value *ucontrol)
 {
-	struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
+	struct snd_soc_card *card = snd_kcontrol_chip(kcontrol);
 	const char *pin = (const char *)kcontrol->private_value;
 
-	mutex_lock(&codec->mutex);
+	mutex_lock_nested(&card->dapm_mutex, SND_SOC_DAPM_CLASS_PCM);
 
 	ucontrol->value.integer.value[0] =
-		snd_soc_dapm_get_pin_status(&codec->dapm, pin);
+		snd_soc_dapm_get_pin_status(&card->dapm, pin);
 
-	mutex_unlock(&codec->mutex);
+	mutex_unlock(&card->dapm_mutex);
 
 	return 0;
 }
@@ -2854,20 +2895,19 @@
 int snd_soc_dapm_put_pin_switch(struct snd_kcontrol *kcontrol,
 				struct snd_ctl_elem_value *ucontrol)
 {
-	struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
+	struct snd_soc_card *card = snd_kcontrol_chip(kcontrol);
 	const char *pin = (const char *)kcontrol->private_value;
 
-	mutex_lock(&codec->mutex);
+	mutex_lock_nested(&card->dapm_mutex, SND_SOC_DAPM_CLASS_PCM);
 
 	if (ucontrol->value.integer.value[0])
-		snd_soc_dapm_enable_pin(&codec->dapm, pin);
+		snd_soc_dapm_enable_pin(&card->dapm, pin);
 	else
-		snd_soc_dapm_disable_pin(&codec->dapm, pin);
+		snd_soc_dapm_disable_pin(&card->dapm, pin);
 
-	snd_soc_dapm_sync(&codec->dapm);
+	mutex_unlock(&card->dapm_mutex);
 
-	mutex_unlock(&codec->mutex);
-
+	snd_soc_dapm_sync(&card->dapm);
 	return 0;
 }
 EXPORT_SYMBOL_GPL(snd_soc_dapm_put_pin_switch);
@@ -2975,6 +3015,7 @@
 {
 	int i, ret;
 
+	mutex_lock_nested(&dapm->card->dapm_mutex, SND_SOC_DAPM_CLASS_INIT);
 	for (i = 0; i < num; i++) {
 		ret = snd_soc_dapm_new_control(dapm, widget);
 		if (ret < 0) {
@@ -2985,6 +3026,7 @@
 		}
 		widget++;
 	}
+	mutex_unlock(&dapm->card->dapm_mutex);
 	return 0;
 }
 EXPORT_SYMBOL_GPL(snd_soc_dapm_new_controls);
@@ -3099,7 +3141,6 @@
 	mutex_lock(&codec->mutex);
 	soc_dapm_stream_event(&codec->dapm, stream, event);
 	mutex_unlock(&codec->mutex);
-
 	return 0;
 }