Merge "ARM: dts: msm: change sound setting for SKUF with WCD9302"
diff --git a/Documentation/devicetree/bindings/arm/msm/cpr-regulator.txt b/Documentation/devicetree/bindings/arm/msm/cpr-regulator.txt
index 4e3abc2..a0b2f6d 100644
--- a/Documentation/devicetree/bindings/arm/msm/cpr-regulator.txt
+++ b/Documentation/devicetree/bindings/arm/msm/cpr-regulator.txt
@@ -22,16 +22,12 @@
 				should be 1 for SVS corner
 - regulator-max-microvolt:	Maximum corner value as max constraint, which
 				should be 4 for SUPER_TURBO or 3 for TURBO
-- qcom,pvs-bin-process:		A list of integers whose length is equal to 2 to
-				the power of qcom,pvs-fuse[num-of-bits]. The location or
-				0-based index of an element in the list corresponds
-				to the bin number. The value of each integer
-				corresponds to the PVS process speed of the APC
-				silicon for a chip with one of these cases:
-					1 = APC_PVS_SLOW
-					2 = APC_PVS_NOM
-					3 = APC_PVS_FAST
-					0 or other values = No PVS
+- qcom,pvs-init-voltage:  	A list of integers whose length is equal to 2
+				to the power of qcom,pvs-fuse[num-of-bits]. The
+				location or 0-based index of an element in the
+				list corresponds to the bin number. The value of
+				each integer corresponds to the initial voltage
+				of the PVS bin in turbo mode in microvolts.
 - qcom,pvs-corner-ceiling-slow:	Ceiling voltages of all corners for APC_PVS_SLOW
 - qcom,pvs-corner-ceiling-nom:	Ceiling voltages of all corners for APC_PVS_NOM
 - qcom,pvs-corner-ceiling-fast:	Ceiling voltages of all corners for APC_PVS_FAST
@@ -155,8 +151,14 @@
 		qcom,pvs-fuse-redun-sel = <22 24 3 2>;
 		qcom,pvs-fuse-redun = <22 27 5>;
 
-		qcom,pvs-bin-process = <0 0 0 0 0 1 1 1 1 1 2 2 2 2 2 2
-					2 2 2 2 3 3 3 3 3 3 3 3 0 0 0 0>;
+		qcom,pvs-init-voltage = <1330000 1330000 1330000 1320000
+						1310000 1300000 1290000 1280000
+						1270000 1260000 1250000 1240000
+						1230000 1220000 1210000 1200000
+						1190000 1180000 1170000 1160000
+						1150000 1140000 1140000 1140000
+						1140000 1140000 1140000 1140000
+						1140000 1140000 1140000 1140000>;
 		qcom,pvs-corner-ceiling-slow = <1050000 1160000 1275000>;
 		qcom,pvs-corner-ceiling-nom  =  <975000 1075000 1200000>;
 		qcom,pvs-corner-ceiling-fast =  <900000 1000000 1140000>;
diff --git a/Documentation/devicetree/bindings/arm/msm/smem.txt b/Documentation/devicetree/bindings/arm/msm/smem.txt
index a38984c..b6dcdc1 100644
--- a/Documentation/devicetree/bindings/arm/msm/smem.txt
+++ b/Documentation/devicetree/bindings/arm/msm/smem.txt
@@ -10,6 +10,10 @@
 	     "aux-mem1", "aux-mem2", "aux-mem3", ... - optional strings to
 			identify any auxiliary shared memory regions
 
+Optional properties:
+-mpu-enabled : boolean value indicating that Memory Protection Unit based
+	security is enabled on the "smem" shared memory region
+
 [Second level nodes]
 
 qcom,smd
diff --git a/Documentation/devicetree/bindings/fb/mdss-dsi-panel.txt b/Documentation/devicetree/bindings/fb/mdss-dsi-panel.txt
index 9ad8abe..20ef421 100644
--- a/Documentation/devicetree/bindings/fb/mdss-dsi-panel.txt
+++ b/Documentation/devicetree/bindings/fb/mdss-dsi-panel.txt
@@ -63,6 +63,10 @@
 Optional properties:
 - qcom,mdss-dsi-panel-name:		A string used as a descriptive name of the panel
 - qcom,cont-splash-enabled:		Boolean used to enable continuous splash mode.
+					If this property is specified, it is required to
+					to specify the memory reserved for the splash
+					screen using the qcom,memblock-reserve binding
+					for the framebuffer device attached to the panel.
 - qcom,mdss-dsi-panel-broadcast-mode:	Boolean used to enable broadcast mode.
 - qcom,mdss-dsi-fbc-enable:		Boolean used to enable frame buffer compression mode.
 - qcom,mdss-dsi-fbc-bpp:		Compressed bpp supported by the panel.
@@ -116,6 +120,12 @@
 					0xff = default value.
 - qcom,mdss-dsi-border-color:		Defines the border color value if border is present.
 					0 = default value.
+- qcom,mdss-dsi-pan-enable-dynamic-fps:	Boolean used to enable change in frame rate dynamically.
+- qcom,mdss-dsi-pan-fps-update:		A string that specifies when to change the frame rate.
+					"dfps_suspend_resume_mode"= FPS change request is
+						implemented during suspend/resume.
+					"dfps_immediate_clk_mode" = FPS change request is
+						implemented immediately using DSI clocks.
 - qcom,mdss-dsi-bl-pmic-control-type:	A string that specifies the implementation of backlight
 					control for this panel.
 					"bl_ctrl_pwm" = Backlight controlled by PWM gpio.
@@ -315,6 +325,8 @@
 		qcom,mdss-dsi-off-command = [22 01 00 00 00 00 00];
 		qcom,mdss-dsi-off-command-state = "dsi_hs_mode";
 		qcom,mdss-dsi-bl-pmic-control-type = "bl_ctrl_wled";
+		qcom,mdss-dsi-pan-enable-dynamic-fps;
+		qcom,mdss-dsi-pan-fps-update = "dfps_suspend_resume_mode";
 		qcom,mdss-dsi-bl-pmic-bank-select = <0>;
 		qcom,mdss-dsi-bl-pmic-pwm-frequency = <0>;
 		qcom,mdss-dsi-pwm-gpio = <&pm8941_mpps 5 0>;
diff --git a/Documentation/devicetree/bindings/fb/mdss-mdp.txt b/Documentation/devicetree/bindings/fb/mdss-mdp.txt
index 829cce2..5a70b6b 100644
--- a/Documentation/devicetree/bindings/fb/mdss-mdp.txt
+++ b/Documentation/devicetree/bindings/fb/mdss-mdp.txt
@@ -163,6 +163,11 @@
 			 enabled if framebuffer size is less than max mixer
 			 width; 2) the defaut even split is enabled if frambuffer
 			 size is greater than max mixer width.
+- qcom,memblock-reserve: Specifies the memory location and the size reserved
+			 for the framebuffer used to display the splash screen.
+			 This property is required whenever the continuous splash
+			 screen feature is enabled for the corresponding
+			 framebuffer device.
 
 Example:
 	mdss_mdp: qcom,mdss_mdp@fd900000 {
diff --git a/Documentation/devicetree/bindings/leds/leds-qpnp.txt b/Documentation/devicetree/bindings/leds/leds-qpnp.txt
index f7e50eb..af6a0b5 100644
--- a/Documentation/devicetree/bindings/leds/leds-qpnp.txt
+++ b/Documentation/devicetree/bindings/leds/leds-qpnp.txt
@@ -38,10 +38,10 @@
 Flash is used primarily as a camera or video flash.
 
 Optional properties for flash:
-- qcom,headroom: headroom to use, mV
-- qcom,duration: duration of the flash, ms
+- qcom,headroom: headroom to use. Values should be 0, 1, 2, 3 for 250mV, 300mV, 400mV and 500mV
+- qcom,duration: duration of the flash and torch, 10ms - 1280ms for flash and 2s - 33s for torch
 - qcom,clamp-curr: current to clamp at, mA
-- qcom,startup-dly: delay before flashing after flash executed, us
+- qcom,startup-dly: delay before flashing after flash executed. Values should 0, 1, 2, 3 for 10us, 32us, 64us, and 128us
 - qcom,saftey-timer: include for safety timer use, otherwise watchdog timer will be used
 - linux,default-trigger: trigger the led from external modules such as display
 - qcom,default-state:  default state of the led, should be "on" or "off"
diff --git a/Documentation/devicetree/bindings/media/video/ovti-image-sensor.txt b/Documentation/devicetree/bindings/media/video/ovti-image-sensor.txt
new file mode 100644
index 0000000..cef9cf5
--- /dev/null
+++ b/Documentation/devicetree/bindings/media/video/ovti-image-sensor.txt
@@ -0,0 +1,9 @@
+OmniVision Image Sensor Device Tree Bindings.
+========================================
+
+Boards with the OmniVision Image Sensor shall have the following properties:
+
+Required root node properties:
+    - compatible:
+    - "ovti,ov8865" : OmniVision OV8865 8 megapixel Image Sensor.
+    - "ovti,ov5648" : OmniVision OV5648 5 megapixel Image Sensor.
diff --git a/Documentation/devicetree/bindings/sound/qcom-audio-dev.txt b/Documentation/devicetree/bindings/sound/qcom-audio-dev.txt
index 6e4f7fc..5e686a4f 100644
--- a/Documentation/devicetree/bindings/sound/qcom-audio-dev.txt
+++ b/Documentation/devicetree/bindings/sound/qcom-audio-dev.txt
@@ -436,6 +436,8 @@
 - qcom,headset-jack-type-NO: Adjust GPIO level based on the headset jack type.
 - qcom,tapan-codec-9302: Indicates that this device node is for WCD9302 audio
 			    codec.
+- qcom,mbhc-bias-internal: Flag to indicate if internal micbias should be used
+			   for headset detection.
 
 * APQ8074 ASoC Machine driver
 
diff --git a/Documentation/devicetree/bindings/usb/msm-ehci-hsic.txt b/Documentation/devicetree/bindings/usb/msm-ehci-hsic.txt
index 7ca741c..24f21b4 100644
--- a/Documentation/devicetree/bindings/usb/msm-ehci-hsic.txt
+++ b/Documentation/devicetree/bindings/usb/msm-ehci-hsic.txt
@@ -7,7 +7,8 @@
 - interrupt-names : Required interrupt resource entries are:
 	"core_irq" : Interrupt for HSIC core
 - <supply-name>-supply: handle to the regulator device tree node
-  Required "supply-name" is "HSIC_VDDCX" and optionally - "HSIC_GDSC".
+  Required "supply-name" is either "hsic_vdd_dig" or "HSIC_VDDCX" and
+  optionally - "HSIC_GDSC".
 
 Optional properties :
 - interrupt-parent - This must provide reference to the current
@@ -81,6 +82,9 @@
   the reset and enumeration. Since some devices might take more than 100ms
   for initialization when receiving the bus reset, add delay to avoid the
   problem that enmueration is before device initialization done.
+- hsic,vdd-voltage-level: This property must be a list of three integer
+  values (no, min, max) where each value represents either a voltage in
+  microvolts or a value corresponding to voltage corner
 
 - Refer to "Documentation/devicetree/bindings/arm/msm/msm_bus.txt" for
   below optional properties:
@@ -104,7 +108,7 @@
 			1 &intc 0 148 0
 			2 &msmgpio 144 0x8>;
 		interrupt-names = "core_irq", "async_irq", "wakeup";
-		HSIC_VDDCX-supply = <&pm8019_l12>;
+		hsic_vdd_dig-supply = <&pm8841_s2_corner>;
 		HSIC_GDSC-supply = <&gdsc_usb_hsic>;
 		hsic,strobe-gpio = <&msmgpio 144 0x00>;
 		hsic,data-gpio = <&msmgpio 145 0x00>;
@@ -113,6 +117,7 @@
 		hsic,strobe-pad-offset = <0x2050>;
 		hsic,data-pad-offset = <0x2054>;
 		hsic,consider-ipa-handshake;
+		hsic,vdd-voltage-level = <1 5 7>;
 
 		qcom,msm-bus,name = "hsic";
 		qcom,msm-bus,num-cases = <2>;
diff --git a/Documentation/devicetree/bindings/usb/msm-hsusb.txt b/Documentation/devicetree/bindings/usb/msm-hsusb.txt
index 44ed2dc..e7eae76 100644
--- a/Documentation/devicetree/bindings/usb/msm-hsusb.txt
+++ b/Documentation/devicetree/bindings/usb/msm-hsusb.txt
@@ -130,7 +130,8 @@
 - interrupt-names : Required interrupt resource entries are:
             HSUSB EHCI expects "core_irq" and optionally "async_irq".
 - <supply-name>-supply: handle to the regulator device tree node
-  Required "supply-name" is "HSUSB_VDDCX" "HSUSB_1p8-supply" "HSUSB_3p3-supply".
+  Required "supply-name" is either "hsusb_vdd_dig" or "HSUSB_VDDCX"
+  "HSUSB_1p8-supply" "HSUSB_3p3-supply".
 - qcom,usb2-power-budget: maximum vbus power (in mA) that can be provided.
 
 Optional properties :
@@ -138,6 +139,15 @@
 - qcom,resume-gpio: if present then peripheral connected to usb controller
   cannot wakeup from XO shutdown using in-band usb bus resume. Use resume
   gpio to wakeup peripheral.
+- qcom,vdd-voltage-level: This property must be a list of five integer
+  values (no, 0.5vsuspend, 0.75suspend, min, max) where each value respresents
+  either a voltage in microvolts or a value corresponding to voltage corner.
+  First value represents value to vote when USB is not at all active, second
+  value represents value to vote when target is not connected to dock during low
+  power mode, third value represents vlaue to vote when target is connected to dock
+  and no peripheral connected over dock during low power mode, fourth value represents
+  minimum value to vote when USB is operational, fifth item represents maximum value
+  to vote for USB is operational.
 
 Example MSM HSUSB EHCI controller device node :
 	ehci: qcom,ehci-host@f9a55000 {
@@ -145,11 +155,12 @@
 		reg = <0xf9a55000 0x400>;
 		interrupts = <0 134 0>, <0 140 0>;
 		interrupt-names = "core_irq", "async_irq";
-		HSUSB_VDDCX-supply = <&pm8841_s2>;
+		hsusb_vdd_dig-supply = <&pm8841_s2_corner>;
 		HSUSB_1p8-supply = <&pm8941_l6>;
 		HSUSB_3p3-supply = <&pm8941_l24>;
 		qcom,usb2-enable-hsphy2;
 		qcom,usb2-power-budget = <500>;
+		qcom,vdd-voltage-level = <1 2 3 5 7>;
 	};
 
 ANDROID USB:
diff --git a/Documentation/devicetree/bindings/vendor-prefixes.txt b/Documentation/devicetree/bindings/vendor-prefixes.txt
index 9fd3afe..1eec990 100644
--- a/Documentation/devicetree/bindings/vendor-prefixes.txt
+++ b/Documentation/devicetree/bindings/vendor-prefixes.txt
@@ -36,6 +36,7 @@
 nintendo	Nintendo
 nvidia	NVIDIA
 nxp	NXP Semiconductors
+ovti	OmniVision Technologies, Inc.
 picochip	Picochip Ltd
 powervr	Imagination Technologies
 qcom	Qualcomm, Inc.
diff --git a/Documentation/devicetree/bindings/wcnss/wcnss-wlan.txt b/Documentation/devicetree/bindings/wcnss/wcnss-wlan.txt
index d0bbc47..5201827 100644
--- a/Documentation/devicetree/bindings/wcnss/wcnss-wlan.txt
+++ b/Documentation/devicetree/bindings/wcnss/wcnss-wlan.txt
@@ -20,6 +20,7 @@
 - gpios: gpio numbers to configure 5-wire interface of WLAN connectivity
 - qcom,has-48mhz-xo: boolean flag to determine the usage of 24MHz XO from RF
 - qcom,has-pronto-hw: boolean flag to determine the revId of the WLAN subsystem
+- qcom,wcnss-adc_tm: ADC handle for vbatt notification APIs.
 
 Optional properties:
 - qcom,has-autodetect-xo: boolean flag to determine whether Iris XO auto detect
@@ -49,4 +50,5 @@
                 <&msmgpio 39 0>, <&msmgpio 40 0>;
         qcom,has-48mhz-xo;
         qcom,has-pronto-hw;
+        qcom,wcnss-adc_tm = <&pm8226_adc_tm>;
     };
diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig
index 58fc698..aa37edc 100644
--- a/arch/arm/Kconfig
+++ b/arch/arm/Kconfig
@@ -1854,6 +1854,11 @@
 
 config DONT_MAP_HOLE_AFTER_MEMBANK0
 	def_bool n
+	depends on ENABLE_VMALLOC_SAVING=n
+
+config ENABLE_VMALLOC_SAVING
+	def_bool n
+	depends on DONT_MAP_HOLE_AFTER_MEMBANK0=n
 
 config HOLES_IN_ZONE
 	def_bool n
diff --git a/arch/arm/boot/dts/apq8074-dragonboard.dtsi b/arch/arm/boot/dts/apq8074-dragonboard.dtsi
index 46f5f22..60bb518 100644
--- a/arch/arm/boot/dts/apq8074-dragonboard.dtsi
+++ b/arch/arm/boot/dts/apq8074-dragonboard.dtsi
@@ -84,7 +84,7 @@
 				1 &intc 0 148 0
 				2 &msmgpio 144 0x8>;
 			interrupt-names = "core_irq", "async_irq", "wakeup";
-			HSIC_VDDCX-supply = <&pm8841_s2>;
+			hsic_vdd_dig-supply = <&pm8841_s2_corner>;
 			HSIC_GDSC-supply = <&gdsc_usb_hsic>;
 			hsic,strobe-gpio = <&msmgpio 144 0x00>;
 			hsic,data-gpio = <&msmgpio 145 0x00>;
@@ -92,6 +92,7 @@
 			hsic,strobe-pad-offset = <0x2050>;
 			hsic,data-pad-offset = <0x2054>;
 			qcom,phy-susp-sof-workaround;
+			hsic,vdd-voltage-level = <1 5 7>;
 
 			qcom,msm-bus,name = "hsic";
 			qcom,msm-bus,num-cases = <2>;
diff --git a/arch/arm/boot/dts/apq8074-v2.0-1.dtsi b/arch/arm/boot/dts/apq8074-v2.0-1.dtsi
index 8314fab..2b75fa2 100644
--- a/arch/arm/boot/dts/apq8074-v2.0-1.dtsi
+++ b/arch/arm/boot/dts/apq8074-v2.0-1.dtsi
@@ -55,3 +55,8 @@
 	status = "ok";
 };
 
+&ehci {
+	hsusb_vdd_dig-supply = <&pm8841_s2_corner>;
+	qcom,vdd-voltage-level = <1 2 3 5 7>;
+};
+
diff --git a/arch/arm/boot/dts/dsi-panel-hx8379a-wvga-video.dtsi b/arch/arm/boot/dts/dsi-panel-hx8379a-wvga-video.dtsi
index 9d244d8..4230018 100644
--- a/arch/arm/boot/dts/dsi-panel-hx8379a-wvga-video.dtsi
+++ b/arch/arm/boot/dts/dsi-panel-hx8379a-wvga-video.dtsi
@@ -26,13 +26,13 @@
 		qcom,mdss-dsi-stream = <0>;
 		qcom,mdss-dsi-panel-width = <480>;
 		qcom,mdss-dsi-panel-height = <800>;
-		qcom,mdss-dsi-h-front-porch = <70>;
-		qcom,mdss-dsi-h-back-porch = <100>;
+		qcom,mdss-dsi-h-front-porch = <100>;
+		qcom,mdss-dsi-h-back-porch = <94>;
 		qcom,mdss-dsi-h-pulse-width = <40>;
 		qcom,mdss-dsi-h-sync-skew = <0>;
-		qcom,mdss-dsi-v-back-porch = <6>;
+		qcom,mdss-dsi-v-back-porch = <4>;
 		qcom,mdss-dsi-v-front-porch = <6>;
-		qcom,mdss-dsi-v-pulse-width = <4>;
+		qcom,mdss-dsi-v-pulse-width = <6>;
 		qcom,mdss-dsi-h-left-border = <0>;
 		qcom,mdss-dsi-h-right-border = <0>;
 		qcom,mdss-dsi-v-top-border = <0>;
@@ -42,62 +42,63 @@
 		qcom,mdss-dsi-underflow-color = <0xff>;
 		qcom,mdss-dsi-border-color = <0>;
 		qcom,mdss-dsi-on-command = [
-					39 01 00 00 00 00 04
-						B9 FF 83 79
-					39 01 00 00 00 00 03
-						BA 51 93
-					39 01 00 00 00 00 14
-						B1 00 50 44
-						EA 8D 08 11
-						11 11 27 2F
-						9A 1A 42 0B
-						6E F1 00 E6
-					39 01 00 00 00 00 0E
-						B2 00 00 3C
-						08 04 19 22
-						00 FF 08 04
-						19 20
-					39 01 00 00 00 00 20
-						B4 82 08 00
-						32 10 03 32
-						13 70 32 10
-						08 37 01 28
-						07 37 08 3C
-						08 44 44 08
-						00 40 08 28
-						08 30 30 04
-					39 01 00 00 00 00 30
-						D5 00 00 0A
-						00 01 05 00
-						03 00 88 88
-						88 88 23 01
-						67 45 02 13
-						88 88 88 88
-						88 88 88 88
-						88 88 54 76
-						10 32 31 20
-						88 88 88 88
-						88 88 00 00
-						00 00 00 00
-					39 01 00 00 00 00 24
-						E0 79 05 0F
-						14 26 29 3F
-						2B 44 04 0E
-						12 15 18 16
-						16 12 15 05
-						0F 14 26 29
-						3F 2B 44 04
-						0E 12 15 18
-						16 16 12 15
-					23 01 00 00 00 00 02
-						cc 02
-					39 01 00 00 00 00 05
-						B6 00 9C 00 9C
-					05 01 00 00 96 00 02
-						11 00
-					05 01 00 00 78 00 02
-						29 00
-					];
+			39 01 00 00 00 00 04
+				B9 FF 83 79
+			39 01 00 00 00 00 03
+				BA 51 93
+			39 01 00 00 00 00 14
+				B1 00 50 44
+				EA 8D 08 11
+				11 11 27 2F
+				9A 1A 42 0B
+				6E F1 00 E6
+			39 01 00 00 00 00 0E
+				B2 00 00 3C
+				08 04 19 22
+				00 FF 08 04
+				19 20
+			39 01 00 00 00 00 20
+				B4 80 08 00
+				32 10 03 32
+				13 70 32 10
+				08 37 01 28
+				07 37 08 35
+				08 3D 44 08
+				00 40 08 28
+				08 30 30 04
+			39 01 00 00 00 00 30
+				D5 00 00 0A
+				00 01 05 00
+				03 00 88 88
+				88 88 23 01
+				67 45 02 13
+				88 88 88 88
+				88 88 88 88
+				88 88 54 76
+				10 32 31 20
+				88 88 88 88
+				88 88 00 00
+				00 00 00 00
+			39 01 00 00 00 00 24
+				E0 79 05 0F
+				14 26 20 3F
+				2A 43 04 0C
+				11 15 17 15
+				15 10 13 05
+				0F 14 26 20
+				3F 2A 43 04
+				0C 11 15 17
+				15 15 10 13
+			23 01 00 00 00 00 02
+				cc 02
+			39 01 00 00 00 00 05
+				B6 00 9C 00
+				9C
+			05 01 00 00 96 00 02
+				11 00
+			05 01 00 00 78 00 02
+				29 00
+			];
 		qcom,mdss-dsi-off-command = [05 01 00 00 32 00 02 28 00
 					05 01 00 00 78 00 02 10 00];
 		qcom,mdss-dsi-on-command-state = "dsi_lp_mode";
@@ -109,7 +110,7 @@
 		qcom,mdss-dsi-bllp-power-mode;
 		qcom,mdss-dsi-lane-0-state;
 		qcom,mdss-dsi-lane-1-state;
-		qcom,mdss-dsi-panel-timings = [75 1A 11 00 3D 45 15 1D 1C 03 04 00];
+		qcom,mdss-dsi-panel-timings = [78 1B 11 00 3E 43 16 1E 1D 03 04 00];
 		qcom,mdss-dsi-t-clk-post = <0x04>;
 		qcom,mdss-dsi-t-clk-pre = <0x1b>;
 		qcom,mdss-dsi-bl-min-level = <1>;
diff --git a/arch/arm/boot/dts/dsi-panel-toshiba-720p-video.dtsi b/arch/arm/boot/dts/dsi-panel-toshiba-720p-video.dtsi
index 0b98db7..021ddef 100644
--- a/arch/arm/boot/dts/dsi-panel-toshiba-720p-video.dtsi
+++ b/arch/arm/boot/dts/dsi-panel-toshiba-720p-video.dtsi
@@ -90,6 +90,7 @@
 		qcom,mdss-dsi-dma-trigger = <0x04>;
 		qcom,mdss-dsi-mdp-trigger = <0x0>;
 		qcom,mdss-dsi-bl-pmic-control-type = "bl_ctrl_wled";
-
+		qcom,mdss-dsi-pan-enable-dynamic-fps;
+		qcom,mdss-dsi-pan-fps-update = "dfps_suspend_resume_mode";
 	};
 };
diff --git a/arch/arm/boot/dts/msm-pm8110.dtsi b/arch/arm/boot/dts/msm-pm8110.dtsi
index 1820dc7..6969940 100644
--- a/arch/arm/boot/dts/msm-pm8110.dtsi
+++ b/arch/arm/boot/dts/msm-pm8110.dtsi
@@ -315,7 +315,7 @@
 			qcom,v-cutoff-uv = <3400000>;
 			qcom,max-voltage-uv = <4200000>;
 			qcom,r-conn-mohm = <0>;
-			qcom,shutdown-soc-valid-limit = <20>;
+			qcom,shutdown-soc-valid-limit = <100>;
 			qcom,adjust-soc-low-threshold = <15>;
 			qcom,ocv-voltage-high-threshold-uv = <3750000>;
 			qcom,ocv-voltage-low-threshold-uv = <3650000>;
diff --git a/arch/arm/boot/dts/msm-pm8226.dtsi b/arch/arm/boot/dts/msm-pm8226.dtsi
index 5642d4d..ba1bf08 100644
--- a/arch/arm/boot/dts/msm-pm8226.dtsi
+++ b/arch/arm/boot/dts/msm-pm8226.dtsi
@@ -189,7 +189,7 @@
 			qcom,v-cutoff-uv = <3400000>;
 			qcom,max-voltage-uv = <4200000>;
 			qcom,r-conn-mohm = <0>;
-			qcom,shutdown-soc-valid-limit = <20>;
+			qcom,shutdown-soc-valid-limit = <100>;
 			qcom,adjust-soc-low-threshold = <15>;
 			qcom,ocv-voltage-high-threshold-uv = <3750000>;
 			qcom,ocv-voltage-low-threshold-uv = <3650000>;
@@ -831,10 +831,10 @@
 			pm8226_flash0: qcom,flash_0 {
 				qcom,max-current = <1000>;
 				qcom,default-state = "off";
-				qcom,headroom = <0>;
+				qcom,headroom = <3>;
 				qcom,duration = <1280>;
 				qcom,clamp-curr = <200>;
-				qcom,startup-dly = <1>;
+				qcom,startup-dly = <3>;
 				qcom,safety-timer;
 				label = "flash";
 				linux,default-trigger =
@@ -847,10 +847,10 @@
 			pm8226_flash1: qcom,flash_1 {
 				qcom,max-current = <1000>;
 				qcom,default-state = "off";
-				qcom,headroom = <0>;
+				qcom,headroom = <3>;
 				qcom,duration = <1280>;
 				qcom,clamp-curr = <200>;
-				qcom,startup-dly = <1>;
+				qcom,startup-dly = <3>;
 				qcom,safety-timer;
 				linux,default-trigger =
 						"flash1_trigger";
diff --git a/arch/arm/boot/dts/msm-pm8941.dtsi b/arch/arm/boot/dts/msm-pm8941.dtsi
index 583cd3c..98d2f5e 100644
--- a/arch/arm/boot/dts/msm-pm8941.dtsi
+++ b/arch/arm/boot/dts/msm-pm8941.dtsi
@@ -120,7 +120,7 @@
 		qcom,v-cutoff-uv = <3400000>;
 		qcom,max-voltage-uv = <4200000>;
 		qcom,r-conn-mohm = <0>;
-		qcom,shutdown-soc-valid-limit = <20>;
+		qcom,shutdown-soc-valid-limit = <100>;
 		qcom,adjust-soc-low-threshold = <15>;
 		qcom,ocv-voltage-high-threshold-uv = <3750000>;
 		qcom,ocv-voltage-low-threshold-uv = <3650000>;
diff --git a/arch/arm/boot/dts/msm8226-camera-sensor-qrd.dtsi b/arch/arm/boot/dts/msm8226-camera-sensor-qrd.dtsi
index 3eacef2..fd6d618 100644
--- a/arch/arm/boot/dts/msm8226-camera-sensor-qrd.dtsi
+++ b/arch/arm/boot/dts/msm8226-camera-sensor-qrd.dtsi
@@ -402,7 +402,7 @@
 	};
 
 	qcom,camera@6a {
-		compatible = "qcom,ov5648";
+		compatible = "ovti,ov5648";
 		reg = <0x6a>;
 		qcom,slave-id = <0x6c 0x300a 0x5648>;
 		qcom,csiphy-sd-index = <1>;
diff --git a/arch/arm/boot/dts/msm8226-cdp.dtsi b/arch/arm/boot/dts/msm8226-cdp.dtsi
index 066d6c2..3ebe225 100644
--- a/arch/arm/boot/dts/msm8226-cdp.dtsi
+++ b/arch/arm/boot/dts/msm8226-cdp.dtsi
@@ -29,6 +29,8 @@
 			synaptics,irq-gpio = <&msmgpio 17 0x2008>;
 			synaptics,button-map = <139 102 158>;
 			synaptics,i2c-pull-up;
+			synaptics,power-down;
+			synaptics,disable-gpios;
 		};
 	};
 
@@ -102,7 +104,7 @@
 
 		qcom,cdc-mclk-gpios = <&pm8226_gpios 1 0>;
 		qcom,cdc-vdd-spkr-gpios = <&pm8226_gpios 2 0>;
-		qcom,headset-jack-type-NO;
+		qcom,headset-jack-type-NC;
 	};
 
 	sound-9302 {
@@ -120,7 +122,7 @@
 
 		qcom,cdc-mclk-gpios = <&pm8226_gpios 1 0>;
 		qcom,cdc-vdd-spkr-gpios = <&pm8226_gpios 2 0>;
-		qcom,headset-jack-type-NO;
+		qcom,headset-jack-type-NC;
 	};
 };
 
diff --git a/arch/arm/boot/dts/msm8226-mdss.dtsi b/arch/arm/boot/dts/msm8226-mdss.dtsi
index 2ec7b6c..c7a4eee 100644
--- a/arch/arm/boot/dts/msm8226-mdss.dtsi
+++ b/arch/arm/boot/dts/msm8226-mdss.dtsi
@@ -49,6 +49,7 @@
 			compatible = "qcom,mdss-fb";
 			qcom,memory-reservation-type = "EBI1";
 			qcom,memory-reservation-size = <0x800000>;
+			qcom,memblock-reserve = <0x03200000 0xFA0000>;
 		};
 
 		mdss_fb1: qcom,mdss_fb_wfd {
diff --git a/arch/arm/boot/dts/msm8226-mtp.dtsi b/arch/arm/boot/dts/msm8226-mtp.dtsi
index f4f7442..318d4fc 100644
--- a/arch/arm/boot/dts/msm8226-mtp.dtsi
+++ b/arch/arm/boot/dts/msm8226-mtp.dtsi
@@ -29,6 +29,8 @@
 			synaptics,irq-gpio = <&msmgpio 17 0x2008>;
 			synaptics,button-map = <139 102 158>;
 			synaptics,i2c-pull-up;
+			synaptics,power-down;
+			synaptics,disable-gpios;
 		};
 	};
 
diff --git a/arch/arm/boot/dts/msm8226-qrd.dtsi b/arch/arm/boot/dts/msm8226-qrd.dtsi
index 53e0578..18a1aea 100644
--- a/arch/arm/boot/dts/msm8226-qrd.dtsi
+++ b/arch/arm/boot/dts/msm8226-qrd.dtsi
@@ -29,7 +29,10 @@
 			synaptics,irq-gpio = <&msmgpio 17 0x2008>;
 			synaptics,button-map = <139 102 158>;
 			synaptics,i2c-pull-up;
+			synaptics,power-down;
+			synaptics,disable-gpios;
 		};
+
 		focaltech@38 {
 			compatible = "focaltech,5x06";
 			reg = <0x38>;
diff --git a/arch/arm/boot/dts/msm8226-regulator.dtsi b/arch/arm/boot/dts/msm8226-regulator.dtsi
index 415912f..838592c 100644
--- a/arch/arm/boot/dts/msm8226-regulator.dtsi
+++ b/arch/arm/boot/dts/msm8226-regulator.dtsi
@@ -41,8 +41,13 @@
 		qcom,pvs-fuse = <22 6 5>;
 		qcom,pvs-fuse-redun = <22 27 5>;
 
-		qcom,pvs-bin-process = <0 0 0 0 0 1 1 1 1 1 2 2 2 2 2 2
-					2 2 2 2 3 3 3 3 3 3 3 3 0 0 0 0>;
+		qcom,pvs-init-voltage = <1275000 1275000 1275000 1275000 1275000
+					1275000 1260000 1245000 1230000 1215000
+					1200000 1185000 1170000 1155000 1140000
+					1140000 1140000 1140000 1140000 1140000
+					1150000 1140000 1140000 1140000 1140000
+					1140000 1140000 1140000 1275000 1275000
+					1275000 1275000>;
 		qcom,pvs-corner-ceiling-slow = <1050000 1150000 1275000>;
 		qcom,pvs-corner-ceiling-nom  = <1050000 1075000 1200000>;
 		qcom,pvs-corner-ceiling-fast = <1050000 1050000 1140000>;
diff --git a/arch/arm/boot/dts/msm8226-v2.dtsi b/arch/arm/boot/dts/msm8226-v2.dtsi
index 8f22ceb..a57adcd 100644
--- a/arch/arm/boot/dts/msm8226-v2.dtsi
+++ b/arch/arm/boot/dts/msm8226-v2.dtsi
@@ -33,27 +33,32 @@
 
 &pm8226_l3 {
 	regulator-min-microvolt = <750000>;
-	regulator-max-microvolt = <1287500>;
+	regulator-max-microvolt = <1337500>;
 };
 
 &pm8226_l3_ao {
 	regulator-min-microvolt = <750000>;
-	regulator-max-microvolt = <1287500>;
+	regulator-max-microvolt = <1337500>;
 };
 
 &pm8226_l3_so {
 	regulator-min-microvolt = <750000>;
-	regulator-max-microvolt = <1287500>;
+	regulator-max-microvolt = <1337500>;
 };
 
 &pm8226_s2 {
 	regulator-min-microvolt = <900000>;
-	regulator-max-microvolt = <1280000>;
+	regulator-max-microvolt = <1330000>;
 };
 
 &apc_vreg_corner {
-	qcom,pvs-bin-process = <1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 2
-				2 2 2 2 2 3 3 3 3 3 3 3 3 3 3 3>;
+	qcom,pvs-init-voltage = <1330000 1330000 1330000 1320000 1310000
+					1300000 1290000 1280000 1270000 1260000
+					1250000 1240000 1230000 1220000 1210000
+					1200000 1190000 1180000 1170000 1160000
+					1150000 1140000 1140000 1140000 1140000
+					1140000 1140000 1140000 1140000 1140000
+					1140000 1140000>;
 	qcom,pvs-corner-ceiling-slow = <1050000 1150000 1280000>;
 	qcom,pvs-corner-ceiling-nom  = <1050000 1080000 1200000>;
 	qcom,pvs-corner-ceiling-fast = <1050000 1050000 1140000>;
diff --git a/arch/arm/boot/dts/msm8226.dtsi b/arch/arm/boot/dts/msm8226.dtsi
index 483aad1..cfb6bed 100644
--- a/arch/arm/boot/dts/msm8226.dtsi
+++ b/arch/arm/boot/dts/msm8226.dtsi
@@ -591,6 +591,7 @@
 		gpios = <&msmgpio 40 0>, <&msmgpio 41 0>, <&msmgpio 42 0>, <&msmgpio 43 0>, <&msmgpio 44 0>;
 		qcom,has-pronto-hw;
 		qcom,has-autodetect-xo;
+		qcom,wcnss-adc_tm = <&pm8226_adc_tm>;
 	};
 
 	qcom,msm-adsp-sensors {
diff --git a/arch/arm/boot/dts/msm8610-cdp.dtsi b/arch/arm/boot/dts/msm8610-cdp.dtsi
index f0d1715..452cc2f 100644
--- a/arch/arm/boot/dts/msm8610-cdp.dtsi
+++ b/arch/arm/boot/dts/msm8610-cdp.dtsi
@@ -172,6 +172,7 @@
 
 		qcom,cdc-on-demand-supplies = "cdc-vdda-cp",
 					      "cdc-vdd-mic-bias";
+		qcom,cdc-micbias1-ext-cap;
 	};
 
 	msm8x10_wcd_codec@77{
diff --git a/arch/arm/boot/dts/msm8610-mdss.dtsi b/arch/arm/boot/dts/msm8610-mdss.dtsi
index f37a42b..de74e52 100644
--- a/arch/arm/boot/dts/msm8610-mdss.dtsi
+++ b/arch/arm/boot/dts/msm8610-mdss.dtsi
@@ -20,6 +20,7 @@
 		mdss_fb0: qcom,mdss_fb_primary {
 			cell-index = <0>;
 			compatible = "qcom,mdss-fb";
+			qcom,memblock-reserve = <0x3200000 0x800000>;
 		};
 	};
 
diff --git a/arch/arm/boot/dts/msm8610-mtp.dtsi b/arch/arm/boot/dts/msm8610-mtp.dtsi
index 56ef7ca..1cc3e61 100644
--- a/arch/arm/boot/dts/msm8610-mtp.dtsi
+++ b/arch/arm/boot/dts/msm8610-mtp.dtsi
@@ -228,6 +228,7 @@
 
 		qcom,cdc-on-demand-supplies = "cdc-vdda-cp",
 					      "cdc-vdd-mic-bias";
+		qcom,cdc-micbias1-ext-cap;
 	};
 
 	msm8x10_wcd_codec@77{
diff --git a/arch/arm/boot/dts/msm8610-qrd.dtsi b/arch/arm/boot/dts/msm8610-qrd.dtsi
index 3fb33e9..83d84c0 100644
--- a/arch/arm/boot/dts/msm8610-qrd.dtsi
+++ b/arch/arm/boot/dts/msm8610-qrd.dtsi
@@ -135,13 +135,14 @@
 	};
 
     sound {
-        qcom,audio-routing =
-            "RX_BIAS", "MCLK",
-            "INT_LDO_H", "MCLK",
-            "MIC BIAS Internal1", "Handset Mic",
-            "MIC BIAS Internal2", "Headset Mic",
-            "AMIC1", "MIC BIAS Internal1",
-            "AMIC2", "MIC BIAS Internal2";
+	qcom,audio-routing =
+		"RX_BIAS", "MCLK",
+		"INT_LDO_H", "MCLK",
+		"MIC BIAS Internal1", "Handset Mic",
+		"MIC BIAS Internal2", "Headset Mic",
+		"AMIC1", "MIC BIAS Internal1",
+		"AMIC2", "MIC BIAS Internal2";
+	qcom,mbhc-bias-internal;
     };
 };
 
diff --git a/arch/arm/boot/dts/msm8610-regulator.dtsi b/arch/arm/boot/dts/msm8610-regulator.dtsi
index 1929b50..eb69678 100644
--- a/arch/arm/boot/dts/msm8610-regulator.dtsi
+++ b/arch/arm/boot/dts/msm8610-regulator.dtsi
@@ -42,10 +42,15 @@
 		qcom,pvs-fuse = <23 6 5>;
 		qcom,pvs-fuse-redun = <61 47 5>;
 
-		qcom,pvs-bin-process = <1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1
-					1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1>;
-		qcom,pvs-corner-ceiling-slow = <1050000 1150000 1275000>;
-		qcom,pvs-corner-ceiling-nom  = <1050000 1075000 1200000>;
+		qcom,pvs-init-voltage = <1275000 1275000 1275000 1275000 1275000
+					1275000 1275000 1275000 1275000 1275000
+					1275000 1275000 1275000 1275000 1275000
+					1275000 1275000 1275000 1275000 1275000
+					1275000 1275000 1275000 1275000 1275000
+					1275000 1275000 1275000 1275000 1275000
+					1275000 1275000>;
+		qcom,pvs-corner-ceiling-slow = <1150000 1150000 1275000>;
+		qcom,pvs-corner-ceiling-nom  = <1075000 1075000 1200000>;
 		qcom,pvs-corner-ceiling-fast = <1050000 1050000 1140000>;
 		vdd-apc-supply = <&pm8110_s2>;
 
diff --git a/arch/arm/boot/dts/msm8926-camera-sensor-qrd.dtsi b/arch/arm/boot/dts/msm8926-camera-sensor-qrd.dtsi
new file mode 100644
index 0000000..a85e048
--- /dev/null
+++ b/arch/arm/boot/dts/msm8926-camera-sensor-qrd.dtsi
@@ -0,0 +1,115 @@
+/*
+ * Copyright (c) 2013, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+&soc {
+
+	led_flash0: qcom,camera-led-flash {
+		cell-index = <0>;
+		compatible = "qcom,camera-led-flash";
+		qcom,flash-type = <1>;
+		qcom,flash-source = <&pm8226_flash0 &pm8226_flash1>;
+		qcom,torch-source = <&pm8226_torch>;
+	};
+};
+
+&cci {
+
+	actuator0: qcom,actuator@6e {
+		cell-index = <5>;
+		reg = <0x18>;
+		compatible = "qcom,actuator";
+		qcom,cci-master = <0>;
+	};
+
+	qcom,camera@20 {
+		compatible = "ovti,ov8865";
+		reg = <0x20>;
+		qcom,slave-id = <0x20 0x300b 0x8865>;
+		qcom,csiphy-sd-index = <0>;
+		qcom,csid-sd-index = <0>;
+		qcom,actuator-src = <&actuator0>;
+		qcom,led-flash-src = <&led_flash0>;
+		qcom,mount-angle = <90>;
+		qcom,sensor-name = "ov8865_q8v18a";
+		cam_vdig-supply = <&pm8226_l5>;
+		cam_vana-supply = <&pm8226_l19>;
+		cam_vio-supply = <&pm8226_lvs1>;
+		cam_vaf-supply = <&pm8226_l15>;
+		qcom,cam-vreg-name = "cam_vdig", "cam_vio", "cam_vana",
+		                                         "cam_vaf";
+		qcom,cam-vreg-type = <0 1 0 0>;
+		qcom,cam-vreg-min-voltage = <1200000 0 2850000 2800000>;
+		qcom,cam-vreg-max-voltage = <1200000 0 2850000 2800000>;
+		qcom,cam-vreg-op-mode = <200000 0 80000 100000>;
+		qcom,gpio-no-mux = <0>;
+		gpios = <&msmgpio 26 0>,
+		        <&msmgpio 37 0>,
+		        <&msmgpio 36 0>,
+		        <&msmgpio 15 0>;
+		qcom,gpio-reset = <1>;
+		qcom,gpio-standby = <2>;
+		qcom,gpio-af-pwdm = <3>;
+		qcom,gpio-req-tbl-num = <0 1 2 3>;
+		qcom,gpio-req-tbl-flags = <1 0 0 0>;
+		qcom,gpio-req-tbl-label = "CAMIF_MCLK",
+		        "CAM_RESET1",
+		        "CAM_STANDBY",
+		        "CAM_AF_PWDM";
+		qcom,csi-lane-assign = <0x4320>;
+		qcom,csi-lane-mask = <0x1F>;
+		qcom,sensor-position = <0>;
+		qcom,sensor-mode = <1>;
+		qcom,cci-master = <0>;
+	};
+
+	qcom,camera@6a {
+		compatible = "ovti,ov5648";
+		reg = <0x6a>;
+		qcom,slave-id = <0x6c 0x300a 0x5648>;
+		qcom,csiphy-sd-index = <1>;
+		qcom,csid-sd-index = <1>;
+		qcom,mount-angle = <270>;
+		qcom,sensor-name = "ov5648_oty5f03";
+		cam_vdig-supply = <&pm8226_l5>;
+		cam_vana-supply = <&pm8226_l19>;
+		cam_vio-supply = <&pm8226_lvs1>;
+		qcom,cam-vreg-name = "cam_vdig", "cam_vio", "cam_vana";
+		qcom,cam-vreg-type = <0 1 0>;
+		qcom,cam-vreg-min-voltage = <1200000 0 2850000>;
+		qcom,cam-vreg-max-voltage = <1200000 0 2850000>;
+		qcom,cam-vreg-op-mode = <200000 0 80000>;
+		qcom,gpio-no-mux = <0>;
+		gpios = <&msmgpio 26 0>,
+				<&msmgpio 28 0>,
+				<&msmgpio 35 0>,
+				<&msmgpio 23 0>;
+		qcom,gpio-reset = <1>;
+		qcom,gpio-standby = <2>;
+		qcom,gpio-vdig = <3>;
+		qcom,gpio-req-tbl-num = <0 1 2 3>;
+		qcom,gpio-req-tbl-flags = <1 0 0 0>;
+		qcom,gpio-req-tbl-label = "CAMIF_MCLK",
+				"CAM_RESET",
+				"CAM_STANDBY",
+				"CAM_VDIG";
+		qcom,gpio-set-tbl-num = <1 1>;
+		qcom,gpio-set-tbl-flags = <0 2>;
+		qcom,gpio-set-tbl-delay = <1000 4000>;
+		qcom,csi-lane-assign = <0x4320>;
+		qcom,csi-lane-mask = <0x3>;
+		qcom,sensor-position = <1>;
+		qcom,sensor-mode = <1>;
+		qcom,cci-master = <0>;
+		status = "ok";
+	};
+};
diff --git a/arch/arm/boot/dts/msm8926-qrd-skug.dts b/arch/arm/boot/dts/msm8926-qrd-skug.dts
index b7826e5..a366205 100644
--- a/arch/arm/boot/dts/msm8926-qrd-skug.dts
+++ b/arch/arm/boot/dts/msm8926-qrd-skug.dts
@@ -13,6 +13,7 @@
 /dts-v1/;
 /include/ "msm8926.dtsi"
 /include/ "msm8226-qrd.dtsi"
+/include/ "msm8926-camera-sensor-qrd.dtsi"
 
 / {
 	model = "Qualcomm MSM 8926 QRD SKUG";
@@ -35,6 +36,51 @@
 	qcom,battery-data = <&qrd_batterydata>;
 };
 
+&soc {
+	i2c@f9927000 { /* BLSP1 QUP5 */
+		focaltech@38 {
+			compatible = "focaltech,5x06";
+			reg = <0x38>;
+			interrupt-parent = <&msmgpio>;
+			interrupts = <17 0x2>;
+			vdd-supply = <&pm8226_l19>;
+			vcc_i2c-supply = <&pm8226_lvs1>;
+			focaltech,name = "ft5336";
+			focaltech,family-id = <0x14>;
+			focaltech,reset-gpio = <&msmgpio 16 0x00>;
+			focaltech,irq-gpio = <&msmgpio 17 0x00>;
+			focaltech,display-coords = <0 0 720 1280>;
+			focaltech,panel-coords = <0 0 720 1400>;
+			focaltech,button-map= <139 102 158>;
+			focaltech,no-force-update;
+			focaltech,i2c-pull-up;
+			focaltech,group-id = <1>;
+			focaltech,hard-reset-delay-ms = <20>;
+			focaltech,soft-reset-delay-ms = <200>;
+			focaltech,num-max-touches = <5>;
+			focaltech,fw-name = "ft_8926_qrd_fw.bin";
+			focaltech,fw-delay-aa-ms = <30>;
+			focaltech,fw-delay-55-ms = <30>;
+			focaltech,fw-upgrade-id1 = <0x79>;
+			focaltech,fw-upgrade-id2 = <0x08>;
+			focaltech,fw-delay-readid-ms = <10>;
+			focaltech,fw-delay-era-flsh-ms = <2000>;
+			focaltech,fw-auto-cal;
+		};
+	};
+
+	gen-vkeys {
+		compatible = "qcom,gen-vkeys";
+		label = "ft5x06_ts";
+		qcom,disp-maxx = <720>;
+		qcom,disp-maxy = <1280>;
+		qcom,panel-maxx = <720>;
+		qcom,panel-maxy = <1404>;
+		qcom,key-codes = <139 172 158>;
+		qcom,y-offset = <0>;
+	};
+};
+
 &mdss_dsi0 {
 	qcom,dsi-pref-prim-pan = <&dsi_ssd2080m_720_vid>;
 };
diff --git a/arch/arm/boot/dts/msm8926.dtsi b/arch/arm/boot/dts/msm8926.dtsi
index 5893a9b..2ab272a 100644
--- a/arch/arm/boot/dts/msm8926.dtsi
+++ b/arch/arm/boot/dts/msm8926.dtsi
@@ -48,28 +48,33 @@
 
 &pm8226_l3 {
 	regulator-min-microvolt = <750000>;
-	regulator-max-microvolt = <1287500>;
+	regulator-max-microvolt = <1350000>;
 };
 
 &pm8226_l3_ao {
 	regulator-min-microvolt = <750000>;
-	regulator-max-microvolt = <1287500>;
+	regulator-max-microvolt = <1350000>;
 };
 
 &pm8226_l3_so {
 	regulator-min-microvolt = <750000>;
-	regulator-max-microvolt = <1287500>;
+	regulator-max-microvolt = <1350000>;
 };
 
 &pm8226_s2 {
 	regulator-min-microvolt = <900000>;
-	regulator-max-microvolt = <1280000>;
+	regulator-max-microvolt = <1350000>;
 };
 
 &apc_vreg_corner {
-	qcom,pvs-bin-process = <1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 2
-				2 2 2 2 2 3 3 3 3 3 3 3 3 3 3 3>;
-	qcom,pvs-corner-ceiling-slow = <1050000 1160000 1280000>;
+	qcom,pvs-init-voltage = <1350000 1340000 1330000 1320000 1310000
+					1300000 1290000 1280000 1270000 1260000
+					1250000 1240000 1230000 1220000 1210000
+					1200000 1190000 1180000 1170000 1160000
+					1150000 1140000 1140000 1140000 1140000
+					1140000 1140000 1140000 1140000 1140000
+					1140000 1140000>;
+	qcom,pvs-corner-ceiling-slow = <1050000 1150000 1280000>;
 	qcom,pvs-corner-ceiling-nom  = <1050000 1080000 1200000>;
 	qcom,pvs-corner-ceiling-fast = <1050000 1050000 1140000>;
 	qcom,cpr-step-quotient = <30>;
diff --git a/arch/arm/boot/dts/msm8974-cdp.dtsi b/arch/arm/boot/dts/msm8974-cdp.dtsi
index d200100..9e7b2e6 100644
--- a/arch/arm/boot/dts/msm8974-cdp.dtsi
+++ b/arch/arm/boot/dts/msm8974-cdp.dtsi
@@ -41,6 +41,22 @@
 	};
 
 	i2c@f9924000 {
+		synaptics@20 {
+			compatible = "synaptics,rmi4";
+			reg = <0x20>;
+			interrupt-parent = <&msmgpio>;
+			interrupts = <61 0x2008>;
+			vdd-supply = <&pm8941_l18>;
+			vcc_i2c-supply = <&pm8941_lvs1>;
+			synaptics,reset-gpio = <&msmgpio 60 0x00>;
+			synaptics,irq-gpio = <&msmgpio 61 0x2008>;
+			synaptics,display-coords = <0 0 1079 1919>;
+			synaptics,i2c-pull-up;
+			synaptics,power-down;
+			synaptics,disable-gpios;
+			synaptics,do-lockdown;
+		};
+
 		atmel_mxt_ts@4a {
 			compatible = "atmel,mxt-ts";
 			reg = <0x4a>;
@@ -227,7 +243,7 @@
 			1 &intc 0 148 0
 			2 &msmgpio 144 0x8>;
 		interrupt-names = "core_irq", "async_irq", "wakeup";
-		HSIC_VDDCX-supply = <&pm8841_s2>;
+		hsic_vdd_dig-supply = <&pm8841_s2_corner>;
 		HSIC_GDSC-supply = <&gdsc_usb_hsic>;
 		hsic,strobe-gpio = <&msmgpio 144 0x00>;
 		hsic,data-gpio = <&msmgpio 145 0x00>;
@@ -236,6 +252,7 @@
 		hsic,strobe-pad-offset = <0x2050>;
 		hsic,data-pad-offset = <0x2054>;
 		qcom,phy-susp-sof-workaround;
+		hsic,vdd-voltage-level = <1 5 7>;
 
 		qcom,msm-bus,name = "hsic";
 		qcom,msm-bus,num-cases = <2>;
diff --git a/arch/arm/boot/dts/msm8974-fluid.dtsi b/arch/arm/boot/dts/msm8974-fluid.dtsi
index d02021c..c112bea 100644
--- a/arch/arm/boot/dts/msm8974-fluid.dtsi
+++ b/arch/arm/boot/dts/msm8974-fluid.dtsi
@@ -37,6 +37,22 @@
 	};
 
 	i2c@f9924000 {
+		synaptics@20 {
+			compatible = "synaptics,rmi4";
+			reg = <0x20>;
+			interrupt-parent = <&msmgpio>;
+			interrupts = <61 0x2008>;
+			vdd-supply = <&pm8941_l18>;
+			vcc_i2c-supply = <&pm8941_lvs1>;
+			synaptics,reset-gpio = <&msmgpio 60 0x00>;
+			synaptics,irq-gpio = <&msmgpio 61 0x2008>;
+			synaptics,display-coords = <0 0 1079 1919>;
+			synaptics,i2c-pull-up;
+			synaptics,power-down;
+			synaptics,disable-gpios;
+			synaptics,do-lockdown;
+		};
+
 		atmel_mxt_ts@4a {
 			compatible = "atmel,mxt-ts";
 			reg = <0x4a>;
diff --git a/arch/arm/boot/dts/msm8974-liquid.dtsi b/arch/arm/boot/dts/msm8974-liquid.dtsi
index 73aba8f..67e1802 100644
--- a/arch/arm/boot/dts/msm8974-liquid.dtsi
+++ b/arch/arm/boot/dts/msm8974-liquid.dtsi
@@ -397,7 +397,7 @@
 		                1 &intc 0 148 0
 		                2 &msmgpio 144 0x8>;
 			interrupt-names = "core_irq", "async_irq", "wakeup";
-			HSIC_VDDCX-supply = <&pm8841_s2>;
+			hsic_vdd_dig-supply = <&pm8841_s2_corner>;
 			HSIC_GDSC-supply = <&gdsc_usb_hsic>;
 			hsic,strobe-gpio = <&msmgpio 144 0x00>;
 			hsic,data-gpio = <&msmgpio 145 0x00>;
@@ -405,6 +405,7 @@
 			hsic,strobe-pad-offset = <0x2050>;
 			hsic,data-pad-offset = <0x2054>;
 			qcom,phy-susp-sof-workaround;
+			hsic,vdd-voltage-level = <1 5 7>;
 
 			qcom,msm-bus,name = "hsic";
 			qcom,msm-bus,num-cases = <2>;
diff --git a/arch/arm/boot/dts/msm8974-mdss.dtsi b/arch/arm/boot/dts/msm8974-mdss.dtsi
index 24b5860..7181db2 100644
--- a/arch/arm/boot/dts/msm8974-mdss.dtsi
+++ b/arch/arm/boot/dts/msm8974-mdss.dtsi
@@ -64,6 +64,7 @@
 			compatible = "qcom,mdss-fb";
 			qcom,memory-reservation-type = "EBI1";
 			qcom,memory-reservation-size = <0x800000>;
+			qcom,memblock-reserve = <0x03200000 0x01E00000>;
 		};
 
 		mdss_fb1: qcom,mdss_fb_external {
diff --git a/arch/arm/boot/dts/msm8974-mtp.dtsi b/arch/arm/boot/dts/msm8974-mtp.dtsi
index 22fff80..7a81e64 100644
--- a/arch/arm/boot/dts/msm8974-mtp.dtsi
+++ b/arch/arm/boot/dts/msm8974-mtp.dtsi
@@ -37,6 +37,22 @@
 	};
 
 	i2c@f9924000 {
+		synaptics@20 {
+			compatible = "synaptics,rmi4";
+			reg = <0x20>;
+			interrupt-parent = <&msmgpio>;
+			interrupts = <61 0x2008>;
+			vdd-supply = <&pm8941_l18>;
+			vcc_i2c-supply = <&pm8941_lvs1>;
+			synaptics,reset-gpio = <&msmgpio 60 0x00>;
+			synaptics,irq-gpio = <&msmgpio 61 0x2008>;
+			synaptics,display-coords = <0 0 1079 1919>;
+			synaptics,i2c-pull-up;
+			synaptics,power-down;
+			synaptics,disable-gpios;
+			synaptics,do-lockdown;
+		};
+
 		atmel_mxt_ts@4a {
 			compatible = "atmel,mxt-ts";
 			reg = <0x4a>;
diff --git a/arch/arm/boot/dts/msm8974-v1-cdp.dts b/arch/arm/boot/dts/msm8974-v1-cdp.dts
index c3fd98d..071c7c9 100644
--- a/arch/arm/boot/dts/msm8974-v1-cdp.dts
+++ b/arch/arm/boot/dts/msm8974-v1-cdp.dts
@@ -26,6 +26,8 @@
 &ehci {
 	status = "ok";
 	vbus-supply = <&usb2_otg_sw>;
+	hsusb_vdd_dig-supply = <&pm8841_s2_corner>;
+	qcom,vdd-voltage-level = <1 2 3 5 7>;
 };
 
 &hsic_host {
diff --git a/arch/arm/boot/dts/msm8974.dtsi b/arch/arm/boot/dts/msm8974.dtsi
index 65307ae..652a8fc 100644
--- a/arch/arm/boot/dts/msm8974.dtsi
+++ b/arch/arm/boot/dts/msm8974.dtsi
@@ -835,9 +835,11 @@
 		reg-names = "qup_phys_addr";
 		interrupts = <0 96 0>;
 		interrupt-names = "qup_err_intr";
-		qcom,i2c-bus-freq = <100000>;
-		qcom,i2c-src-freq = <50000000>;
+		qcom,i2c-bus-freq = <384000>;
+		qcom,i2c-src-freq = <19200000>;
 		qcom,master-id = <86>;
+		qcom,scl-gpio = <&msmgpio 7 0>;
+		qcom,sda-gpio = <&msmgpio 6 0>;
 	};
 
 	spi_0: spi@f9923000 { /* BLSP1 QUP1 */
@@ -1559,7 +1561,8 @@
 
         memory_hole: qcom,msm-mem-hole {
                 compatible = "qcom,msm-mem-hole";
-                qcom,memblock-remove = <0x5d00000 0xa200000>; /* Address and Size of Hole */
+                qcom,memblock-remove = <0x5d00000 0x7d00000
+					0xfa00000 0x500000>; /* Address and Size of Hole */
         };
 
 	uart7: uart@f995d000 { /*BLSP #2, UART #7 */
diff --git a/arch/arm/boot/dts/msm8974pro-ac-mtp.dtsi b/arch/arm/boot/dts/msm8974pro-ac-mtp.dtsi
index debf7fb..cdb4ed0 100644
--- a/arch/arm/boot/dts/msm8974pro-ac-mtp.dtsi
+++ b/arch/arm/boot/dts/msm8974pro-ac-mtp.dtsi
@@ -46,6 +46,11 @@
 
 &soc {
 	i2c@f9924000 {
+		synaptics@20 {
+			vdd-supply = <&pma8084_l18>;
+			vcc_i2c-supply = <&pma8084_lvs1>;
+		};
+
 		atmel_mxt_ts@4a {
 			vdd_ana-supply = <&pma8084_l18>;
 			vcc_i2c-supply = <&pma8084_lvs1>;
diff --git a/arch/arm/configs/msm8226-perf_defconfig b/arch/arm/configs/msm8226-perf_defconfig
index 9535e05..f8369a9 100644
--- a/arch/arm/configs/msm8226-perf_defconfig
+++ b/arch/arm/configs/msm8226-perf_defconfig
@@ -82,6 +82,7 @@
 CONFIG_AEABI=y
 CONFIG_HIGHMEM=y
 CONFIG_COMPACTION=y
+CONFIG_CC_STACKPROTECTOR=y
 CONFIG_CP_ACCESS=y
 CONFIG_USE_OF=y
 CONFIG_CPU_FREQ_GOV_POWERSAVE=y
@@ -301,6 +302,7 @@
 CONFIG_OV8825=y
 CONFIG_OV12830=y
 CONFIG_IMX135=y
+CONFIG_OV8865=y
 CONFIG_MSM_CAMERA_SENSOR=y
 CONFIG_MSM_EEPROM=y
 CONFIG_MSM_CPP=y
diff --git a/arch/arm/configs/msm8226_defconfig b/arch/arm/configs/msm8226_defconfig
index 176a8a2..816b020 100644
--- a/arch/arm/configs/msm8226_defconfig
+++ b/arch/arm/configs/msm8226_defconfig
@@ -83,6 +83,7 @@
 CONFIG_AEABI=y
 CONFIG_HIGHMEM=y
 CONFIG_COMPACTION=y
+CONFIG_CC_STACKPROTECTOR=y
 CONFIG_CP_ACCESS=y
 CONFIG_USE_OF=y
 CONFIG_CPU_FREQ_GOV_POWERSAVE=y
@@ -305,6 +306,7 @@
 CONFIG_OV8825=y
 CONFIG_OV12830=y
 CONFIG_IMX135=y
+CONFIG_OV8865=y
 CONFIG_MSM_CAMERA_SENSOR=y
 CONFIG_MSM_EEPROM=y
 CONFIG_MSM_CPP=y
diff --git a/arch/arm/configs/msm8960_defconfig b/arch/arm/configs/msm8960_defconfig
index 1d645e2..c668cb2 100644
--- a/arch/arm/configs/msm8960_defconfig
+++ b/arch/arm/configs/msm8960_defconfig
@@ -240,18 +240,18 @@
 CONFIG_NET_EMATCH_TEXT=y
 CONFIG_NET_CLS_ACT=y
 CONFIG_BT=y
-CONFIG_BT_RFCOMM=y
-CONFIG_BT_RFCOMM_TTY=y
-CONFIG_BT_BNEP=y
-CONFIG_BT_BNEP_MC_FILTER=y
-CONFIG_BT_BNEP_PROTO_FILTER=y
+# CONFIG_BT_RFCOMM is not set
+# CONFIG_BT_RFCOMM_TTY is not set
+# CONFIG_BT_BNEP is not set
+# CONFIG_BT_BNEP_MC_FILTER is not set
+# CONFIG_BT_BNEP_PROTO_FILTER is not set
 CONFIG_BT_HIDP=y
-CONFIG_BT_HCISMD=y
-CONFIG_BT_HCIUART=y
-CONFIG_BT_HCIUART_H4=y
-CONFIG_BT_HCIUART_ATH3K=y
-CONFIG_BT_HCIUART_IBS=y
-CONFIG_MSM_BT_POWER=y
+# CONFIG_BT_HCISMD is not set
+# CONFIG_BT_HCIUART is not set
+# CONFIG_BT_HCIUART_H4 is not set
+# CONFIG_BT_HCIUART_ATH3K is not set
+# CONFIG_BT_HCIUART_IBS is not set
+# CONFIG_MSM_BT_POWER is not set
 CONFIG_CFG80211=m
 CONFIG_CFG80211_INTERNAL_REGDB=y
 # CONFIG_CFG80211_WEXT is not set
diff --git a/arch/arm/configs/msm8974-perf_defconfig b/arch/arm/configs/msm8974-perf_defconfig
index a9e39ed..3224889 100644
--- a/arch/arm/configs/msm8974-perf_defconfig
+++ b/arch/arm/configs/msm8974-perf_defconfig
@@ -94,6 +94,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
@@ -286,6 +287,8 @@
 CONFIG_INPUT_TOUCHSCREEN=y
 CONFIG_TOUCHSCREEN_ATMEL_MXT=y
 CONFIG_TOUCHSCREEN_GEN_VKEYS=y
+CONFIG_TOUCHSCREEN_SYNAPTICS_I2C_RMI4=y
+CONFIG_TOUCHSCREEN_SYNAPTICS_DSX_FW_UPDATE=y
 CONFIG_INPUT_MISC=y
 CONFIG_INPUT_UINPUT=y
 CONFIG_SERIAL_MSM_HS=y
diff --git a/arch/arm/configs/msm8974_defconfig b/arch/arm/configs/msm8974_defconfig
index ee38cc8..cd0e638 100644
--- a/arch/arm/configs/msm8974_defconfig
+++ b/arch/arm/configs/msm8974_defconfig
@@ -100,6 +100,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
@@ -294,6 +295,8 @@
 CONFIG_INPUT_TOUCHSCREEN=y
 CONFIG_TOUCHSCREEN_ATMEL_MXT=y
 CONFIG_TOUCHSCREEN_GEN_VKEYS=y
+CONFIG_TOUCHSCREEN_SYNAPTICS_I2C_RMI4=y
+CONFIG_TOUCHSCREEN_SYNAPTICS_DSX_FW_UPDATE=y
 CONFIG_INPUT_MISC=y
 CONFIG_INPUT_UINPUT=y
 CONFIG_SERIAL_MSM_HS=y
diff --git a/arch/arm/mach-msm/Kconfig b/arch/arm/mach-msm/Kconfig
index 87e3e5b..2fda467 100644
--- a/arch/arm/mach-msm/Kconfig
+++ b/arch/arm/mach-msm/Kconfig
@@ -280,11 +280,12 @@
 	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 USB_ARCH_HAS_XHCI
+	select ENABLE_VMALLOC_SAVING
 
 config ARCH_APQ8084
 	bool "APQ8084"
@@ -1761,6 +1762,16 @@
 	help
 	  SMD Transport Layer for IPC Router
 
+config MSM_IPC_ROUTER_HSIC_XPRT
+	depends on USB_QCOM_IPC_BRIDGE
+	depends on MSM_IPC_ROUTER
+	bool "MSM HSIC XPRT Layer"
+	help
+	  HSIC Transport Layer that enables off-chip communication of
+	  IPC Router. When the HSIC endpoint becomes available, this layer
+	  registers the transport with IPC Router and enable message
+	  exchange.
+
 config MSM_IPC_ROUTER_SECURITY
 	depends on MSM_IPC_ROUTER
 	bool "MSM IPC Router Security support"
diff --git a/arch/arm/mach-msm/Makefile b/arch/arm/mach-msm/Makefile
index 89eb589..dd533f4 100644
--- a/arch/arm/mach-msm/Makefile
+++ b/arch/arm/mach-msm/Makefile
@@ -130,6 +130,7 @@
 obj-$(CONFIG_MSM_SMD_NMEA) += smd_nmea.o
 obj-$(CONFIG_MSM_RESET_MODEM) += reset_modem.o
 obj-$(CONFIG_MSM_IPC_ROUTER_SMD_XPRT) += ipc_router_smd_xprt.o
+obj-$(CONFIG_MSM_IPC_ROUTER_HSIC_XPRT) += ipc_router_hsic_xprt.o
 obj-$(CONFIG_MSM_ONCRPCROUTER) += smd_rpcrouter.o
 obj-$(CONFIG_MSM_ONCRPCROUTER) += smd_rpcrouter_device.o
 obj-$(CONFIG_MSM_IPC_ROUTER) += ipc_router.o
diff --git a/arch/arm/mach-msm/acpuclock-8226.c b/arch/arm/mach-msm/acpuclock-8226.c
index 9ea00c1..da3cfba 100644
--- a/arch/arm/mach-msm/acpuclock-8226.c
+++ b/arch/arm/mach-msm/acpuclock-8226.c
@@ -49,7 +49,7 @@
 	[2] =  BW_MBPS(400), /* At least 50 MHz on bus. */
 	[3] =  BW_MBPS(800), /* At least 100 MHz on bus. */
 	[4] = BW_MBPS(1600), /* At least 200 MHz on bus. */
-	[5] = BW_MBPS(2128), /* At least 266 MHz on bus. */
+	[5] = BW_MBPS(2664), /* At least 333 MHz on bus. */
 };
 
 static struct msm_bus_scale_pdata bus_client_pdata = {
@@ -63,7 +63,7 @@
 	{ 1,  300000, PLL0,    4, 2,   CPR_CORNER_SVS,    0, 4 },
 	{ 1,  384000, ACPUPLL, 5, 2,   CPR_CORNER_SVS,    0, 4 },
 	{ 1,  600000, PLL0,    4, 0,   CPR_CORNER_NORMAL, 0, 6 },
-	{ 1,  787200, ACPUPLL, 5, 0,   CPR_CORNER_NORMAL, 0, 7 },
+	{ 1,  787200, ACPUPLL, 5, 0,   CPR_CORNER_NORMAL, 0, 6 },
 	{ 1,  998400, ACPUPLL, 5, 0,   CPR_CORNER_TURBO,  0, 7 },
 	{ 1, 1094400, ACPUPLL, 5, 0,   CPR_CORNER_TURBO,  0, 7 },
 	{ 0, 1190400, ACPUPLL, 5, 0,   CPR_CORNER_TURBO,  0, 7 },
@@ -74,7 +74,7 @@
 	{ 1,  300000, PLL0,    4, 2,   CPR_CORNER_SVS,    0, 4 },
 	{ 1,  384000, ACPUPLL, 5, 2,   CPR_CORNER_SVS,    0, 4 },
 	{ 1,  600000, PLL0,    4, 0,   CPR_CORNER_NORMAL, 0, 6 },
-	{ 1,  787200, ACPUPLL, 5, 0,   CPR_CORNER_NORMAL, 0, 7 },
+	{ 1,  787200, ACPUPLL, 5, 0,   CPR_CORNER_NORMAL, 0, 6 },
 	{ 1,  998400, ACPUPLL, 5, 0,   CPR_CORNER_TURBO,  0, 7 },
 	{ 1, 1094400, ACPUPLL, 5, 0,   CPR_CORNER_TURBO,  0, 7 },
 	{ 1, 1190400, ACPUPLL, 5, 0,   CPR_CORNER_TURBO,  0, 7 },
@@ -85,7 +85,7 @@
 	{ 1,  300000, PLL0,    4, 2,   CPR_CORNER_SVS,    0, 4 },
 	{ 1,  384000, ACPUPLL, 5, 2,   CPR_CORNER_SVS,    0, 4 },
 	{ 1,  600000, PLL0,    4, 0,   CPR_CORNER_NORMAL, 0, 6 },
-	{ 1,  787200, ACPUPLL, 5, 0,   CPR_CORNER_NORMAL, 0, 7 },
+	{ 1,  787200, ACPUPLL, 5, 0,   CPR_CORNER_NORMAL, 0, 6 },
 	{ 1,  998400, ACPUPLL, 5, 0,   CPR_CORNER_TURBO,  0, 7 },
 	{ 1, 1094400, ACPUPLL, 5, 0,   CPR_CORNER_TURBO,  0, 7 },
 	{ 1, 1190400, ACPUPLL, 5, 0,   CPR_CORNER_TURBO,  0, 7 },
@@ -95,26 +95,11 @@
 	{ 0 }
 };
 
-static struct clkctl_acpu_speed acpu_freq_tbl_8226_1p5[] = {
-	{ 1,  300000, PLL0,    4, 2,   CPR_CORNER_SVS,    0, 4 },
-	{ 1,  384000, ACPUPLL, 5, 2,   CPR_CORNER_SVS,    0, 4 },
-	{ 1,  600000, PLL0,    4, 0,   CPR_CORNER_NORMAL, 0, 6 },
-	{ 1,  787200, ACPUPLL, 5, 0,   CPR_CORNER_NORMAL, 0, 7 },
-	{ 1,  998400, ACPUPLL, 5, 0,   CPR_CORNER_TURBO,  0, 7 },
-	{ 1, 1094400, ACPUPLL, 5, 0,   CPR_CORNER_TURBO,  0, 7 },
-	{ 1, 1190400, ACPUPLL, 5, 0,   CPR_CORNER_TURBO,  0, 7 },
-	{ 1, 1305600, ACPUPLL, 5, 0,   CPR_CORNER_TURBO,  0, 7 },
-	{ 1, 1344000, ACPUPLL, 5, 0,   CPR_CORNER_TURBO,  0, 7 },
-	{ 1, 1401600, ACPUPLL, 5, 0,   CPR_CORNER_TURBO,  0, 7 },
-	{ 1, 1497600, ACPUPLL, 5, 0,   CPR_CORNER_TURBO,  0, 7 },
-	{ 0 }
-};
-
 static struct clkctl_acpu_speed acpu_freq_tbl_8226_1p6[] = {
 	{ 1,  300000, PLL0,    4, 2,   CPR_CORNER_SVS,    0, 4 },
 	{ 1,  384000, ACPUPLL, 5, 2,   CPR_CORNER_SVS,    0, 4 },
 	{ 1,  600000, PLL0,    4, 0,   CPR_CORNER_NORMAL, 0, 6 },
-	{ 1,  787200, ACPUPLL, 5, 0,   CPR_CORNER_NORMAL, 0, 7 },
+	{ 1,  787200, ACPUPLL, 5, 0,   CPR_CORNER_NORMAL, 0, 6 },
 	{ 1,  998400, ACPUPLL, 5, 0,   CPR_CORNER_TURBO,  0, 7 },
 	{ 1, 1094400, ACPUPLL, 5, 0,   CPR_CORNER_TURBO,  0, 7 },
 	{ 1, 1190400, ACPUPLL, 5, 0,   CPR_CORNER_TURBO,  0, 7 },
@@ -141,8 +126,8 @@
 	[6] = acpu_freq_tbl_8226_1p2,
 	[2] = acpu_freq_tbl_8226_1p4,
 	[5] = acpu_freq_tbl_8226_1p4,
-	[4] = acpu_freq_tbl_8226_1p5,
-	[7] = acpu_freq_tbl_8226_1p5,
+	[4] = acpu_freq_tbl_8226_1p4,
+	[7] = acpu_freq_tbl_8226_1p4,
 	[1] = acpu_freq_tbl_8226_1p6,
 };
 
diff --git a/arch/arm/mach-msm/acpuclock-8974.c b/arch/arm/mach-msm/acpuclock-8974.c
index 6d848d2..8410019 100644
--- a/arch/arm/mach-msm/acpuclock-8974.c
+++ b/arch/arm/mach-msm/acpuclock-8974.c
@@ -899,38 +899,460 @@
 	{ 0, { 0 } }
 };
 
-static struct acpu_level acpu_freq_tbl_pro_pvs0[] __initdata = {
-	{ 1, {  300000, PLL_0, 0,   0 },  L2(0),  800000, 999 },
-	{ 0, {  345600, HFPLL, 2,  36 },  L2(1),  800000, 999 },
-	{ 1, {  422400, HFPLL, 2,  44 },  L2(2),  800000, 999 },
-	{ 0, {  499200, HFPLL, 2,  52 },  L2(2),  805000, 999 },
-	{ 0, {  576000, HFPLL, 1,  30 },  L2(3),  815000, 999 },
-	{ 1, {  652800, HFPLL, 1,  34 },  L2(3),  825000, 999 },
-	{ 1, {  729600, HFPLL, 1,  38 },  L2(4),  835000, 999 },
-	{ 0, {  806400, HFPLL, 1,  42 },  L2(4),  845000, 999 },
-	{ 1, {  883200, HFPLL, 1,  46 },  L2(4),  855000, 999 },
-	{ 1, {  960000, HFPLL, 1,  50 },  L2(9),  865000, 999 },
-	{ 1, { 1036800, HFPLL, 1,  54 }, L2(10),  875000, 999 },
-	{ 0, { 1113600, HFPLL, 1,  58 }, L2(10),  890000, 999 },
-	{ 1, { 1190400, HFPLL, 1,  62 }, L2(10),  900000, 999 },
-	{ 1, { 1267200, HFPLL, 1,  66 }, L2(13),  915000, 999 },
-	{ 0, { 1344000, HFPLL, 1,  70 }, L2(14),  925000, 999 },
-	{ 0, { 1420800, HFPLL, 1,  74 }, L2(15),  940000, 999 },
-	{ 1, { 1497600, HFPLL, 1,  78 }, L2(16),  950000, 999 },
-	{ 1, { 1574400, HFPLL, 1,  82 }, L2(17),  965000, 999 },
-	{ 0, { 1651200, HFPLL, 1,  86 }, L2(17),  980000, 999 },
-	{ 1, { 1728000, HFPLL, 1,  90 }, L2(18),  995000, 999 },
-	{ 0, { 1804800, HFPLL, 1,  94 }, L2(18), 1010000, 999 },
-	{ 0, { 1881600, HFPLL, 1,  98 }, L2(18), 1025000, 999 },
-	{ 1, { 1958400, HFPLL, 1, 102 }, L2(19), 1040000, 999 },
-	{ 0, { 2035200, HFPLL, 1, 106 }, L2(19), 1055000, 999 },
-	{ 0, { 2112000, HFPLL, 1, 110 }, L2(19), 1070000, 999 },
-	{ 0, { 2188800, HFPLL, 1, 114 }, L2(19), 1085000, 999 },
-	{ 1, { 2265600, HFPLL, 1, 118 }, L2(19), 1100000, 999 },
-	/* higher frequencies aren't available for bring up */
+static struct acpu_level acpu_ftbl_pro_2p3g_pvs0[] __initdata = {
+	{ 1, {  300000, PLL_0, 0,   0 },  L2(0),  775000,  72 },
+	{ 0, {  345600, HFPLL, 2,  36 },  L2(1),  775000,  83 },
+	{ 1, {  422400, HFPLL, 2,  44 },  L2(2),  775000, 101 },
+	{ 0, {  499200, HFPLL, 2,  52 },  L2(2),  780000, 120 },
+	{ 0, {  576000, HFPLL, 1,  30 },  L2(3),  790000, 139 },
+	{ 1, {  652800, HFPLL, 1,  34 },  L2(3),  800000, 159 },
+	{ 1, {  729600, HFPLL, 1,  38 },  L2(4),  810000, 180 },
+	{ 0, {  806400, HFPLL, 1,  42 },  L2(4),  820000, 200 },
+	{ 1, {  883200, HFPLL, 1,  46 },  L2(4),  830000, 221 },
+	{ 1, {  960000, HFPLL, 1,  50 },  L2(9),  840000, 242 },
+	{ 1, { 1036800, HFPLL, 1,  54 }, L2(10),  850000, 264 },
+	{ 0, { 1113600, HFPLL, 1,  58 }, L2(10),  865000, 287 },
+	{ 1, { 1190400, HFPLL, 1,  62 }, L2(10),  875000, 308 },
+	{ 1, { 1267200, HFPLL, 1,  66 }, L2(13),  890000, 333 },
+	{ 0, { 1344000, HFPLL, 1,  70 }, L2(14),  900000, 356 },
+	{ 0, { 1420800, HFPLL, 1,  74 }, L2(15),  915000, 380 },
+	{ 1, { 1497600, HFPLL, 1,  78 }, L2(16),  925000, 404 },
+	{ 1, { 1574400, HFPLL, 1,  82 }, L2(17),  940000, 430 },
+	{ 0, { 1651200, HFPLL, 1,  86 }, L2(17),  955000, 456 },
+	{ 1, { 1728000, HFPLL, 1,  90 }, L2(18),  970000, 482 },
+	{ 0, { 1804800, HFPLL, 1,  94 }, L2(18),  985000, 510 },
+	{ 0, { 1881600, HFPLL, 1,  98 }, L2(18), 1000000, 538 },
+	{ 1, { 1958400, HFPLL, 1, 102 }, L2(19), 1015000, 565 },
+	{ 0, { 2035200, HFPLL, 1, 106 }, L2(19), 1030000, 596 },
+	{ 0, { 2112000, HFPLL, 1, 110 }, L2(19), 1045000, 627 },
+	{ 0, { 2188800, HFPLL, 1, 114 }, L2(19), 1060000, 659 },
+	{ 1, { 2265600, HFPLL, 1, 118 }, L2(19), 1075000, 691 },
 	{ 0, { 0 } }
 };
 
+static struct acpu_level acpu_ftbl_pro_2p3g_pvs1[] __initdata = {
+	{ 1, {  300000, PLL_0, 0,   0 },  L2(0),  775000,  72},
+	{ 0, {  345600, HFPLL, 2,  36 },  L2(1),  775000,  83},
+	{ 1, {  422400, HFPLL, 2,  44 },  L2(2),  775000, 101},
+	{ 0, {  499200, HFPLL, 2,  52 },  L2(2),  775000, 120},
+	{ 0, {  576000, HFPLL, 1,  30 },  L2(3),  775000, 139},
+	{ 1, {  652800, HFPLL, 1,  34 },  L2(3),  785000, 159},
+	{ 1, {  729600, HFPLL, 1,  38 },  L2(4),  795000, 180},
+	{ 0, {  806400, HFPLL, 1,  42 },  L2(4),  805000, 200},
+	{ 1, {  883200, HFPLL, 1,  46 },  L2(4),  815000, 221},
+	{ 1, {  960000, HFPLL, 1,  50 },  L2(9),  825000, 242},
+	{ 1, { 1036800, HFPLL, 1,  54 }, L2(10),  835000, 264},
+	{ 0, { 1113600, HFPLL, 1,  58 }, L2(10),  850000, 287},
+	{ 1, { 1190400, HFPLL, 1,  62 }, L2(10),  860000, 308},
+	{ 1, { 1267200, HFPLL, 1,  66 }, L2(13),  870000, 333},
+	{ 0, { 1344000, HFPLL, 1,  70 }, L2(14),  885000, 356},
+	{ 0, { 1420800, HFPLL, 1,  74 }, L2(15),  895000, 380},
+	{ 1, { 1497600, HFPLL, 1,  78 }, L2(16),  905000, 404},
+	{ 1, { 1574400, HFPLL, 1,  82 }, L2(17),  920000, 430},
+	{ 0, { 1651200, HFPLL, 1,  86 }, L2(17),  935000, 456},
+	{ 1, { 1728000, HFPLL, 1,  90 }, L2(18),  950000, 482},
+	{ 0, { 1804800, HFPLL, 1,  94 }, L2(18),  965000, 510},
+	{ 0, { 1881600, HFPLL, 1,  98 }, L2(18),  980000, 538},
+	{ 1, { 1958400, HFPLL, 1, 102 }, L2(19),  995000, 565},
+	{ 0, { 2035200, HFPLL, 1, 106 }, L2(19), 1005000, 596},
+	{ 0, { 2112000, HFPLL, 1, 110 }, L2(19), 1020000, 627},
+	{ 0, { 2188800, HFPLL, 1, 114 }, L2(19), 1035000, 659},
+	{ 1, { 2265600, HFPLL, 1, 118 }, L2(19), 1050000, 691},
+	{ 0, { 0 } }
+};
+
+static struct acpu_level acpu_ftbl_pro_2p3g_pvs2[] __initdata = {
+	{ 1, {  300000, PLL_0, 0,   0 },  L2(0),  750000,  72 },
+	{ 0, {  345600, HFPLL, 2,  36 },  L2(1),  750000,  83 },
+	{ 1, {  422400, HFPLL, 2,  44 },  L2(2),  750000, 101 },
+	{ 0, {  499200, HFPLL, 2,  52 },  L2(2),  750000, 120 },
+	{ 0, {  576000, HFPLL, 1,  30 },  L2(3),  760000, 139 },
+	{ 1, {  652800, HFPLL, 1,  34 },  L2(3),  770000, 159 },
+	{ 1, {  729600, HFPLL, 1,  38 },  L2(4),  780000, 180 },
+	{ 0, {  806400, HFPLL, 1,  42 },  L2(4),  790000, 200 },
+	{ 1, {  883200, HFPLL, 1,  46 },  L2(4),  800000, 221 },
+	{ 1, {  960000, HFPLL, 1,  50 },  L2(9),  810000, 242 },
+	{ 1, { 1036800, HFPLL, 1,  54 }, L2(10),  820000, 264 },
+	{ 0, { 1113600, HFPLL, 1,  58 }, L2(10),  830000, 287 },
+	{ 1, { 1190400, HFPLL, 1,  62 }, L2(10),  840000, 308 },
+	{ 1, { 1267200, HFPLL, 1,  66 }, L2(13),  850000, 333 },
+	{ 0, { 1344000, HFPLL, 1,  70 }, L2(14),  865000, 356 },
+	{ 0, { 1420800, HFPLL, 1,  74 }, L2(15),  875000, 380 },
+	{ 1, { 1497600, HFPLL, 1,  78 }, L2(16),  885000, 404 },
+	{ 1, { 1574400, HFPLL, 1,  82 }, L2(17),  900000, 430 },
+	{ 0, { 1651200, HFPLL, 1,  86 }, L2(17),  915000, 456 },
+	{ 1, { 1728000, HFPLL, 1,  90 }, L2(18),  930000, 482 },
+	{ 0, { 1804800, HFPLL, 1,  94 }, L2(18),  945000, 510 },
+	{ 0, { 1881600, HFPLL, 1,  98 }, L2(18),  955000, 538 },
+	{ 1, { 1958400, HFPLL, 1, 102 }, L2(19),  970000, 565 },
+	{ 0, { 2035200, HFPLL, 1, 106 }, L2(19),  980000, 596 },
+	{ 0, { 2112000, HFPLL, 1, 110 }, L2(19),  995000, 627 },
+	{ 0, { 2188800, HFPLL, 1, 114 }, L2(19), 1010000, 659 },
+	{ 1, { 2265600, HFPLL, 1, 118 }, L2(19), 1025000, 691 },
+	{ 0, { 0 } }
+};
+
+static struct acpu_level acpu_ftbl_pro_2p3g_pvs3[] __initdata = {
+	{ 1, {  300000, PLL_0, 0,   0 },  L2(0),  750000,  72},
+	{ 0, {  345600, HFPLL, 2,  36 },  L2(1),  750000,  83},
+	{ 1, {  422400, HFPLL, 2,  44 },  L2(2),  750000, 101},
+	{ 0, {  499200, HFPLL, 2,  52 },  L2(2),  750000, 120},
+	{ 0, {  576000, HFPLL, 1,  30 },  L2(3),  750000, 139},
+	{ 1, {  652800, HFPLL, 1,  34 },  L2(3),  755000, 159},
+	{ 1, {  729600, HFPLL, 1,  38 },  L2(4),  765000, 180},
+	{ 0, {  806400, HFPLL, 1,  42 },  L2(4),  775000, 200},
+	{ 1, {  883200, HFPLL, 1,  46 },  L2(4),  785000, 221},
+	{ 1, {  960000, HFPLL, 1,  50 },  L2(9),  795000, 242},
+	{ 1, { 1036800, HFPLL, 1,  54 }, L2(10),  805000, 264},
+	{ 0, { 1113600, HFPLL, 1,  58 }, L2(10),  815000, 287},
+	{ 1, { 1190400, HFPLL, 1,  62 }, L2(10),  825000, 308},
+	{ 1, { 1267200, HFPLL, 1,  66 }, L2(13),  835000, 333},
+	{ 0, { 1344000, HFPLL, 1,  70 }, L2(14),  850000, 356},
+	{ 0, { 1420800, HFPLL, 1,  74 }, L2(15),  860000, 380},
+	{ 1, { 1497600, HFPLL, 1,  78 }, L2(16),  870000, 404},
+	{ 1, { 1574400, HFPLL, 1,  82 }, L2(17),  885000, 430},
+	{ 0, { 1651200, HFPLL, 1,  86 }, L2(17),  900000, 456},
+	{ 1, { 1728000, HFPLL, 1,  90 }, L2(18),  910000, 482},
+	{ 0, { 1804800, HFPLL, 1,  94 }, L2(18),  925000, 510},
+	{ 0, { 1881600, HFPLL, 1,  98 }, L2(18),  935000, 538},
+	{ 1, { 1958400, HFPLL, 1, 102 }, L2(19),  945000, 565},
+	{ 0, { 2035200, HFPLL, 1, 106 }, L2(19),  960000, 596},
+	{ 0, { 2112000, HFPLL, 1, 110 }, L2(19),  970000, 627},
+	{ 0, { 2188800, HFPLL, 1, 114 }, L2(19),  985000, 659},
+	{ 1, { 2265600, HFPLL, 1, 118 }, L2(19), 1000000, 691},
+	{ 0, { 0 } }
+};
+
+static struct acpu_level acpu_ftbl_pro_2p3g_pvs4[] __initdata = {
+	{ 1, {  300000, PLL_0, 0,   0 },  L2(0),  750000,  72},
+	{ 0, {  345600, HFPLL, 2,  36 },  L2(1),  750000,  83},
+	{ 1, {  422400, HFPLL, 2,  44 },  L2(2),  750000, 101},
+	{ 0, {  499200, HFPLL, 2,  52 },  L2(2),  750000, 120},
+	{ 0, {  576000, HFPLL, 1,  30 },  L2(3),  750000, 139},
+	{ 1, {  652800, HFPLL, 1,  34 },  L2(3),  750000, 159},
+	{ 1, {  729600, HFPLL, 1,  38 },  L2(4),  755000, 180},
+	{ 0, {  806400, HFPLL, 1,  42 },  L2(4),  765000, 200},
+	{ 1, {  883200, HFPLL, 1,  46 },  L2(4),  775000, 221},
+	{ 1, {  960000, HFPLL, 1,  50 },  L2(9),  785000, 242},
+	{ 1, { 1036800, HFPLL, 1,  54 }, L2(10),  795000, 264},
+	{ 0, { 1113600, HFPLL, 1,  58 }, L2(10),  805000, 287},
+	{ 1, { 1190400, HFPLL, 1,  62 }, L2(10),  815000, 308},
+	{ 1, { 1267200, HFPLL, 1,  66 }, L2(13),  825000, 333},
+	{ 0, { 1344000, HFPLL, 1,  70 }, L2(14),  835000, 356},
+	{ 0, { 1420800, HFPLL, 1,  74 }, L2(15),  845000, 380},
+	{ 1, { 1497600, HFPLL, 1,  78 }, L2(16),  855000, 404},
+	{ 1, { 1574400, HFPLL, 1,  82 }, L2(17),  870000, 430},
+	{ 0, { 1651200, HFPLL, 1,  86 }, L2(17),  885000, 456},
+	{ 1, { 1728000, HFPLL, 1,  90 }, L2(18),  895000, 482},
+	{ 0, { 1804800, HFPLL, 1,  94 }, L2(18),  905000, 510},
+	{ 0, { 1881600, HFPLL, 1,  98 }, L2(18),  915000, 538},
+	{ 1, { 1958400, HFPLL, 1, 102 }, L2(19),  925000, 565},
+	{ 0, { 2035200, HFPLL, 1, 106 }, L2(19),  935000, 596},
+	{ 0, { 2112000, HFPLL, 1, 110 }, L2(19),  950000, 627},
+	{ 0, { 2188800, HFPLL, 1, 114 }, L2(19),  960000, 659},
+	{ 1, { 2265600, HFPLL, 1, 118 }, L2(19),  975000, 691},
+	{ 0, { 0 } }
+};
+
+static struct acpu_level acpu_ftbl_pro_2p3g_pvs5[] __initdata = {
+	{ 1, {  300000, PLL_0, 0,   0 },  L2(0),  725000,  72},
+	{ 0, {  345600, HFPLL, 2,  36 },  L2(1),  725000,  83},
+	{ 1, {  422400, HFPLL, 2,  44 },  L2(2),  725000, 101},
+	{ 0, {  499200, HFPLL, 2,  52 },  L2(2),  725000, 120},
+	{ 0, {  576000, HFPLL, 1,  30 },  L2(3),  725000, 139},
+	{ 1, {  652800, HFPLL, 1,  34 },  L2(3),  735000, 159},
+	{ 1, {  729600, HFPLL, 1,  38 },  L2(4),  745000, 180},
+	{ 0, {  806400, HFPLL, 1,  42 },  L2(4),  755000, 200},
+	{ 1, {  883200, HFPLL, 1,  46 },  L2(4),  765000, 221},
+	{ 1, {  960000, HFPLL, 1,  50 },  L2(9),  775000, 242},
+	{ 1, { 1036800, HFPLL, 1,  54 }, L2(10),  785000, 264},
+	{ 0, { 1113600, HFPLL, 1,  58 }, L2(10),  795000, 287},
+	{ 1, { 1190400, HFPLL, 1,  62 }, L2(10),  805000, 308},
+	{ 1, { 1267200, HFPLL, 1,  66 }, L2(13),  815000, 333},
+	{ 0, { 1344000, HFPLL, 1,  70 }, L2(14),  825000, 356},
+	{ 0, { 1420800, HFPLL, 1,  74 }, L2(15),  835000, 380},
+	{ 1, { 1497600, HFPLL, 1,  78 }, L2(16),  845000, 404},
+	{ 1, { 1574400, HFPLL, 1,  82 }, L2(17),  855000, 430},
+	{ 0, { 1651200, HFPLL, 1,  86 }, L2(17),  865000, 456},
+	{ 1, { 1728000, HFPLL, 1,  90 }, L2(18),  875000, 482},
+	{ 0, { 1804800, HFPLL, 1,  94 }, L2(18),  885000, 510},
+	{ 0, { 1881600, HFPLL, 1,  98 }, L2(18),  895000, 538},
+	{ 1, { 1958400, HFPLL, 1, 102 }, L2(19),  905000, 565},
+	{ 0, { 2035200, HFPLL, 1, 106 }, L2(19),  915000, 596},
+	{ 0, { 2112000, HFPLL, 1, 110 }, L2(19),  930000, 627},
+	{ 0, { 2188800, HFPLL, 1, 114 }, L2(19),  940000, 659},
+	{ 1, { 2265600, HFPLL, 1, 118 }, L2(19),  950000, 691},
+	{ 0, { 0 } }
+};
+
+static struct acpu_level acpu_ftbl_pro_2p3g_pvs6[] __initdata = {
+	{ 1, {  300000, PLL_0, 0,   0 },  L2(0),  725000,  72},
+	{ 0, {  345600, HFPLL, 2,  36 },  L2(1),  725000,  83},
+	{ 1, {  422400, HFPLL, 2,  44 },  L2(2),  725000, 101},
+	{ 0, {  499200, HFPLL, 2,  52 },  L2(2),  725000, 120},
+	{ 0, {  576000, HFPLL, 1,  30 },  L2(3),  725000, 139},
+	{ 1, {  652800, HFPLL, 1,  34 },  L2(3),  725000, 159},
+	{ 1, {  729600, HFPLL, 1,  38 },  L2(4),  735000, 180},
+	{ 0, {  806400, HFPLL, 1,  42 },  L2(4),  745000, 200},
+	{ 1, {  883200, HFPLL, 1,  46 },  L2(4),  755000, 221},
+	{ 1, {  960000, HFPLL, 1,  50 },  L2(9),  765000, 242},
+	{ 1, { 1036800, HFPLL, 1,  54 }, L2(10),  775000, 264},
+	{ 0, { 1113600, HFPLL, 1,  58 }, L2(10),  785000, 287},
+	{ 1, { 1190400, HFPLL, 1,  62 }, L2(10),  795000, 308},
+	{ 1, { 1267200, HFPLL, 1,  66 }, L2(13),  805000, 333},
+	{ 0, { 1344000, HFPLL, 1,  70 }, L2(14),  815000, 356},
+	{ 0, { 1420800, HFPLL, 1,  74 }, L2(15),  825000, 380},
+	{ 1, { 1497600, HFPLL, 1,  78 }, L2(16),  835000, 404},
+	{ 1, { 1574400, HFPLL, 1,  82 }, L2(17),  845000, 430},
+	{ 0, { 1651200, HFPLL, 1,  86 }, L2(17),  850000, 456},
+	{ 1, { 1728000, HFPLL, 1,  90 }, L2(18),  860000, 482},
+	{ 0, { 1804800, HFPLL, 1,  94 }, L2(18),  870000, 510},
+	{ 0, { 1881600, HFPLL, 1,  98 }, L2(18),  880000, 538},
+	{ 1, { 1958400, HFPLL, 1, 102 }, L2(19),  890000, 565},
+	{ 0, { 2035200, HFPLL, 1, 106 }, L2(19),  895000, 596},
+	{ 0, { 2112000, HFPLL, 1, 110 }, L2(19),  905000, 627},
+	{ 0, { 2188800, HFPLL, 1, 114 }, L2(19),  915000, 659},
+	{ 1, { 2265600, HFPLL, 1, 118 }, L2(19),  925000, 691},
+	{ 0, { 0 } }
+};
+
+static struct acpu_level acpu_ftbl_pro_2p5g_pvs0[] __initdata = {
+	{ 1, {  300000, PLL_0, 0,   0 },  L2(0),  800000,  76},
+	{ 0, {  345600, HFPLL, 2,  36 },  L2(1),  800000,  87},
+	{ 1, {  422400, HFPLL, 2,  44 },  L2(2),  800000, 106},
+	{ 0, {  499200, HFPLL, 2,  52 },  L2(2),  800000, 125},
+	{ 0, {  576000, HFPLL, 1,  30 },  L2(3),  800000, 145},
+	{ 1, {  652800, HFPLL, 1,  34 },  L2(3),  800000, 164},
+	{ 1, {  729600, HFPLL, 1,  38 },  L2(4),  800000, 183},
+	{ 0, {  806400, HFPLL, 1,  42 },  L2(4),  800000, 202},
+	{ 1, {  883200, HFPLL, 1,  46 },  L2(4),  800000, 222},
+	{ 1, {  960000, HFPLL, 1,  50 },  L2(9),  800000, 241},
+	{ 1, { 1036800, HFPLL, 1,  54 }, L2(10),  805000, 261},
+	{ 0, { 1113600, HFPLL, 1,  58 }, L2(10),  815000, 282},
+	{ 1, { 1190400, HFPLL, 1,  62 }, L2(10),  825000, 305},
+	{ 1, { 1267200, HFPLL, 1,  66 }, L2(13),  835000, 327},
+	{ 0, { 1344000, HFPLL, 1,  70 }, L2(14),  845000, 350},
+	{ 0, { 1420800, HFPLL, 1,  74 }, L2(15),  855000, 373},
+	{ 1, { 1497600, HFPLL, 1,  78 }, L2(16),  870000, 398},
+	{ 1, { 1574400, HFPLL, 1,  82 }, L2(17),  885000, 424},
+	{ 0, { 1651200, HFPLL, 1,  86 }, L2(17),  900000, 449},
+	{ 1, { 1728000, HFPLL, 1,  90 }, L2(18),  915000, 476},
+	{ 0, { 1804800, HFPLL, 1,  94 }, L2(18),  930000, 503},
+	{ 0, { 1881600, HFPLL, 1,  98 }, L2(18),  945000, 530},
+	{ 1, { 1958400, HFPLL, 1, 102 }, L2(19),  960000, 559},
+	{ 0, { 2035200, HFPLL, 1, 106 }, L2(19),  980000, 590},
+	{ 0, { 2112000, HFPLL, 1, 110 }, L2(19), 1000000, 621},
+	{ 0, { 2188800, HFPLL, 1, 114 }, L2(19), 1020000, 654},
+	{ 1, { 2265600, HFPLL, 1, 118 }, L2(19), 1040000, 686},
+	{ 0, { 2342400, HFPLL, 1, 122 }, L2(19), 1060000, 723},
+	{ 0, { 2419200, HFPLL, 1, 126 }, L2(19), 1080000, 761},
+	{ 1, { 2496000, HFPLL, 1, 130 }, L2(19), 1100000, 800},
+	{ 0, { 0 } }
+};
+
+static struct acpu_level acpu_ftbl_pro_2p5g_pvs1[] __initdata = {
+	{ 1, {  300000, PLL_0, 0,   0 },  L2(0),  800000,  76},
+	{ 0, {  345600, HFPLL, 2,  36 },  L2(1),  800000,  87},
+	{ 1, {  422400, HFPLL, 2,  44 },  L2(2),  800000, 106},
+	{ 0, {  499200, HFPLL, 2,  52 },  L2(2),  800000, 125},
+	{ 0, {  576000, HFPLL, 1,  30 },  L2(3),  800000, 145},
+	{ 1, {  652800, HFPLL, 1,  34 },  L2(3),  800000, 164},
+	{ 1, {  729600, HFPLL, 1,  38 },  L2(4),  800000, 183},
+	{ 0, {  806400, HFPLL, 1,  42 },  L2(4),  800000, 202},
+	{ 1, {  883200, HFPLL, 1,  46 },  L2(4),  800000, 222},
+	{ 1, {  960000, HFPLL, 1,  50 },  L2(9),  800000, 241},
+	{ 1, { 1036800, HFPLL, 1,  54 }, L2(10),  800000, 261},
+	{ 0, { 1113600, HFPLL, 1,  58 }, L2(10),  805000, 282},
+	{ 1, { 1190400, HFPLL, 1,  62 }, L2(10),  815000, 305},
+	{ 1, { 1267200, HFPLL, 1,  66 }, L2(13),  825000, 327},
+	{ 0, { 1344000, HFPLL, 1,  70 }, L2(14),  835000, 350},
+	{ 0, { 1420800, HFPLL, 1,  74 }, L2(15),  845000, 373},
+	{ 1, { 1497600, HFPLL, 1,  78 }, L2(16),  855000, 398},
+	{ 1, { 1574400, HFPLL, 1,  82 }, L2(17),  870000, 424},
+	{ 0, { 1651200, HFPLL, 1,  86 }, L2(17),  885000, 449},
+	{ 1, { 1728000, HFPLL, 1,  90 }, L2(18),  900000, 476},
+	{ 0, { 1804800, HFPLL, 1,  94 }, L2(18),  915000, 503},
+	{ 0, { 1881600, HFPLL, 1,  98 }, L2(18),  930000, 530},
+	{ 1, { 1958400, HFPLL, 1, 102 }, L2(19),  945000, 559},
+	{ 0, { 2035200, HFPLL, 1, 106 }, L2(19),  960000, 590},
+	{ 0, { 2112000, HFPLL, 1, 110 }, L2(19),  975000, 621},
+	{ 0, { 2188800, HFPLL, 1, 114 }, L2(19),  995000, 654},
+	{ 1, { 2265600, HFPLL, 1, 118 }, L2(19), 1015000, 686},
+	{ 0, { 2342400, HFPLL, 1, 122 }, L2(19), 1035000, 723},
+	{ 0, { 2419200, HFPLL, 1, 126 }, L2(19), 1055000, 761},
+	{ 1, { 2496000, HFPLL, 1, 130 }, L2(19), 1075000, 800},
+	{ 0, { 0 } }
+};
+
+static struct acpu_level acpu_ftbl_pro_2p5g_pvs2[] __initdata = {
+	{ 1, {  300000, PLL_0, 0,   0 },  L2(0),  775000,  76},
+	{ 0, {  345600, HFPLL, 2,  36 },  L2(1),  775000,  87},
+	{ 1, {  422400, HFPLL, 2,  44 },  L2(2),  775000, 106},
+	{ 0, {  499200, HFPLL, 2,  52 },  L2(2),  775000, 125},
+	{ 0, {  576000, HFPLL, 1,  30 },  L2(3),  775000, 145},
+	{ 1, {  652800, HFPLL, 1,  34 },  L2(3),  775000, 164},
+	{ 1, {  729600, HFPLL, 1,  38 },  L2(4),  775000, 183},
+	{ 0, {  806400, HFPLL, 1,  42 },  L2(4),  775000, 202},
+	{ 1, {  883200, HFPLL, 1,  46 },  L2(4),  775000, 222},
+	{ 1, {  960000, HFPLL, 1,  50 },  L2(9),  775000, 241},
+	{ 1, { 1036800, HFPLL, 1,  54 }, L2(10),  780000, 261},
+	{ 0, { 1113600, HFPLL, 1,  58 }, L2(10),  790000, 282},
+	{ 1, { 1190400, HFPLL, 1,  62 }, L2(10),  800000, 305},
+	{ 1, { 1267200, HFPLL, 1,  66 }, L2(13),  810000, 327},
+	{ 0, { 1344000, HFPLL, 1,  70 }, L2(14),  820000, 350},
+	{ 0, { 1420800, HFPLL, 1,  74 }, L2(15),  830000, 373},
+	{ 1, { 1497600, HFPLL, 1,  78 }, L2(16),  840000, 398},
+	{ 1, { 1574400, HFPLL, 1,  82 }, L2(17),  850000, 424},
+	{ 0, { 1651200, HFPLL, 1,  86 }, L2(17),  865000, 449},
+	{ 1, { 1728000, HFPLL, 1,  90 }, L2(18),  880000, 476},
+	{ 0, { 1804800, HFPLL, 1,  94 }, L2(18),  895000, 503},
+	{ 0, { 1881600, HFPLL, 1,  98 }, L2(18),  910000, 530},
+	{ 1, { 1958400, HFPLL, 1, 102 }, L2(19),  925000, 559},
+	{ 0, { 2035200, HFPLL, 1, 106 }, L2(19),  940000, 590},
+	{ 0, { 2112000, HFPLL, 1, 110 }, L2(19),  955000, 621},
+	{ 0, { 2188800, HFPLL, 1, 114 }, L2(19),  970000, 654},
+	{ 1, { 2265600, HFPLL, 1, 118 }, L2(19),  990000, 686},
+	{ 0, { 2342400, HFPLL, 1, 122 }, L2(19), 1010000, 723},
+	{ 0, { 2419200, HFPLL, 1, 126 }, L2(19), 1030000, 761},
+	{ 1, { 2496000, HFPLL, 1, 130 }, L2(19), 1050000, 800},
+	{ 0, { 0 } }
+};
+
+static struct acpu_level acpu_ftbl_pro_2p5g_pvs3[] __initdata = {
+	{ 1, {  300000, PLL_0, 0,   0 },  L2(0),  775000,  76},
+	{ 0, {  345600, HFPLL, 2,  36 },  L2(1),  775000,  87},
+	{ 1, {  422400, HFPLL, 2,  44 },  L2(2),  775000, 106},
+	{ 0, {  499200, HFPLL, 2,  52 },  L2(2),  775000, 125},
+	{ 0, {  576000, HFPLL, 1,  30 },  L2(3),  775000, 145},
+	{ 1, {  652800, HFPLL, 1,  34 },  L2(3),  775000, 164},
+	{ 1, {  729600, HFPLL, 1,  38 },  L2(4),  775000, 183},
+	{ 0, {  806400, HFPLL, 1,  42 },  L2(4),  775000, 202},
+	{ 1, {  883200, HFPLL, 1,  46 },  L2(4),  775000, 222},
+	{ 1, {  960000, HFPLL, 1,  50 },  L2(9),  775000, 241},
+	{ 1, { 1036800, HFPLL, 1,  54 }, L2(10),  775000, 261},
+	{ 0, { 1113600, HFPLL, 1,  58 }, L2(10),  780000, 282},
+	{ 1, { 1190400, HFPLL, 1,  62 }, L2(10),  790000, 305},
+	{ 1, { 1267200, HFPLL, 1,  66 }, L2(13),  800000, 327},
+	{ 0, { 1344000, HFPLL, 1,  70 }, L2(14),  810000, 350},
+	{ 0, { 1420800, HFPLL, 1,  74 }, L2(15),  820000, 373},
+	{ 1, { 1497600, HFPLL, 1,  78 }, L2(16),  830000, 398},
+	{ 1, { 1574400, HFPLL, 1,  82 }, L2(17),  840000, 424},
+	{ 0, { 1651200, HFPLL, 1,  86 }, L2(17),  850000, 449},
+	{ 1, { 1728000, HFPLL, 1,  90 }, L2(18),  865000, 476},
+	{ 0, { 1804800, HFPLL, 1,  94 }, L2(18),  880000, 503},
+	{ 0, { 1881600, HFPLL, 1,  98 }, L2(18),  895000, 530},
+	{ 1, { 1958400, HFPLL, 1, 102 }, L2(19),  910000, 559},
+	{ 0, { 2035200, HFPLL, 1, 106 }, L2(19),  925000, 590},
+	{ 0, { 2112000, HFPLL, 1, 110 }, L2(19),  940000, 621},
+	{ 0, { 2188800, HFPLL, 1, 114 }, L2(19),  955000, 654},
+	{ 1, { 2265600, HFPLL, 1, 118 }, L2(19),  970000, 686},
+	{ 0, { 2342400, HFPLL, 1, 122 }, L2(19),  985000, 723},
+	{ 0, { 2419200, HFPLL, 1, 126 }, L2(19), 1005000, 761},
+	{ 1, { 2496000, HFPLL, 1, 130 }, L2(19), 1025000, 800},
+	{ 0, { 0 } }
+};
+
+static struct acpu_level acpu_ftbl_pro_2p5g_pvs4[] __initdata = {
+	{ 1, {  300000, PLL_0, 0,   0 },  L2(0),  750000,  76},
+	{ 0, {  345600, HFPLL, 2,  36 },  L2(1),  750000,  87},
+	{ 1, {  422400, HFPLL, 2,  44 },  L2(2),  750000, 106},
+	{ 0, {  499200, HFPLL, 2,  52 },  L2(2),  750000, 125},
+	{ 0, {  576000, HFPLL, 1,  30 },  L2(3),  750000, 145},
+	{ 1, {  652800, HFPLL, 1,  34 },  L2(3),  750000, 164},
+	{ 1, {  729600, HFPLL, 1,  38 },  L2(4),  750000, 183},
+	{ 0, {  806400, HFPLL, 1,  42 },  L2(4),  750000, 202},
+	{ 1, {  883200, HFPLL, 1,  46 },  L2(4),  750000, 222},
+	{ 1, {  960000, HFPLL, 1,  50 },  L2(9),  750000, 241},
+	{ 1, { 1036800, HFPLL, 1,  54 }, L2(10),  760000, 261},
+	{ 0, { 1113600, HFPLL, 1,  58 }, L2(10),  770000, 282},
+	{ 1, { 1190400, HFPLL, 1,  62 }, L2(10),  780000, 305},
+	{ 1, { 1267200, HFPLL, 1,  66 }, L2(13),  790000, 327},
+	{ 0, { 1344000, HFPLL, 1,  70 }, L2(14),  800000, 350},
+	{ 0, { 1420800, HFPLL, 1,  74 }, L2(15),  810000, 373},
+	{ 1, { 1497600, HFPLL, 1,  78 }, L2(16),  820000, 398},
+	{ 1, { 1574400, HFPLL, 1,  82 }, L2(17),  830000, 424},
+	{ 0, { 1651200, HFPLL, 1,  86 }, L2(17),  840000, 449},
+	{ 1, { 1728000, HFPLL, 1,  90 }, L2(18),  850000, 476},
+	{ 0, { 1804800, HFPLL, 1,  94 }, L2(18),  865000, 503},
+	{ 0, { 1881600, HFPLL, 1,  98 }, L2(18),  880000, 530},
+	{ 1, { 1958400, HFPLL, 1, 102 }, L2(19),  895000, 559},
+	{ 0, { 2035200, HFPLL, 1, 106 }, L2(19),  910000, 590},
+	{ 0, { 2112000, HFPLL, 1, 110 }, L2(19),  925000, 621},
+	{ 0, { 2188800, HFPLL, 1, 114 }, L2(19),  940000, 654},
+	{ 1, { 2265600, HFPLL, 1, 118 }, L2(19),  955000, 686},
+	{ 0, { 2342400, HFPLL, 1, 122 }, L2(19),  970000, 723},
+	{ 0, { 2419200, HFPLL, 1, 126 }, L2(19),  985000, 761},
+	{ 1, { 2496000, HFPLL, 1, 130 }, L2(19), 1000000, 800},
+	{ 0, { 0 } }
+};
+
+static struct acpu_level acpu_ftbl_pro_2p5g_pvs5[] __initdata = {
+	{ 1, {  300000, PLL_0, 0,   0 },  L2(0),  750000,  76},
+	{ 0, {  345600, HFPLL, 2,  36 },  L2(1),  750000,  87},
+	{ 1, {  422400, HFPLL, 2,  44 },  L2(2),  750000, 106},
+	{ 0, {  499200, HFPLL, 2,  52 },  L2(2),  750000, 125},
+	{ 0, {  576000, HFPLL, 1,  30 },  L2(3),  750000, 145},
+	{ 1, {  652800, HFPLL, 1,  34 },  L2(3),  750000, 164},
+	{ 1, {  729600, HFPLL, 1,  38 },  L2(4),  750000, 183},
+	{ 0, {  806400, HFPLL, 1,  42 },  L2(4),  750000, 202},
+	{ 1, {  883200, HFPLL, 1,  46 },  L2(4),  750000, 222},
+	{ 1, {  960000, HFPLL, 1,  50 },  L2(9),  750000, 241},
+	{ 1, { 1036800, HFPLL, 1,  54 }, L2(10),  750000, 261},
+	{ 0, { 1113600, HFPLL, 1,  58 }, L2(10),  760000, 282},
+	{ 1, { 1190400, HFPLL, 1,  62 }, L2(10),  770000, 305},
+	{ 1, { 1267200, HFPLL, 1,  66 }, L2(13),  780000, 327},
+	{ 0, { 1344000, HFPLL, 1,  70 }, L2(14),  790000, 350},
+	{ 0, { 1420800, HFPLL, 1,  74 }, L2(15),  800000, 373},
+	{ 1, { 1497600, HFPLL, 1,  78 }, L2(16),  810000, 398},
+	{ 1, { 1574400, HFPLL, 1,  82 }, L2(17),  820000, 424},
+	{ 0, { 1651200, HFPLL, 1,  86 }, L2(17),  830000, 449},
+	{ 1, { 1728000, HFPLL, 1,  90 }, L2(18),  840000, 476},
+	{ 0, { 1804800, HFPLL, 1,  94 }, L2(18),  850000, 503},
+	{ 0, { 1881600, HFPLL, 1,  98 }, L2(18),  860000, 530},
+	{ 1, { 1958400, HFPLL, 1, 102 }, L2(19),  870000, 559},
+	{ 0, { 2035200, HFPLL, 1, 106 }, L2(19),  885000, 590},
+	{ 0, { 2112000, HFPLL, 1, 110 }, L2(19),  900000, 621},
+	{ 0, { 2188800, HFPLL, 1, 114 }, L2(19),  915000, 654},
+	{ 1, { 2265600, HFPLL, 1, 118 }, L2(19),  930000, 686},
+	{ 0, { 2342400, HFPLL, 1, 122 }, L2(19),  945000, 723},
+	{ 0, { 2419200, HFPLL, 1, 126 }, L2(19),  960000, 761},
+	{ 1, { 2496000, HFPLL, 1, 130 }, L2(19),  975000, 800},
+	{ 0, { 0 } }
+};
+
+static struct acpu_level acpu_ftbl_pro_2p5g_pvs6[] __initdata = {
+	{ 1, {  300000, PLL_0, 0,   0 },  L2(0),  725000,  76},
+	{ 0, {  345600, HFPLL, 2,  36 },  L2(1),  725000,  87},
+	{ 1, {  422400, HFPLL, 2,  44 },  L2(2),  725000, 106},
+	{ 0, {  499200, HFPLL, 2,  52 },  L2(2),  725000, 125},
+	{ 0, {  576000, HFPLL, 1,  30 },  L2(3),  725000, 145},
+	{ 1, {  652800, HFPLL, 1,  34 },  L2(3),  725000, 164},
+	{ 1, {  729600, HFPLL, 1,  38 },  L2(4),  725000, 183},
+	{ 0, {  806400, HFPLL, 1,  42 },  L2(4),  725000, 202},
+	{ 1, {  883200, HFPLL, 1,  46 },  L2(4),  725000, 222},
+	{ 1, {  960000, HFPLL, 1,  50 },  L2(9),  725000, 241},
+	{ 1, { 1036800, HFPLL, 1,  54 }, L2(10),  735000, 261},
+	{ 0, { 1113600, HFPLL, 1,  58 }, L2(10),  745000, 282},
+	{ 1, { 1190400, HFPLL, 1,  62 }, L2(10),  755000, 305},
+	{ 1, { 1267200, HFPLL, 1,  66 }, L2(13),  765000, 327},
+	{ 0, { 1344000, HFPLL, 1,  70 }, L2(14),  775000, 350},
+	{ 0, { 1420800, HFPLL, 1,  74 }, L2(15),  785000, 373},
+	{ 1, { 1497600, HFPLL, 1,  78 }, L2(16),  795000, 398},
+	{ 1, { 1574400, HFPLL, 1,  82 }, L2(17),  805000, 424},
+	{ 0, { 1651200, HFPLL, 1,  86 }, L2(17),  815000, 449},
+	{ 1, { 1728000, HFPLL, 1,  90 }, L2(18),  825000, 476},
+	{ 0, { 1804800, HFPLL, 1,  94 }, L2(18),  835000, 503},
+	{ 0, { 1881600, HFPLL, 1,  98 }, L2(18),  845000, 530},
+	{ 1, { 1958400, HFPLL, 1, 102 }, L2(19),  855000, 559},
+	{ 0, { 2035200, HFPLL, 1, 106 }, L2(19),  865000, 590},
+	{ 0, { 2112000, HFPLL, 1, 110 }, L2(19),  875000, 621},
+	{ 0, { 2188800, HFPLL, 1, 114 }, L2(19),  890000, 654},
+	{ 1, { 2265600, HFPLL, 1, 118 }, L2(19),  905000, 686},
+	{ 0, { 2342400, HFPLL, 1, 122 }, L2(19),  920000, 723},
+	{ 0, { 2419200, HFPLL, 1, 126 }, L2(19),  935000, 761},
+	{ 1, { 2496000, HFPLL, 1, 130 }, L2(19),  950000, 800},
+	{ 0, { 0 } }
+};
 
 static struct pvs_table pvs_v1[NUM_SPEED_BINS][NUM_PVS] __initdata = {
 	/* 8974v1 1.7GHz Parts */
@@ -974,45 +1396,45 @@
 };
 
 static struct pvs_table pvs_pro[NUM_SPEED_BINS][NUM_PVS] __initdata = {
-	/* Not used by 8974Pro */
-	[0][0] = { acpu_freq_tbl_pro_pvs0, sizeof(acpu_freq_tbl_pro_pvs0) },
-	[0][1] = { acpu_freq_tbl_pro_pvs0, sizeof(acpu_freq_tbl_pro_pvs0) },
-	[0][2] = { acpu_freq_tbl_pro_pvs0, sizeof(acpu_freq_tbl_pro_pvs0) },
-	[0][3] = { acpu_freq_tbl_pro_pvs0, sizeof(acpu_freq_tbl_pro_pvs0) },
-	[0][4] = { acpu_freq_tbl_pro_pvs0, sizeof(acpu_freq_tbl_pro_pvs0) },
-	[0][5] = { acpu_freq_tbl_pro_pvs0, sizeof(acpu_freq_tbl_pro_pvs0) },
-	[0][6] = { acpu_freq_tbl_pro_pvs0, sizeof(acpu_freq_tbl_pro_pvs0) },
-	[0][7] = { acpu_freq_tbl_pro_pvs0, sizeof(acpu_freq_tbl_pro_pvs0) },
+	/* 2.0 GHz is not used on 8974Pro */
+	[0][0] = { acpu_freq_tbl_2g_pvs0, sizeof(acpu_freq_tbl_2g_pvs0) },
+	[0][1] = { acpu_freq_tbl_2g_pvs1, sizeof(acpu_freq_tbl_2g_pvs1) },
+	[0][2] = { acpu_freq_tbl_2g_pvs2, sizeof(acpu_freq_tbl_2g_pvs2) },
+	[0][3] = { acpu_freq_tbl_2g_pvs3, sizeof(acpu_freq_tbl_2g_pvs3) },
+	[0][4] = { acpu_freq_tbl_2g_pvs4, sizeof(acpu_freq_tbl_2g_pvs4) },
+	[0][5] = { acpu_freq_tbl_2g_pvs5, sizeof(acpu_freq_tbl_2g_pvs5) },
+	[0][6] = { acpu_freq_tbl_2g_pvs6, sizeof(acpu_freq_tbl_2g_pvs6) },
+	[0][7] = { acpu_freq_tbl_2g_pvs6, sizeof(acpu_freq_tbl_2g_pvs6) },
 
-	/* 8974Pro AB Bringup */
-	[1][0] = { acpu_freq_tbl_pro_pvs0, sizeof(acpu_freq_tbl_pro_pvs0) },
-	[1][1] = { acpu_freq_tbl_pro_pvs0, sizeof(acpu_freq_tbl_pro_pvs0) },
-	[1][2] = { acpu_freq_tbl_pro_pvs0, sizeof(acpu_freq_tbl_pro_pvs0) },
-	[1][3] = { acpu_freq_tbl_pro_pvs0, sizeof(acpu_freq_tbl_pro_pvs0) },
-	[1][4] = { acpu_freq_tbl_pro_pvs0, sizeof(acpu_freq_tbl_pro_pvs0) },
-	[1][5] = { acpu_freq_tbl_pro_pvs0, sizeof(acpu_freq_tbl_pro_pvs0) },
-	[1][6] = { acpu_freq_tbl_pro_pvs0, sizeof(acpu_freq_tbl_pro_pvs0) },
-	[1][7] = { acpu_freq_tbl_pro_pvs0, sizeof(acpu_freq_tbl_pro_pvs0) },
+	/* 8974Pro AB 2.3GHz */
+	[1][0] = { acpu_ftbl_pro_2p3g_pvs0, sizeof(acpu_ftbl_pro_2p3g_pvs0) },
+	[1][1] = { acpu_ftbl_pro_2p3g_pvs1, sizeof(acpu_ftbl_pro_2p3g_pvs1) },
+	[1][2] = { acpu_ftbl_pro_2p3g_pvs2, sizeof(acpu_ftbl_pro_2p3g_pvs2) },
+	[1][3] = { acpu_ftbl_pro_2p3g_pvs3, sizeof(acpu_ftbl_pro_2p3g_pvs3) },
+	[1][4] = { acpu_ftbl_pro_2p3g_pvs4, sizeof(acpu_ftbl_pro_2p3g_pvs4) },
+	[1][5] = { acpu_ftbl_pro_2p3g_pvs5, sizeof(acpu_ftbl_pro_2p3g_pvs5) },
+	[1][6] = { acpu_ftbl_pro_2p3g_pvs6, sizeof(acpu_ftbl_pro_2p3g_pvs6) },
+	[1][7] = { acpu_ftbl_pro_2p3g_pvs6, sizeof(acpu_ftbl_pro_2p3g_pvs6) },
 
-	/* Not used by 8974Pro */
-	[2][0] = { acpu_freq_tbl_pro_pvs0, sizeof(acpu_freq_tbl_pro_pvs0) },
-	[2][1] = { acpu_freq_tbl_pro_pvs0, sizeof(acpu_freq_tbl_pro_pvs0) },
-	[2][2] = { acpu_freq_tbl_pro_pvs0, sizeof(acpu_freq_tbl_pro_pvs0) },
-	[2][3] = { acpu_freq_tbl_pro_pvs0, sizeof(acpu_freq_tbl_pro_pvs0) },
-	[2][4] = { acpu_freq_tbl_pro_pvs0, sizeof(acpu_freq_tbl_pro_pvs0) },
-	[2][5] = { acpu_freq_tbl_pro_pvs0, sizeof(acpu_freq_tbl_pro_pvs0) },
-	[2][6] = { acpu_freq_tbl_pro_pvs0, sizeof(acpu_freq_tbl_pro_pvs0) },
-	[2][7] = { acpu_freq_tbl_pro_pvs0, sizeof(acpu_freq_tbl_pro_pvs0) },
+	/* 2.2GHz is not used on 8974Pro */
+	[2][0] = { acpu_freq_tbl_2p2g_pvs0, sizeof(acpu_freq_tbl_2p2g_pvs0) },
+	[2][1] = { acpu_freq_tbl_2p2g_pvs1, sizeof(acpu_freq_tbl_2p2g_pvs1) },
+	[2][2] = { acpu_freq_tbl_2p2g_pvs2, sizeof(acpu_freq_tbl_2p2g_pvs2) },
+	[2][3] = { acpu_freq_tbl_2p2g_pvs3, sizeof(acpu_freq_tbl_2p2g_pvs3) },
+	[2][4] = { acpu_freq_tbl_2p2g_pvs4, sizeof(acpu_freq_tbl_2p2g_pvs4) },
+	[2][5] = { acpu_freq_tbl_2p2g_pvs5, sizeof(acpu_freq_tbl_2p2g_pvs5) },
+	[2][6] = { acpu_freq_tbl_2p2g_pvs6, sizeof(acpu_freq_tbl_2p2g_pvs6) },
+	[2][7] = { acpu_freq_tbl_2p2g_pvs6, sizeof(acpu_freq_tbl_2p2g_pvs6) },
 
-	/* 8974Pro Bringup */
-	[3][0] = { acpu_freq_tbl_pro_pvs0, sizeof(acpu_freq_tbl_pro_pvs0) },
-	[3][1] = { acpu_freq_tbl_pro_pvs0, sizeof(acpu_freq_tbl_pro_pvs0) },
-	[3][2] = { acpu_freq_tbl_pro_pvs0, sizeof(acpu_freq_tbl_pro_pvs0) },
-	[3][3] = { acpu_freq_tbl_pro_pvs0, sizeof(acpu_freq_tbl_pro_pvs0) },
-	[3][4] = { acpu_freq_tbl_pro_pvs0, sizeof(acpu_freq_tbl_pro_pvs0) },
-	[3][5] = { acpu_freq_tbl_pro_pvs0, sizeof(acpu_freq_tbl_pro_pvs0) },
-	[3][6] = { acpu_freq_tbl_pro_pvs0, sizeof(acpu_freq_tbl_pro_pvs0) },
-	[3][7] = { acpu_freq_tbl_pro_pvs0, sizeof(acpu_freq_tbl_pro_pvs0) },
+	/* 8974Pro AC 2.5GHz */
+	[3][0] = { acpu_ftbl_pro_2p5g_pvs0, sizeof(acpu_ftbl_pro_2p5g_pvs0) },
+	[3][1] = { acpu_ftbl_pro_2p5g_pvs1, sizeof(acpu_ftbl_pro_2p5g_pvs1) },
+	[3][2] = { acpu_ftbl_pro_2p5g_pvs2, sizeof(acpu_ftbl_pro_2p5g_pvs2) },
+	[3][3] = { acpu_ftbl_pro_2p5g_pvs3, sizeof(acpu_ftbl_pro_2p5g_pvs3) },
+	[3][4] = { acpu_ftbl_pro_2p5g_pvs4, sizeof(acpu_ftbl_pro_2p5g_pvs4) },
+	[3][5] = { acpu_ftbl_pro_2p5g_pvs5, sizeof(acpu_ftbl_pro_2p5g_pvs5) },
+	[3][6] = { acpu_ftbl_pro_2p5g_pvs6, sizeof(acpu_ftbl_pro_2p5g_pvs6) },
+	[3][7] = { acpu_ftbl_pro_2p5g_pvs6, sizeof(acpu_ftbl_pro_2p5g_pvs6) },
 };
 
 static struct msm_bus_scale_pdata bus_scale_data __initdata = {
diff --git a/arch/arm/mach-msm/acpuclock-krait.c b/arch/arm/mach-msm/acpuclock-krait.c
index db66d27..0479844 100644
--- a/arch/arm/mach-msm/acpuclock-krait.c
+++ b/arch/arm/mach-msm/acpuclock-krait.c
@@ -55,8 +55,12 @@
 	return drv.scalable[cpu].cur_speed->khz;
 }
 
-/* Select a source on the primary MUX. */
-static void set_pri_clk_src(struct scalable *sc, u32 pri_src_sel)
+struct set_clk_src_args {
+	struct scalable *sc;
+	u32 src_sel;
+};
+
+static void __set_pri_clk_src(struct scalable *sc, u32 pri_src_sel)
 {
 	u32 regval;
 
@@ -73,6 +77,27 @@
 	udelay(1);
 }
 
+static void __set_cpu_pri_clk_src(void *data)
+{
+	struct set_clk_src_args *args = data;
+	__set_pri_clk_src(args->sc, args->src_sel);
+}
+
+/* Select a source on the primary MUX. */
+static void set_pri_clk_src(struct scalable *sc, u32 pri_src_sel)
+{
+	int cpu = sc - drv.scalable;
+	if (sc != &drv.scalable[L2] && cpu_online(cpu)) {
+		struct set_clk_src_args args = {
+			.sc = sc,
+			.src_sel = pri_src_sel,
+		};
+		smp_call_function_single(cpu, __set_cpu_pri_clk_src, &args, 1);
+	} else {
+		__set_pri_clk_src(sc, pri_src_sel);
+	}
+}
+
 /* Select a source on the secondary MUX. */
 static void __cpuinit set_sec_clk_src(struct scalable *sc, u32 sec_src_sel)
 {
diff --git a/arch/arm/mach-msm/board-8610-gpiomux.c b/arch/arm/mach-msm/board-8610-gpiomux.c
index e9ad86f..87794c4 100644
--- a/arch/arm/mach-msm/board-8610-gpiomux.c
+++ b/arch/arm/mach-msm/board-8610-gpiomux.c
@@ -23,6 +23,11 @@
 	.drv = GPIOMUX_DRV_6MA,
 	.pull = GPIOMUX_PULL_NONE,
 };
+static struct gpiomux_setting gpio_spi_susp_config = {
+	.func = GPIOMUX_FUNC_GPIO,
+	.drv = GPIOMUX_DRV_2MA,
+	.pull = GPIOMUX_PULL_DOWN,
+};
 
 static struct gpiomux_setting gpio_i2c_config = {
 	.func = GPIOMUX_FUNC_3,
@@ -247,25 +252,29 @@
 	{
 		.gpio      = 86,		/* BLSP1 QUP4 SPI_DATA_MOSI */
 		.settings = {
-			[GPIOMUX_SUSPENDED] = &gpio_spi_config,
+			[GPIOMUX_ACTIVE] = &gpio_spi_config,
+			[GPIOMUX_SUSPENDED] = &gpio_spi_susp_config,
 		},
 	},
 	{
 		.gpio      = 87,		/* BLSP1 QUP4 SPI_DATA_MISO */
 		.settings = {
-			[GPIOMUX_SUSPENDED] = &gpio_spi_config,
+			[GPIOMUX_ACTIVE] = &gpio_spi_config,
+			[GPIOMUX_SUSPENDED] = &gpio_spi_susp_config,
 		},
 	},
 	{
 		.gpio      = 89,		/* BLSP1 QUP4 SPI_CLK */
 		.settings = {
-			[GPIOMUX_SUSPENDED] = &gpio_spi_config,
+			[GPIOMUX_ACTIVE] = &gpio_spi_config,
+			[GPIOMUX_SUSPENDED] = &gpio_spi_susp_config,
 		},
 	},
 	{
 		.gpio      = 88,		/* BLSP1 QUP4 SPI_CS */
 		.settings = {
-			[GPIOMUX_SUSPENDED] = &gpio_spi_config,
+			[GPIOMUX_ACTIVE] = &gpio_spi_config,
+			[GPIOMUX_SUSPENDED] = &gpio_spi_susp_config,
 		},
 	},
 };
@@ -288,25 +297,29 @@
 	{
 		.gpio      = 86,		/* BLSP1 QUP4 SPI_DATA_MOSI */
 		.settings = {
-			[GPIOMUX_SUSPENDED] = &gpio_spi_config,
+			[GPIOMUX_ACTIVE] = &gpio_spi_config,
+			[GPIOMUX_SUSPENDED] = &gpio_spi_susp_config,
 		},
 	},
 	{
 		.gpio      = 87,		/* BLSP1 QUP4 SPI_DATA_MISO */
 		.settings = {
-			[GPIOMUX_SUSPENDED] = &gpio_spi_config,
+			[GPIOMUX_ACTIVE] = &gpio_spi_config,
+			[GPIOMUX_SUSPENDED] = &gpio_spi_susp_config,
 		},
 	},
 	{
 		.gpio      = 89,		/* BLSP1 QUP4 SPI_CLK */
 		.settings = {
-			[GPIOMUX_SUSPENDED] = &gpio_spi_config,
+			[GPIOMUX_ACTIVE] = &gpio_spi_config,
+			[GPIOMUX_SUSPENDED] = &gpio_spi_susp_config,
 		},
 	},
 	{
 		.gpio      = 88,		/* BLSP1 QUP4 SPI_CS */
 		.settings = {
-			[GPIOMUX_SUSPENDED] = &gpio_spi_config,
+			[GPIOMUX_ACTIVE] = &gpio_spi_config,
+			[GPIOMUX_SUSPENDED] = &gpio_spi_susp_config,
 		},
 	},
 };
diff --git a/arch/arm/mach-msm/board-8974-gpiomux.c b/arch/arm/mach-msm/board-8974-gpiomux.c
index f170b7b..c35a607 100644
--- a/arch/arm/mach-msm/board-8974-gpiomux.c
+++ b/arch/arm/mach-msm/board-8974-gpiomux.c
@@ -143,6 +143,11 @@
 	.drv = GPIOMUX_DRV_12MA,
 	.pull = GPIOMUX_PULL_NONE,
 };
+static struct gpiomux_setting gpio_spi_susp_config = {
+	.func = GPIOMUX_FUNC_GPIO,
+	.drv = GPIOMUX_DRV_2MA,
+	.pull = GPIOMUX_PULL_DOWN,
+};
 
 static struct gpiomux_setting gpio_spi_cs1_config = {
 	.func = GPIOMUX_FUNC_GPIO,
@@ -223,6 +228,17 @@
 	.pull = GPIOMUX_PULL_NONE,
 };
 
+static struct gpiomux_setting gpio_i2c_act_config = {
+	.func = GPIOMUX_FUNC_3,
+	/*
+	 * Please keep I2C GPIOs drive-strength at minimum (2ma). It is a
+	 * workaround for HW issue of glitches caused by rapid GPIO current-
+	 * change.
+	 */
+	.drv = GPIOMUX_DRV_2MA,
+	.pull = GPIOMUX_PULL_UP,
+};
+
 static struct gpiomux_setting lcd_en_act_cfg = {
 	.func = GPIOMUX_FUNC_GPIO,
 	.drv = GPIOMUX_DRV_8MA,
@@ -553,31 +569,36 @@
 	{
 		.gpio      = 0,		/* BLSP1 QUP SPI_DATA_MOSI */
 		.settings = {
-			[GPIOMUX_SUSPENDED] = &gpio_spi_config,
+			[GPIOMUX_ACTIVE] = &gpio_spi_config,
+			[GPIOMUX_SUSPENDED] = &gpio_spi_susp_config,
 		},
 	},
 	{
 		.gpio      = 1,		/* BLSP1 QUP SPI_DATA_MISO */
 		.settings = {
-			[GPIOMUX_SUSPENDED] = &gpio_spi_config,
+			[GPIOMUX_ACTIVE] = &gpio_spi_config,
+			[GPIOMUX_SUSPENDED] = &gpio_spi_susp_config,
 		},
 	},
 	{
 		.gpio      = 3,		/* BLSP1 QUP SPI_CLK */
 		.settings = {
-			[GPIOMUX_SUSPENDED] = &gpio_spi_config,
+			[GPIOMUX_ACTIVE] = &gpio_spi_config,
+			[GPIOMUX_SUSPENDED] = &gpio_spi_susp_config,
 		},
 	},
 	{
 		.gpio      = 9,		/* BLSP1 QUP SPI_CS2A_N */
 		.settings = {
-			[GPIOMUX_SUSPENDED] = &gpio_spi_cs2_config,
+			[GPIOMUX_ACTIVE] = &gpio_spi_cs2_config,
+			[GPIOMUX_SUSPENDED] = &gpio_spi_susp_config,
 		},
 	},
 	{
 		.gpio      = 8,		/* BLSP1 QUP SPI_CS1_N */
 		.settings = {
-			[GPIOMUX_SUSPENDED] = &gpio_spi_cs1_config,
+			[GPIOMUX_ACTIVE] = &gpio_spi_cs1_config,
+			[GPIOMUX_SUSPENDED] = &gpio_spi_susp_config,
 		},
 	},
 #endif
@@ -585,12 +606,14 @@
 		.gpio      = 6,		/* BLSP1 QUP2 I2C_DAT */
 		.settings = {
 			[GPIOMUX_SUSPENDED] = &gpio_i2c_config,
+			[GPIOMUX_ACTIVE] = &gpio_i2c_act_config,
 		},
 	},
 	{
 		.gpio      = 7,		/* BLSP1 QUP2 I2C_CLK */
 		.settings = {
 			[GPIOMUX_SUSPENDED] = &gpio_i2c_config,
+			[GPIOMUX_ACTIVE] = &gpio_i2c_act_config,
 		},
 	},
 	{
diff --git a/arch/arm/mach-msm/clock-mdss-8974.c b/arch/arm/mach-msm/clock-mdss-8974.c
index 3bb4c57..cf2df18 100644
--- a/arch/arm/mach-msm/clock-mdss-8974.c
+++ b/arch/arm/mach-msm/clock-mdss-8974.c
@@ -1398,7 +1398,8 @@
 {
 	int rc = 0;
 
-	if (vco_cached_rate != 0) {
+	if ((vco_cached_rate != 0)
+	    && (vco_cached_rate == c->rate)) {
 		rc = vco_set_rate(c, vco_cached_rate);
 		if (rc) {
 			pr_err("%s: vco_set_rate failed. rc=%d\n",
diff --git a/arch/arm/mach-msm/cpr-regulator.c b/arch/arm/mach-msm/cpr-regulator.c
index b69b155..6ddf340 100644
--- a/arch/arm/mach-msm/cpr-regulator.c
+++ b/arch/arm/mach-msm/cpr-regulator.c
@@ -148,7 +148,7 @@
 	void __iomem	*efuse_base;
 
 	/* Process voltage parameters */
-	u32		pvs_bin_process[CPR_PVS_EFUSE_BINS_MAX];
+	u32		pvs_init_v[CPR_PVS_EFUSE_BINS_MAX];
 	u32		pvs_corner_v[NUM_APC_PVS][CPR_CORNER_MAX];
 	/* Process voltage variables */
 	u32		pvs_bin;
@@ -999,6 +999,7 @@
 	u64 efuse_bits;
 	int rc, process;
 	u32 pvs_fuse[3], pvs_fuse_redun_sel[4];
+	u32 init_v;
 	bool redundant;
 	size_t pvs_bins;
 
@@ -1034,25 +1035,35 @@
 				   ((1 << pvs_fuse[2]) - 1);
 
 	pvs_bins = 1 << pvs_fuse[2];
-	rc = of_property_read_u32_array(of_node, "qcom,pvs-bin-process",
-					cpr_vreg->pvs_bin_process,
-					pvs_bins);
+
+	rc = of_property_read_u32_array(of_node, "qcom,pvs-init-voltage",
+					cpr_vreg->pvs_init_v, pvs_bins);
 	if (rc < 0) {
-		pr_err("pvs-bin-process missing: rc=%d\n", rc);
+		pr_err("pvs-init-voltage missing: rc=%d\n", rc);
 		return rc;
 	}
 
-	process = cpr_vreg->pvs_bin_process[cpr_vreg->pvs_bin];
-	pr_info("[row:%d] = 0x%llX, n_bits=%d, bin=%d (%d)\n",
-		pvs_fuse[0], efuse_bits, pvs_fuse[2],
-		cpr_vreg->pvs_bin, process);
+	init_v = cpr_vreg->pvs_init_v[cpr_vreg->pvs_bin];
+	for (process = NUM_APC_PVS - 1; process > APC_PVS_NO; process--) {
+		if (init_v <= cpr_vreg->pvs_corner_v[process][CPR_CORNER_TURBO])
+			break;
+	}
 
-	if (process == APC_PVS_NO || process >= NUM_APC_PVS) {
-		pr_err("Bin=%d (%d) is out of spec. Assume SLOW.\n",
-		       cpr_vreg->pvs_bin, process);
+	if (process == APC_PVS_NO) {
+		process = APC_PVS_SLOW;
+		cpr_vreg->pvs_corner_v[process][CPR_CORNER_TURBO] = init_v;
+		cpr_vreg->ceiling_max = init_v;
+	} else if (process == APC_PVS_FAST &&
+		init_v < cpr_vreg->pvs_corner_v[APC_PVS_FAST][CPR_CORNER_SVS]) {
 		process = APC_PVS_SLOW;
 	}
 
+	pr_info("[row:%d] = 0x%llX, n_bits=%d, bin=%d (%d)",
+		pvs_fuse[0], efuse_bits, pvs_fuse[2],
+		cpr_vreg->pvs_bin, process);
+	pr_info("pvs initial turbo voltage_= from %u to %u\n",
+		init_v, cpr_vreg->pvs_corner_v[process][CPR_CORNER_TURBO]);
+
 	cpr_vreg->process = process;
 
 	return 0;
@@ -1263,10 +1274,6 @@
 			     quot[CPR_CORNER_NORMAL])
 					<= CPR_FUSE_MIN_QUOT_DIFF)
 				valid_fuse = false;
-			else if ((quot[CPR_CORNER_NORMAL] -
-				  quot[CPR_CORNER_SVS])
-					<= CPR_FUSE_MIN_QUOT_DIFF)
-				valid_fuse = false;
 		} else {
 			valid_fuse = false;
 		}
diff --git a/arch/arm/mach-msm/include/mach/msm_smem.h b/arch/arm/mach-msm/include/mach/msm_smem.h
index 5556db9..19f9c0e 100644
--- a/arch/arm/mach-msm/include/mach/msm_smem.h
+++ b/arch/arm/mach-msm/include/mach/msm_smem.h
@@ -26,6 +26,18 @@
 	NUM_SMEM_SUBSYSTEMS,
 };
 
+/*
+ * Flag options for the XXX_to_proc() API
+ *
+ * SMEM_ITEM_CACHED_FLAG - Indicates this operation should use cachable smem
+ *
+ * SMEM_ANY_HOST_FLAG - Indicates this operation should not apply to smem items
+ *                      which are limited to a specific host pairing.  Will
+ *                      cause this operation to ignore the to_proc parameter.
+ */
+#define SMEM_ITEM_CACHED_FLAG 1
+#define SMEM_ANY_HOST_FLAG 2
+
 #define SMEM_NUM_SMD_STREAM_CHANNELS        64
 
 enum {
@@ -145,6 +157,15 @@
 void *smem_get_entry(unsigned id, unsigned *size);
 void *smem_find(unsigned id, unsigned size);
 
+void *smem_alloc2_to_proc(unsigned id, unsigned size_in, unsigned to_proc,
+								unsigned flags);
+void *smem_alloc_to_proc(unsigned id, unsigned size, unsigned to_proc,
+								unsigned flags);
+void *smem_find_to_proc(unsigned id, unsigned size_in, unsigned to_proc,
+								unsigned flags);
+void *smem_get_entry_to_proc(unsigned id, unsigned *size, unsigned to_proc,
+								unsigned flags);
+
 /**
  * smem_get_entry_no_rlock - Get existing item without using remote spinlock
  *
@@ -193,6 +214,26 @@
 {
 	return NULL;
 }
+void *smem_alloc2_to_proc(unsigned id, unsigned size_in, unsigned to_proc,
+								unsigned flags)
+{
+	return NULL;
+}
+static void *smem_alloc_to_proc(unsigned id, unsigned size, unsigned to_proc,
+								unsigned flags)
+{
+	return NULL;
+}
+static void *smem_find_to_proc(unsigned id, unsigned size_in, unsigned to_proc,
+								unsigned flags)
+{
+	return NULL;
+}
+static void *smem_get_entry_to_proc(unsigned id, unsigned *size,
+					unsigned to_proc, unsigned flags)
+{
+	return NULL;
+}
 void *smem_get_entry_no_rlock(unsigned id, unsigned *size_out)
 {
 	return NULL;
diff --git a/arch/arm/mach-msm/ipc_router.c b/arch/arm/mach-msm/ipc_router.c
index 6fe945c..ce66531 100644
--- a/arch/arm/mach-msm/ipc_router.c
+++ b/arch/arm/mach-msm/ipc_router.c
@@ -298,6 +298,8 @@
 		pr_err("%s: failure\n", __func__);
 		return NULL;
 	}
+	memcpy(&(cloned_pkt->hdr), &(pkt->hdr), sizeof(struct rr_header_v1));
+	/* TODO: Copy optional headers, if available */
 
 	pkt_fragment_q = kmalloc(sizeof(struct sk_buff_head), GFP_KERNEL);
 	if (!pkt_fragment_q) {
@@ -323,6 +325,7 @@
 		kfree_skb(temp_skb);
 	}
 	kfree(pkt_fragment_q);
+	/* TODO: Free optional headers, if present */
 	kfree(cloned_pkt);
 	return NULL;
 }
@@ -361,6 +364,7 @@
 		kfree_skb(temp_skb);
 	}
 	kfree(pkt->pkt_fragment_q);
+	/* TODO: Free Optional headers, if present */
 	kfree(pkt);
 	return;
 }
@@ -373,6 +377,8 @@
 	int first = 1, offset = 0;
 	int skb_size, data_size;
 	void *data;
+	int last = 1;
+	int align_size;
 
 	skb_head = kmalloc(sizeof(struct sk_buff_head), GFP_KERNEL);
 	if (!skb_head) {
@@ -382,10 +388,13 @@
 	skb_queue_head_init(skb_head);
 
 	data_size = buf_len;
+	align_size = ALIGN_SIZE(data_size);
 	while (offset != buf_len) {
 		skb_size = data_size;
 		if (first)
 			skb_size += IPC_ROUTER_HDR_SIZE;
+		if (last)
+			skb_size += align_size;
 
 		skb = alloc_skb(skb_size, GFP_KERNEL);
 		if (!skb) {
@@ -394,6 +403,7 @@
 				goto buf_to_skb_error;
 			}
 			data_size = data_size / 2;
+			last = 0;
 			continue;
 		}
 
@@ -407,6 +417,7 @@
 		skb_queue_tail(skb_head, skb);
 		offset += data_size;
 		data_size = buf_len - offset;
+		last = 1;
 	}
 	return skb_head;
 
@@ -447,7 +458,7 @@
 	return buf;
 }
 
-static void msm_ipc_router_free_skb(struct sk_buff_head *skb_head)
+void msm_ipc_router_free_skb(struct sk_buff_head *skb_head)
 {
 	struct sk_buff *temp_skb;
 
@@ -461,6 +472,328 @@
 	kfree(skb_head);
 }
 
+/**
+ * extract_header_v1() - Extract IPC Router header of version 1
+ * @pkt: Packet structure into which the header has to be extraced.
+ * @skb: SKB from which the header has to be extracted.
+ *
+ * @return: 0 on success, standard Linux error codes on failure.
+ */
+static int extract_header_v1(struct rr_packet *pkt, struct sk_buff *skb)
+{
+	if (!pkt || !skb) {
+		pr_err("%s: Invalid pkt or skb\n", __func__);
+		return -EINVAL;
+	}
+
+	memcpy(&pkt->hdr, skb->data, sizeof(struct rr_header_v1));
+	skb_pull(skb, sizeof(struct rr_header_v1));
+	pkt->length -= sizeof(struct rr_header_v1);
+	return 0;
+}
+
+/**
+ * extract_header_v2() - Extract IPC Router header of version 2
+ * @pkt: Packet structure into which the header has to be extraced.
+ * @skb: SKB from which the header has to be extracted.
+ *
+ * @return: 0 on success, standard Linux error codes on failure.
+ */
+static int extract_header_v2(struct rr_packet *pkt, struct sk_buff *skb)
+{
+	struct rr_header_v2 *hdr;
+
+	if (!pkt || !skb) {
+		pr_err("%s: Invalid pkt or skb\n", __func__);
+		return -EINVAL;
+	}
+
+	hdr = (struct rr_header_v2 *)skb->data;
+	pkt->hdr.version = (uint32_t)hdr->version;
+	pkt->hdr.type = (uint32_t)hdr->type;
+	pkt->hdr.src_node_id = (uint32_t)hdr->src_node_id;
+	pkt->hdr.src_port_id = (uint32_t)hdr->src_port_id;
+	pkt->hdr.size = (uint32_t)hdr->size;
+	pkt->hdr.control_flag = (uint32_t)hdr->control_flag;
+	pkt->hdr.dst_node_id = (uint32_t)hdr->dst_node_id;
+	pkt->hdr.dst_port_id = (uint32_t)hdr->dst_port_id;
+	skb_pull(skb, sizeof(struct rr_header_v2));
+	pkt->length -= sizeof(struct rr_header_v2);
+	return 0;
+}
+
+/**
+ * extract_header() - Extract IPC Router header
+ * @pkt: Packet from which the header has to be extraced.
+ *
+ * @return: 0 on success, standard Linux error codes on failure.
+ *
+ * This function will check if the header version is v1 or v2 and invoke
+ * the corresponding helper function to extract the IPC Router header.
+ */
+static int extract_header(struct rr_packet *pkt)
+{
+	struct sk_buff *temp_skb;
+	int ret;
+
+	if (!pkt) {
+		pr_err("%s: NULL PKT\n", __func__);
+		return -EINVAL;
+	}
+
+	temp_skb = skb_peek(pkt->pkt_fragment_q);
+	if (!temp_skb || !temp_skb->data) {
+		pr_err("%s: No SKBs in skb_queue\n", __func__);
+		return -EINVAL;
+	}
+
+	if (temp_skb->data[0] == IPC_ROUTER_V1) {
+		ret = extract_header_v1(pkt, temp_skb);
+	} else if (temp_skb->data[0] == IPC_ROUTER_V2) {
+		ret = extract_header_v2(pkt, temp_skb);
+		/* TODO: Extract optional headers if present */
+	} else {
+		pr_err("%s: Invalid Header version %02x\n",
+			__func__, temp_skb->data[0]);
+		print_hex_dump(KERN_ERR, "Header: ", DUMP_PREFIX_ADDRESS,
+			       16, 1, temp_skb->data, pkt->length, true);
+		return -EINVAL;
+	}
+	return ret;
+}
+
+/**
+ * calc_tx_header_size() - Calculate header size to be reserved in SKB
+ * @pkt: Packet in which the space for header has to be reserved.
+ * @dst_xprt_info: XPRT through which the destination is reachable.
+ *
+ * @return: required header size on success,
+ *          starndard Linux error codes on failure.
+ *
+ * This function is used to calculate the header size that has to be reserved
+ * in a transmit SKB. The header size is calculated based on the XPRT through
+ * which the destination node is reachable.
+ */
+static int calc_tx_header_size(struct rr_packet *pkt,
+			       struct msm_ipc_router_xprt_info *dst_xprt_info)
+{
+	int hdr_size = 0;
+	int xprt_version = 0;
+	struct msm_ipc_routing_table_entry *rt_entry;
+	struct msm_ipc_router_xprt_info *xprt_info = dst_xprt_info;
+
+	if (!pkt) {
+		pr_err("%s: NULL PKT\n", __func__);
+		return -EINVAL;
+	}
+
+	if (!xprt_info) {
+		rt_entry = lookup_routing_table(pkt->hdr.dst_node_id);
+		if (!rt_entry || !(rt_entry->xprt_info)) {
+			pr_err("%s: Node %d is not up\n",
+				__func__, pkt->hdr.dst_node_id);
+			return -ENODEV;
+		}
+
+		xprt_info = rt_entry->xprt_info;
+	}
+	if (xprt_info)
+		xprt_version = xprt_info->xprt->get_version(xprt_info->xprt);
+
+	if (xprt_version == IPC_ROUTER_V1) {
+		pkt->hdr.version = IPC_ROUTER_V1;
+		hdr_size = sizeof(struct rr_header_v1);
+	} else if (xprt_version == IPC_ROUTER_V2) {
+		pkt->hdr.version = IPC_ROUTER_V2;
+		hdr_size = sizeof(struct rr_header_v2);
+		/* TODO: Calculate optional header length, if present */
+	} else {
+		pr_err("%s: Invalid xprt_version %d\n",
+			__func__, xprt_version);
+		hdr_size = -EINVAL;
+	}
+
+	return hdr_size;
+}
+
+/**
+ * prepend_header_v1() - Prepend IPC Router header of version 1
+ * @pkt: Packet structure which contains the header info to be prepended.
+ * @hdr_size: Size of the header
+ *
+ * @return: 0 on success, standard Linux error codes on failure.
+ */
+static int prepend_header_v1(struct rr_packet *pkt, int hdr_size)
+{
+	struct sk_buff *temp_skb;
+	struct rr_header_v1 *hdr;
+
+	if (!pkt || hdr_size <= 0) {
+		pr_err("%s: Invalid input parameters\n", __func__);
+		return -EINVAL;
+	}
+
+	temp_skb = skb_peek(pkt->pkt_fragment_q);
+	if (!temp_skb || !temp_skb->data) {
+		pr_err("%s: No SKBs in skb_queue\n", __func__);
+		return -EINVAL;
+	}
+
+	if (skb_headroom(temp_skb) < hdr_size) {
+		temp_skb = alloc_skb(hdr_size, GFP_KERNEL);
+		if (!temp_skb) {
+			pr_err("%s: Could not allocate SKB of size %d\n",
+				__func__, hdr_size);
+			return -ENOMEM;
+		}
+	}
+
+	hdr = (struct rr_header_v1 *)skb_push(temp_skb, hdr_size);
+	memcpy(hdr, &pkt->hdr, hdr_size);
+	if (temp_skb != skb_peek(pkt->pkt_fragment_q))
+		skb_queue_head(pkt->pkt_fragment_q, temp_skb);
+	pkt->length += hdr_size;
+	return 0;
+}
+
+/**
+ * prepend_header_v2() - Prepend IPC Router header of version 2
+ * @pkt: Packet structure which contains the header info to be prepended.
+ * @hdr_size: Size of the header
+ *
+ * @return: 0 on success, standard Linux error codes on failure.
+ */
+static int prepend_header_v2(struct rr_packet *pkt, int hdr_size)
+{
+	struct sk_buff *temp_skb;
+	struct rr_header_v2 *hdr;
+
+	if (!pkt || hdr_size <= 0) {
+		pr_err("%s: Invalid input parameters\n", __func__);
+		return -EINVAL;
+	}
+
+	temp_skb = skb_peek(pkt->pkt_fragment_q);
+	if (!temp_skb || !temp_skb->data) {
+		pr_err("%s: No SKBs in skb_queue\n", __func__);
+		return -EINVAL;
+	}
+
+	if (skb_headroom(temp_skb) < hdr_size) {
+		temp_skb = alloc_skb(hdr_size, GFP_KERNEL);
+		if (!temp_skb) {
+			pr_err("%s: Could not allocate SKB of size %d\n",
+				__func__, hdr_size);
+			return -ENOMEM;
+		}
+	}
+
+	hdr = (struct rr_header_v2 *)skb_push(temp_skb, hdr_size);
+	hdr->version = (uint8_t)pkt->hdr.version;
+	hdr->type = (uint8_t)pkt->hdr.type;
+	hdr->control_flag = (uint16_t)pkt->hdr.control_flag;
+	hdr->size = (uint32_t)pkt->hdr.size;
+	hdr->src_node_id = (uint16_t)pkt->hdr.src_node_id;
+	hdr->src_port_id = (uint16_t)pkt->hdr.src_port_id;
+	hdr->dst_node_id = (uint16_t)pkt->hdr.dst_node_id;
+	hdr->dst_port_id = (uint16_t)pkt->hdr.dst_port_id;
+	/* TODO: Add optional headers, if present */
+	if (temp_skb != skb_peek(pkt->pkt_fragment_q))
+		skb_queue_head(pkt->pkt_fragment_q, temp_skb);
+	pkt->length += hdr_size;
+	return 0;
+}
+
+/**
+ * prepend_header() - Prepend IPC Router header
+ * @pkt: Packet structure which contains the header info to be prepended.
+ * @xprt_info: XPRT through which the packet is transmitted.
+ *
+ * @return: 0 on success, standard Linux error codes on failure.
+ *
+ * This function prepends the header to the packet to be transmitted. The
+ * IPC Router header version to be prepended depends on the XPRT through
+ * which the destination is reachable.
+ */
+static int prepend_header(struct rr_packet *pkt,
+			  struct msm_ipc_router_xprt_info *xprt_info)
+{
+	int hdr_size;
+	struct sk_buff *temp_skb;
+
+	if (!pkt) {
+		pr_err("%s: NULL PKT\n", __func__);
+		return -EINVAL;
+	}
+
+	temp_skb = skb_peek(pkt->pkt_fragment_q);
+	if (!temp_skb || !temp_skb->data) {
+		pr_err("%s: No SKBs in skb_queue\n", __func__);
+		return -EINVAL;
+	}
+
+	hdr_size = calc_tx_header_size(pkt, xprt_info);
+	if (hdr_size <= 0)
+		return hdr_size;
+
+	if (pkt->hdr.version == IPC_ROUTER_V1)
+		return prepend_header_v1(pkt, hdr_size);
+	else if (pkt->hdr.version == IPC_ROUTER_V2)
+		return prepend_header_v2(pkt, hdr_size);
+	else
+		return -EINVAL;
+}
+
+/**
+ * defragment_pkt() - Defragment and linearize the packet
+ * @pkt: Packet to be linearized.
+ *
+ * @return: 0 on success, standard Linux error codes on failure.
+ *
+ * Some packets contain fragments of data over multiple SKBs. If an XPRT
+ * does not supported fragmented writes, linearize multiple SKBs into one
+ * single SKB.
+ */
+static int defragment_pkt(struct rr_packet *pkt)
+{
+	struct sk_buff *dst_skb, *src_skb, *temp_skb;
+	int offset = 0, buf_len = 0, copy_len;
+	void *buf;
+	int align_size;
+
+	if (!pkt || pkt->length <= 0) {
+		pr_err("%s: Invalid PKT\n", __func__);
+		return -EINVAL;
+	}
+
+	if (skb_queue_len(pkt->pkt_fragment_q) == 1)
+		return 0;
+
+	align_size = ALIGN_SIZE(pkt->length);
+	dst_skb = alloc_skb(pkt->length + align_size, GFP_KERNEL);
+	if (!dst_skb) {
+		pr_err("%s: could not allocate one skb of size %d\n",
+			__func__, pkt->length);
+		return -ENOMEM;
+	}
+	buf = skb_put(dst_skb, pkt->length);
+	buf_len = pkt->length;
+
+	skb_queue_walk(pkt->pkt_fragment_q, src_skb) {
+		copy_len =  buf_len < src_skb->len ? buf_len : src_skb->len;
+		memcpy(buf + offset, src_skb->data, copy_len);
+		offset += copy_len;
+		buf_len -= copy_len;
+	}
+
+	while (!skb_queue_empty(pkt->pkt_fragment_q)) {
+		temp_skb = skb_dequeue(pkt->pkt_fragment_q);
+		kfree_skb(temp_skb);
+	}
+	skb_queue_tail(pkt->pkt_fragment_q, dst_skb);
+	return 0;
+}
+
 static int post_pkt_to_port(struct msm_ipc_port *port_ptr,
 			    struct rr_packet *pkt, int clone)
 {
@@ -515,7 +848,7 @@
 	down_read(&local_ports_lock_lha2);
 	do {
 		next_port_id++;
-		if ((next_port_id & 0xFFFFFFFE) == 0xFFFFFFFE)
+		if ((next_port_id & IPC_ROUTER_ADDRESS) == IPC_ROUTER_ADDRESS)
 			next_port_id = 1;
 
 		key = (next_port_id & (LP_HASH_SIZE - 1));
@@ -932,7 +1265,7 @@
 {
 	struct rr_packet *pkt;
 	struct sk_buff *ipc_rtr_pkt;
-	struct rr_header *hdr;
+	struct rr_header_v1 *hdr;
 	int pkt_size;
 	void *data;
 	struct sk_buff_head *pkt_fragment_q;
@@ -973,32 +1306,33 @@
 	skb_reserve(ipc_rtr_pkt, IPC_ROUTER_HDR_SIZE);
 	data = skb_put(ipc_rtr_pkt, sizeof(*msg));
 	memcpy(data, msg, sizeof(*msg));
-	hdr = (struct rr_header *)skb_push(ipc_rtr_pkt, IPC_ROUTER_HDR_SIZE);
-	if (!hdr) {
-		pr_err("%s: skb_push failed\n", __func__);
-		kfree_skb(ipc_rtr_pkt);
-		kfree(pkt_fragment_q);
-		kfree(pkt);
-		return -ENOMEM;
-	}
+	skb_queue_tail(pkt_fragment_q, ipc_rtr_pkt);
+	pkt->pkt_fragment_q = pkt_fragment_q;
+	pkt->length = sizeof(*msg);
 
-	hdr->version = IPC_ROUTER_VERSION;
+	hdr = &(pkt->hdr);
+	hdr->version = IPC_ROUTER_V1;
 	hdr->type = msg->cmd;
 	hdr->src_node_id = IPC_ROUTER_NID_LOCAL;
 	hdr->src_port_id = IPC_ROUTER_ADDRESS;
-	hdr->confirm_rx = 0;
+	hdr->control_flag = 0;
 	hdr->size = sizeof(*msg);
 	if (hdr->type == IPC_ROUTER_CTRL_CMD_RESUME_TX)
 		hdr->dst_node_id = dst_node_id;
 	else
 		hdr->dst_node_id = xprt_info->remote_node_id;
 	hdr->dst_port_id = IPC_ROUTER_ADDRESS;
-	skb_queue_tail(pkt_fragment_q, ipc_rtr_pkt);
-	pkt->pkt_fragment_q = pkt_fragment_q;
-	pkt->length = pkt_size;
 
 	mutex_lock(&xprt_info->tx_lock_lhb2);
-	ret = xprt_info->xprt->write(pkt, pkt_size, xprt_info->xprt);
+	ret = prepend_header(pkt, xprt_info);
+	if (ret < 0) {
+		mutex_unlock(&xprt_info->tx_lock_lhb2);
+		pr_err("%s: Prepend Header failed\n", __func__);
+		release_pkt(pkt);
+		return ret;
+	}
+
+	ret = xprt_info->xprt->write(pkt, pkt->length, xprt_info->xprt);
 	mutex_unlock(&xprt_info->tx_lock_lhb2);
 
 	release_pkt(pkt);
@@ -1074,7 +1408,7 @@
 {
 	struct rr_packet *pkt;
 	struct sk_buff *ipc_rtr_pkt;
-	struct rr_header *hdr;
+	struct rr_header_v1 *hdr;
 	int pkt_size;
 	void *data;
 	struct sk_buff_head *pkt_fragment_q;
@@ -1094,7 +1428,7 @@
 	}
 	skb_queue_head_init(pkt_fragment_q);
 
-	pkt_size = IPC_ROUTER_HDR_SIZE + sizeof(*msg);
+	pkt_size = sizeof(*msg);
 	ipc_rtr_pkt = alloc_skb(pkt_size, GFP_KERNEL);
 	if (!ipc_rtr_pkt) {
 		pr_err("%s: ipc_rtr_pkt alloc failed\n", __func__);
@@ -1103,22 +1437,14 @@
 		return -ENOMEM;
 	}
 
-	skb_reserve(ipc_rtr_pkt, IPC_ROUTER_HDR_SIZE);
 	data = skb_put(ipc_rtr_pkt, sizeof(*msg));
 	memcpy(data, msg, sizeof(*msg));
-	hdr = (struct rr_header *)skb_push(ipc_rtr_pkt, IPC_ROUTER_HDR_SIZE);
-	if (!hdr) {
-		pr_err("%s: skb_push failed\n", __func__);
-		kfree_skb(ipc_rtr_pkt);
-		kfree(pkt_fragment_q);
-		kfree(pkt);
-		return -ENOMEM;
-	}
-	hdr->version = IPC_ROUTER_VERSION;
+	hdr = &(pkt->hdr);
+	hdr->version = IPC_ROUTER_V1;
 	hdr->type = msg->cmd;
 	hdr->src_node_id = IPC_ROUTER_NID_LOCAL;
 	hdr->src_port_id = IPC_ROUTER_ADDRESS;
-	hdr->confirm_rx = 0;
+	hdr->control_flag = 0;
 	hdr->size = sizeof(*msg);
 	hdr->dst_node_id = IPC_ROUTER_NID_LOCAL;
 	hdr->dst_port_id = IPC_ROUTER_ADDRESS;
@@ -1164,70 +1490,60 @@
 	return 0;
 }
 
-static int relay_msg(struct msm_ipc_router_xprt_info *xprt_info,
-		     struct rr_packet *pkt)
-{
-	struct msm_ipc_router_xprt_info *fwd_xprt_info;
-
-	if (!xprt_info || !pkt)
-		return -EINVAL;
-
-	down_read(&xprt_info_list_lock_lha5);
-	list_for_each_entry(fwd_xprt_info, &xprt_info_list, list) {
-		mutex_lock(&fwd_xprt_info->tx_lock_lhb2);
-		if (xprt_info->xprt->link_id != fwd_xprt_info->xprt->link_id)
-			fwd_xprt_info->xprt->write(pkt, pkt->length,
-						   fwd_xprt_info->xprt);
-		mutex_unlock(&fwd_xprt_info->tx_lock_lhb2);
-	}
-	up_read(&xprt_info_list_lock_lha5);
-	return 0;
-}
-
 static int forward_msg(struct msm_ipc_router_xprt_info *xprt_info,
 		       struct rr_packet *pkt)
 {
-	uint32_t dst_node_id;
-	struct sk_buff *head_pkt;
-	struct rr_header *hdr;
+	struct rr_header_v1 *hdr;
 	struct msm_ipc_router_xprt_info *fwd_xprt_info;
 	struct msm_ipc_routing_table_entry *rt_entry;
 	int ret = 0;
+	int fwd_xprt_option;
 
 	if (!xprt_info || !pkt)
 		return -EINVAL;
 
-	head_pkt = skb_peek(pkt->pkt_fragment_q);
-	if (!head_pkt)
-		return -EINVAL;
-
-	hdr = (struct rr_header *)head_pkt->data;
-	dst_node_id = hdr->dst_node_id;
+	hdr = &(pkt->hdr);
 	down_read(&routing_table_lock_lha3);
-	rt_entry = lookup_routing_table(dst_node_id);
+	rt_entry = lookup_routing_table(hdr->dst_node_id);
 	if (!(rt_entry) || !(rt_entry->xprt_info)) {
-		up_read(&routing_table_lock_lha3);
 		pr_err("%s: Routing table not initialized\n", __func__);
-		return -ENODEV;
+		ret = -ENODEV;
+		goto fm_error1;
 	}
 
 	down_read(&rt_entry->lock_lha4);
 	fwd_xprt_info = rt_entry->xprt_info;
+	ret = prepend_header(pkt, fwd_xprt_info);
+	if (ret < 0) {
+		pr_err("%s: Prepend Header failed\n", __func__);
+		goto fm_error2;
+	}
+	fwd_xprt_option = fwd_xprt_info->xprt->get_option(fwd_xprt_info->xprt);
+	if (!(fwd_xprt_option & FRAG_PKT_WRITE_ENABLE)) {
+		ret = defragment_pkt(pkt);
+		if (ret < 0)
+			goto fm_error2;
+	}
+
+	mutex_lock(&fwd_xprt_info->tx_lock_lhb2);
 	if (xprt_info->remote_node_id == fwd_xprt_info->remote_node_id) {
 		pr_err("%s: Discarding Command to route back\n", __func__);
 		ret = -EINVAL;
-		goto fwd_msg_out;
+		goto fm_error3;
 	}
 
 	if (xprt_info->xprt->link_id == fwd_xprt_info->xprt->link_id) {
 		pr_err("%s: DST in the same cluster\n", __func__);
-		goto fwd_msg_out;
+		ret = 0;
+		goto fm_error3;
 	}
-	mutex_lock(&fwd_xprt_info->tx_lock_lhb2);
 	fwd_xprt_info->xprt->write(pkt, pkt->length, fwd_xprt_info->xprt);
+
+fm_error3:
 	mutex_unlock(&fwd_xprt_info->tx_lock_lhb2);
-fwd_msg_out:
+fm_error2:
 	up_read(&rt_entry->lock_lha4);
+fm_error1:
 	up_read(&routing_table_lock_lha3);
 
 	return ret;
@@ -1470,7 +1786,7 @@
 }
 
 static int process_hello_msg(struct msm_ipc_router_xprt_info *xprt_info,
-			     struct rr_header *hdr)
+			     struct rr_header_v1 *hdr)
 {
 	int i, rc = 0;
 	union rr_control_msg ctl;
@@ -1508,7 +1824,7 @@
 
 	/* Send a reply HELLO message */
 	memset(&ctl, 0, sizeof(ctl));
-	ctl.cmd = IPC_ROUTER_CTRL_CMD_HELLO;
+	ctl.hello.cmd = IPC_ROUTER_CTRL_CMD_HELLO;
 	rc = msm_ipc_router_send_control_msg(xprt_info, &ctl,
 						IPC_ROUTER_DUMMY_DEST_NODE);
 	if (rc < 0) {
@@ -1654,7 +1970,7 @@
 	 * to the cluster from which this message is received. Notify the
 	 * local clients waiting for this service.
 	 */
-	relay_msg(xprt_info, pkt);
+	relay_ctl_msg(xprt_info, msg);
 	post_control_ports(pkt);
 	return 0;
 }
@@ -1677,7 +1993,7 @@
 		 * belong to the cluster from which this message is received.
 		 * Notify the local clients communicating with the service.
 		 */
-		relay_msg(xprt_info, pkt);
+		relay_ctl_msg(xprt_info, msg);
 		post_control_ports(pkt);
 	}
 	up_write(&server_list_lock_lha2);
@@ -1697,7 +2013,7 @@
 		msm_ipc_router_destroy_remote_port(rport_ptr);
 	up_write(&routing_table_lock_lha3);
 
-	relay_msg(xprt_info, pkt);
+	relay_ctl_msg(xprt_info, msg);
 	post_control_ports(pkt);
 	return 0;
 }
@@ -1707,26 +2023,20 @@
 {
 	union rr_control_msg *msg;
 	int rc = 0;
-	struct sk_buff *temp_ptr;
-	struct rr_header *hdr;
+	struct rr_header_v1 *hdr;
 
-	if (pkt->length != (IPC_ROUTER_HDR_SIZE + sizeof(*msg))) {
+	if (pkt->length != sizeof(*msg)) {
 		pr_err("%s: r2r msg size %d != %d\n", __func__, pkt->length,
-			(IPC_ROUTER_HDR_SIZE + sizeof(*msg)));
+			sizeof(*msg));
 		return -EINVAL;
 	}
 
-	temp_ptr = skb_peek(pkt->pkt_fragment_q);
-	if (!temp_ptr) {
-		pr_err("%s: pkt_fragment_q is empty\n", __func__);
-		return -EINVAL;
+	hdr = &(pkt->hdr);
+	msg = msm_ipc_router_skb_to_buf(pkt->pkt_fragment_q, sizeof(*msg));
+	if (!msg) {
+		pr_err("%s: Error extracting control msg\n", __func__);
+		return -ENOMEM;
 	}
-	hdr = (struct rr_header *)temp_ptr->data;
-	if (!hdr) {
-		pr_err("%s: No data inside the skb\n", __func__);
-		return -EINVAL;
-	}
-	msg = (union rr_control_msg *)((char *)hdr + IPC_ROUTER_HDR_SIZE);
 
 	switch (msg->cmd) {
 	case IPC_ROUTER_CTRL_CMD_HELLO:
@@ -1752,17 +2062,17 @@
 		RR("o UNKNOWN(%08x)\n", msg->cmd);
 		rc = -ENOSYS;
 	}
-
+	kfree(msg);
 	return rc;
 }
 
 static void do_read_data(struct work_struct *work)
 {
-	struct rr_header *hdr;
+	struct rr_header_v1 *hdr;
 	struct rr_packet *pkt = NULL;
 	struct msm_ipc_port *port_ptr;
-	struct sk_buff *head_skb;
 	struct msm_ipc_router_remote_port *rport_ptr;
+	int ret;
 
 	struct msm_ipc_router_xprt_info *xprt_info =
 		container_of(work,
@@ -1777,24 +2087,15 @@
 			goto fail_data;
 		}
 
-		head_skb = skb_peek(pkt->pkt_fragment_q);
-		if (!head_skb) {
-			pr_err("%s: head_skb is invalid\n", __func__);
+		ret = extract_header(pkt);
+		if (ret < 0)
 			goto fail_data;
-		}
-
-		hdr = (struct rr_header *)(head_skb->data);
+		hdr = &(pkt->hdr);
 		RAW("ver=%d type=%d src=%d:%08x crx=%d siz=%d dst=%d:%08x\n",
 		     hdr->version, hdr->type, hdr->src_node_id,
-		     hdr->src_port_id, hdr->confirm_rx, hdr->size,
+		     hdr->src_port_id, hdr->control_flag, hdr->size,
 		     hdr->dst_node_id, hdr->dst_port_id);
 
-		if (hdr->version != IPC_ROUTER_VERSION) {
-			pr_err("version %d != %d\n",
-				hdr->version, IPC_ROUTER_VERSION);
-			goto fail_data;
-		}
-
 		if ((hdr->dst_node_id != IPC_ROUTER_NID_LOCAL) &&
 		    ((hdr->type == IPC_ROUTER_CTRL_CMD_RESUME_TX) ||
 		     (hdr->type == IPC_ROUTER_CTRL_CMD_DATA))) {
@@ -1803,8 +2104,7 @@
 			continue;
 		}
 
-		if ((hdr->dst_port_id == IPC_ROUTER_ADDRESS) ||
-		    (hdr->type == IPC_ROUTER_CTRL_CMD_HELLO)) {
+		if (hdr->type != IPC_ROUTER_CTRL_CMD_DATA) {
 			process_control_msg(xprt_info, pkt);
 			release_pkt(pkt);
 			continue;
@@ -1819,7 +2119,7 @@
 				(hdr->src_port_id & 0xffffff),
 				(hdr->dst_node_id << 24) |
 				(hdr->dst_port_id & 0xffffff),
-				(hdr->type << 24) | (hdr->confirm_rx << 16) |
+				(hdr->type << 24) | (hdr->control_flag << 16) |
 				(hdr->size & 0xffff));
 		}
 #endif
@@ -1906,6 +2206,7 @@
 	ctl.srv.port_id = port_ptr->this_port.port_id;
 	up_write(&server_list_lock_lha2);
 	broadcast_ctl_msg(&ctl);
+	broadcast_ctl_msg_locally(&ctl);
 	spin_lock_irqsave(&port_ptr->port_lock, flags);
 	port_ptr->type = SERVER_PORT;
 	port_ptr->mode_info.mode = MULTI_LINK_MODE;
@@ -1957,6 +2258,7 @@
 				      port_ptr->this_port.port_id);
 	up_write(&server_list_lock_lha2);
 	broadcast_ctl_msg(&ctl);
+	broadcast_ctl_msg_locally(&ctl);
 	spin_lock_irqsave(&port_ptr->port_lock, flags);
 	port_ptr->type = CLIENT_PORT;
 	spin_unlock_irqrestore(&port_ptr->port_lock, flags);
@@ -1967,8 +2269,7 @@
 			uint32_t port_id,
 			struct sk_buff_head *data)
 {
-	struct sk_buff *head_skb;
-	struct rr_header *hdr;
+	struct rr_header_v1 *hdr;
 	struct msm_ipc_port *port_ptr;
 	struct rr_packet *pkt;
 	int ret_len;
@@ -1983,34 +2284,22 @@
 		pr_err("%s: New pkt create failed\n", __func__);
 		return -ENOMEM;
 	}
-
-	head_skb = skb_peek(pkt->pkt_fragment_q);
-	if (!head_skb) {
-		pr_err("%s: pkt_fragment_q is empty\n", __func__);
-		release_pkt(pkt);
-		return -EINVAL;
-	}
-	hdr = (struct rr_header *)skb_push(head_skb, IPC_ROUTER_HDR_SIZE);
-	if (!hdr) {
-		pr_err("%s: Prepend Header failed\n", __func__);
-		release_pkt(pkt);
-		return -ENOMEM;
-	}
-	hdr->version = IPC_ROUTER_VERSION;
+	hdr = &(pkt->hdr);
+	hdr->version = IPC_ROUTER_V1;
 	hdr->type = IPC_ROUTER_CTRL_CMD_DATA;
 	hdr->src_node_id = src->this_port.node_id;
 	hdr->src_port_id = src->this_port.port_id;
 	hdr->size = pkt->length;
-	hdr->confirm_rx = 0;
+	hdr->control_flag = 0;
 	hdr->dst_node_id = IPC_ROUTER_NID_LOCAL;
 	hdr->dst_port_id = port_id;
-	pkt->length += IPC_ROUTER_HDR_SIZE;
 
 	down_read(&local_ports_lock_lha2);
 	port_ptr = msm_ipc_router_lookup_local_port(port_id);
 	if (!port_ptr) {
 		pr_err("%s: Local port %d not present\n", __func__, port_id);
 		up_read(&local_ports_lock_lha2);
+		pkt->pkt_fragment_q = NULL;
 		release_pkt(pkt);
 		return -ENODEV;
 	}
@@ -2027,35 +2316,26 @@
 				struct msm_ipc_router_remote_port *rport_ptr,
 				struct rr_packet *pkt)
 {
-	struct sk_buff *head_skb;
-	struct rr_header *hdr;
+	struct rr_header_v1 *hdr;
 	struct msm_ipc_router_xprt_info *xprt_info;
 	struct msm_ipc_routing_table_entry *rt_entry;
 	struct msm_ipc_resume_tx_port  *resume_tx_port;
+	struct sk_buff *temp_skb;
+	int xprt_option;
 	int ret;
+	int align_size;
 
 	if (!rport_ptr || !src || !pkt)
 		return -EINVAL;
 
-	head_skb = skb_peek(pkt->pkt_fragment_q);
-	if (!head_skb) {
-		pr_err("%s: pkt_fragment_q is empty\n", __func__);
-		return -EINVAL;
-	}
-	hdr = (struct rr_header *)skb_push(head_skb, IPC_ROUTER_HDR_SIZE);
-	if (!hdr) {
-		pr_err("%s: Prepend Header failed\n", __func__);
-		return -ENOMEM;
-	}
-	hdr->version = IPC_ROUTER_VERSION;
+	hdr = &(pkt->hdr);
 	hdr->type = IPC_ROUTER_CTRL_CMD_DATA;
 	hdr->src_node_id = src->this_port.node_id;
 	hdr->src_port_id = src->this_port.port_id;
 	hdr->size = pkt->length;
-	hdr->confirm_rx = 0;
+	hdr->control_flag = 0;
 	hdr->dst_node_id = rport_ptr->node_id;
 	hdr->dst_port_id = rport_ptr->port_id;
-	pkt->length += IPC_ROUTER_HDR_SIZE;
 
 	mutex_lock(&rport_ptr->quota_lock_lhb2);
 	if (rport_ptr->tx_quota_cnt == IPC_ROUTER_DEFAULT_RX_QUOTA) {
@@ -2083,7 +2363,7 @@
 	}
 	rport_ptr->tx_quota_cnt++;
 	if (rport_ptr->tx_quota_cnt == IPC_ROUTER_DEFAULT_RX_QUOTA)
-		hdr->confirm_rx = 1;
+		hdr->control_flag |= CONTROL_FLAG_CONFIRM_RX;
 	mutex_unlock(&rport_ptr->quota_lock_lhb2);
 
 	rt_entry = lookup_routing_table(hdr->dst_node_id);
@@ -2094,6 +2374,25 @@
 	}
 	down_read(&rt_entry->lock_lha4);
 	xprt_info = rt_entry->xprt_info;
+	ret = prepend_header(pkt, xprt_info);
+	if (ret < 0) {
+		up_read(&rt_entry->lock_lha4);
+		pr_err("%s: Prepend Header failed\n", __func__);
+		return ret;
+	}
+	xprt_option = xprt_info->xprt->get_option(xprt_info->xprt);
+	if (!(xprt_option & FRAG_PKT_WRITE_ENABLE)) {
+		ret = defragment_pkt(pkt);
+		if (ret < 0) {
+			up_read(&rt_entry->lock_lha4);
+			return ret;
+		}
+	}
+
+	temp_skb = skb_peek_tail(pkt->pkt_fragment_q);
+	align_size = ALIGN_SIZE(pkt->length);
+	skb_put(temp_skb, align_size);
+	pkt->length += align_size;
 	mutex_lock(&xprt_info->tx_lock_lhb2);
 	ret = xprt_info->xprt->write(pkt, pkt->length, xprt_info->xprt);
 	mutex_unlock(&xprt_info->tx_lock_lhb2);
@@ -2107,10 +2406,10 @@
 
 	RAW_HDR("[w rr_h] "
 		"ver=%i,type=%s,src_nid=%08x,src_port_id=%08x,"
-		"confirm_rx=%i,size=%3i,dst_pid=%08x,dst_cid=%08x\n",
+		"control_flag=%i,size=%3i,dst_pid=%08x,dst_cid=%08x\n",
 		hdr->version, type_to_str(hdr->type),
 		hdr->src_node_id, hdr->src_port_id,
-		hdr->confirm_rx, hdr->size,
+		hdr->control_flag, hdr->size,
 		hdr->dst_node_id, hdr->dst_port_id);
 
 #if defined(CONFIG_MSM_SMD_LOGGING)
@@ -2123,13 +2422,13 @@
 			(hdr->src_port_id & 0xffffff),
 			(hdr->dst_node_id << 24) |
 			(hdr->dst_port_id & 0xffffff),
-			(hdr->type << 24) | (hdr->confirm_rx << 16) |
+			(hdr->type << 24) | (hdr->control_flag << 16) |
 			(hdr->size & 0xffff));
 	}
 #endif
 #endif
 
-	return pkt->length;
+	return hdr->size;
 }
 
 int msm_ipc_router_send_to(struct msm_ipc_port *src,
@@ -2203,6 +2502,8 @@
 
 	ret = msm_ipc_router_write_pkt(src, rport_ptr, pkt);
 	up_read(&routing_table_lock_lha3);
+	if (ret < 0)
+		pkt->pkt_fragment_q = NULL;
 	release_pkt(pkt);
 
 	return ret;
@@ -2222,11 +2523,10 @@
 	}
 
 	ret = msm_ipc_router_send_to(src, out_skb_head, dest);
-	if (ret == -EAGAIN)
-		return ret;
 	if (ret < 0) {
-		pr_err("%s: msm_ipc_router_send_to failed - ret: %d\n",
-			__func__, ret);
+		if (ret != -EAGAIN)
+			pr_err("%s: msm_ipc_router_send_to failed - ret: %d\n",
+				__func__, ret);
 		msm_ipc_router_free_skb(out_skb_head);
 		return ret;
 	}
@@ -2248,7 +2548,7 @@
 static int msm_ipc_router_send_resume_tx(void *data)
 {
 	union rr_control_msg msg;
-	struct rr_header *hdr = (struct rr_header *)data;
+	struct rr_header_v1 *hdr = (struct rr_header_v1 *)data;
 	struct msm_ipc_routing_table_entry *rt_entry;
 	int ret;
 
@@ -2278,14 +2578,12 @@
 }
 
 int msm_ipc_router_read(struct msm_ipc_port *port_ptr,
-			struct sk_buff_head **data,
+			struct rr_packet **read_pkt,
 			size_t buf_len)
 {
 	struct rr_packet *pkt;
-	struct sk_buff *head_skb;
-	int ret;
 
-	if (!port_ptr || !data)
+	if (!port_ptr || !read_pkt)
 		return -EINVAL;
 
 	mutex_lock(&port_ptr->port_rx_q_lock_lhb3);
@@ -2295,26 +2593,19 @@
 	}
 
 	pkt = list_first_entry(&port_ptr->port_rx_q, struct rr_packet, list);
-	if ((buf_len) && ((pkt->length - IPC_ROUTER_HDR_SIZE) > buf_len)) {
+	if ((buf_len) && (pkt->hdr.size > buf_len)) {
 		mutex_unlock(&port_ptr->port_rx_q_lock_lhb3);
 		return -ETOOSMALL;
 	}
 	list_del(&pkt->list);
 	if (list_empty(&port_ptr->port_rx_q))
 		wake_unlock(&port_ptr->port_rx_wake_lock);
-	*data = pkt->pkt_fragment_q;
-	ret = pkt->length;
+	*read_pkt = pkt;
 	mutex_unlock(&port_ptr->port_rx_q_lock_lhb3);
-	kfree(pkt);
-	head_skb = skb_peek(*data);
-	if (!head_skb) {
-		pr_err("%s: Socket Buffer not found", __func__);
-		return -EFAULT;
-	}
-	if (((struct rr_header *)(head_skb->data))->confirm_rx)
-		msm_ipc_router_send_resume_tx((void *)(head_skb->data));
+	if (pkt->hdr.control_flag & CONTROL_FLAG_CONFIRM_RX)
+		msm_ipc_router_send_resume_tx(&pkt->hdr);
 
-	return ret;
+	return pkt->length;
 }
 
 /**
@@ -2362,7 +2653,7 @@
 /**
  * msm_ipc_router_recv_from() - Recieve messages destined to a local port.
  * @port_ptr: Pointer to the local port
- * @data : Pointer to the socket buffer head
+ * @pkt : Pointer to the router-to-router packet
  * @src: Pointer to local port address
  * @timeout: < 0 timeout indicates infinite wait till a message arrives.
  *	     > 0 timeout indicates the wait time.
@@ -2383,31 +2674,30 @@
  * of bytes that are read.
  */
 int msm_ipc_router_recv_from(struct msm_ipc_port *port_ptr,
-			     struct sk_buff_head **data,
+			     struct rr_packet **pkt,
 			     struct msm_ipc_addr *src,
 			     long timeout)
 {
 	int ret, data_len, align_size;
 	struct sk_buff *temp_skb;
-	struct rr_header *hdr = NULL;
+	struct rr_header_v1 *hdr = NULL;
 
-	if (!port_ptr || !data) {
+	if (!port_ptr || !pkt) {
 		pr_err("%s: Invalid pointers being passed\n", __func__);
 		return -EINVAL;
 	}
 
-	*data = NULL;
+	*pkt = NULL;
 
 	ret = msm_ipc_router_rx_data_wait(port_ptr, timeout);
 	if (ret)
 		return ret;
 
-	ret = msm_ipc_router_read(port_ptr, data, 0);
-	if (ret <= 0 || !(*data))
+	ret = msm_ipc_router_read(port_ptr, pkt, 0);
+	if (ret <= 0 || !(*pkt))
 		return ret;
 
-	temp_skb = skb_peek(*data);
-	hdr = (struct rr_header *)(temp_skb->data);
+	hdr = &((*pkt)->hdr);
 	if (src) {
 		src->addrtype = MSM_IPC_ADDR_ID;
 		src->addr.port_addr.node_id = hdr->src_node_id;
@@ -2415,10 +2705,9 @@
 	}
 
 	data_len = hdr->size;
-	skb_pull(temp_skb, IPC_ROUTER_HDR_SIZE);
 	align_size = ALIGN_SIZE(data_len);
 	if (align_size) {
-		temp_skb = skb_peek_tail(*data);
+		temp_skb = skb_peek_tail((*pkt)->pkt_fragment_q);
 		skb_trim(temp_skb, (temp_skb->len - align_size));
 	}
 	return data_len;
@@ -2429,11 +2718,10 @@
 			    unsigned char **data,
 			    unsigned int *len)
 {
-	struct sk_buff_head *in_skb_head;
+	struct rr_packet *pkt;
 	int ret;
 
-	ret = msm_ipc_router_recv_from(port_ptr, &in_skb_head, src, 0);
-
+	ret = msm_ipc_router_recv_from(port_ptr, &pkt, src, 0);
 	if (ret < 0) {
 		if (ret != -ENOMSG)
 			pr_err("%s: msm_ipc_router_recv_from failed - ret: %d\n",
@@ -2441,12 +2729,12 @@
 		return ret;
 	}
 
-	*data = msm_ipc_router_skb_to_buf(in_skb_head, ret);
+	*data = msm_ipc_router_skb_to_buf(pkt->pkt_fragment_q, ret);
 	if (!(*data))
 		pr_err("%s: Buf conversion failed\n", __func__);
 
 	*len = ret;
-	msm_ipc_router_free_skb(in_skb_head);
+	release_pkt(pkt);
 	return 0;
 }
 
diff --git a/arch/arm/mach-msm/ipc_router.h b/arch/arm/mach-msm/ipc_router.h
index 7bfc52b..8ffd661 100644
--- a/arch/arm/mach-msm/ipc_router.h
+++ b/arch/arm/mach-msm/ipc_router.h
@@ -24,12 +24,17 @@
 #include <net/sock.h>
 
 /* definitions for the R2R wire protcol */
-#define IPC_ROUTER_VERSION			1
+#define IPC_ROUTER_V1		1
+/*
+ * Ambiguous definition but will enable multiplexing IPC_ROUTER_V2 packets
+ * with an existing alternate transport in user-space, if needed.
+ */
+#define IPC_ROUTER_V2		3
 
-#define IPC_ROUTER_CLIENT_BCAST_ID		0xffffffff
-#define IPC_ROUTER_ADDRESS			0xfffffffe
+#define IPC_ROUTER_ADDRESS			0x0000FFFF
 
 #define IPC_ROUTER_NID_LOCAL			1
+#define MAX_IPC_PKT_SIZE 66000
 
 #define IPC_ROUTER_CTRL_CMD_DATA		1
 #define IPC_ROUTER_CTRL_CMD_HELLO		2
@@ -55,6 +60,11 @@
 #define ALL_SERVICE 0xFFFFFFFF
 #define ALL_INSTANCE 0xFFFFFFFF
 
+#define CONTROL_FLAG_CONFIRM_RX 0x1
+#define CONTROL_FLAG_OPT_HDR 0x2
+
+#define FRAG_PKT_WRITE_ENABLE 0x1
+
 enum {
 	CLIENT_PORT,
 	SERVER_PORT,
@@ -68,10 +78,22 @@
 	MULTI_LINK_MODE,
 };
 
+/**
+ * rr_control_msg - Control message structure
+ * @cmd: Command identifier for HELLO message in Version 1.
+ * @hello: Message structure for HELLO message in Version 2.
+ * @srv: Message structure for NEW_SERVER/REMOVE_SERVER events.
+ * @cli: Message structure for REMOVE_CLIENT event.
+ */
 union rr_control_msg {
 	uint32_t cmd;
 	struct {
 		uint32_t cmd;
+		uint32_t magic;
+		uint32_t capability;
+	} hello;
+	struct {
+		uint32_t cmd;
 		uint32_t service;
 		uint32_t instance;
 		uint32_t node_id;
@@ -84,22 +106,67 @@
 	} cli;
 };
 
-struct rr_header {
+/**
+ * rr_header_v1 - IPC Router header version 1
+ * @version: Version information.
+ * @type: IPC Router Message Type.
+ * @src_node_id: Source Node ID of the message.
+ * @src_port_id: Source Port ID of the message.
+ * @control_flag: Flag to indicate flow control.
+ * @size: Size of the IPC Router payload.
+ * @dst_node_id: Destination Node ID of the message.
+ * @dst_port_id: Destination Port ID of the message.
+ */
+struct rr_header_v1 {
 	uint32_t version;
 	uint32_t type;
 	uint32_t src_node_id;
 	uint32_t src_port_id;
-	uint32_t confirm_rx;
+	uint32_t control_flag;
 	uint32_t size;
 	uint32_t dst_node_id;
 	uint32_t dst_port_id;
 };
 
-#define IPC_ROUTER_HDR_SIZE sizeof(struct rr_header)
-#define MAX_IPC_PKT_SIZE 66000
+/**
+ * rr_header_v2 - IPC Router header version 2
+ * @version: Version information.
+ * @type: IPC Router Message Type.
+ * @control_flag: Flags to indicate flow control, optional header etc.
+ * @size: Size of the IPC Router payload.
+ * @src_node_id: Source Node ID of the message.
+ * @src_port_id: Source Port ID of the message.
+ * @dst_node_id: Destination Node ID of the message.
+ * @dst_port_id: Destination Port ID of the message.
+ */
+struct rr_header_v2 {
+	uint8_t version;
+	uint8_t type;
+	uint16_t control_flag;
+	uint32_t size;
+	uint16_t src_node_id;
+	uint16_t src_port_id;
+	uint16_t dst_node_id;
+	uint16_t dst_port_id;
+} __attribute__((__packed__));
 
+union rr_header {
+	struct rr_header_v1 hdr_v1;
+	struct rr_header_v2 hdr_v2;
+};
+
+#define IPC_ROUTER_HDR_SIZE sizeof(union rr_header)
+
+/**
+ * rr_packet - Router to Router packet structure
+ * @list: Pointer to prev & next packets in a port's rx list.
+ * @hdr: Header information extracted from or prepended to a packet.
+ * @pkt_fragment_q: Queue of SKBs containing payload.
+ * @length: Length of data in the chain of SKBs
+ */
 struct rr_packet {
 	struct list_head list;
+	struct rr_header_v1 hdr;
 	struct sk_buff_head *pkt_fragment_q;
 	uint32_t length;
 };
@@ -110,11 +177,28 @@
 	void *default_pil;
 };
 
+/**
+ * msm_ipc_router_xprt - Structure to hold XPRT specific information
+ * @name: Name of the XPRT.
+ * @link_id: Network cluster ID to which the XPRT belongs to.
+ * @priv: XPRT's private data.
+ * @get_version: Method to get header version supported by the XPRT.
+ * @get_option: Method to get XPRT specific options.
+ * @read_avail: Method to get data size available to be read from the XPRT.
+ * @read: Method to read data from the XPRT.
+ * @write_avail: Method to get write space available in the XPRT.
+ * @write: Method to write data to the XPRT.
+ * @close: Method to close the XPRT.
+ * @sft_close_done: Method to indicate to the XPRT that handling of reset
+ *                  event is complete.
+ */
 struct msm_ipc_router_xprt {
 	char *name;
 	uint32_t link_id;
 	void *priv;
 
+	int (*get_version)(struct msm_ipc_router_xprt *xprt);
+	int (*get_option)(struct msm_ipc_router_xprt *xprt);
 	int (*read_avail)(struct msm_ipc_router_xprt *xprt);
 	int (*read)(void *data, uint32_t len,
 		    struct msm_ipc_router_xprt *xprt);
@@ -141,12 +225,12 @@
 			   struct sk_buff_head *data,
 			   struct msm_ipc_addr *dest);
 int msm_ipc_router_read(struct msm_ipc_port *port_ptr,
-			struct sk_buff_head **data,
+			struct rr_packet **pkt,
 			size_t buf_len);
 int msm_ipc_router_bind_control_port(struct msm_ipc_port *port_ptr);
 
 int msm_ipc_router_recv_from(struct msm_ipc_port *port_ptr,
-		      struct sk_buff_head **data,
+		      struct rr_packet **pkt,
 		      struct msm_ipc_addr *src_addr,
 		      long timeout);
 int msm_ipc_router_register_server(struct msm_ipc_port *server_port,
@@ -173,4 +257,5 @@
 static inline void msm_ipc_unload_default_node(void *pil) { }
 #endif
 
+void msm_ipc_router_free_skb(struct sk_buff_head *skb_head);
 #endif
diff --git a/arch/arm/mach-msm/ipc_router_hsic_xprt.c b/arch/arm/mach-msm/ipc_router_hsic_xprt.c
new file mode 100644
index 0000000..0427c1c
--- /dev/null
+++ b/arch/arm/mach-msm/ipc_router_hsic_xprt.c
@@ -0,0 +1,503 @@
+/* Copyright (c) 2013, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+/*
+ * IPC ROUTER HSIC XPRT module.
+ */
+#define DEBUG
+
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/types.h>
+
+#include <mach/ipc_bridge.h>
+#include <mach/subsystem_restart.h>
+
+#include "ipc_router.h"
+
+static int msm_ipc_router_hsic_xprt_debug_mask;
+module_param_named(debug_mask, msm_ipc_router_hsic_xprt_debug_mask,
+		   int, S_IRUGO | S_IWUSR | S_IWGRP);
+
+#if defined(DEBUG)
+#define D(x...) do { \
+if (msm_ipc_router_hsic_xprt_debug_mask) \
+	pr_info(x); \
+} while (0)
+#else
+#define D(x...) do { } while (0)
+#endif
+
+#define NUM_HSIC_XPRTS 1
+#define XPRT_NAME_LEN 32
+
+/**
+ * msm_ipc_router_hsic_xprt - IPC Router's HSIC XPRT strucutre
+ * @xprt: IPC Router XPRT structure to contain HSIC XPRT specific info.
+ * @pdev: Platform device registered by IPC Bridge function driver.
+ * @hsic_xprt_wq: Workqueue to queue read & other XPRT related works.
+ * @read_work: Read Work to perform read operation from HSIC's ipc_bridge.
+ * @in_pkt: Pointer to any partially read packet.
+ * @ss_reset_lock: Lock to protect access to the ss_reset flag.
+ * @sft_close_complete: Variable to indicate completion of SSR handling
+ *                      by IPC Router.
+ * @xprt_version: IPC Router header version supported by this XPRT.
+ * @xprt_option: XPRT specific options to be handled by IPC Router.
+ */
+struct msm_ipc_router_hsic_xprt {
+	struct msm_ipc_router_xprt xprt;
+	struct platform_device *pdev;
+	struct workqueue_struct *hsic_xprt_wq;
+	struct delayed_work read_work;
+	struct rr_packet *in_pkt;
+	struct mutex ss_reset_lock;
+	int ss_reset;
+	struct completion sft_close_complete;
+	unsigned xprt_version;
+	unsigned xprt_option;
+};
+
+struct msm_ipc_router_hsic_xprt_work {
+	struct msm_ipc_router_xprt *xprt;
+	struct work_struct work;
+};
+
+static void hsic_xprt_read_data(struct work_struct *work);
+
+/**
+ * msm_ipc_router_hsic_xprt_config - Config. Info. of each HSIC XPRT
+ * @ch_name: Name of the HSIC endpoint exported by ipc_bridge driver.
+ * @xprt_name: Name of the XPRT to be registered with IPC Router.
+ * @hsic_pdev_id: ID to differentiate among multiple ipc_bridge endpoints.
+ * @link_id: Network Cluster ID to which this XPRT belongs to.
+ * @xprt_version: IPC Router header version supported by this XPRT.
+ */
+struct msm_ipc_router_hsic_xprt_config {
+	char ch_name[XPRT_NAME_LEN];
+	char xprt_name[XPRT_NAME_LEN];
+	int hsic_pdev_id;
+	uint32_t link_id;
+	unsigned xprt_version;
+};
+
+struct msm_ipc_router_hsic_xprt_config hsic_xprt_cfg[] = {
+	{"ipc_bridge", "ipc_rtr_ipc_bridge1", 1, 1, 3},
+};
+
+static struct msm_ipc_router_hsic_xprt hsic_remote_xprt[NUM_HSIC_XPRTS];
+
+/**
+ * find_hsic_xprt_cfg() - Find the config info specific to an HSIC endpoint
+ * @pdev: Platform device registered by HSIC's ipc_bridge driver
+ *
+ * @return: Index to the entry in the hsic_remote_xprt table if matching
+ *          endpoint is found, < 0 on error.
+ *
+ * This function is used to find the configuration information specific to
+ * an HSIC endpoint from the hsic_remote_xprt table.
+ */
+static int find_hsic_xprt_cfg(struct platform_device *pdev)
+{
+	int i;
+
+	for (i = 0; i < NUM_HSIC_XPRTS; i++) {
+		/* TODO: Update the condition for multiple hsic links */
+		if (!strncmp(pdev->name, hsic_xprt_cfg[i].ch_name, 32))
+			return i;
+	}
+
+	return -ENODEV;
+}
+
+/**
+ * msm_ipc_router_hsic_get_xprt_version() - Get IPC Router header version
+ *                                          supported by the XPRT
+ * @xprt: XPRT for which the version information is required.
+ *
+ * @return: IPC Router header version supported by the XPRT.
+ */
+static int msm_ipc_router_hsic_get_xprt_version(
+	struct msm_ipc_router_xprt *xprt)
+{
+	struct msm_ipc_router_hsic_xprt *hsic_xprtp;
+	if (!xprt)
+		return -EINVAL;
+	hsic_xprtp = container_of(xprt, struct msm_ipc_router_hsic_xprt, xprt);
+
+	return (int)hsic_xprtp->xprt_version;
+}
+
+/**
+ * msm_ipc_router_hsic_get_xprt_option() - Get XPRT options
+ * @xprt: XPRT for which the option information is required.
+ *
+ * @return: Options supported by the XPRT.
+ */
+static int msm_ipc_router_hsic_get_xprt_option(
+	struct msm_ipc_router_xprt *xprt)
+{
+	struct msm_ipc_router_hsic_xprt *hsic_xprtp;
+	if (!xprt)
+		return -EINVAL;
+	hsic_xprtp = container_of(xprt, struct msm_ipc_router_hsic_xprt, xprt);
+
+	return (int)hsic_xprtp->xprt_option;
+}
+
+/**
+ * msm_ipc_router_hsic_remote_write_avail() - Get available write space
+ * @xprt: XPRT for which the available write space info. is required.
+ *
+ * @return: Write space in bytes on success, 0 on SSR.
+ */
+static int msm_ipc_router_hsic_remote_write_avail(
+	struct msm_ipc_router_xprt *xprt)
+{
+	struct ipc_bridge_platform_data *pdata;
+	int write_avail;
+	struct msm_ipc_router_hsic_xprt *hsic_xprtp =
+		container_of(xprt, struct msm_ipc_router_hsic_xprt, xprt);
+
+	mutex_lock(&hsic_xprtp->ss_reset_lock);
+	if (hsic_xprtp->ss_reset || !hsic_xprtp->pdev) {
+		write_avail = 0;
+	} else {
+		pdata = hsic_xprtp->pdev->dev.platform_data;
+		write_avail = pdata->max_write_size;
+	}
+	mutex_unlock(&hsic_xprtp->ss_reset_lock);
+	return write_avail;
+}
+
+/**
+ * msm_ipc_router_hsic_remote_write() - Write to XPRT
+ * @data: Data to be written to the XPRT.
+ * @len: Length of the data to be written.
+ * @xprt: XPRT to which the data has to be written.
+ *
+ * @return: Data Length on success, standard Linux error codes on failure.
+ */
+static int msm_ipc_router_hsic_remote_write(void *data,
+		uint32_t len, struct msm_ipc_router_xprt *xprt)
+{
+	struct rr_packet *pkt = (struct rr_packet *)data;
+	struct sk_buff *skb;
+	struct ipc_bridge_platform_data *pdata;
+	struct msm_ipc_router_hsic_xprt *hsic_xprtp;
+	int ret;
+
+	if (!pkt || pkt->length != len || !xprt) {
+		pr_err("%s: Invalid input parameters\n", __func__);
+		return -EINVAL;
+	}
+
+	hsic_xprtp = container_of(xprt, struct msm_ipc_router_hsic_xprt, xprt);
+	mutex_lock(&hsic_xprtp->ss_reset_lock);
+	if (hsic_xprtp->ss_reset) {
+		pr_err("%s: Trying to write on a reset link\n", __func__);
+		mutex_unlock(&hsic_xprtp->ss_reset_lock);
+		return -ENETRESET;
+	}
+
+	if (!hsic_xprtp->pdev) {
+		pr_err("%s: Trying to write on a closed link\n", __func__);
+		mutex_unlock(&hsic_xprtp->ss_reset_lock);
+		return -ENODEV;
+	}
+
+	pdata = hsic_xprtp->pdev->dev.platform_data;
+	if (!pdata || !pdata->write) {
+		pr_err("%s on a uninitialized link\n", __func__);
+		mutex_unlock(&hsic_xprtp->ss_reset_lock);
+		return -EFAULT;
+	}
+
+	skb = skb_peek(pkt->pkt_fragment_q);
+	if (!skb) {
+		pr_err("%s SKB is NULL\n", __func__);
+		mutex_unlock(&hsic_xprtp->ss_reset_lock);
+		return -EINVAL;
+	}
+	D("%s: About to write %d bytes\n", __func__, len);
+	ret = pdata->write(hsic_xprtp->pdev, skb->data, skb->len);
+	if (ret == skb->len)
+		ret = len;
+	D("%s: Finished writing %d bytes\n", __func__, len);
+	mutex_unlock(&hsic_xprtp->ss_reset_lock);
+	return ret;
+}
+
+/**
+ * msm_ipc_router_hsic_remote_close() - Close the XPRT
+ * @xprt: XPRT which needs to be closed.
+ *
+ * @return: 0 on success, standard Linux error codes on failure.
+ */
+static int msm_ipc_router_hsic_remote_close(
+	struct msm_ipc_router_xprt *xprt)
+{
+	struct msm_ipc_router_hsic_xprt *hsic_xprtp;
+	struct ipc_bridge_platform_data *pdata;
+
+	if (!xprt)
+		return -EINVAL;
+	hsic_xprtp = container_of(xprt, struct msm_ipc_router_hsic_xprt, xprt);
+
+	mutex_lock(&hsic_xprtp->ss_reset_lock);
+	hsic_xprtp->ss_reset = 1;
+	mutex_unlock(&hsic_xprtp->ss_reset_lock);
+	flush_workqueue(hsic_xprtp->hsic_xprt_wq);
+	destroy_workqueue(hsic_xprtp->hsic_xprt_wq);
+	pdata = hsic_xprtp->pdev->dev.platform_data;
+	if (pdata && pdata->close)
+		pdata->close(hsic_xprtp->pdev);
+	hsic_xprtp->pdev = NULL;
+	return 0;
+}
+
+/**
+ * hsic_xprt_read_data() - Read work to read from the XPRT
+ * @work: Read work to be executed.
+ *
+ * This function is a read work item queued on a XPRT specific workqueue.
+ * The work parameter contains information regarding the XPRT on which this
+ * read work has to be performed. The work item keeps reading from the HSIC
+ * endpoint, until the endpoint returns an error.
+ */
+static void hsic_xprt_read_data(struct work_struct *work)
+{
+	int pkt_size;
+	struct sk_buff *skb = NULL;
+	void *data;
+	struct ipc_bridge_platform_data *pdata;
+	struct delayed_work *rwork = to_delayed_work(work);
+	struct msm_ipc_router_hsic_xprt *hsic_xprtp =
+		container_of(rwork, struct msm_ipc_router_hsic_xprt, read_work);
+
+	while (1) {
+		mutex_lock(&hsic_xprtp->ss_reset_lock);
+		if (hsic_xprtp->ss_reset) {
+			mutex_unlock(&hsic_xprtp->ss_reset_lock);
+			break;
+		}
+		pdata = hsic_xprtp->pdev->dev.platform_data;
+		mutex_unlock(&hsic_xprtp->ss_reset_lock);
+		while (!hsic_xprtp->in_pkt) {
+			hsic_xprtp->in_pkt = kzalloc(sizeof(struct rr_packet),
+						     GFP_KERNEL);
+			if (hsic_xprtp->in_pkt)
+				break;
+			pr_err("%s: packet allocation failure\n", __func__);
+			msleep(100);
+		}
+		while (!hsic_xprtp->in_pkt->pkt_fragment_q) {
+			hsic_xprtp->in_pkt->pkt_fragment_q =
+				kmalloc(sizeof(struct sk_buff_head),
+					GFP_KERNEL);
+			if (hsic_xprtp->in_pkt->pkt_fragment_q)
+				break;
+			pr_err("%s: Couldn't alloc pkt_fragment_q\n",
+				__func__);
+			msleep(100);
+		}
+		skb_queue_head_init(hsic_xprtp->in_pkt->pkt_fragment_q);
+		D("%s: Allocated rr_packet\n", __func__);
+
+		while (!skb) {
+			skb = alloc_skb(pdata->max_read_size, GFP_KERNEL);
+			if (skb)
+				break;
+			pr_err("%s: Couldn't alloc SKB\n", __func__);
+			msleep(100);
+		}
+		data = skb_put(skb, pdata->max_read_size);
+		pkt_size = pdata->read(hsic_xprtp->pdev, data,
+					pdata->max_read_size);
+		if (pkt_size < 0) {
+			pr_err("%s: Error %d @ read operation\n",
+				__func__, pkt_size);
+			kfree_skb(skb);
+			kfree(hsic_xprtp->in_pkt->pkt_fragment_q);
+			kfree(hsic_xprtp->in_pkt);
+			break;
+		}
+		skb_queue_tail(hsic_xprtp->in_pkt->pkt_fragment_q, skb);
+		hsic_xprtp->in_pkt->length = pkt_size;
+		D("%s: Packet size read %d\n", __func__, pkt_size);
+		msm_ipc_router_xprt_notify(&hsic_xprtp->xprt,
+			IPC_ROUTER_XPRT_EVENT_DATA, (void *)hsic_xprtp->in_pkt);
+		release_pkt(hsic_xprtp->in_pkt);
+		hsic_xprtp->in_pkt = NULL;
+		skb = NULL;
+	}
+}
+
+/**
+ * hsic_xprt_sft_close_done() - Completion of XPRT reset
+ * @xprt: XPRT on which the reset operation is complete.
+ *
+ * This function is used by IPC Router to signal this HSIC XPRT Abstraction
+ * Layer(XAL) that the reset of XPRT is completely handled by IPC Router.
+ */
+static void hsic_xprt_sft_close_done(struct msm_ipc_router_xprt *xprt)
+{
+	struct msm_ipc_router_hsic_xprt *hsic_xprtp =
+		container_of(xprt, struct msm_ipc_router_hsic_xprt, xprt);
+
+	complete_all(&hsic_xprtp->sft_close_complete);
+}
+
+/**
+ * msm_ipc_router_hsic_remote_remove() - Remove an HSIC endpoint
+ * @pdev: Platform device corresponding to HSIC endpoint.
+ *
+ * @return: 0 on success, standard Linux error codes on error.
+ *
+ * This function is called when the underlying ipc_bridge driver unregisters
+ * a platform device, mapped to an HSIC endpoint, during SSR.
+ */
+static int msm_ipc_router_hsic_remote_remove(struct platform_device *pdev)
+{
+	int id;
+	struct ipc_bridge_platform_data *pdata;
+
+	id = find_hsic_xprt_cfg(pdev);
+	if (id < 0) {
+		pr_err("%s: called for unknown ch %s\n",
+			__func__, pdev->name);
+		return id;
+	}
+
+	mutex_lock(&hsic_remote_xprt[id].ss_reset_lock);
+	hsic_remote_xprt[id].ss_reset = 1;
+	mutex_unlock(&hsic_remote_xprt[id].ss_reset_lock);
+	flush_workqueue(hsic_remote_xprt[id].hsic_xprt_wq);
+	destroy_workqueue(hsic_remote_xprt[id].hsic_xprt_wq);
+	init_completion(&hsic_remote_xprt[id].sft_close_complete);
+	msm_ipc_router_xprt_notify(&hsic_remote_xprt[id].xprt,
+				   IPC_ROUTER_XPRT_EVENT_CLOSE, NULL);
+	D("%s: Notified IPC Router of %s CLOSE\n",
+	  __func__, hsic_remote_xprt[id].xprt.name);
+	wait_for_completion(&hsic_remote_xprt[id].sft_close_complete);
+	hsic_remote_xprt[id].pdev = NULL;
+	pdata = pdev->dev.platform_data;
+	if (pdata && pdata->close)
+		pdata->close(pdev);
+	return 0;
+}
+
+/**
+ * msm_ipc_router_hsic_remote_probe() - Probe an HSIC endpoint
+ * @pdev: Platform device corresponding to HSIC endpoint.
+ *
+ * @return: 0 on success, standard Linux error codes on error.
+ *
+ * This function is called when the underlying ipc_bridge driver registers
+ * a platform device, mapped to an HSIC endpoint.
+ */
+static int msm_ipc_router_hsic_remote_probe(struct platform_device *pdev)
+{
+	int rc;
+	int id;		/*Index into the hsic_xprt_cfg table*/
+	struct ipc_bridge_platform_data *pdata;
+
+	pdata = pdev->dev.platform_data;
+	if (!pdata || !pdata->open || !pdata->read ||
+	    !pdata->write || !pdata->close) {
+		pr_err("%s: pdata or pdata->operations is NULL\n", __func__);
+		return -EINVAL;
+	}
+
+	id = find_hsic_xprt_cfg(pdev);
+	if (id < 0) {
+		pr_err("%s: called for unknown ch %s\n",
+			__func__, pdev->name);
+		return id;
+	}
+
+	hsic_remote_xprt[id].hsic_xprt_wq =
+		create_singlethread_workqueue(pdev->name);
+	if (!hsic_remote_xprt[id].hsic_xprt_wq) {
+		pr_err("%s: WQ creation failed for %s\n",
+			__func__, pdev->name);
+		return -EFAULT;
+	}
+
+	hsic_remote_xprt[id].xprt.name = hsic_xprt_cfg[id].xprt_name;
+	hsic_remote_xprt[id].xprt.link_id = hsic_xprt_cfg[id].link_id;
+	hsic_remote_xprt[id].xprt.get_version =
+		msm_ipc_router_hsic_get_xprt_version;
+	hsic_remote_xprt[id].xprt.get_option =
+		 msm_ipc_router_hsic_get_xprt_option;
+	hsic_remote_xprt[id].xprt.read_avail = NULL;
+	hsic_remote_xprt[id].xprt.read = NULL;
+	hsic_remote_xprt[id].xprt.write_avail =
+		msm_ipc_router_hsic_remote_write_avail;
+	hsic_remote_xprt[id].xprt.write = msm_ipc_router_hsic_remote_write;
+	hsic_remote_xprt[id].xprt.close = msm_ipc_router_hsic_remote_close;
+	hsic_remote_xprt[id].xprt.sft_close_done = hsic_xprt_sft_close_done;
+	hsic_remote_xprt[id].xprt.priv = NULL;
+
+	hsic_remote_xprt[id].in_pkt = NULL;
+	INIT_DELAYED_WORK(&hsic_remote_xprt[id].read_work, hsic_xprt_read_data);
+	mutex_init(&hsic_remote_xprt[id].ss_reset_lock);
+	hsic_remote_xprt[id].ss_reset = 0;
+	hsic_remote_xprt[id].xprt_version = hsic_xprt_cfg[id].xprt_version;
+	hsic_remote_xprt[id].xprt_option = 0;
+
+	rc = pdata->open(pdev);
+	if (rc < 0) {
+		pr_err("%s: Channel open failed for %s.%d\n",
+			__func__, pdev->name, pdev->id);
+		destroy_workqueue(hsic_remote_xprt[id].hsic_xprt_wq);
+		return rc;
+	}
+	hsic_remote_xprt[id].pdev = pdev;
+	msm_ipc_router_xprt_notify(&hsic_remote_xprt[id].xprt,
+				   IPC_ROUTER_XPRT_EVENT_OPEN, NULL);
+	D("%s: Notified IPC Router of %s OPEN\n",
+	  __func__, hsic_remote_xprt[id].xprt.name);
+	queue_delayed_work(hsic_remote_xprt[id].hsic_xprt_wq,
+			   &hsic_remote_xprt[id].read_work, 0);
+	return 0;
+}
+
+static struct platform_driver msm_ipc_router_hsic_remote_driver[] = {
+	{
+		.probe		= msm_ipc_router_hsic_remote_probe,
+		.remove		= msm_ipc_router_hsic_remote_remove,
+		.driver		= {
+				.name	= "ipc_bridge",
+				.owner	= THIS_MODULE,
+		},
+	},
+};
+
+static int __init msm_ipc_router_hsic_init(void)
+{
+	int i, ret, rc = 0;
+	BUG_ON(ARRAY_SIZE(hsic_xprt_cfg) != NUM_HSIC_XPRTS);
+	for (i = 0; i < ARRAY_SIZE(msm_ipc_router_hsic_remote_driver); i++) {
+		ret = platform_driver_register(
+				&msm_ipc_router_hsic_remote_driver[i]);
+		if (ret) {
+			pr_err("%s: Failed to register platform driver for xprt%d. Continuing...\n",
+				__func__, i);
+			rc = ret;
+		}
+	}
+	return rc;
+}
+
+module_init(msm_ipc_router_hsic_init);
+MODULE_DESCRIPTION("IPC Router HSIC XPRT");
+MODULE_LICENSE("GPL v2");
diff --git a/arch/arm/mach-msm/ipc_router_smd_xprt.c b/arch/arm/mach-msm/ipc_router_smd_xprt.c
index d6a3e03..87880c2 100644
--- a/arch/arm/mach-msm/ipc_router_smd_xprt.c
+++ b/arch/arm/mach-msm/ipc_router_smd_xprt.c
@@ -55,6 +55,8 @@
 	int ss_reset;
 	void *pil;
 	struct completion sft_close_complete;
+	unsigned xprt_version;
+	unsigned xprt_option;
 };
 
 struct msm_ipc_router_smd_xprt_work {
@@ -71,13 +73,14 @@
 	char xprt_name[XPRT_NAME_LEN];
 	uint32_t edge;
 	uint32_t link_id;
+	unsigned xprt_version;
 };
 
 struct msm_ipc_router_smd_xprt_config smd_xprt_cfg[] = {
-	{"RPCRPY_CNTL", "ipc_rtr_smd_rpcrpy_cntl", SMD_APPS_MODEM, 1},
-	{"IPCRTR", "ipc_rtr_smd_ipcrtr", SMD_APPS_MODEM, 1},
-	{"IPCRTR", "ipc_rtr_q6_ipcrtr", SMD_APPS_QDSP, 1},
-	{"IPCRTR", "ipc_rtr_wcnss_ipcrtr", SMD_APPS_WCNSS, 1},
+	{"RPCRPY_CNTL", "ipc_rtr_smd_rpcrpy_cntl", SMD_APPS_MODEM, 1, 1},
+	{"IPCRTR", "ipc_rtr_smd_ipcrtr", SMD_APPS_MODEM, 1, 1},
+	{"IPCRTR", "ipc_rtr_q6_ipcrtr", SMD_APPS_QDSP, 1, 1},
+	{"IPCRTR", "ipc_rtr_wcnss_ipcrtr", SMD_APPS_WCNSS, 1, 1},
 };
 
 static struct msm_ipc_router_smd_xprt smd_remote_xprt[NUM_SMD_XPRTS];
@@ -95,6 +98,28 @@
 	return -ENODEV;
 }
 
+static int msm_ipc_router_smd_get_xprt_version(
+	struct msm_ipc_router_xprt *xprt)
+{
+	struct msm_ipc_router_smd_xprt *smd_xprtp;
+	if (!xprt)
+		return -EINVAL;
+	smd_xprtp = container_of(xprt, struct msm_ipc_router_smd_xprt, xprt);
+
+	return (int)smd_xprtp->xprt_version;
+}
+
+static int msm_ipc_router_smd_get_xprt_option(
+	struct msm_ipc_router_xprt *xprt)
+{
+	struct msm_ipc_router_smd_xprt *smd_xprtp;
+	if (!xprt)
+		return -EINVAL;
+	smd_xprtp = container_of(xprt, struct msm_ipc_router_smd_xprt, xprt);
+
+	return (int)smd_xprtp->xprt_option;
+}
+
 static int msm_ipc_router_smd_remote_write_avail(
 	struct msm_ipc_router_xprt *xprt)
 {
@@ -110,7 +135,6 @@
 {
 	struct rr_packet *pkt = (struct rr_packet *)data;
 	struct sk_buff *ipc_rtr_pkt;
-	int align_sz, align_data = 0;
 	int offset, sz_written = 0;
 	int ret, num_retries = 0;
 	unsigned long flags;
@@ -123,9 +147,7 @@
 	if (!len || pkt->length != len)
 		return -EINVAL;
 
-	align_sz = ALIGN_SIZE(pkt->length);
-	while ((ret = smd_write_start(smd_xprtp->channel,
-				      (len + align_sz))) < 0) {
+	while ((ret = smd_write_start(smd_xprtp->channel, len)) < 0) {
 		spin_lock_irqsave(&smd_xprtp->ss_reset_lock, flags);
 		if (smd_xprtp->ss_reset) {
 			spin_unlock_irqrestore(&smd_xprtp->ss_reset_lock,
@@ -143,7 +165,7 @@
 		num_retries++;
 	}
 
-	D("%s: Ready to write\n", __func__);
+	D("%s: Ready to write %d bytes\n", __func__, len);
 	skb_queue_walk(pkt->pkt_fragment_q, ipc_rtr_pkt) {
 		offset = 0;
 		while (offset < ipc_rtr_pkt->len) {
@@ -175,30 +197,6 @@
 		  __func__, offset, xprt->name);
 	}
 
-	if (align_sz) {
-		if (smd_write_segment_avail(smd_xprtp->channel) < align_sz)
-			smd_enable_read_intr(smd_xprtp->channel);
-
-		wait_event(smd_xprtp->write_avail_wait_q,
-			((smd_write_segment_avail(smd_xprtp->channel) >=
-			 align_sz) || smd_xprtp->ss_reset));
-		smd_disable_read_intr(smd_xprtp->channel);
-		spin_lock_irqsave(&smd_xprtp->ss_reset_lock, flags);
-		if (smd_xprtp->ss_reset) {
-			spin_unlock_irqrestore(
-				&smd_xprtp->ss_reset_lock, flags);
-			pr_err("%s: %s chnl reset\n",
-				__func__, xprt->name);
-			return -ENETRESET;
-		}
-		spin_unlock_irqrestore(&smd_xprtp->ss_reset_lock,
-					flags);
-
-		smd_write_segment(smd_xprtp->channel,
-				  &align_data, align_sz, 0);
-		D("%s: Wrote %d align bytes over %s\n",
-		  __func__, align_sz, xprt->name);
-	}
 	if (!smd_write_end(smd_xprtp->channel))
 		D("%s: Finished writing\n", __func__);
 	return len;
@@ -453,6 +451,10 @@
 
 	smd_remote_xprt[id].xprt.name = smd_xprt_cfg[id].xprt_name;
 	smd_remote_xprt[id].xprt.link_id = smd_xprt_cfg[id].link_id;
+	smd_remote_xprt[id].xprt.get_version =
+		msm_ipc_router_smd_get_xprt_version;
+	smd_remote_xprt[id].xprt.get_option =
+		msm_ipc_router_smd_get_xprt_option;
 	smd_remote_xprt[id].xprt.read_avail = NULL;
 	smd_remote_xprt[id].xprt.read = NULL;
 	smd_remote_xprt[id].xprt.write_avail =
@@ -468,6 +470,8 @@
 	INIT_DELAYED_WORK(&smd_remote_xprt[id].read_work, smd_xprt_read_data);
 	spin_lock_init(&smd_remote_xprt[id].ss_reset_lock);
 	smd_remote_xprt[id].ss_reset = 0;
+	smd_remote_xprt[id].xprt_version = smd_xprt_cfg[id].xprt_version;
+	smd_remote_xprt[id].xprt_option = FRAG_PKT_WRITE_ENABLE;
 
 	smd_remote_xprt[id].pil = msm_ipc_load_subsystem(
 					smd_xprt_cfg[id].edge);
diff --git a/arch/arm/mach-msm/ipc_socket.c b/arch/arm/mach-msm/ipc_socket.c
index ea27c71..bdda546 100644
--- a/arch/arm/mach-msm/ipc_socket.c
+++ b/arch/arm/mach-msm/ipc_socket.c
@@ -131,12 +131,15 @@
 	int i, copied, first = 1;
 	int data_size = 0, request_size, offset;
 	void *data;
+	int last = 0;
+	int align_size;
 
 	for (i = 0; i < num_sect; i++)
 		data_size += msg_sect[i].iov_len;
 
 	if (!data_size)
 		return NULL;
+	align_size = ALIGN_SIZE(data_size);
 
 	msg_head = kmalloc(sizeof(struct sk_buff_head), GFP_KERNEL);
 	if (!msg_head) {
@@ -148,10 +151,14 @@
 	for (copied = 1, i = 0; copied && (i < num_sect); i++) {
 		data_size = msg_sect[i].iov_len;
 		offset = 0;
+		if (i == (num_sect - 1))
+			last = 1;
 		while (offset != msg_sect[i].iov_len) {
 			request_size = data_size;
 			if (first)
 				request_size += IPC_ROUTER_HDR_SIZE;
+			if (last)
+				request_size += align_size;
 
 			msg = alloc_skb(request_size, GFP_KERNEL);
 			if (!msg) {
@@ -161,6 +168,7 @@
 					goto msg_build_failure;
 				}
 				data_size = data_size / 2;
+				last = 0;
 				continue;
 			}
 
@@ -182,6 +190,8 @@
 			skb_queue_tail(msg_head, msg);
 			offset += data_size;
 			data_size = msg_sect[i].iov_len - offset;
+			if (i == (num_sect - 1))
+				last = 1;
 		}
 	}
 	return msg_head;
@@ -196,24 +206,23 @@
 }
 
 static int msm_ipc_router_extract_msg(struct msghdr *m,
-				      struct sk_buff_head *msg_head)
+				      struct rr_packet *pkt)
 {
 	struct sockaddr_msm_ipc *addr;
-	struct rr_header *hdr;
+	struct rr_header_v1 *hdr;
 	struct sk_buff *temp;
 	union rr_control_msg *ctl_msg;
 	int offset = 0, data_len = 0, copy_len;
 
-	if (!m || !msg_head) {
+	if (!m || !pkt) {
 		pr_err("%s: Invalid pointers passed\n", __func__);
 		return -EINVAL;
 	}
 	addr = (struct sockaddr_msm_ipc *)m->msg_name;
 
-	temp = skb_peek(msg_head);
-	hdr = (struct rr_header *)(temp->data);
+	hdr = &(pkt->hdr);
 	if (addr && (hdr->type == IPC_ROUTER_CTRL_CMD_RESUME_TX)) {
-		skb_pull(temp, IPC_ROUTER_HDR_SIZE);
+		temp = skb_peek(pkt->pkt_fragment_q);
 		ctl_msg = (union rr_control_msg *)(temp->data);
 		addr->family = AF_MSM_IPC;
 		addr->address.addrtype = MSM_IPC_ADDR_ID;
@@ -222,7 +231,7 @@
 		m->msg_namelen = sizeof(struct sockaddr_msm_ipc);
 		return offset;
 	}
-	if (addr && (hdr->src_port_id != IPC_ROUTER_ADDRESS)) {
+	if (addr && (hdr->type == IPC_ROUTER_CTRL_CMD_DATA)) {
 		addr->family = AF_MSM_IPC;
 		addr->address.addrtype = MSM_IPC_ADDR_ID;
 		addr->address.addr.port_addr.node_id = hdr->src_node_id;
@@ -231,8 +240,7 @@
 	}
 
 	data_len = hdr->size;
-	skb_pull(temp, IPC_ROUTER_HDR_SIZE);
-	skb_queue_walk(msg_head, temp) {
+	skb_queue_walk(pkt->pkt_fragment_q, temp) {
 		copy_len = data_len < temp->len ? data_len : temp->len;
 		if (copy_to_user(m->msg_iov->iov_base + offset, temp->data,
 				 copy_len)) {
@@ -245,22 +253,6 @@
 	return offset;
 }
 
-static void msm_ipc_router_release_msg(struct sk_buff_head *msg_head)
-{
-	struct sk_buff *temp;
-
-	if (!msg_head) {
-		pr_err("%s: Invalid msg pointer\n", __func__);
-		return;
-	}
-
-	while (!skb_queue_empty(msg_head)) {
-		temp = skb_dequeue(msg_head);
-		kfree_skb(temp);
-	}
-	kfree(msg_head);
-}
-
 static int msm_ipc_router_create(struct net *net,
 				 struct socket *sock,
 				 int protocol,
@@ -385,8 +377,16 @@
 	if (ipc_buf)
 		msm_ipc_router_ipc_log(IPC_SEND, ipc_buf, port_ptr);
 	ret = msm_ipc_router_send_to(port_ptr, msg, &dest->address);
-	if (ret == (IPC_ROUTER_HDR_SIZE + total_len))
-		ret = total_len;
+	if (ret != total_len) {
+		if (ret < 0) {
+			if (ret != -EAGAIN)
+				pr_err("%s: Send_to failure %d\n",
+							__func__, ret);
+			msm_ipc_router_free_skb(msg);
+		} else if (ret >= 0) {
+			ret = -EFAULT;
+		}
+	}
 
 out_sendmsg:
 	release_sock(sk);
@@ -398,7 +398,7 @@
 {
 	struct sock *sk = sock->sk;
 	struct msm_ipc_port *port_ptr = msm_ipc_sk_port(sk);
-	struct sk_buff_head *msg;
+	struct rr_packet *pkt;
 	struct sk_buff *ipc_buf;
 	long timeout;
 	int ret;
@@ -420,18 +420,17 @@
 		return ret;
 	}
 
-	ret = msm_ipc_router_read(port_ptr, &msg, buf_len);
-	if (ret <= 0 || !msg) {
+	ret = msm_ipc_router_read(port_ptr, &pkt, buf_len);
+	if (ret <= 0 || !pkt) {
 		release_sock(sk);
 		return ret;
 	}
 
-	ret = msm_ipc_router_extract_msg(m, msg);
-	ipc_buf = skb_peek(msg);
+	ret = msm_ipc_router_extract_msg(m, pkt);
+	ipc_buf = skb_peek(pkt->pkt_fragment_q);
 	if (ipc_buf)
 		msm_ipc_router_ipc_log(IPC_RECV, ipc_buf, port_ptr);
-	msm_ipc_router_release_msg(msg);
-	msg = NULL;
+	release_pkt(pkt);
 	release_sock(sk);
 	return ret;
 }
@@ -460,7 +459,7 @@
 
 	switch (cmd) {
 	case IPC_ROUTER_IOCTL_GET_VERSION:
-		n = IPC_ROUTER_VERSION;
+		n = IPC_ROUTER_V1;
 		ret = put_user(n, (unsigned int *)arg);
 		break;
 
diff --git a/arch/arm/mach-msm/msm_bus/msm_bus_bimc.c b/arch/arm/mach-msm/msm_bus/msm_bus_bimc.c
index bc15fe8..8b64653 100644
--- a/arch/arm/mach-msm/msm_bus/msm_bus_bimc.c
+++ b/arch/arm/mach-msm/msm_bus/msm_bus_bimc.c
@@ -1876,7 +1876,7 @@
 	struct msm_bus_bimc_info *binfo;
 	struct msm_bus_bimc_qos_bw qbw;
 	int i;
-	long int bw;
+	int64_t bw;
 	int ports = info->node_info->num_mports;
 	struct msm_bus_bimc_commit *sel_cd =
 		(struct msm_bus_bimc_commit *)sel_cdata;
@@ -1912,11 +1912,11 @@
 			qbw.bw = sel_cd->mas[info->node_info->masterp[i]].bw;
 			qbw.ws = info->node_info->ws;
 			/* Threshold low = 90% of bw */
-			qbw.thl = (90 * bw) / 100;
+			qbw.thl = div_s64((90 * bw), 100);
 			/* Threshold medium = bw */
 			qbw.thm = bw;
 			/* Threshold high = 10% more than bw */
-			qbw.thh = (110 * bw) / 100;
+			qbw.thh = div_s64((110 * bw), 100);
 			/* Check if info is a shared master.
 			 * If it is, mark it dirty
 			 * If it isn't, then set QOS Bandwidth
diff --git a/arch/arm/mach-msm/msm_bus/msm_bus_noc.c b/arch/arm/mach-msm/msm_bus/msm_bus_noc.c
index d33c340..8f7b7f2 100644
--- a/arch/arm/mach-msm/msm_bus/msm_bus_noc.c
+++ b/arch/arm/mach-msm/msm_bus/msm_bus_noc.c
@@ -511,7 +511,7 @@
 	struct msm_bus_noc_info *ninfo;
 	struct msm_bus_noc_qos_bw qos_bw;
 	int i, ports;
-	long int bw;
+	int64_t bw;
 	struct msm_bus_noc_commit *sel_cd =
 		(struct msm_bus_noc_commit *)sel_cdata;
 
diff --git a/arch/arm/mach-msm/pil-q6v5-lpass.c b/arch/arm/mach-msm/pil-q6v5-lpass.c
index a9a6942..de15be5 100644
--- a/arch/arm/mach-msm/pil-q6v5-lpass.c
+++ b/arch/arm/mach-msm/pil-q6v5-lpass.c
@@ -378,9 +378,7 @@
 {
 	struct lpass_data *drv = subsys_to_drv(dev_id);
 
-	disable_irq_nosync(drv->subsys_desc.wdog_bite_irq);
 	schedule_work(&drv->work);
-
 	return IRQ_HANDLED;
 }
 
diff --git a/arch/arm/mach-msm/qdsp6v2/audio_acdb.c b/arch/arm/mach-msm/qdsp6v2/audio_acdb.c
index b5ccc31..a13100b 100644
--- a/arch/arm/mach-msm/qdsp6v2/audio_acdb.c
+++ b/arch/arm/mach-msm/qdsp6v2/audio_acdb.c
@@ -887,7 +887,7 @@
 static int acdb_mmap(struct file *file, struct vm_area_struct *vma)
 {
 	int result = 0;
-	int size = vma->vm_end - vma->vm_start;
+	uint32_t size = vma->vm_end - vma->vm_start;
 
 	pr_debug("%s\n", __func__);
 
diff --git a/arch/arm/mach-msm/smem.c b/arch/arm/mach-msm/smem.c
index 1ec2a78..5a9b341 100644
--- a/arch/arm/mach-msm/smem.c
+++ b/arch/arm/mach-msm/smem.c
@@ -16,12 +16,14 @@
 #include <linux/moduleparam.h>
 #include <linux/printk.h>
 #include <linux/notifier.h>
+#include <linux/of.h>
 
 #include <mach/board.h>
 #include <mach/msm_iomap.h>
 #include <mach/msm_smem.h>
 #include <mach/ramdump.h>
 #include <mach/subsystem_notif.h>
+#include <mach/msm_ipc_logging.h>
 
 #include "smem_private.h"
 
@@ -45,13 +47,29 @@
 	MSM_SMEM_INFO = 1U << 1,
 };
 
-static int msm_smem_debug_mask;
+static int msm_smem_debug_mask = MSM_SMEM_INFO;
 module_param_named(debug_mask, msm_smem_debug_mask,
 			int, S_IRUGO | S_IWUSR | S_IWGRP);
+static void *smem_ipc_log_ctx;
+#define NUM_LOG_PAGES 4
 
+#define IPC_LOG(x...) do {                                   \
+		if (smem_ipc_log_ctx)                        \
+			ipc_log_string(smem_ipc_log_ctx, x); \
+	} while (0)
+
+
+#define LOG_ERR(x...) do {  \
+		pr_err(x);  \
+		IPC_LOG(x); \
+	} while (0)
 #define SMEM_DBG(x...) do {                               \
 		if (msm_smem_debug_mask & MSM_SMEM_DEBUG) \
-			pr_debug(x);                      \
+			IPC_LOG(x);                       \
+	} while (0)
+#define SMEM_INFO(x...) do {                             \
+		if (msm_smem_debug_mask & MSM_SMEM_INFO) \
+			IPC_LOG(x);                      \
 	} while (0)
 
 #define SMEM_SPINLOCK_SMEM_ALLOC       "S:3"
@@ -68,6 +86,61 @@
 static RAW_NOTIFIER_HEAD(smem_module_init_notifier_list);
 static DEFINE_MUTEX(smem_module_init_notifier_lock);
 
+/* smem security feature components */
+#define SMEM_TOC_IDENTIFIER 0x434f5424 /* "$TOC" */
+#define SMEM_TOC_MAX_EXCLUSIONS 4
+#define SMEM_PART_HDR_IDENTIFIER 0x54525024 /* "$PRT" */
+#define SMEM_ALLOCATION_CANARY 0xa5a5
+
+struct smem_toc_entry {
+	uint32_t offset;
+	uint32_t size;
+	uint32_t flags;
+	uint16_t host0;
+	uint16_t host1;
+	uint32_t size_cacheline;
+	uint32_t reserved[3];
+	uint32_t exclusion_sizes[SMEM_TOC_MAX_EXCLUSIONS];
+};
+
+struct smem_toc {
+	/* Identifier is a constant, set to SMEM_TOC_IDENTIFIER. */
+	uint32_t identifier;
+	uint32_t version;
+	uint32_t num_entries;
+	uint32_t reserved[5];
+	struct smem_toc_entry entry[];
+};
+
+struct smem_partition_header {
+	/* Identifier is a constant, set to SMEM_PART_HDR_IDENTIFIER. */
+	uint32_t identifier;
+	uint16_t host0;
+	uint16_t host1;
+	uint32_t size;
+	uint32_t offset_free_uncached;
+	uint32_t offset_free_cached;
+	uint32_t reserved[3];
+};
+
+struct smem_partition_allocation_header {
+	/* Canary is a constant, set to SMEM_ALLOCATION_CANARY */
+	uint16_t canary;
+	uint16_t smem_type;
+	uint32_t size; /* includes padding bytes */
+	uint16_t padding_data;
+	uint16_t padding_hdr;
+	uint32_t reserved[1];
+};
+
+struct smem_partition_info {
+	uint32_t partition_num;
+	uint32_t offset;
+	uint32_t size_cacheline;
+};
+
+static struct smem_partition_info partitions[NUM_SMEM_SUBSYSTEMS];
+/* end smem security feature components */
 
 struct restart_notifier_block {
 	unsigned processor;
@@ -128,7 +201,7 @@
 		if (base >= phys_addr && base + offset < phys_addr + size) {
 			if (OVERFLOW_ADD_UNSIGNED(uintptr_t,
 				(uintptr_t)MSM_SHARED_RAM_BASE, offset)) {
-				pr_err("%s: overflow %p %x\n", __func__,
+				SMEM_INFO("%s: overflow %p %x\n", __func__,
 					MSM_SHARED_RAM_BASE, offset);
 				return NULL;
 			}
@@ -147,7 +220,7 @@
 
 		if (OVERFLOW_ADD_UNSIGNED(uintptr_t,
 				(uintptr_t)smem_areas[i].virt_addr, offset)) {
-			pr_err("%s: overflow %p %x\n", __func__,
+			SMEM_INFO("%s: overflow %p %x\n", __func__,
 				smem_areas[i].virt_addr, offset);
 			return NULL;
 		}
@@ -201,6 +274,22 @@
 EXPORT_SYMBOL(smem_alloc);
 
 /**
+ * smem_alloc_to_proc - Find existing item with security support
+ *
+ * @id:       ID of SMEM item
+ * @size:     Size of the SMEM item
+ * @to_proc:  SMEM host that shares the item with apps
+ * @flags:    Item attribute flags
+ * @returns:  Pointer to SMEM item or NULL if it doesn't exist
+ */
+void *smem_alloc_to_proc(unsigned id, unsigned size, unsigned to_proc,
+								unsigned flags)
+{
+	return smem_find_to_proc(id, size, to_proc, flags);
+}
+EXPORT_SYMBOL(smem_alloc_to_proc);
+
+/**
  * __smem_get_entry - Get pointer and size of existing SMEM item
  *
  * @id:              ID of SMEM item
@@ -246,6 +335,138 @@
 	return ret;
 }
 
+/**
+ * __smem_get_entry_to_proc - Get pointer and size of existing SMEM item with
+ *                   security support
+ *
+ * @id:              ID of SMEM item
+ * @size:            Pointer to size variable for storing the result
+ * @to_proc:         SMEM host that shares the item with apps
+ * @flags:           Item attribute flags
+ * @skip_init_check: True means do not verify that SMEM has been initialized
+ * @use_rspinlock:   True to use the remote spinlock
+ * @returns:         Pointer to SMEM item or NULL if it doesn't exist
+ */
+static void *__smem_get_entry_to_proc(unsigned id,
+					unsigned *size,
+					unsigned to_proc,
+					unsigned flags,
+					bool skip_init_check,
+					bool use_rspinlock)
+{
+	struct smem_partition_header *hdr;
+	unsigned long lflags = 0;
+	void *item = NULL;
+	struct smem_partition_allocation_header *alloc_hdr;
+	uint32_t partition_num;
+	uint32_t a_hdr_size;
+	int rc;
+
+	SMEM_DBG("%s(%u, %u, %u, %u, %d, %d)\n", __func__, id, *size, to_proc,
+					flags, skip_init_check, use_rspinlock);
+
+	if (!skip_init_check && !smem_initialized_check())
+		return NULL;
+
+	if (id >= SMEM_NUM_ITEMS) {
+		SMEM_INFO("%s: invalid id %d\n", __func__, id);
+		return NULL;
+	}
+
+	if (!(flags & SMEM_ANY_HOST_FLAG) && to_proc >= NUM_SMEM_SUBSYSTEMS) {
+		SMEM_INFO("%s: id %u invalid to_proc %d\n", __func__, id,
+								to_proc);
+		return NULL;
+	}
+
+	if (flags & SMEM_ANY_HOST_FLAG || !partitions[to_proc].offset)
+		return __smem_get_entry(id, size, skip_init_check,
+								use_rspinlock);
+
+	partition_num = partitions[to_proc].partition_num;
+	hdr = smem_areas[0].virt_addr + partitions[to_proc].offset;
+	if (unlikely(!spinlocks_initialized)) {
+		rc = init_smem_remote_spinlock();
+		if (unlikely(rc)) {
+			SMEM_INFO(
+				"%s: id:%u remote spinlock init failed %d\n",
+						__func__, id, rc);
+			return NULL;
+		}
+	}
+	if (use_rspinlock)
+		remote_spin_lock_irqsave(&remote_spinlock, lflags);
+	if (hdr->identifier != SMEM_PART_HDR_IDENTIFIER) {
+		LOG_ERR(
+			"%s: SMEM corruption detected.  Partition %d to %d at %p\n",
+								__func__,
+								partition_num,
+								to_proc,
+								hdr);
+		BUG();
+	}
+
+	if (flags & SMEM_ITEM_CACHED_FLAG) {
+		a_hdr_size = ALIGN(sizeof(*alloc_hdr),
+				partitions[to_proc].size_cacheline);
+		for (alloc_hdr = (void *)(hdr) + hdr->size - a_hdr_size;
+				(void *)(alloc_hdr) > (void *)(hdr) +
+					hdr->offset_free_cached;
+				alloc_hdr = (void *)(alloc_hdr) -
+						alloc_hdr->size - a_hdr_size) {
+			if (alloc_hdr->canary != SMEM_ALLOCATION_CANARY) {
+				LOG_ERR(
+					"%s: SMEM corruption detected.  Partition %d to %d at %p\n",
+								__func__,
+								partition_num,
+								to_proc,
+								alloc_hdr);
+				BUG();
+
+			}
+			if (alloc_hdr->smem_type == id) {
+				/* 8 byte alignment to match legacy */
+				*size = ALIGN(alloc_hdr->size -
+						alloc_hdr->padding_data, 8);
+				item = (void *)(alloc_hdr) - alloc_hdr->size;
+				break;
+			}
+		}
+	} else {
+		for (alloc_hdr = (void *)(hdr) + sizeof(*hdr);
+				(void *)(alloc_hdr) < (void *)(hdr) +
+					hdr->offset_free_uncached;
+				alloc_hdr = (void *)(alloc_hdr) +
+						sizeof(*alloc_hdr) +
+						alloc_hdr->padding_hdr +
+						alloc_hdr->size) {
+			if (alloc_hdr->canary != SMEM_ALLOCATION_CANARY) {
+				LOG_ERR(
+					"%s: SMEM corruption detected.  Partition %d to %d at %p\n",
+								__func__,
+								partition_num,
+								to_proc,
+								alloc_hdr);
+				BUG();
+
+			}
+			if (alloc_hdr->smem_type == id) {
+				/* 8 byte alignment to match legacy */
+				*size = ALIGN(alloc_hdr->size -
+						alloc_hdr->padding_data, 8);
+				item = (void *)(alloc_hdr) +
+						sizeof(*alloc_hdr) +
+						alloc_hdr->padding_hdr;
+				break;
+			}
+		}
+	}
+	if (use_rspinlock)
+		remote_spin_unlock_irqrestore(&remote_spinlock, lflags);
+
+	return item;
+}
+
 static void *__smem_find(unsigned id, unsigned size_in, bool skip_init_check)
 {
 	unsigned size;
@@ -257,7 +478,7 @@
 
 	size_in = ALIGN(size_in, 8);
 	if (size_in != size) {
-		pr_err("smem_find(%d, %d): wrong size %d\n",
+		SMEM_INFO("smem_find(%u, %u): wrong size %u\n",
 			id, size_in, size);
 		return 0;
 	}
@@ -271,6 +492,189 @@
 }
 EXPORT_SYMBOL(smem_find);
 
+/**
+ * smem_find_to_proc - Find existing item with security support
+ *
+ * @id:       ID of SMEM item
+ * @size_in:  Size of the SMEM item
+ * @to_proc:  SMEM host that shares the item with apps
+ * @flags:    Item attribute flags
+ * @returns:  Pointer to SMEM item or NULL if it doesn't exist
+ */
+void *smem_find_to_proc(unsigned id, unsigned size_in, unsigned to_proc,
+								unsigned flags)
+{
+	unsigned size;
+	void *ptr;
+
+	SMEM_DBG("%s(%u, %u, %u, %u)\n", __func__, id, size_in, to_proc,
+									flags);
+
+	ptr = smem_get_entry_to_proc(id, &size, to_proc, flags);
+	if (!ptr)
+		return 0;
+
+	size_in = ALIGN(size_in, 8);
+	if (size_in != size) {
+		SMEM_INFO("smem_find_to_proc(%u, %u, %u, %u): wrong size %u\n",
+			id, size_in, to_proc, flags, size);
+		return 0;
+	}
+
+	return ptr;
+}
+EXPORT_SYMBOL(smem_find_to_proc);
+
+/**
+ * alloc_item_nonsecure - Allocate an SMEM item in the nonsecure partition
+ *
+ * @id:              ID of SMEM item
+ * @size_in:         Size to allocate
+ * @returns:         Pointer to SMEM item or NULL for error
+ *
+ * Assumes the id parameter is valid and does not already exist.  Assumes
+ * size_in is already adjusted for alignment, if necessary.  Requires the
+ * remote spinlock to already be locked.
+ */
+static void *alloc_item_nonsecure(unsigned id, unsigned size_in)
+{
+	void *smem_base = MSM_SHARED_RAM_BASE;
+	struct smem_shared *shared = smem_base;
+	struct smem_heap_entry *toc = shared->heap_toc;
+	void *ret = NULL;
+
+	if (shared->heap_info.heap_remaining >= size_in) {
+		toc[id].offset = shared->heap_info.free_offset;
+		toc[id].size = size_in;
+		/*
+		 * wmb() is necessary to ensure the allocation data is
+		 * consistent before setting the allocated flag to prevent race
+		 * conditions with remote processors
+		 */
+		wmb();
+		toc[id].allocated = 1;
+
+		shared->heap_info.free_offset += size_in;
+		shared->heap_info.heap_remaining -= size_in;
+		ret = smem_base + toc[id].offset;
+		/*
+		 * wmb() is necessary to ensure the heap data is consistent
+		 * before continuing to prevent race conditions with remote
+		 * processors
+		 */
+		wmb();
+	} else {
+		SMEM_INFO("%s: id %u not enough memory %u (required %u)\n",
+			__func__, id, shared->heap_info.heap_remaining,
+			size_in);
+	}
+
+	return ret;
+}
+
+/**
+ * alloc_item_secure - Allocate an SMEM item in a secure partition
+ *
+ * @id:              ID of SMEM item
+ * @size_in:         Size to allocate
+ * @to_proc:         SMEM host that shares the item with apps
+ * @flags:           Item attribute flags
+ * @returns:         Pointer to SMEM item or NULL for error
+ *
+ * Assumes the id parameter is valid and does  not already exist.  Assumes
+ * size_in is the raw size requested by the client.  Assumes to_proc is a valid
+ * host, and a valid partition to that host exists.  Requires the remote
+ * spinlock to already be locked.
+ */
+static void *alloc_item_secure(unsigned id, unsigned size_in, unsigned to_proc,
+								unsigned flags)
+{
+	void *smem_base = MSM_SHARED_RAM_BASE;
+	struct smem_partition_header *hdr;
+	struct smem_partition_allocation_header *alloc_hdr;
+	uint32_t a_hdr_size;
+	uint32_t a_data_size;
+	uint32_t size_cacheline;
+	uint32_t free_space;
+	uint32_t partition_num;
+	void *ret = NULL;
+
+	hdr = smem_base + partitions[to_proc].offset;
+	partition_num = partitions[to_proc].partition_num;
+
+	if (hdr->identifier != SMEM_PART_HDR_IDENTIFIER) {
+		LOG_ERR(
+			"%s: SMEM corruption detected.  Partition %d to %d at %p\n",
+								__func__,
+								partition_num,
+								to_proc,
+								hdr);
+		BUG();
+	}
+
+	size_cacheline = partitions[to_proc].size_cacheline;
+	free_space = hdr->offset_free_cached -
+					hdr->offset_free_uncached;
+
+	if (flags & SMEM_ITEM_CACHED_FLAG) {
+		a_hdr_size = ALIGN(sizeof(*alloc_hdr), size_cacheline);
+		a_data_size = ALIGN(size_in, size_cacheline);
+		if (free_space < a_hdr_size + a_data_size) {
+			SMEM_INFO(
+				"%s: id %u not enough memory %u (required %u)\n",
+						__func__, id, free_space,
+						a_hdr_size + a_data_size);
+			return ret;
+		}
+		alloc_hdr = (void *)(hdr) + hdr->offset_free_cached -
+								a_hdr_size;
+		alloc_hdr->canary = SMEM_ALLOCATION_CANARY;
+		alloc_hdr->smem_type = id;
+		alloc_hdr->size = a_data_size;
+		alloc_hdr->padding_data = a_data_size - size_in;
+		alloc_hdr->padding_hdr = a_hdr_size - sizeof(*alloc_hdr);
+		hdr->offset_free_cached = hdr->offset_free_cached -
+						a_hdr_size - a_data_size;
+		ret = (void *)(alloc_hdr) - a_data_size;
+		/*
+		 * The SMEM protocol currently does not support cacheable
+		 * areas within the smem region, but if it ever does in the
+		 * future, then cache management needs to be done here.
+		 * The area of memory this item is allocated from will need to
+		 * be dynamically made cachable, and a cache flush of the
+		 * allocation header using __cpuc_flush_dcache_area and
+		 * outer_flush_area will need to be done.
+		 */
+	} else {
+		a_hdr_size = sizeof(*alloc_hdr);
+		a_data_size = ALIGN(size_in, 8);
+		if (free_space < a_hdr_size + a_data_size) {
+			SMEM_INFO(
+				"%s: id %u not enough memory %u (required %u)\n",
+						__func__, id, free_space,
+						a_hdr_size + a_data_size);
+			return ret;
+		}
+		alloc_hdr = (void *)(hdr) + hdr->offset_free_uncached;
+		alloc_hdr->canary = SMEM_ALLOCATION_CANARY;
+		alloc_hdr->smem_type = id;
+		alloc_hdr->size = a_data_size;
+		alloc_hdr->padding_data = a_data_size - size_in;
+		alloc_hdr->padding_hdr = a_hdr_size - sizeof(*alloc_hdr);
+		hdr->offset_free_uncached = hdr->offset_free_uncached +
+						a_hdr_size + a_data_size;
+		ret = alloc_hdr + 1;
+	}
+	/*
+	 * wmb() is necessary to ensure the heap and allocation data is
+	 * consistent before continuing to prevent race conditions with remote
+	 * processors
+	 */
+	wmb();
+
+	return ret;
+}
+
 /* smem_alloc2 returns the pointer to smem item.  If it is not allocated,
  * it allocates it and then returns the pointer to it.
  */
@@ -285,13 +689,15 @@
 	if (!smem_initialized_check())
 		return NULL;
 
-	if (id >= SMEM_NUM_ITEMS)
+	if (id >= SMEM_NUM_ITEMS) {
+		SMEM_INFO("%s: invalid id %u\n", __func__, id);
 		return NULL;
+	}
 
 	if (unlikely(!spinlocks_initialized)) {
 		rc = init_smem_remote_spinlock();
 		if (unlikely(rc)) {
-			pr_err("%s: remote spinlock init failed %d\n",
+			SMEM_INFO("%s: remote spinlock init failed %d\n",
 								__func__, rc);
 			return NULL;
 		}
@@ -300,34 +706,102 @@
 	size_in = ALIGN(size_in, 8);
 	remote_spin_lock_irqsave(&remote_spinlock, flags);
 	if (toc[id].allocated) {
-		SMEM_DBG("%s: %u already allocated\n", __func__, id);
+		SMEM_INFO("%s: %u already allocated\n", __func__, id);
 		if (size_in != toc[id].size)
-			pr_err("%s: wrong size %u (expected %u)\n",
+			SMEM_INFO("%s: wrong size %u (expected %u)\n",
 				__func__, toc[id].size, size_in);
 		else
 			ret = (void *)(MSM_SHARED_RAM_BASE + toc[id].offset);
 	} else if (id > SMEM_FIXED_ITEM_LAST) {
-		SMEM_DBG("%s: allocating %u\n", __func__, id);
-		if (shared->heap_info.heap_remaining >= size_in) {
-			toc[id].offset = shared->heap_info.free_offset;
-			toc[id].size = size_in;
-			wmb();
-			toc[id].allocated = 1;
-
-			shared->heap_info.free_offset += size_in;
-			shared->heap_info.heap_remaining -= size_in;
-			ret = (void *)(MSM_SHARED_RAM_BASE + toc[id].offset);
-		} else
-			pr_err("%s: not enough memory %u (required %u)\n",
-				__func__, shared->heap_info.heap_remaining,
-				size_in);
+		SMEM_INFO("%s: allocating %u\n", __func__, id);
+		ret = alloc_item_nonsecure(id, size_in);
 	}
-	wmb();
 	remote_spin_unlock_irqrestore(&remote_spinlock, flags);
 	return ret;
 }
 EXPORT_SYMBOL(smem_alloc2);
 
+/**
+ * smem_alloc2_to_proc - Find an existing item, otherwise allocate it with
+ *				security support
+ *
+ * @id:       ID of SMEM item
+ * @size_in:  Size of the SMEM item
+ * @to_proc:  SMEM host that shares the item with apps
+ * @flags:    Item attribute flags
+ * @returns:  Pointer to SMEM item or NULL if it couldn't be found/allocated
+ */
+void *smem_alloc2_to_proc(unsigned id, unsigned size_in, unsigned to_proc,
+								unsigned flags)
+{
+	unsigned long lflags;
+	void *ret = NULL;
+	int rc;
+	unsigned size_out;
+	unsigned a_size_in;
+
+	SMEM_DBG("%s(%u, %u, %u, %u)\n", __func__, id, size_in, to_proc,
+									flags);
+
+	if (!smem_initialized_check())
+		return NULL;
+
+	if (id >= SMEM_NUM_ITEMS) {
+		SMEM_INFO("%s: invalid id %u\n", __func__, id);
+		return NULL;
+	}
+
+	if (!(flags & SMEM_ANY_HOST_FLAG) && to_proc >= NUM_SMEM_SUBSYSTEMS) {
+		SMEM_INFO("%s: invalid to_proc %u for id %u\n", __func__,
+								to_proc, id);
+		return NULL;
+	}
+
+	if (unlikely(!spinlocks_initialized)) {
+		rc = init_smem_remote_spinlock();
+		if (unlikely(rc)) {
+			SMEM_INFO("%s: id:%u remote spinlock init failed %d\n",
+							__func__, id, rc);
+			return NULL;
+		}
+	}
+
+	a_size_in = ALIGN(size_in, 8);
+	remote_spin_lock_irqsave(&remote_spinlock, lflags);
+
+	ret = __smem_get_entry_to_proc(id, &size_out, to_proc, flags, true,
+									false);
+	if (ret) {
+		SMEM_INFO("%s: %u already allocated\n", __func__, id);
+		if (a_size_in == size_out) {
+			remote_spin_unlock_irqrestore(&remote_spinlock, lflags);
+			return ret;
+		} else {
+			remote_spin_unlock_irqrestore(&remote_spinlock, lflags);
+			SMEM_INFO("%s: id %u wrong size %u (expected %u)\n",
+				__func__, id, size_out, a_size_in);
+			return NULL;
+		}
+	}
+
+	if (id > SMEM_FIXED_ITEM_LAST) {
+		SMEM_INFO("%s: allocating %u size %u to_proc %u flags %u\n",
+					__func__, id, size_in, to_proc, flags);
+		if (flags & SMEM_ANY_HOST_FLAG || !partitions[to_proc].offset)
+			ret = alloc_item_nonsecure(id, a_size_in);
+		else
+			ret = alloc_item_secure(id, size_in, to_proc, flags);
+
+	} else {
+		SMEM_INFO("%s: attempted to allocate non-dynamic item %u\n",
+								__func__, id);
+	}
+
+	remote_spin_unlock_irqrestore(&remote_spinlock, lflags);
+	return ret;
+}
+EXPORT_SYMBOL(smem_alloc2_to_proc);
+
 void *smem_get_entry(unsigned id, unsigned *size)
 {
 	return __smem_get_entry(id, size, false, true);
@@ -335,6 +809,24 @@
 EXPORT_SYMBOL(smem_get_entry);
 
 /**
+ * smem_get_entry_to_proc - Get existing item with security support
+ *
+ * @id:       ID of SMEM item
+ * @size:     Pointer to size variable for storing the result
+ * @to_proc:  SMEM host that shares the item with apps
+ * @flags:    Item attribute flags
+ * @returns:  Pointer to SMEM item or NULL if it doesn't exist
+ */
+void *smem_get_entry_to_proc(unsigned id, unsigned *size, unsigned to_proc,
+								unsigned flags)
+{
+	SMEM_DBG("%s(%u, %u, %u, %u)\n", __func__, id, *size, to_proc, flags);
+
+	return __smem_get_entry_to_proc(id, size, to_proc, flags, false, true);
+}
+EXPORT_SYMBOL(smem_get_entry_to_proc);
+
+/**
  * smem_get_entry_no_rlock - Get existing item without using remote spinlock
  *
  * @id:       ID of SMEM item
@@ -367,7 +859,7 @@
 /**
  * init_smem_remote_spinlock - Reentrant remote spinlock initialization
  *
- * @returns: sucess or error code for failure
+ * @returns: success or error code for failure
  */
 static int init_smem_remote_spinlock(void)
 {
@@ -408,7 +900,7 @@
 
 	if (likely(checked)) {
 		if (unlikely(!is_inited))
-			pr_err("%s: smem not initialized\n", __func__);
+			LOG_ERR("%s: smem not initialized\n", __func__);
 		return is_inited;
 	}
 
@@ -416,7 +908,7 @@
 	if (checked) {
 		spin_unlock_irqrestore(&smem_init_check_lock, flags);
 		if (unlikely(!is_inited))
-			pr_err("%s: smem not initialized\n", __func__);
+			LOG_ERR("%s: smem not initialized\n", __func__);
 		return is_inited;
 	}
 
@@ -443,7 +935,7 @@
 	is_inited = 0;
 	checked = 1;
 	spin_unlock_irqrestore(&smem_init_check_lock, flags);
-	pr_err("%s: bootloader failure detected, shared memory not inited\n",
+	LOG_ERR("%s: bootloader failure detected, shared memory not inited\n",
 								__func__);
 	return is_inited;
 }
@@ -458,7 +950,7 @@
 
 		notifier = container_of(this,
 					struct restart_notifier_block, nb);
-		SMEM_DBG("%s: ssrestart for processor %d ('%s')\n",
+		SMEM_INFO("%s: ssrestart for processor %d ('%s')\n",
 				__func__, notifier->processor,
 				notifier->name);
 
@@ -478,8 +970,8 @@
 			ret = do_elf_ramdump(smem_ramdump_dev,
 					smem_ramdump_segments, 1);
 			if (ret < 0)
-				pr_err("%s: unable to dump smem %d\n", __func__,
-						ret);
+				LOG_ERR("%s: unable to dump smem %d\n",
+								__func__, ret);
 		}
 	}
 
@@ -494,7 +986,7 @@
 
 	smem_ramdump_dev = create_ramdump_device("smem", NULL);
 	if (IS_ERR_OR_NULL(smem_ramdump_dev)) {
-		pr_err("%s: Unable to create smem ramdump device.\n",
+		LOG_ERR("%s: Unable to create smem ramdump device.\n",
 			__func__);
 		smem_ramdump_dev = NULL;
 	}
@@ -546,6 +1038,124 @@
 	mutex_unlock(&smem_module_init_notifier_lock);
 }
 
+/**
+ * smem_init_security_partition - Init local structures for a secured smem
+ *                   partition that has apps as one of the hosts
+ *
+ * @entry:           Entry in the security TOC for the partition to init
+ * @num:             Partition ID
+ *
+ * Initialize local data structures to point to a secured smem partition
+ * that is accessible by apps and another processor.  Assumes that one of the
+ * listed hosts is apps.  Verifiess that the partition is valid, otherwise will
+ * skip.  Checks for memory corruption and will BUG() if detected.  Assumes
+ * smem_areas is already initialized and that smem_areas[0] corresponds to the
+ * smem region with the secured partitions.
+ */
+static void smem_init_security_partition(struct smem_toc_entry *entry,
+								uint32_t num)
+{
+	uint16_t remote_host;
+	struct smem_partition_header *hdr;
+
+	if (!entry->offset) {
+		SMEM_INFO("Skipping smem partition %d - bad offset\n", num);
+		return;
+	}
+	if (!entry->size) {
+		SMEM_INFO("Skipping smem partition %d - bad size\n", num);
+		return;
+	}
+	if (!entry->size_cacheline) {
+		SMEM_INFO("Skipping smem partition %d - bad cacheline\n", num);
+		return;
+	}
+
+	if (entry->host0 == SMEM_APPS)
+		remote_host = entry->host1;
+	else
+		remote_host = entry->host0;
+
+	if (remote_host >= NUM_SMEM_SUBSYSTEMS) {
+		SMEM_INFO("Skipping smem partition %d - bad remote:%d\n", num,
+								remote_host);
+		return;
+	}
+	if (partitions[remote_host].offset) {
+		SMEM_INFO("Skipping smem partition %d - duplicate of %d\n", num,
+					partitions[remote_host].partition_num);
+		return;
+	}
+
+	hdr = smem_areas[0].virt_addr + entry->offset;
+
+	if (hdr->identifier != SMEM_PART_HDR_IDENTIFIER) {
+		LOG_ERR("Smem partition %d hdr magic is bad\n", num);
+		BUG();
+	}
+	if (!hdr->size) {
+		LOG_ERR("Smem partition %d size is 0\n", num);
+		BUG();
+	}
+	if (hdr->offset_free_uncached > hdr->size) {
+		LOG_ERR("Smem partition %d uncached heap exceeds size\n", num);
+		BUG();
+	}
+	if (hdr->offset_free_cached > hdr->size) {
+		LOG_ERR("Smem partition %d cached heap exceeds size\n", num);
+		BUG();
+	}
+	if (hdr->host0 != SMEM_APPS && hdr->host1 != SMEM_APPS) {
+		LOG_ERR("Smem partition %d hosts don't match TOC\n", num);
+		BUG();
+	}
+	if (hdr->host0 != remote_host && hdr->host1 != remote_host) {
+		LOG_ERR("Smem partition %d hosts don't match TOC\n", num);
+		BUG();
+	}
+
+	partitions[remote_host].partition_num = num;
+	partitions[remote_host].offset = entry->offset;
+	partitions[remote_host].size_cacheline = entry->size_cacheline;
+	SMEM_INFO("Partition %d offset:%x remote:%d\n", num, entry->offset,
+								remote_host);
+}
+
+/**
+ * smem_init_security - Init local support for secured smem
+ *
+ * Looks for a valid security TOC, and if one is found, parses it looking for
+ * partitions that apps can access.  If any such partitions are found, do the
+ * required local initialization to support them.  Assumes smem_areas is inited
+ * and smem_area[0] corresponds to the smem region with the TOC.
+ */
+static void smem_init_security(void)
+{
+	struct smem_toc *toc;
+	uint32_t i;
+
+	SMEM_DBG("%s\n", __func__);
+
+	toc = smem_areas[0].virt_addr + smem_areas[0].size - 4 * 1024;
+
+	if (toc->identifier != SMEM_TOC_IDENTIFIER) {
+		LOG_ERR("%s failed: invalid TOC magic\n", __func__);
+		return;
+	}
+
+	for (i = 0; i < toc->num_entries; ++i) {
+		SMEM_DBG("Partition %d host0:%d host1:%d\n", i,
+							toc->entry[i].host0,
+							toc->entry[i].host1);
+
+		if (toc->entry[i].host0 == SMEM_APPS ||
+					toc->entry[i].host1 == SMEM_APPS)
+			smem_init_security_partition(&toc->entry[i], i);
+	}
+
+	SMEM_DBG("%s done\n", __func__);
+}
+
 static int msm_smem_probe(struct platform_device *pdev)
 {
 	char *key;
@@ -558,6 +1168,7 @@
 	struct ramdump_segment *ramdump_segments_tmp = NULL;
 	struct smem_area *smem_areas_tmp = NULL;
 	int smem_idx = 0;
+	bool security_enabled;
 
 	if (!smem_initialized_check())
 		return -ENODEV;
@@ -565,7 +1176,7 @@
 	key = "irq-reg-base";
 	r = platform_get_resource_byname(pdev, IORESOURCE_MEM, key);
 	if (!r) {
-		pr_err("%s: missing '%s'\n", __func__, key);
+		LOG_ERR("%s: missing '%s'\n", __func__, key);
 		return -ENODEV;
 	}
 
@@ -580,7 +1191,7 @@
 
 		++num_smem_areas;
 		if (num_smem_areas > 999) {
-			pr_err("%s: max num aux mem regions reached\n",
+			LOG_ERR("%s: max num aux mem regions reached\n",
 								__func__);
 			break;
 		}
@@ -589,14 +1200,14 @@
 	key = "smem";
 	r = platform_get_resource_byname(pdev, IORESOURCE_MEM, key);
 	if (!r) {
-		pr_err("%s: missing '%s'\n", __func__, key);
+		LOG_ERR("%s: missing '%s'\n", __func__, key);
 		return -ENODEV;
 	}
 
 	smem_areas_tmp = kmalloc_array(num_smem_areas, sizeof(struct smem_area),
 				GFP_KERNEL);
 	if (!smem_areas_tmp) {
-		pr_err("%s: smem areas kmalloc failed\n", __func__);
+		LOG_ERR("%s: smem areas kmalloc failed\n", __func__);
 		ret = -ENOMEM;
 		goto free_smem_areas;
 	}
@@ -604,7 +1215,7 @@
 	ramdump_segments_tmp = kmalloc_array(num_smem_areas,
 			sizeof(struct ramdump_segment), GFP_KERNEL);
 	if (!ramdump_segments_tmp) {
-		pr_err("%s: ramdump segment kmalloc failed\n", __func__);
+		LOG_ERR("%s: ramdump segment kmalloc failed\n", __func__);
 		ret = -ENOMEM;
 		goto free_smem_areas;
 	}
@@ -640,7 +1251,7 @@
 				smem_areas_tmp[smem_idx].virt_addr);
 
 		if (!smem_areas_tmp[smem_idx].virt_addr) {
-			pr_err("%s: ioremap_nocache() of addr:%pa size: %pa\n",
+			LOG_ERR("%s: ioremap_nocache() of addr:%pa size: %pa\n",
 				__func__,
 				&smem_areas_tmp[smem_idx].phys_addr,
 				&smem_areas_tmp[smem_idx].size);
@@ -651,7 +1262,8 @@
 		if (OVERFLOW_ADD_UNSIGNED(uintptr_t,
 				(uintptr_t)smem_areas_tmp[smem_idx].virt_addr,
 				smem_areas_tmp[smem_idx].size)) {
-			pr_err("%s: invalid virtual address block %i: %p:%pa\n",
+			LOG_ERR(
+				"%s: invalid virtual address block %i: %p:%pa\n",
 					__func__, smem_idx,
 					smem_areas_tmp[smem_idx].virt_addr,
 					&smem_areas_tmp[smem_idx].size);
@@ -662,18 +1274,26 @@
 
 		++smem_idx;
 		if (smem_idx > 999) {
-			pr_err("%s: max num aux mem regions reached\n",
+			LOG_ERR("%s: max num aux mem regions reached\n",
 							__func__);
 			break;
 		}
 	}
 
-	ret = of_platform_populate(pdev->dev.of_node, NULL, NULL, &pdev->dev);
-	if (ret)
-		pr_err("%s: of_platform_populate failed %d\n", __func__, ret);
-
 	smem_areas = smem_areas_tmp;
 	smem_ramdump_segments = ramdump_segments_tmp;
+
+	key = "mpu-enabled";
+	security_enabled = of_property_read_bool(pdev->dev.of_node, key);
+	if (security_enabled) {
+		SMEM_INFO("smem security enabled\n");
+		smem_init_security();
+	}
+
+	ret = of_platform_populate(pdev->dev.of_node, NULL, NULL, &pdev->dev);
+	if (ret)
+		LOG_ERR("%s: of_platform_populate failed %d\n", __func__, ret);
+
 	return 0;
 
 free_smem_areas:
@@ -710,15 +1330,21 @@
 
 	registered = true;
 
+	smem_ipc_log_ctx = ipc_log_context_create(NUM_LOG_PAGES, "smem");
+	if (!smem_ipc_log_ctx) {
+		pr_err("%s: unable to create logging context\n", __func__);
+		msm_smem_debug_mask = 0;
+	}
+
 	rc = init_smem_remote_spinlock();
 	if (rc) {
-		pr_err("%s: remote spinlock init failed %d\n", __func__, rc);
+		LOG_ERR("%s: remote spinlock init failed %d\n", __func__, rc);
 		return rc;
 	}
 
 	rc = platform_driver_register(&msm_smem_driver);
 	if (rc) {
-		pr_err("%s: msm_smem_driver register failed %d\n",
+		LOG_ERR("%s: msm_smem_driver register failed %d\n",
 							__func__, rc);
 		return rc;
 	}
diff --git a/arch/arm/mm/init.c b/arch/arm/mm/init.c
index e82ea2b..34ae4e6 100644
--- a/arch/arm/mm/init.c
+++ b/arch/arm/mm/init.c
@@ -734,6 +734,46 @@
 #endif
 }
 
+#define MLK(b, t) b, t, ((t) - (b)) >> 10
+#define MLM(b, t) b, t, ((t) - (b)) >> 20
+#define MLK_ROUNDUP(b, t) b, t, DIV_ROUND_UP(((t) - (b)), SZ_1K)
+
+#ifdef CONFIG_ENABLE_VMALLOC_SAVING
+void print_vmalloc_lowmem_info(void)
+{
+	int i;
+	void *va_start, *va_end;
+
+	printk(KERN_NOTICE
+		"	   vmalloc : 0x%08lx - 0x%08lx   (%4ld MB)\n",
+		MLM(VMALLOC_START, VMALLOC_END));
+
+	for (i = meminfo.nr_banks - 1; i >= 0; i--) {
+		if (!meminfo.bank[i].highmem) {
+			va_start = __va(meminfo.bank[i].start);
+			va_end = __va(meminfo.bank[i].start +
+						meminfo.bank[i].size);
+			printk(KERN_NOTICE
+			 "	    lowmem : 0x%08lx - 0x%08lx   (%4ld MB)\n",
+			MLM((unsigned long)va_start, (unsigned long)va_end));
+		}
+		if (i && ((meminfo.bank[i-1].start + meminfo.bank[i-1].size) !=
+			   meminfo.bank[i].start)) {
+			if (meminfo.bank[i-1].start + meminfo.bank[i-1].size
+				   <= MAX_HOLE_ADDRESS) {
+				va_start = __va(meminfo.bank[i-1].start
+						+ meminfo.bank[i-1].size);
+				va_end = __va(meminfo.bank[i].start);
+				printk(KERN_NOTICE
+				"	   vmalloc : 0x%08lx - 0x%08lx   (%4ld MB)\n",
+					   MLM((unsigned long)va_start,
+						   (unsigned long)va_end));
+			}
+		}
+	}
+}
+#endif
+
 /*
  * mem_init() marks the free areas in the mem_map and tells us how much
  * memory is free.  This is done after various parts of the system have
@@ -814,10 +854,6 @@
 		reserved_pages << (PAGE_SHIFT-10),
 		totalhigh_pages << (PAGE_SHIFT-10));
 
-#define MLK(b, t) b, t, ((t) - (b)) >> 10
-#define MLM(b, t) b, t, ((t) - (b)) >> 20
-#define MLK_ROUNDUP(b, t) b, t, DIV_ROUND_UP(((t) - (b)), SZ_1K)
-
 	printk(KERN_NOTICE "Virtual kernel memory layout:\n"
 			"    vector  : 0x%08lx - 0x%08lx   (%4ld kB)\n"
 #ifdef CONFIG_ARM_USE_USER_ACCESSIBLE_TIMERS
@@ -827,20 +863,7 @@
 			"    DTCM    : 0x%08lx - 0x%08lx   (%4ld kB)\n"
 			"    ITCM    : 0x%08lx - 0x%08lx   (%4ld kB)\n"
 #endif
-			"    fixmap  : 0x%08lx - 0x%08lx   (%4ld kB)\n"
-			"    vmalloc : 0x%08lx - 0x%08lx   (%4ld MB)\n"
-			"    lowmem  : 0x%08lx - 0x%08lx   (%4ld MB)\n"
-#ifdef CONFIG_HIGHMEM
-			"    pkmap   : 0x%08lx - 0x%08lx   (%4ld MB)\n"
-#endif
-#ifdef CONFIG_MODULES
-			"    modules : 0x%08lx - 0x%08lx   (%4ld MB)\n"
-#endif
-			"      .text : 0x%p" " - 0x%p" "   (%4d kB)\n"
-			"      .init : 0x%p" " - 0x%p" "   (%4d kB)\n"
-			"      .data : 0x%p" " - 0x%p" "   (%4d kB)\n"
-			"       .bss : 0x%p" " - 0x%p" "   (%4d kB)\n",
-
+			"    fixmap  : 0x%08lx - 0x%08lx   (%4ld kB)\n",
 			MLK(UL(CONFIG_VECTORS_BASE), UL(CONFIG_VECTORS_BASE) +
 				(PAGE_SIZE)),
 #ifdef CONFIG_ARM_USE_USER_ACCESSIBLE_TIMERS
@@ -852,25 +875,39 @@
 			MLK(DTCM_OFFSET, (unsigned long) dtcm_end),
 			MLK(ITCM_OFFSET, (unsigned long) itcm_end),
 #endif
-			MLK(FIXADDR_START, FIXADDR_TOP),
-			MLM(VMALLOC_START, VMALLOC_END),
-			MLM(PAGE_OFFSET, (unsigned long)high_memory),
+			MLK(FIXADDR_START, FIXADDR_TOP));
+#ifdef CONFIG_ENABLE_VMALLOC_SAVING
+	print_vmalloc_lowmem_info();
+#else
+	printk(KERN_NOTICE
+		   "    vmalloc : 0x%08lx - 0x%08lx   (%4ld MB)\n"
+		   "    lowmem  : 0x%08lx - 0x%08lx   (%4ld MB)\n",
+		   MLM(VMALLOC_START, VMALLOC_END),
+		   MLM(PAGE_OFFSET, (unsigned long)high_memory));
+#endif
 #ifdef CONFIG_HIGHMEM
-			MLM(PKMAP_BASE, (PKMAP_BASE) + (LAST_PKMAP) *
+	printk(KERN_NOTICE
+		   "    pkmap   : 0x%08lx - 0x%08lx   (%4ld MB)\n"
+#endif
+#ifdef CONFIG_MODULES
+		   "    modules : 0x%08lx - 0x%08lx   (%4ld MB)\n"
+#endif
+		   "      .text : 0x%p" " - 0x%p" "   (%4d kB)\n"
+		   "      .init : 0x%p" " - 0x%p" "   (%4d kB)\n"
+		   "      .data : 0x%p" " - 0x%p" "   (%4d kB)\n"
+		   "       .bss : 0x%p" " - 0x%p" "   (%4d kB)\n",
+#ifdef CONFIG_HIGHMEM
+		   MLM(PKMAP_BASE, (PKMAP_BASE) + (LAST_PKMAP) *
 				(PAGE_SIZE)),
 #endif
 #ifdef CONFIG_MODULES
-			MLM(MODULES_VADDR, MODULES_END),
+		   MLM(MODULES_VADDR, MODULES_END),
 #endif
 
-			MLK_ROUNDUP(_text, _etext),
-			MLK_ROUNDUP(__init_begin, __init_end),
-			MLK_ROUNDUP(_sdata, _edata),
-			MLK_ROUNDUP(__bss_start, __bss_stop));
-
-#undef MLK
-#undef MLM
-#undef MLK_ROUNDUP
+		   MLK_ROUNDUP(_text, _etext),
+		   MLK_ROUNDUP(__init_begin, __init_end),
+		   MLK_ROUNDUP(_sdata, _edata),
+		   MLK_ROUNDUP(__bss_start, __bss_stop));
 
 	/*
 	 * Check boundaries twice: Some fundamental inconsistencies can
@@ -878,7 +915,7 @@
 	 */
 #ifdef CONFIG_MMU
 	BUILD_BUG_ON(TASK_SIZE				> MODULES_VADDR);
-	BUG_ON(TASK_SIZE 				> MODULES_VADDR);
+	BUG_ON(TASK_SIZE				> MODULES_VADDR);
 #endif
 
 #ifdef CONFIG_HIGHMEM
@@ -897,6 +934,9 @@
 	}
 }
 
+#undef MLK
+#undef MLM
+#undef MLK_ROUNDUP
 void free_initmem(void)
 {
 	unsigned long reclaimed_initmem;
diff --git a/arch/arm/mm/mmu.c b/arch/arm/mm/mmu.c
index e5a60a9..509f59d 100644
--- a/arch/arm/mm/mmu.c
+++ b/arch/arm/mm/mmu.c
@@ -871,6 +871,7 @@
 {
 	struct map_desc *md;
 	struct vm_struct *vm;
+	int rc = 0;
 
 	if (!nr)
 		return;
@@ -881,11 +882,13 @@
 		create_mapping(md);
 		vm->addr = (void *)(md->virtual & PAGE_MASK);
 		vm->size = PAGE_ALIGN(md->length + (md->virtual & ~PAGE_MASK));
-		vm->phys_addr = __pfn_to_phys(md->pfn); 
-		vm->flags = VM_IOREMAP | VM_ARM_STATIC_MAPPING; 
+		vm->phys_addr = __pfn_to_phys(md->pfn);
+		vm->flags = VM_IOREMAP | VM_ARM_STATIC_MAPPING;
 		vm->flags |= VM_ARM_MTYPE(md->type);
 		vm->caller = iotable_init;
-		vm_area_add_early(vm++);
+		rc = vm_area_check_early(vm);
+		if (!rc)
+			vm_area_add_early(vm++);
 	}
 }
 
@@ -999,6 +1002,18 @@
 {
 	int i, j, highmem = 0;
 
+#ifdef CONFIG_ENABLE_VMALLOC_SAVING
+	unsigned long hole_start;
+	for (i = 0; i < (meminfo.nr_banks - 1); i++) {
+		hole_start = meminfo.bank[i].start + meminfo.bank[i].size;
+		if (hole_start != meminfo.bank[i+1].start) {
+			if (hole_start <= MAX_HOLE_ADDRESS) {
+				vmalloc_min = (void *) (vmalloc_min +
+				(meminfo.bank[i+1].start - hole_start));
+			}
+		}
+	}
+#endif
 #ifdef CONFIG_DONT_MAP_HOLE_AFTER_MEMBANK0
 	find_memory_hole();
 #endif
@@ -1382,12 +1397,21 @@
 static void __init map_lowmem(void)
 {
 	struct memblock_region *reg;
+	struct vm_struct *vm;
+	phys_addr_t start;
+	phys_addr_t end;
+	unsigned long vaddr;
+	unsigned long pfn;
+	unsigned long length;
+	unsigned int type;
+	int nr = 0;
 
 	/* Map all the lowmem memory banks. */
 	for_each_memblock(memory, reg) {
-		phys_addr_t start = reg->base;
-		phys_addr_t end = start + reg->size;
 		struct map_desc map;
+		nr++;
+		start = reg->base;
+		end = start + reg->size;
 
 		if (end > arm_lowmem_limit)
 			end = arm_lowmem_limit;
@@ -1440,6 +1464,32 @@
 
 		create_mapping(&map);
 	}
+
+	vm = early_alloc_aligned(sizeof(*vm) * nr, __alignof__(*vm));
+
+	for_each_memblock(memory, reg) {
+
+		start = reg->base;
+		end = start + reg->size;
+
+		if (end > arm_lowmem_limit)
+			end = arm_lowmem_limit;
+		if (start >= end)
+			break;
+
+		pfn = __phys_to_pfn(start);
+		vaddr = __phys_to_virt(start);
+		length = end - start;
+		type = MT_MEMORY;
+
+		vm->addr = (void *)(vaddr & PAGE_MASK);
+		vm->size = PAGE_ALIGN(length + (vaddr & ~PAGE_MASK));
+		vm->phys_addr = __pfn_to_phys(pfn);
+		vm->flags = VM_IOREMAP | VM_ARM_STATIC_MAPPING;
+		vm->flags |= VM_ARM_MTYPE(type);
+		vm->caller = map_lowmem;
+		vm_area_add_early(vm++);
+	}
 }
 
 /*
diff --git a/drivers/gpu/ion/ion_cma_secure_heap.c b/drivers/gpu/ion/ion_cma_secure_heap.c
index 415c73e..90451ca 100644
--- a/drivers/gpu/ion/ion_cma_secure_heap.c
+++ b/drivers/gpu/ion/ion_cma_secure_heap.c
@@ -136,10 +136,28 @@
 	buf = __ion_secure_cma_allocate(heap, buffer, len, align, flags);
 
 	if (buf) {
+		int ret;
+
 		buf->secure.want_delayed_unsecure = 0;
 		atomic_set(&buf->secure.secure_cnt, 0);
 		mutex_init(&buf->secure.lock);
 		buf->secure.is_secure = 1;
+		buf->secure.ignore_check = true;
+
+		/*
+		 * make sure the size is set before trying to secure
+		 */
+		buffer->size = len;
+		ret = ion_cp_secure_buffer(buffer, ION_CP_V2, 0, 0);
+		if (ret) {
+			/*
+			 * Don't treat the secure buffer failing here as an
+			 * error for backwards compatibility reasons. If
+			 * the secure fails, the map will also fail so there
+			 * is no security risk.
+			 */
+			pr_debug("%s: failed to secure buffer\n", __func__);
+		}
 		return 0;
 	} else {
 		return -ENOMEM;
@@ -153,6 +171,8 @@
 	struct ion_secure_cma_buffer_info *info = buffer->priv_virt;
 
 	dev_dbg(dev, "Release buffer %p\n", buffer);
+
+	ion_cp_unsecure_buffer(buffer, 1);
 	/* release memory */
 	dma_free_coherent(dev, buffer->size, info->cpu_addr, info->handle);
 	sg_free_table(info->table);
diff --git a/drivers/gpu/ion/msm/ion_cp_common.c b/drivers/gpu/ion/msm/ion_cp_common.c
index d315fc4..7ffab09 100644
--- a/drivers/gpu/ion/msm/ion_cp_common.c
+++ b/drivers/gpu/ion/msm/ion_cp_common.c
@@ -286,7 +286,7 @@
 		goto out_unlock;
 	}
 
-	if (atomic_read(&buf->secure_cnt)) {
+	if (atomic_read(&buf->secure_cnt) && !buf->ignore_check) {
 		if (buf->version != version || buf->data != data) {
 			pr_err("%s: Trying to re-secure buffer with different values",
 				__func__);
diff --git a/drivers/gpu/ion/msm/ion_cp_common.h b/drivers/gpu/ion/msm/ion_cp_common.h
index 8ae19be..ded6af9 100644
--- a/drivers/gpu/ion/msm/ion_cp_common.h
+++ b/drivers/gpu/ion/msm/ion_cp_common.h
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2012, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2012-2013, The Linux Foundation. All rights reserved.
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 and
@@ -38,6 +38,10 @@
 	struct mutex lock;
 	int version;
 	void *data;
+	/*
+	 * secure is happening at allocation time, ignore version/data check
+	 */
+	bool ignore_check;
 };
 
 #if defined(CONFIG_ION_MSM)
diff --git a/drivers/input/touchscreen/synaptics_i2c_rmi4.c b/drivers/input/touchscreen/synaptics_i2c_rmi4.c
index cf1c717..aec655c 100644
--- a/drivers/input/touchscreen/synaptics_i2c_rmi4.c
+++ b/drivers/input/touchscreen/synaptics_i2c_rmi4.c
@@ -3461,17 +3461,6 @@
 	rmi4_data->touch_stopped = false;
 	synaptics_rmi4_irq_enable(rmi4_data, true);
 
-	if (rmi4_data->board->power_down_enable ||
-			rmi4_data->board->disable_gpios) {
-		retval = synaptics_rmi4_reset_device(rmi4_data);
-		if (retval < 0) {
-			dev_err(&rmi4_data->i2c_client->dev,
-				"%s: Failed to issue reset command, " \
-				"rc = %d\n", __func__, retval);
-			return retval;
-		}
-	}
-
 	rmi4_data->suspended = false;
 
 	return 0;
diff --git a/drivers/leds/leds-qpnp.c b/drivers/leds/leds-qpnp.c
index ecab061..bf59d03 100644
--- a/drivers/leds/leds-qpnp.c
+++ b/drivers/leds/leds-qpnp.c
@@ -23,6 +23,7 @@
 #include <linux/spmi.h>
 #include <linux/qpnp/pwm.h>
 #include <linux/workqueue.h>
+#include <linux/delay.h>
 #include <linux/regulator/consumer.h>
 
 #define WLED_MOD_EN_REG(base, n)	(base + 0x60 + n*0x10)
@@ -43,6 +44,7 @@
 #define WLED_HIGH_POLE_CAP_REG(base)		(base + 0x58)
 #define WLED_CURR_SINK_MASK		0xE0
 #define WLED_CURR_SINK_SHFT		0x05
+#define WLED_DISABLE_ALL_SINKS		0x00
 #define WLED_SWITCH_FREQ_MASK		0x0F
 #define WLED_OVP_VAL_MASK		0x03
 #define WLED_OVP_VAL_BIT_SHFT		0x00
@@ -58,6 +60,8 @@
 #define WLED_CTL_DLY_STEP		200
 #define WLED_CTL_DLY_MAX		1400
 #define WLED_MAX_CURR			25
+#define WLED_NO_CURRENT			0x00
+#define WLED_OVP_DELAY			1000
 #define WLED_MSB_MASK			0x0F
 #define WLED_MAX_CURR_MASK		0x1F
 #define WLED_OP_FDBCK_MASK		0x07
@@ -73,6 +77,9 @@
 #define WLED_SYNC_VAL			0x07
 #define WLED_SYNC_RESET_VAL		0x00
 
+#define PMIC_VER_8026			0x04
+#define PMIC_VERSION_REG		0x0105
+
 #define WLED_DEFAULT_STRINGS		0x01
 #define WLED_DEFAULT_OVP_VAL		0x02
 #define WLED_BOOST_LIM_DEFAULT		0x03
@@ -337,6 +344,7 @@
 	u8	ctrl_delay_us;
 	u8	switch_freq;
 	u8	op_fdbck;
+	u8	pmic_version;
 	bool	dig_mod_gen_en;
 	bool	cs_out_en;
 };
@@ -511,16 +519,86 @@
 	pr_debug("===== %s LED register dump end =====\n", led->cdev.name);
 }
 
+static int qpnp_wled_sync(struct qpnp_led_data *led)
+{
+	int rc;
+	u8 val;
+
+	/* sync */
+	val = WLED_SYNC_VAL;
+	rc = spmi_ext_register_writel(led->spmi_dev->ctrl, led->spmi_dev->sid,
+		WLED_SYNC_REG(led->base), &val, 1);
+	if (rc) {
+		dev_err(&led->spmi_dev->dev,
+				"WLED set sync reg failed(%d)\n", rc);
+		return rc;
+	}
+
+	val = WLED_SYNC_RESET_VAL;
+	rc = spmi_ext_register_writel(led->spmi_dev->ctrl, led->spmi_dev->sid,
+		WLED_SYNC_REG(led->base), &val, 1);
+	if (rc) {
+		dev_err(&led->spmi_dev->dev,
+				"WLED reset sync reg failed(%d)\n", rc);
+		return rc;
+	}
+	return 0;
+}
+
 static int qpnp_wled_set(struct qpnp_led_data *led)
 {
 	int rc, duty, level;
-	u8 val, i, num_wled_strings;
+	u8 val, i, num_wled_strings, sink_val;
+
+	num_wled_strings = led->wled_cfg->num_strings;
 
 	level = led->cdev.brightness;
 
 	if (level > WLED_MAX_LEVEL)
 		level = WLED_MAX_LEVEL;
 	if (level == 0) {
+		for (i = 0; i < num_wled_strings; i++) {
+			rc = qpnp_led_masked_write(led,
+				WLED_FULL_SCALE_REG(led->base, i),
+				WLED_MAX_CURR_MASK, WLED_NO_CURRENT);
+			if (rc) {
+				dev_err(&led->spmi_dev->dev,
+					"Write max current failure (%d)\n",
+					rc);
+				return rc;
+			}
+		}
+
+		rc = qpnp_wled_sync(led);
+		if (rc) {
+			dev_err(&led->spmi_dev->dev,
+				"WLED sync failed(%d)\n", rc);
+			return rc;
+		}
+
+		rc = spmi_ext_register_readl(led->spmi_dev->ctrl,
+			led->spmi_dev->sid, WLED_CURR_SINK_REG(led->base),
+			&sink_val, 1);
+		if (rc) {
+			dev_err(&led->spmi_dev->dev,
+				"WLED read sink reg failed(%d)\n", rc);
+			return rc;
+		}
+
+		if (led->wled_cfg->pmic_version == PMIC_VER_8026) {
+			val = WLED_DISABLE_ALL_SINKS;
+			rc = spmi_ext_register_writel(led->spmi_dev->ctrl,
+				led->spmi_dev->sid,
+				WLED_CURR_SINK_REG(led->base), &val, 1);
+			if (rc) {
+				dev_err(&led->spmi_dev->dev,
+					"WLED write sink reg failed(%d)\n", rc);
+				return rc;
+			}
+
+			usleep(WLED_OVP_DELAY);
+		}
+
 		val = WLED_BOOST_OFF;
 		rc = spmi_ext_register_writel(led->spmi_dev->ctrl,
 			led->spmi_dev->sid, WLED_MOD_CTRL_REG(led->base),
@@ -530,6 +608,35 @@
 				"WLED write ctrl reg failed(%d)\n", rc);
 			return rc;
 		}
+
+		for (i = 0; i < num_wled_strings; i++) {
+			rc = qpnp_led_masked_write(led,
+				WLED_FULL_SCALE_REG(led->base, i),
+				WLED_MAX_CURR_MASK, led->max_current);
+			if (rc) {
+				dev_err(&led->spmi_dev->dev,
+					"Write max current failure (%d)\n",
+					rc);
+				return rc;
+			}
+		}
+
+		rc = qpnp_wled_sync(led);
+		if (rc) {
+			dev_err(&led->spmi_dev->dev,
+				"WLED sync failed(%d)\n", rc);
+			return rc;
+		}
+
+		rc = spmi_ext_register_writel(led->spmi_dev->ctrl,
+			led->spmi_dev->sid, WLED_CURR_SINK_REG(led->base),
+			&sink_val, 1);
+		if (rc) {
+			dev_err(&led->spmi_dev->dev,
+				"WLED write sink reg failed(%d)\n", rc);
+			return rc;
+		}
+
 	} else {
 		val = WLED_BOOST_ON;
 		rc = spmi_ext_register_writel(led->spmi_dev->ctrl,
@@ -544,8 +651,6 @@
 
 	duty = (WLED_MAX_DUTY_CYCLE * level) / WLED_MAX_LEVEL;
 
-	num_wled_strings = led->wled_cfg->num_strings;
-
 	/* program brightness control registers */
 	for (i = 0; i < num_wled_strings; i++) {
 		rc = qpnp_led_masked_write(led,
@@ -567,22 +672,9 @@
 		}
 	}
 
-	/* sync */
-	val = WLED_SYNC_VAL;
-	rc = spmi_ext_register_writel(led->spmi_dev->ctrl, led->spmi_dev->sid,
-		WLED_SYNC_REG(led->base), &val, 1);
+	rc = qpnp_wled_sync(led);
 	if (rc) {
-		dev_err(&led->spmi_dev->dev,
-				"WLED set sync reg failed(%d)\n", rc);
-		return rc;
-	}
-
-	val = WLED_SYNC_RESET_VAL;
-	rc = spmi_ext_register_writel(led->spmi_dev->ctrl, led->spmi_dev->sid,
-		WLED_SYNC_REG(led->base), &val, 1);
-	if (rc) {
-		dev_err(&led->spmi_dev->dev,
-				"WLED reset sync reg failed(%d)\n", rc);
+		dev_err(&led->spmi_dev->dev, "WLED sync failed(%d)\n", rc);
 		return rc;
 	}
 	return 0;
@@ -2489,6 +2581,13 @@
 		return -ENOMEM;
 	}
 
+	rc = spmi_ext_register_readl(led->spmi_dev->ctrl, led->spmi_dev->sid,
+		PMIC_VERSION_REG, &led->wled_cfg->pmic_version, 1);
+	if (rc) {
+		dev_err(&led->spmi_dev->dev,
+			"Unable to read pmic ver, rc(%d)\n", rc);
+	}
+
 	led->wled_cfg->num_strings = WLED_DEFAULT_STRINGS;
 	rc = of_property_read_u32(node, "qcom,num-strings", &val);
 	if (!rc)
diff --git a/drivers/media/platform/msm/camera_v1/server/msm_cam_server.c b/drivers/media/platform/msm/camera_v1/server/msm_cam_server.c
index 78d15d9..d9fba33 100644
--- a/drivers/media/platform/msm/camera_v1/server/msm_cam_server.c
+++ b/drivers/media/platform/msm/camera_v1/server/msm_cam_server.c
@@ -2777,40 +2777,6 @@
 	return rc;
 }
 
-static int msm_mmap_config(struct file *fp, struct vm_area_struct *vma)
-{
-	struct msm_cam_config_dev *config_cam = fp->private_data;
-	int rc = 0;
-	int phyaddr;
-	int retval;
-	unsigned long size;
-
-	D("%s: phy_addr=0x%x", __func__, config_cam->mem_map.cookie);
-	phyaddr = (int)config_cam->mem_map.cookie;
-	if (!phyaddr) {
-		pr_err("%s: no physical memory to map", __func__);
-		return -EFAULT;
-	}
-	memset(&config_cam->mem_map, 0,
-		sizeof(struct msm_mem_map_info));
-	size = vma->vm_end - vma->vm_start;
-	vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot);
-	retval = remap_pfn_range(vma, vma->vm_start,
-					phyaddr >> PAGE_SHIFT,
-					size, vma->vm_page_prot);
-	if (retval) {
-		pr_err("%s: remap failed, rc = %d",
-					__func__, retval);
-		rc = -ENOMEM;
-		goto end;
-	}
-	D("%s: phy_addr=0x%x: %08lx-%08lx, pgoff %08lx\n",
-			__func__, (uint32_t)phyaddr,
-			vma->vm_start, vma->vm_end, vma->vm_pgoff);
-end:
-	return rc;
-}
-
 static int msm_open_config(struct inode *inode, struct file *fp)
 {
 	int rc;
@@ -3081,12 +3047,6 @@
 		rc = msm_v4l2_evt_notify(config_cam->p_mctl, cmd, arg);
 		break;
 
-	case MSM_CAM_IOCTL_SET_MEM_MAP_INFO:
-		if (copy_from_user(&config_cam->mem_map, (void __user *)arg,
-				sizeof(struct msm_mem_map_info)))
-			rc = -EINVAL;
-		break;
-
 	case MSM_CAM_IOCTL_SET_MCTL_SDEV:{
 		struct msm_mctl_set_sdev_data set_data;
 		if (copy_from_user(&set_data, (void __user *)arg,
@@ -3148,7 +3108,6 @@
 	.open  = msm_open_config,
 	.poll  = msm_poll_config,
 	.unlocked_ioctl = msm_ioctl_config,
-	.mmap	= msm_mmap_config,
 	.release = msm_close_config,
 };
 
diff --git a/drivers/media/platform/msm/camera_v2/Kconfig b/drivers/media/platform/msm/camera_v2/Kconfig
index 4668d02..bc7d135 100644
--- a/drivers/media/platform/msm/camera_v2/Kconfig
+++ b/drivers/media/platform/msm/camera_v2/Kconfig
@@ -191,6 +191,15 @@
 		snapshot config = 3264 * 2448 at 18 fps.
 		2 lanes max fps is 18, 4 lanes max fps is 24.
 
+config OV8865
+	bool "OmniVision OV8865 (BAYER 8MP)"
+	depends on MSMB_CAMERA
+	---help---
+		OmniVision 8 MP Bayer Sensor with auto focus.uses
+		4 mipi lanes, preview config = 1632*1224 30 fps,
+		snapshot config = 3264 * 2448 at 30 fps.
+		Max fps is 30fps at 3264 * 2448, 60fps at 1632 * 1224
+
 config s5k4e1
 	bool "Sensor s5k4e1 (BAYER 5MP)"
 	depends on MSMB_CAMERA
diff --git a/drivers/media/platform/msm/camera_v2/sensor/Makefile b/drivers/media/platform/msm/camera_v2/sensor/Makefile
index bd1b10b..bbfbbdf 100644
--- a/drivers/media/platform/msm/camera_v2/sensor/Makefile
+++ b/drivers/media/platform/msm/camera_v2/sensor/Makefile
@@ -17,3 +17,4 @@
 obj-$(CONFIG_MT9M114) += mt9m114.o
 obj-$(CONFIG_SP1628) += sp1628.o
 obj-$(CONFIG_GC0339) += gc0339.o
+obj-$(CONFIG_OV8865) += ov8865.o
diff --git a/drivers/media/platform/msm/camera_v2/sensor/actuator/msm_actuator.c b/drivers/media/platform/msm/camera_v2/sensor/actuator/msm_actuator.c
index 32d74ba..16a1616 100644
--- a/drivers/media/platform/msm/camera_v2/sensor/actuator/msm_actuator.c
+++ b/drivers/media/platform/msm/camera_v2/sensor/actuator/msm_actuator.c
@@ -41,6 +41,7 @@
 	struct msm_actuator_move_params_t *move_params)
 {
 	int32_t rc = 0;
+	struct msm_camera_i2c_reg_setting reg_setting;
 	CDBG("Enter\n");
 
 	if (a_ctrl->curr_step_pos != 0) {
@@ -49,10 +50,12 @@
 			a_ctrl->initial_code, 0, 0);
 		a_ctrl->func_tbl->actuator_parse_i2c_params(a_ctrl,
 			a_ctrl->initial_code, 0, 0);
+		reg_setting.reg_setting = a_ctrl->i2c_reg_tbl;
+		reg_setting.data_type = a_ctrl->i2c_data_type;
+		reg_setting.size = a_ctrl->i2c_tbl_index;
 		rc = a_ctrl->i2c_client.i2c_func_tbl->
 			i2c_write_table_w_microdelay(
-			&a_ctrl->i2c_client, a_ctrl->i2c_reg_tbl,
-			a_ctrl->i2c_tbl_index, a_ctrl->i2c_data_type);
+			&a_ctrl->i2c_client, &reg_setting);
 		if (rc < 0) {
 			pr_err("%s: i2c write error:%d\n",
 				__func__, rc);
@@ -73,7 +76,7 @@
 	uint16_t i2c_byte1 = 0, i2c_byte2 = 0;
 	uint16_t value = 0;
 	uint32_t size = a_ctrl->reg_tbl_size, i = 0;
-	struct msm_camera_i2c_reg_tbl *i2c_tbl = a_ctrl->i2c_reg_tbl;
+	struct msm_camera_i2c_reg_array *i2c_tbl = a_ctrl->i2c_reg_tbl;
 	CDBG("Enter\n");
 	for (i = 0; i < size; i++) {
 		if (write_arr[i].reg_write_type == MSM_ACTUATOR_WRITE_DAC) {
@@ -195,6 +198,7 @@
 	int32_t dest_step_position = move_params->dest_step_pos;
 	int32_t rc = 0;
 	int32_t num_steps = move_params->num_steps;
+	struct msm_camera_i2c_reg_setting reg_setting;
 	CDBG("Enter\n");
 
 	if (num_steps == 0)
@@ -206,10 +210,11 @@
 		a_ctrl->region_params[0].code_per_step),
 		move_params->ringing_params[0].hw_params, 0);
 
+	reg_setting.reg_setting = a_ctrl->i2c_reg_tbl;
+	reg_setting.data_type = a_ctrl->i2c_data_type;
+	reg_setting.size = a_ctrl->i2c_tbl_index;
 	rc = a_ctrl->i2c_client.i2c_func_tbl->i2c_write_table_w_microdelay(
-		&a_ctrl->i2c_client,
-		a_ctrl->i2c_reg_tbl, a_ctrl->i2c_tbl_index,
-		a_ctrl->i2c_data_type);
+		&a_ctrl->i2c_client, &reg_setting);
 	if (rc < 0) {
 		pr_err("i2c write error:%d\n", rc);
 		return rc;
@@ -233,6 +238,7 @@
 	uint16_t curr_lens_pos = 0;
 	int dir = move_params->dir;
 	int32_t num_steps = move_params->num_steps;
+	struct msm_camera_i2c_reg_setting reg_setting;
 
 	CDBG("called, dir %d, num_steps %d\n", dir, num_steps);
 
@@ -280,10 +286,11 @@
 		a_ctrl->curr_step_pos = target_step_pos;
 	}
 
+	reg_setting.reg_setting = a_ctrl->i2c_reg_tbl;
+	reg_setting.data_type = a_ctrl->i2c_data_type;
+	reg_setting.size = a_ctrl->i2c_tbl_index;
 	rc = a_ctrl->i2c_client.i2c_func_tbl->i2c_write_table_w_microdelay(
-		&a_ctrl->i2c_client,
-		a_ctrl->i2c_reg_tbl, a_ctrl->i2c_tbl_index,
-		a_ctrl->i2c_data_type);
+		&a_ctrl->i2c_client, &reg_setting);
 	if (rc < 0) {
 		pr_err("i2c write error:%d\n", rc);
 		return rc;
@@ -439,7 +446,7 @@
 	kfree(a_ctrl->i2c_reg_tbl);
 
 	a_ctrl->i2c_reg_tbl =
-		kmalloc(sizeof(struct msm_camera_i2c_reg_tbl) *
+		kmalloc(sizeof(struct msm_camera_i2c_reg_array) *
 		(set_info->af_tuning_params.total_steps + 1), GFP_KERNEL);
 	if (!a_ctrl->i2c_reg_tbl) {
 		pr_err("kmalloc fail\n");
diff --git a/drivers/media/platform/msm/camera_v2/sensor/actuator/msm_actuator.h b/drivers/media/platform/msm/camera_v2/sensor/actuator/msm_actuator.h
index c4a4137..809c9cf 100644
--- a/drivers/media/platform/msm/camera_v2/sensor/actuator/msm_actuator.h
+++ b/drivers/media/platform/msm/camera_v2/sensor/actuator/msm_actuator.h
@@ -77,7 +77,7 @@
 	uint32_t total_steps;
 	uint16_t pwd_step;
 	uint16_t initial_code;
-	struct msm_camera_i2c_reg_tbl *i2c_reg_tbl;
+	struct msm_camera_i2c_reg_array *i2c_reg_tbl;
 	uint16_t i2c_tbl_index;
 	enum cci_i2c_master_t cci_master;
 	uint32_t subdev_id;
diff --git a/drivers/media/platform/msm/camera_v2/sensor/cci/msm_cci.c b/drivers/media/platform/msm/camera_v2/sensor/cci/msm_cci.c
index d11798e..968dcd7 100644
--- a/drivers/media/platform/msm/camera_v2/sensor/cci/msm_cci.c
+++ b/drivers/media/platform/msm/camera_v2/sensor/cci/msm_cci.c
@@ -26,6 +26,8 @@
 #define V4L2_IDENT_CCI 50005
 #define CCI_I2C_QUEUE_0_SIZE 64
 #define CCI_I2C_QUEUE_1_SIZE 16
+#define CYCLES_PER_MICRO_SEC 4915
+#define CCI_MAX_DELAY 10000
 
 #define CCI_TIMEOUT msecs_to_jiffies(100)
 
@@ -178,13 +180,13 @@
 {
 	uint16_t i = 0, j = 0, k = 0, h = 0, len = 0;
 	int32_t rc = 0;
-	uint32_t cmd = 0;
+	uint32_t cmd = 0, delay = 0;
 	uint8_t data[10];
 	uint16_t reg_addr = 0;
-	struct msm_camera_cci_i2c_write_cfg *i2c_msg =
+	struct msm_camera_i2c_reg_setting *i2c_msg =
 		&c_ctrl->cfg.cci_i2c_write_cfg;
 	uint16_t cmd_size = i2c_msg->size;
-	struct msm_camera_i2c_reg_conf *i2c_cmd = i2c_msg->reg_conf_tbl;
+	struct msm_camera_i2c_reg_array *i2c_cmd = i2c_msg->reg_setting;
 	enum cci_i2c_master_t master = c_ctrl->cci_info->cci_i2c_master;
 
 	if (i2c_cmd == NULL) {
@@ -213,6 +215,7 @@
 	while (cmd_size) {
 		CDBG("%s cmd_size %d addr 0x%x data 0x%x", __func__,
 			cmd_size, i2c_cmd->reg_addr, i2c_cmd->reg_data);
+		delay = i2c_cmd->delay;
 		data[i++] = CCI_I2C_WRITE_CMD;
 		if (i2c_cmd->reg_addr)
 			reg_addr = i2c_cmd->reg_addr;
@@ -257,6 +260,17 @@
 				CCI_I2C_M0_Q0_LOAD_DATA_ADDR +
 				master * 0x200 + queue * 0x100);
 		}
+		if ((delay > 0) && (delay < CCI_MAX_DELAY)) {
+			cmd = (uint32_t)((delay * CYCLES_PER_MICRO_SEC) /
+				0x100);
+			cmd <<= 4;
+			cmd |= CCI_I2C_WAIT_CMD;
+			CDBG("%s CCI_I2C_M0_Q0_LOAD_DATA_ADDR 0x%x\n",
+				__func__, cmd);
+			msm_camera_io_w(cmd, cci_dev->base +
+				CCI_I2C_M0_Q0_LOAD_DATA_ADDR +
+				master * 0x200 + queue * 0x100);
+		}
 		i = 0;
 	}
 	return rc;
diff --git a/drivers/media/platform/msm/camera_v2/sensor/cci/msm_cci.h b/drivers/media/platform/msm/camera_v2/sensor/cci/msm_cci.h
index 16edaae..6067f26 100644
--- a/drivers/media/platform/msm/camera_v2/sensor/cci/msm_cci.h
+++ b/drivers/media/platform/msm/camera_v2/sensor/cci/msm_cci.h
@@ -64,13 +64,6 @@
 	uint16_t i2c_queue;
 };
 
-struct msm_camera_cci_i2c_write_cfg {
-	struct msm_camera_i2c_reg_conf *reg_conf_tbl;
-	enum msm_camera_i2c_reg_addr_type addr_type;
-	enum msm_camera_i2c_data_type data_type;
-	uint16_t size;
-};
-
 struct msm_camera_cci_i2c_read_cfg {
 	uint16_t addr;
 	enum msm_camera_i2c_reg_addr_type addr_type;
@@ -90,7 +83,7 @@
 	struct msm_camera_cci_client *cci_info;
 	enum msm_cci_cmd_type cmd;
 	union {
-		struct msm_camera_cci_i2c_write_cfg cci_i2c_write_cfg;
+		struct msm_camera_i2c_reg_setting cci_i2c_write_cfg;
 		struct msm_camera_cci_i2c_read_cfg cci_i2c_read_cfg;
 		struct msm_camera_cci_wait_sync_cfg cci_wait_sync_cfg;
 		struct msm_camera_cci_gpio_cfg gpio_cfg;
diff --git a/drivers/media/platform/msm/camera_v2/sensor/io/msm_camera_cci_i2c.c b/drivers/media/platform/msm/camera_v2/sensor/io/msm_camera_cci_i2c.c
index 3792247..8d9274b 100644
--- a/drivers/media/platform/msm/camera_v2/sensor/io/msm_camera_cci_i2c.c
+++ b/drivers/media/platform/msm/camera_v2/sensor/io/msm_camera_cci_i2c.c
@@ -108,7 +108,7 @@
 {
 	int32_t rc = -EFAULT;
 	struct msm_camera_cci_ctrl cci_ctrl;
-	struct msm_camera_i2c_reg_conf reg_conf_tbl;
+	struct msm_camera_i2c_reg_array reg_conf_tbl;
 
 	if ((client->addr_type != MSM_CAMERA_I2C_BYTE_ADDR
 		&& client->addr_type != MSM_CAMERA_I2C_WORD_ADDR)
@@ -122,7 +122,7 @@
 	reg_conf_tbl.reg_data = data;
 	cci_ctrl.cmd = MSM_CCI_I2C_WRITE;
 	cci_ctrl.cci_info = client->cci_client;
-	cci_ctrl.cfg.cci_i2c_write_cfg.reg_conf_tbl = &reg_conf_tbl;
+	cci_ctrl.cfg.cci_i2c_write_cfg.reg_setting = &reg_conf_tbl;
 	cci_ctrl.cfg.cci_i2c_write_cfg.data_type = data_type;
 	cci_ctrl.cfg.cci_i2c_write_cfg.addr_type = client->addr_type;
 	cci_ctrl.cfg.cci_i2c_write_cfg.size = 1;
@@ -142,7 +142,7 @@
 	int32_t rc = -EFAULT;
 	uint8_t i = 0;
 	struct msm_camera_cci_ctrl cci_ctrl;
-	struct msm_camera_i2c_reg_conf reg_conf_tbl[num_byte];
+	struct msm_camera_i2c_reg_array reg_conf_tbl[num_byte];
 
 	if ((client->addr_type != MSM_CAMERA_I2C_BYTE_ADDR
 		&& client->addr_type != MSM_CAMERA_I2C_WORD_ADDR)
@@ -152,13 +152,15 @@
 	S_I2C_DBG("%s reg addr = 0x%x num bytes: %d\n",
 			  __func__, addr, num_byte);
 	memset(reg_conf_tbl, 0,
-		num_byte * sizeof(struct msm_camera_i2c_reg_conf));
+		num_byte * sizeof(struct msm_camera_i2c_reg_array));
 	reg_conf_tbl[0].reg_addr = addr;
-	for (i = 0; i < num_byte; i++)
+	for (i = 0; i < num_byte; i++) {
 		reg_conf_tbl[i].reg_data = data[i];
+		reg_conf_tbl[i].delay = 0;
+	}
 	cci_ctrl.cmd = MSM_CCI_I2C_WRITE;
 	cci_ctrl.cci_info = client->cci_client;
-	cci_ctrl.cfg.cci_i2c_write_cfg.reg_conf_tbl = reg_conf_tbl;
+	cci_ctrl.cfg.cci_i2c_write_cfg.reg_setting = reg_conf_tbl;
 	cci_ctrl.cfg.cci_i2c_write_cfg.data_type = MSM_CAMERA_I2C_BYTE_DATA;
 	cci_ctrl.cfg.cci_i2c_write_cfg.addr_type = client->addr_type;
 	cci_ctrl.cfg.cci_i2c_write_cfg.size = num_byte;
@@ -173,10 +175,8 @@
 	struct msm_camera_i2c_client *client,
 	struct msm_camera_i2c_reg_setting *write_setting)
 {
-	int i;
 	int32_t rc = -EFAULT;
-	struct msm_camera_i2c_reg_array *reg_setting;
-	uint16_t client_addr_type;
+	struct msm_camera_cci_ctrl cci_ctrl;
 
 	if (!client || !write_setting)
 		return rc;
@@ -187,24 +187,26 @@
 		&& write_setting->data_type != MSM_CAMERA_I2C_WORD_DATA))
 		return rc;
 
-	reg_setting = write_setting->reg_setting;
-	client_addr_type = client->addr_type;
-	client->addr_type = write_setting->addr_type;
-
-	for (i = 0; i < write_setting->size; i++) {
-		rc = msm_camera_cci_i2c_write(client, reg_setting->reg_addr,
-			reg_setting->reg_data, write_setting->data_type);
-		if (rc < 0)
-			return rc;
-		reg_setting++;
+	cci_ctrl.cmd = MSM_CCI_I2C_WRITE;
+	cci_ctrl.cci_info = client->cci_client;
+	cci_ctrl.cfg.cci_i2c_write_cfg.reg_setting =
+		write_setting->reg_setting;
+	cci_ctrl.cfg.cci_i2c_write_cfg.data_type = write_setting->data_type;
+	cci_ctrl.cfg.cci_i2c_write_cfg.addr_type = client->addr_type;
+	cci_ctrl.cfg.cci_i2c_write_cfg.size = write_setting->size;
+	rc = v4l2_subdev_call(client->cci_client->cci_subdev,
+			core, ioctl, VIDIOC_MSM_CCI_CFG, &cci_ctrl);
+	if (rc < 0) {
+		pr_err("%s: line %d rc = %d\n", __func__, __LINE__, rc);
+		return rc;
 	}
+	rc = cci_ctrl.status;
 	if (write_setting->delay > 20)
 		msleep(write_setting->delay);
 	else if (write_setting->delay)
 		usleep_range(write_setting->delay * 1000, (write_setting->delay
 			* 1000) + 1000);
 
-	client->addr_type = client_addr_type;
 	return rc;
 }
 
@@ -250,30 +252,34 @@
 
 int32_t msm_camera_cci_i2c_write_table_w_microdelay(
 	struct msm_camera_i2c_client *client,
-	struct msm_camera_i2c_reg_tbl *reg_tbl, uint16_t size,
-	enum msm_camera_i2c_data_type data_type)
+	struct msm_camera_i2c_reg_setting *write_setting)
 {
-	int i;
 	int32_t rc = -EFAULT;
+	struct msm_camera_cci_ctrl cci_ctrl;
 
-	if (!client || !reg_tbl)
+	if (!client || !write_setting)
 		return rc;
 
 	if ((client->addr_type != MSM_CAMERA_I2C_BYTE_ADDR
 		&& client->addr_type != MSM_CAMERA_I2C_WORD_ADDR)
-		|| (data_type != MSM_CAMERA_I2C_BYTE_DATA
-		&& data_type != MSM_CAMERA_I2C_WORD_DATA))
+		|| (write_setting->data_type != MSM_CAMERA_I2C_BYTE_DATA
+		&& write_setting->data_type != MSM_CAMERA_I2C_WORD_DATA))
 		return rc;
 
-	for (i = 0; i < size; i++) {
-		rc = msm_camera_cci_i2c_write(client, reg_tbl->reg_addr,
-			reg_tbl->reg_data, data_type);
-		if (rc < 0)
-			return rc;
-		if (reg_tbl->delay)
-			usleep_range(reg_tbl->delay, reg_tbl->delay + 1000);
-		reg_tbl++;
+	cci_ctrl.cmd = MSM_CCI_I2C_WRITE;
+	cci_ctrl.cci_info = client->cci_client;
+	cci_ctrl.cfg.cci_i2c_write_cfg.reg_setting =
+		write_setting->reg_setting;
+	cci_ctrl.cfg.cci_i2c_write_cfg.data_type = write_setting->data_type;
+	cci_ctrl.cfg.cci_i2c_write_cfg.addr_type = client->addr_type;
+	cci_ctrl.cfg.cci_i2c_write_cfg.size = write_setting->size;
+	rc = v4l2_subdev_call(client->cci_client->cci_subdev,
+			core, ioctl, VIDIOC_MSM_CCI_CFG, &cci_ctrl);
+	if (rc < 0) {
+		pr_err("%s: line %d rc = %d\n", __func__, __LINE__, rc);
+		return rc;
 	}
+	rc = cci_ctrl.status;
 	return rc;
 }
 
diff --git a/drivers/media/platform/msm/camera_v2/sensor/io/msm_camera_i2c.h b/drivers/media/platform/msm/camera_v2/sensor/io/msm_camera_i2c.h
index 389e9d9..763c131 100644
--- a/drivers/media/platform/msm/camera_v2/sensor/io/msm_camera_i2c.h
+++ b/drivers/media/platform/msm/camera_v2/sensor/io/msm_camera_i2c.h
@@ -25,12 +25,6 @@
 	enum msm_camera_i2c_reg_addr_type addr_type;
 };
 
-struct msm_camera_i2c_reg_tbl {
-	uint16_t reg_addr;
-	uint16_t reg_data;
-	uint16_t delay;
-};
-
 struct msm_camera_i2c_fn_t {
 	int (*i2c_read) (struct msm_camera_i2c_client *, uint32_t, uint16_t *,
 		enum msm_camera_i2c_data_type);
@@ -46,8 +40,7 @@
 		struct msm_camera_i2c_seq_reg_setting *);
 	int32_t (*i2c_write_table_w_microdelay)
 		(struct msm_camera_i2c_client *,
-		struct msm_camera_i2c_reg_tbl *, uint16_t,
-		enum msm_camera_i2c_data_type);
+		struct msm_camera_i2c_reg_setting *);
 	int32_t (*i2c_util)(struct msm_camera_i2c_client *, uint16_t);
 	int32_t (*i2c_write_conf_tbl)(struct msm_camera_i2c_client *client,
 		struct msm_camera_i2c_reg_conf *reg_conf_tbl, uint16_t size,
@@ -81,8 +74,7 @@
 
 int32_t msm_camera_cci_i2c_write_table_w_microdelay(
 	struct msm_camera_i2c_client *client,
-	struct msm_camera_i2c_reg_tbl *reg_tbl, uint16_t size,
-	enum msm_camera_i2c_data_type data_type);
+	struct msm_camera_i2c_reg_setting *write_setting);
 
 int32_t msm_camera_cci_i2c_write_conf_tbl(
 	struct msm_camera_i2c_client *client,
@@ -118,8 +110,7 @@
 
 int32_t msm_camera_qup_i2c_write_table_w_microdelay(
 	struct msm_camera_i2c_client *client,
-	struct msm_camera_i2c_reg_tbl *reg_tbl, uint16_t size,
-	enum msm_camera_i2c_data_type data_type);
+	struct msm_camera_i2c_reg_setting *write_setting);
 
 int32_t msm_camera_qup_i2c_write_conf_tbl(
 	struct msm_camera_i2c_client *client,
diff --git a/drivers/media/platform/msm/camera_v2/sensor/io/msm_camera_qup_i2c.c b/drivers/media/platform/msm/camera_v2/sensor/io/msm_camera_qup_i2c.c
index 60d1509..d5b89b7 100644
--- a/drivers/media/platform/msm/camera_v2/sensor/io/msm_camera_qup_i2c.c
+++ b/drivers/media/platform/msm/camera_v2/sensor/io/msm_camera_qup_i2c.c
@@ -308,29 +308,31 @@
 
 int32_t msm_camera_qup_i2c_write_table_w_microdelay(
 	struct msm_camera_i2c_client *client,
-	struct msm_camera_i2c_reg_tbl *reg_tbl, uint16_t size,
-	enum msm_camera_i2c_data_type data_type)
+	struct msm_camera_i2c_reg_setting *write_setting)
 {
 	int i;
 	int32_t rc = -EFAULT;
+	struct msm_camera_i2c_reg_array *reg_setting = NULL;
 
-	if (!client || !reg_tbl)
+	if (!client || !write_setting)
 		return rc;
 
 	if ((client->addr_type != MSM_CAMERA_I2C_BYTE_ADDR
 		&& client->addr_type != MSM_CAMERA_I2C_WORD_ADDR)
-		|| (data_type != MSM_CAMERA_I2C_BYTE_DATA
-		&& data_type != MSM_CAMERA_I2C_WORD_DATA))
+		|| (write_setting->data_type != MSM_CAMERA_I2C_BYTE_DATA
+		&& write_setting->data_type != MSM_CAMERA_I2C_WORD_DATA))
 		return rc;
 
-	for (i = 0; i < size; i++) {
-		rc = msm_camera_qup_i2c_write(client, reg_tbl->reg_addr,
-			reg_tbl->reg_data, data_type);
+	reg_setting = write_setting->reg_setting;
+	for (i = 0; i < write_setting->size; i++) {
+		rc = msm_camera_qup_i2c_write(client, reg_setting->reg_addr,
+			reg_setting->reg_data, write_setting->data_type);
 		if (rc < 0)
 			break;
-		if (reg_tbl->delay)
-			usleep_range(reg_tbl->delay, reg_tbl->delay + 1000);
-		reg_tbl++;
+		if (reg_setting->delay)
+			usleep_range(reg_setting->delay,
+				reg_setting->delay + 1000);
+		reg_setting++;
 	}
 	return rc;
 }
diff --git a/drivers/media/platform/msm/camera_v2/sensor/ov5648.c b/drivers/media/platform/msm/camera_v2/sensor/ov5648.c
index 417c7ab..9922468 100644
--- a/drivers/media/platform/msm/camera_v2/sensor/ov5648.c
+++ b/drivers/media/platform/msm/camera_v2/sensor/ov5648.c
@@ -126,7 +126,7 @@
 
 static const struct of_device_id ov5648_dt_match[] = {
 	{
-		.compatible = "qcom,ov5648",
+		.compatible = "ovti,ov5648",
 		.data = &ov5648_s_ctrl
 	},
 	{}
@@ -136,7 +136,7 @@
 
 static struct platform_driver ov5648_platform_driver = {
 	.driver = {
-		.name = "qcom,ov5648",
+		.name = "ovti,ov5648",
 		.owner = THIS_MODULE,
 		.of_match_table = ov5648_dt_match,
 	},
diff --git a/drivers/media/platform/msm/camera_v2/sensor/ov8865.c b/drivers/media/platform/msm/camera_v2/sensor/ov8865.c
new file mode 100644
index 0000000..6d788f5
--- /dev/null
+++ b/drivers/media/platform/msm/camera_v2/sensor/ov8865.c
@@ -0,0 +1,185 @@
+/* Copyright (c) 2013, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ */
+#include "msm_sensor.h"
+#define OV8865_SENSOR_NAME "ov8865"
+DEFINE_MSM_MUTEX(ov8865_mut);
+
+static struct msm_sensor_ctrl_t ov8865_s_ctrl;
+
+static struct msm_sensor_power_setting ov8865_power_setting[] = {
+	{
+		.seq_type = SENSOR_VREG,
+		.seq_val = CAM_VIO,
+		.config_val = 0,
+		.delay = 1,
+	},
+	{
+		.seq_type = SENSOR_VREG,
+		.seq_val = CAM_VANA,
+		.config_val = 0,
+		.delay = 1,
+	},
+	{
+		.seq_type = SENSOR_VREG,
+		.seq_val = CAM_VDIG,
+		.config_val = 0,
+		.delay = 1,
+	},
+	{
+		.seq_type = SENSOR_VREG,
+		.seq_val = CAM_VAF,
+		.config_val = 0,
+		.delay = 5,
+	},
+	{
+		.seq_type = SENSOR_GPIO,
+		.seq_val = SENSOR_GPIO_STANDBY,
+		.config_val = GPIO_OUT_LOW,
+		.delay = 1,
+	},
+	{
+		.seq_type = SENSOR_GPIO,
+		.seq_val = SENSOR_GPIO_RESET,
+		.config_val = GPIO_OUT_LOW,
+		.delay = 5,
+	},
+	{
+		.seq_type = SENSOR_GPIO,
+		.seq_val = SENSOR_GPIO_AF_PWDM,
+		.config_val = GPIO_OUT_LOW,
+		.delay = 5,
+	},
+	{
+		.seq_type = SENSOR_GPIO,
+		.seq_val = SENSOR_GPIO_STANDBY,
+		.config_val = GPIO_OUT_HIGH,
+		.delay = 5,
+	},
+	{
+		.seq_type = SENSOR_GPIO,
+		.seq_val = SENSOR_GPIO_RESET,
+		.config_val = GPIO_OUT_HIGH,
+		.delay = 10,
+	},
+	{
+		.seq_type = SENSOR_GPIO,
+		.seq_val = SENSOR_GPIO_AF_PWDM,
+		.config_val = GPIO_OUT_HIGH,
+		.delay = 5,
+	},
+	{
+		.seq_type = SENSOR_CLK,
+		.seq_val = SENSOR_CAM_MCLK,
+		.config_val = 24000000,
+		.delay = 10,
+	},
+	{
+		.seq_type = SENSOR_I2C_MUX,
+		.seq_val = 0,
+		.config_val = 0,
+		.delay = 0,
+	},
+};
+
+static struct v4l2_subdev_info ov8865_subdev_info[] = {
+	{
+		.code   = V4L2_MBUS_FMT_SBGGR10_1X10,
+		.colorspace = V4L2_COLORSPACE_JPEG,
+		.fmt    = 1,
+		.order    = 0,
+	},
+};
+
+static const struct i2c_device_id ov8865_i2c_id[] = {
+	{OV8865_SENSOR_NAME, (kernel_ulong_t)&ov8865_s_ctrl},
+	{ }
+};
+
+static int32_t msm_ov8865_i2c_probe(struct i2c_client *client,
+	const struct i2c_device_id *id)
+{
+	return msm_sensor_i2c_probe(client, id, &ov8865_s_ctrl);
+}
+
+static struct i2c_driver ov8865_i2c_driver = {
+	.id_table = ov8865_i2c_id,
+	.probe  = msm_ov8865_i2c_probe,
+	.driver = {
+		.name = OV8865_SENSOR_NAME,
+	},
+};
+
+static struct msm_camera_i2c_client ov8865_sensor_i2c_client = {
+	.addr_type = MSM_CAMERA_I2C_WORD_ADDR,
+};
+
+static const struct of_device_id ov8865_dt_match[] = {
+	{.compatible = "ovti,ov8865", .data = &ov8865_s_ctrl},
+	{}
+};
+
+MODULE_DEVICE_TABLE(of, ov8865_dt_match);
+
+static struct platform_driver ov8865_platform_driver = {
+	.driver = {
+		.name = "ovti,ov8865",
+		.owner = THIS_MODULE,
+		.of_match_table = ov8865_dt_match,
+	},
+};
+
+static int32_t ov8865_platform_probe(struct platform_device *pdev)
+{
+	int32_t rc = 0;
+	const struct of_device_id *match;
+	match = of_match_device(ov8865_dt_match, &pdev->dev);
+	rc = msm_sensor_platform_probe(pdev, match->data);
+	return rc;
+}
+
+static int __init ov8865_init_module(void)
+{
+	int32_t rc = 0;
+	pr_info("%s:%d\n", __func__, __LINE__);
+	rc = platform_driver_probe(&ov8865_platform_driver,
+		ov8865_platform_probe);
+	if (!rc)
+		return rc;
+	pr_err("%s:%d rc %d\n", __func__, __LINE__, rc);
+	return i2c_add_driver(&ov8865_i2c_driver);
+}
+
+static void __exit ov8865_exit_module(void)
+{
+	pr_info("%s:%d\n", __func__, __LINE__);
+	if (ov8865_s_ctrl.pdev) {
+		msm_sensor_free_sensor_data(&ov8865_s_ctrl);
+		platform_driver_unregister(&ov8865_platform_driver);
+	} else
+		i2c_del_driver(&ov8865_i2c_driver);
+	return;
+}
+
+static struct msm_sensor_ctrl_t ov8865_s_ctrl = {
+	.sensor_i2c_client = &ov8865_sensor_i2c_client,
+	.power_setting_array.power_setting = ov8865_power_setting,
+	.power_setting_array.size = ARRAY_SIZE(ov8865_power_setting),
+	.msm_sensor_mutex = &ov8865_mut,
+	.sensor_v4l2_subdev_info = ov8865_subdev_info,
+	.sensor_v4l2_subdev_info_size = ARRAY_SIZE(ov8865_subdev_info),
+};
+
+module_init(ov8865_init_module);
+module_exit(ov8865_exit_module);
+MODULE_DESCRIPTION("ov8865");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/media/platform/msm/vidc/venus_hfi.c b/drivers/media/platform/msm/vidc/venus_hfi.c
index aaf1f50..a5aebd5 100644
--- a/drivers/media/platform/msm/vidc/venus_hfi.c
+++ b/drivers/media/platform/msm/vidc/venus_hfi.c
@@ -2691,6 +2691,7 @@
 		dprintk(VIDC_ERR, "Invalid params: %p\n", device);
 		return;
 	}
+	mutex_lock(&device->clk_pwr_lock);
 	if (device->clocks_enabled) {
 		for (i = VCODEC_CLK; i < VCODEC_MAX_CLKS; i++) {
 			cl = &device->resources.clock[i];
@@ -2710,6 +2711,7 @@
 		clk_unprepare(cl->clk);
 	}
 	device->clocks_enabled = 0;
+	mutex_unlock(&device->clk_pwr_lock);
 }
 static inline int venus_hfi_enable_clks(struct venus_hfi_device *device)
 {
@@ -2720,7 +2722,7 @@
 		dprintk(VIDC_ERR, "Invalid params: %p\n", device);
 		return -EINVAL;
 	}
-
+	mutex_lock(&device->clk_pwr_lock);
 	for (i = VCODEC_CLK; i < VCODEC_MAX_CLKS; i++) {
 		if (i == VCODEC_OCMEM_CLK && !device->res->has_ocmem)
 			continue;
@@ -2734,12 +2736,14 @@
 		}
 	}
 	device->clocks_enabled = 1;
+	mutex_unlock(&device->clk_pwr_lock);
 	return rc;
 fail_clk_enable:
 	for (; i >= 0; i--) {
 		cl = &device->resources.clock[i];
 		clk_disable_unprepare(cl->clk);
 	}
+	mutex_unlock(&device->clk_pwr_lock);
 	return rc;
 }
 static int venus_hfi_register_iommu_domains(struct venus_hfi_device *device,
@@ -3184,10 +3188,12 @@
 		goto fail_iommu_attach;
 	}
 
+	mutex_lock(&device->clk_pwr_lock);
 	if (!device->resources.fw.cookie) {
 		rc = regulator_enable(device->gdsc);
 		if (rc) {
 			dprintk(VIDC_ERR, "Failed to enable GDSC %d", rc);
+			mutex_unlock(&device->clk_pwr_lock);
 			goto fail_enable_gdsc;
 		}
 		device->resources.fw.cookie = subsystem_get("venus");
@@ -3196,9 +3202,11 @@
 	if (IS_ERR_OR_NULL(device->resources.fw.cookie)) {
 		dprintk(VIDC_ERR, "Failed to download firmware\n");
 		rc = -ENOMEM;
+		mutex_unlock(&device->clk_pwr_lock);
 		goto fail_load_fw;
 	}
 	device->power_enabled = 1;
+	mutex_unlock(&device->clk_pwr_lock);
 	/*Clocks can be enabled only after pil_get since
 	 * gdsc is turned-on in pil_get*/
 	rc = venus_hfi_enable_clks(device);
@@ -3219,8 +3227,11 @@
 fail_enable_clks:
 	subsystem_put(device->resources.fw.cookie);
 fail_load_fw:
+	mutex_lock(&device->clk_pwr_lock);
 	device->resources.fw.cookie = NULL;
 	regulator_disable(device->gdsc);
+	device->power_enabled = 0;
+	mutex_unlock(&device->clk_pwr_lock);
 fail_enable_gdsc:
 	venus_hfi_iommu_detach(device);
 fail_iommu_attach:
@@ -3239,8 +3250,11 @@
 		flush_workqueue(device->vidc_workq);
 		flush_workqueue(device->venus_pm_workq);
 		venus_hfi_disable_clks(device);
+		mutex_lock(&device->clk_pwr_lock);
 		subsystem_put(device->resources.fw.cookie);
 		regulator_disable(device->gdsc);
+		device->power_enabled = 0;
+		mutex_unlock(&device->clk_pwr_lock);
 		venus_hfi_interface_queues_release(dev);
 		venus_hfi_iommu_detach(device);
 		device->resources.fw.cookie = NULL;
diff --git a/drivers/mmc/card/block.c b/drivers/mmc/card/block.c
index 6ef389c..e5315bd 100644
--- a/drivers/mmc/card/block.c
+++ b/drivers/mmc/card/block.c
@@ -1384,15 +1384,25 @@
 static int mmc_blk_issue_flush(struct mmc_queue *mq, struct request *req)
 {
 	struct mmc_blk_data *md = mq->data;
+	struct request_queue *q = mq->queue;
 	struct mmc_card *card = md->queue.card;
 	int ret = 0;
 
 	ret = mmc_flush_cache(card);
-	if (ret)
+	if (ret == -ETIMEDOUT) {
+		pr_info("%s: requeue flush request after timeout", __func__);
+		spin_lock_irq(q->queue_lock);
+		blk_requeue_request(q, req);
+		spin_unlock_irq(q->queue_lock);
+		ret = 0;
+		goto exit;
+	} else if (ret) {
+		pr_err("%s: notify flush error to upper layers", __func__);
 		ret = -EIO;
+	}
 
 	blk_end_request_all(req, ret);
-
+exit:
 	return ret ? 0 : 1;
 }
 
diff --git a/drivers/mmc/core/core.c b/drivers/mmc/core/core.c
index 91efb12..1e2d367 100644
--- a/drivers/mmc/core/core.c
+++ b/drivers/mmc/core/core.c
@@ -60,7 +60,7 @@
 #define MMC_BKOPS_MAX_TIMEOUT	(30 * 1000) /* max time to wait in ms */
 
 /* Flushing a large amount of cached data may take a long time. */
-#define MMC_FLUSH_REQ_TIMEOUT_MS 30000 /* msec */
+#define MMC_FLUSH_REQ_TIMEOUT_MS 90000 /* msec */
 
 static struct workqueue_struct *workqueue;
 
@@ -3339,7 +3339,7 @@
 						EXT_CSD_FLUSH_CACHE, 1,
 						MMC_FLUSH_REQ_TIMEOUT_MS);
 		if (err == -ETIMEDOUT) {
-			pr_debug("%s: cache flush timeout\n",
+			pr_err("%s: cache flush timeout\n",
 					mmc_hostname(card->host));
 			rc = mmc_interrupt_hpi(card);
 			if (rc)
diff --git a/drivers/net/ethernet/msm/msm_rmnet_bam.c b/drivers/net/ethernet/msm/msm_rmnet_bam.c
index 44f86dd..9f06258 100644
--- a/drivers/net/ethernet/msm/msm_rmnet_bam.c
+++ b/drivers/net/ethernet/msm/msm_rmnet_bam.c
@@ -42,6 +42,11 @@
 module_param_named(debug_enable, msm_rmnet_bam_debug_mask,
 			int, S_IRUGO | S_IWUSR | S_IWGRP);
 
+static unsigned long int msm_rmnet_bam_headroom_check_failure;
+module_param(msm_rmnet_bam_headroom_check_failure, ulong, S_IRUGO);
+MODULE_PARM_DESC(msm_rmnet_bam_headroom_check_failure,
+		 "Number of packets with insufficient headroom");
+
 #define DEBUG_MASK_LVL0 (1U << 0)
 #define DEBUG_MASK_LVL1 (1U << 1)
 #define DEBUG_MASK_LVL2 (1U << 2)
@@ -287,6 +292,23 @@
 			((struct net_device *)dev)->name, __func__);
 }
 
+static struct sk_buff *_rmnet_add_headroom(struct sk_buff **skb,
+					   struct net_device *dev)
+{
+	struct sk_buff *skbn;
+
+	if (skb_headroom(*skb) < dev->needed_headroom) {
+		msm_rmnet_bam_headroom_check_failure++;
+		skbn = skb_realloc_headroom(*skb, dev->needed_headroom);
+		kfree_skb(*skb);
+		*skb = skbn;
+	} else {
+		skbn = *skb;
+	}
+
+	return skbn;
+}
+
 static int _rmnet_xmit(struct sk_buff *skb, struct net_device *dev)
 {
 	struct rmnet_private *p = netdev_priv(dev);
@@ -295,6 +317,10 @@
 	u32 opmode;
 	unsigned long flags;
 
+	if (unlikely(!_rmnet_add_headroom(&skb, dev))) {
+		dev->stats.tx_dropped++;
+		return NETDEV_TX_OK;
+	}
 	/* For QoS mode, prepend QMI header and assign flow ID from skb->mark */
 	spin_lock_irqsave(&p->lock, flags);
 	opmode = p->operation_mode;
diff --git a/drivers/net/wireless/wcnss/wcnss_wlan.c b/drivers/net/wireless/wcnss/wcnss_wlan.c
index 7d6e345..64d1478 100644
--- a/drivers/net/wireless/wcnss/wcnss_wlan.c
+++ b/drivers/net/wireless/wcnss/wcnss_wlan.c
@@ -34,6 +34,7 @@
 #include <linux/suspend.h>
 #include <linux/rwsem.h>
 #include <linux/mfd/pm8xxx/misc.h>
+#include <linux/qpnp/qpnp-adc.h>
 
 #include <mach/msm_smd.h>
 #include <mach/msm_iomap.h>
@@ -97,6 +98,12 @@
 #define PRONTO_PMU_CBCR_OFFSET        0x0008
 #define PRONTO_PMU_CBCR_CLK_EN        BIT(0)
 
+#define PRONTO_PMU_COM_CPU_CBCR_OFFSET     0x0030
+#define PRONTO_PMU_COM_AHB_CBCR_OFFSET     0x0034
+#define PRONTO_PMU_CFG_OFFSET              0x1004
+#define PRONTO_PMU_COM_CSR_OFFSET          0x1040
+#define PRONTO_PMU_SOFT_RESET_OFFSET       0x104C
+
 #define MSM_PRONTO_A2XB_BASE		0xfb100400
 #define A2XB_CFG_OFFSET				0x00
 #define A2XB_INT_SRC_OFFSET			0x0c
@@ -131,6 +138,10 @@
 #define MSM_PRONTO_BRDG_ERR_SRC         0xfb080fb0
 
 #define WCNSS_DEF_WLAN_RX_BUFF_COUNT		1024
+#define WCNSS_VBATT_THRESHOLD		3500000
+#define WCNSS_VBATT_GUARD		200
+#define WCNSS_VBATT_HIGH		3700000
+#define WCNSS_VBATT_LOW			3300000
 
 #define WCNSS_CTRL_CHANNEL			"WCNSS_CTRL"
 #define WCNSS_MAX_FRAME_SIZE		(4*1024)
@@ -146,6 +157,7 @@
 #define	WCNSS_CALDATA_UPLD_RSP        (WCNSS_CTRL_MSG_START + 5)
 #define	WCNSS_CALDATA_DNLD_REQ        (WCNSS_CTRL_MSG_START + 6)
 #define	WCNSS_CALDATA_DNLD_RSP        (WCNSS_CTRL_MSG_START + 7)
+#define	WCNSS_VBATT_LEVEL_IND         (WCNSS_CTRL_MSG_START + 8)
 
 
 #define VALID_VERSION(version) \
@@ -277,6 +289,16 @@
 	struct cal_data_params cal_params;
 };
 
+struct vbatt_level {
+	u32 curr_volt;
+	u32 threshold;
+};
+
+struct vbatt_message {
+	struct smd_msg_hdr hdr;
+	struct vbatt_level vbatt;
+};
+
 static struct {
 	struct platform_device *pdev;
 	void		*pil;
@@ -298,6 +320,7 @@
 	void		(*tm_notify)(struct device *, int);
 	struct wcnss_wlan_config wlan_config;
 	struct delayed_work wcnss_work;
+	struct delayed_work vbatt_work;
 	struct work_struct wcnssctrl_version_work;
 	struct work_struct wcnssctrl_nvbin_dnld_work;
 	struct work_struct wcnssctrl_rx_work;
@@ -324,8 +347,12 @@
 	int	user_cal_exp_size;
 	int	device_opened;
 	int	iris_xo_mode_set;
+	int	fw_vbatt_state;
 	struct mutex dev_lock;
 	wait_queue_head_t read_wait;
+	struct qpnp_adc_tm_btm_param vbat_monitor_params;
+	struct qpnp_adc_tm_chip *adc_tm_dev;
+	struct mutex vbat_monitor_mutex;
 } *penv = NULL;
 
 static ssize_t wcnss_serial_number_show(struct device *dev,
@@ -456,8 +483,34 @@
 	reg = readl_relaxed(reg_addr);
 	pr_info_ratelimited("%s:  PRONTO_PMU_SPARE %08x\n", __func__, reg);
 
+	reg_addr = penv->msm_wcnss_base + PRONTO_PMU_COM_CPU_CBCR_OFFSET;
+	reg = readl_relaxed(reg_addr);
+	pr_info_ratelimited("%s:  PRONTO_PMU_COM_CPU_CBCR %08x\n",
+						__func__, reg);
+
+	reg_addr = penv->msm_wcnss_base + PRONTO_PMU_COM_AHB_CBCR_OFFSET;
+	reg = readl_relaxed(reg_addr);
+	pr_info_ratelimited("%s:  PRONTO_PMU_COM_AHB_CBCR %08x\n",
+						__func__, reg);
+
+	reg_addr = penv->msm_wcnss_base + PRONTO_PMU_CFG_OFFSET;
+	reg = readl_relaxed(reg_addr);
+	pr_info_ratelimited("%s:  PRONTO_PMU_CFG %08x\n", __func__, reg);
+
+	reg_addr = penv->msm_wcnss_base + PRONTO_PMU_COM_CSR_OFFSET;
+	reg = readl_relaxed(reg_addr);
+	pr_info_ratelimited("%s:  PRONTO_PMU_COM_CSR %08x\n",
+						__func__, reg);
+
+	reg_addr = penv->msm_wcnss_base + PRONTO_PMU_SOFT_RESET_OFFSET;
+	reg = readl_relaxed(reg_addr);
+	pr_info_ratelimited("%s:  PRONTO_PMU_SOFT_RESET %08x\n",
+						__func__, reg);
+
 	reg_addr = penv->msm_wcnss_base + PRONTO_PMU_COM_GDSCR_OFFSET;
 	reg = readl_relaxed(reg_addr);
+	pr_info_ratelimited("%s:  PRONTO_PMU_COM_GDSCR %08x\n",
+						__func__, reg);
 	reg >>= 31;
 
 	if (!reg) {
@@ -1081,7 +1134,6 @@
 }
 EXPORT_SYMBOL(wcnss_get_wlan_rx_buff_count);
 
-
 static int wcnss_smd_tx(void *data, int len)
 {
 	int ret = 0;
@@ -1099,6 +1151,102 @@
 	return ret;
 }
 
+static void wcnss_notify_vbat(enum qpnp_tm_state state, void *ctx)
+{
+	mutex_lock(&penv->vbat_monitor_mutex);
+	cancel_delayed_work_sync(&penv->vbatt_work);
+
+	if (state == ADC_TM_LOW_STATE) {
+		pr_debug("wcnss: low voltage notification triggered\n");
+		penv->vbat_monitor_params.state_request =
+			ADC_TM_HIGH_THR_ENABLE;
+		penv->vbat_monitor_params.high_thr = WCNSS_VBATT_THRESHOLD +
+		WCNSS_VBATT_GUARD;
+		penv->vbat_monitor_params.low_thr = 0;
+	} else if (state == ADC_TM_HIGH_STATE) {
+		penv->vbat_monitor_params.state_request =
+			ADC_TM_LOW_THR_ENABLE;
+		penv->vbat_monitor_params.low_thr = WCNSS_VBATT_THRESHOLD -
+		WCNSS_VBATT_GUARD;
+		penv->vbat_monitor_params.high_thr = 0;
+		pr_debug("wcnss: high voltage notification triggered\n");
+	} else {
+		pr_debug("wcnss: unknown voltage notification state: %d\n",
+				state);
+		mutex_unlock(&penv->vbat_monitor_mutex);
+		return;
+	}
+	pr_debug("wcnss: set low thr to %d and high to %d\n",
+			penv->vbat_monitor_params.low_thr,
+			penv->vbat_monitor_params.high_thr);
+
+	qpnp_adc_tm_channel_measure(penv->adc_tm_dev,
+			&penv->vbat_monitor_params);
+	schedule_delayed_work(&penv->vbatt_work, msecs_to_jiffies(2000));
+	mutex_unlock(&penv->vbat_monitor_mutex);
+}
+
+static int wcnss_setup_vbat_monitoring(void)
+{
+	int rc = -1;
+
+	if (!penv->adc_tm_dev) {
+		pr_err("wcnss: not setting up vbatt\n");
+		return rc;
+	}
+	penv->vbat_monitor_params.low_thr = WCNSS_VBATT_THRESHOLD;
+	penv->vbat_monitor_params.high_thr = WCNSS_VBATT_THRESHOLD;
+	penv->vbat_monitor_params.state_request = ADC_TM_HIGH_LOW_THR_ENABLE;
+	penv->vbat_monitor_params.channel = VBAT_SNS;
+	penv->vbat_monitor_params.btm_ctx = (void *)penv;
+	penv->vbat_monitor_params.timer_interval = ADC_MEAS1_INTERVAL_1S;
+	penv->vbat_monitor_params.threshold_notification = &wcnss_notify_vbat;
+	pr_debug("wcnss: set low thr to %d and high to %d\n",
+			penv->vbat_monitor_params.low_thr,
+			penv->vbat_monitor_params.high_thr);
+
+	rc = qpnp_adc_tm_channel_measure(penv->adc_tm_dev,
+					&penv->vbat_monitor_params);
+	if (rc)
+		pr_err("wcnss: tm setup failed: %d\n", rc);
+
+	return rc;
+}
+
+static void wcnss_update_vbatt(struct work_struct *work)
+{
+	struct vbatt_message vbatt_msg;
+	int ret = 0;
+
+	vbatt_msg.hdr.msg_type = WCNSS_VBATT_LEVEL_IND;
+	vbatt_msg.hdr.msg_len = sizeof(struct vbatt_message);
+	vbatt_msg.vbatt.threshold = WCNSS_VBATT_THRESHOLD;
+
+	mutex_lock(&penv->vbat_monitor_mutex);
+	if (penv->vbat_monitor_params.low_thr &&
+		(penv->fw_vbatt_state == WCNSS_VBATT_LOW ||
+			penv->fw_vbatt_state == WCNSS_CONFIG_UNSPECIFIED)) {
+		vbatt_msg.vbatt.curr_volt = WCNSS_VBATT_HIGH;
+		penv->fw_vbatt_state = WCNSS_VBATT_HIGH;
+		pr_debug("wcnss: send HIGH BATT to FW\n");
+	} else if (!penv->vbat_monitor_params.low_thr &&
+		(penv->fw_vbatt_state == WCNSS_VBATT_HIGH ||
+			penv->fw_vbatt_state == WCNSS_CONFIG_UNSPECIFIED)){
+		vbatt_msg.vbatt.curr_volt = WCNSS_VBATT_LOW;
+		penv->fw_vbatt_state = WCNSS_VBATT_LOW;
+		pr_debug("wcnss: send LOW BATT to FW\n");
+	} else {
+		mutex_unlock(&penv->vbat_monitor_mutex);
+		return;
+	}
+	mutex_unlock(&penv->vbat_monitor_mutex);
+	ret = wcnss_smd_tx(&vbatt_msg, vbatt_msg.hdr.msg_len);
+	if (ret < 0)
+		pr_err("wcnss: smd tx failed\n");
+	return;
+}
+
+
 static unsigned char wcnss_fw_status(void)
 {
 	int len = 0;
@@ -1312,6 +1460,7 @@
 		fw_status = wcnss_fw_status();
 		pr_debug("wcnss: received WCNSS_NVBIN_DNLD_RSP from ccpu %u\n",
 			fw_status);
+		wcnss_setup_vbat_monitoring();
 		break;
 
 	case WCNSS_CALDATA_DNLD_RSP:
@@ -1791,6 +1940,14 @@
 		}
 
 	}
+	penv->adc_tm_dev = qpnp_get_adc_tm(&penv->pdev->dev, "wcnss");
+	if (IS_ERR(penv->adc_tm_dev)) {
+		pr_err("%s:  adc get failed\n", __func__);
+		penv->adc_tm_dev = NULL;
+	} else {
+		INIT_DELAYED_WORK(&penv->vbatt_work, wcnss_update_vbatt);
+		penv->fw_vbatt_state = WCNSS_CONFIG_UNSPECIFIED;
+	}
 
 	/* trigger initialization of the WCNSS */
 	penv->pil = subsystem_get(WCNSS_PIL_DEVICE);
@@ -2005,6 +2162,7 @@
 	}
 
 	mutex_init(&penv->dev_lock);
+	mutex_init(&penv->vbat_monitor_mutex);
 	init_waitqueue_head(&penv->read_wait);
 
 	/* Since we were built into the kernel we'll be called as part
diff --git a/drivers/power/qpnp-bms.c b/drivers/power/qpnp-bms.c
index 6706e0d..49e57b9 100644
--- a/drivers/power/qpnp-bms.c
+++ b/drivers/power/qpnp-bms.c
@@ -190,6 +190,7 @@
 	struct mutex			vbat_monitor_mutex;
 	struct mutex			soc_invalidation_mutex;
 	struct mutex			last_soc_mutex;
+	struct mutex			status_lock;
 
 	bool				use_external_rsense;
 	bool				use_ocv_thresholds;
@@ -295,6 +296,7 @@
 
 static enum power_supply_property msm_bms_power_props[] = {
 	POWER_SUPPLY_PROP_CAPACITY,
+	POWER_SUPPLY_PROP_STATUS,
 	POWER_SUPPLY_PROP_CURRENT_NOW,
 	POWER_SUPPLY_PROP_RESISTANCE,
 	POWER_SUPPLY_PROP_CHARGE_COUNTER,
@@ -3110,6 +3112,7 @@
 {
 	int status = get_battery_status(chip);
 
+	mutex_lock(&chip->status_lock);
 	if (chip->battery_status != status) {
 		pr_debug("status = %d, shadow status = %d\n",
 				status, chip->battery_status);
@@ -3126,6 +3129,7 @@
 			pr_debug("battery full\n");
 			enable_bms_irq(&chip->ocv_thr_irq);
 			enable_bms_irq(&chip->sw_cc_thr_irq);
+			recalculate_soc(chip);
 		} else if (chip->battery_status
 				== POWER_SUPPLY_STATUS_FULL) {
 			pr_debug("battery not full any more\n");
@@ -3138,6 +3142,7 @@
 		 * recalculation to update the SoC */
 		schedule_work(&chip->recalc_work);
 	}
+	mutex_unlock(&chip->status_lock);
 }
 
 #define CALIB_WRKARND_DIG_MAJOR_MAX		0x03
@@ -3212,6 +3217,9 @@
 	case POWER_SUPPLY_PROP_CAPACITY:
 		val->intval = get_prop_bms_capacity(chip);
 		break;
+	case POWER_SUPPLY_PROP_STATUS:
+		val->intval = chip->battery_status;
+		break;
 	case POWER_SUPPLY_PROP_CURRENT_NOW:
 		val->intval = get_prop_bms_current_now(chip);
 		break;
@@ -3989,6 +3997,7 @@
 	mutex_init(&chip->vbat_monitor_mutex);
 	mutex_init(&chip->soc_invalidation_mutex);
 	mutex_init(&chip->last_soc_mutex);
+	mutex_init(&chip->status_lock);
 	init_waitqueue_head(&chip->bms_wait_queue);
 
 	warm_reset = qpnp_pon_is_warm_reset();
diff --git a/drivers/power/qpnp-charger.c b/drivers/power/qpnp-charger.c
index f9e05fc..6e9dc57 100644
--- a/drivers/power/qpnp-charger.c
+++ b/drivers/power/qpnp-charger.c
@@ -1693,7 +1693,7 @@
 get_prop_capacity(struct qpnp_chg_chip *chip)
 {
 	union power_supply_propval ret = {0,};
-	int battery_status, charger_in;
+	int battery_status, bms_status, soc, charger_in;
 
 	if (chip->use_default_batt_values || !get_prop_batt_present(chip))
 		return DEFAULT_CAPACITY;
@@ -1701,28 +1701,32 @@
 	if (chip->bms_psy) {
 		chip->bms_psy->get_property(chip->bms_psy,
 				POWER_SUPPLY_PROP_CAPACITY, &ret);
+		soc = ret.intval;
 		battery_status = get_prop_batt_status(chip);
+		chip->bms_psy->get_property(chip->bms_psy,
+				POWER_SUPPLY_PROP_STATUS, &ret);
+		bms_status = ret.intval;
 		charger_in = qpnp_chg_is_usb_chg_plugged_in(chip) ||
 			qpnp_chg_is_dc_chg_plugged_in(chip);
 
 		if (battery_status != POWER_SUPPLY_STATUS_CHARGING
+				&& bms_status != POWER_SUPPLY_STATUS_CHARGING
 				&& charger_in
 				&& !chip->resuming_charging
 				&& !chip->charging_disabled
 				&& chip->soc_resume_limit
-				&& ret.intval <= chip->soc_resume_limit) {
-			pr_debug("resuming charging at %d%% soc\n",
-					ret.intval);
+				&& soc <= chip->soc_resume_limit) {
+			pr_debug("resuming charging at %d%% soc\n", soc);
 			chip->resuming_charging = true;
 			qpnp_chg_set_appropriate_vbatdet(chip);
 			qpnp_chg_charge_en(chip, !chip->charging_disabled);
 		}
-		if (ret.intval == 0) {
+		if (soc == 0) {
 			if (!qpnp_chg_is_usb_chg_plugged_in(chip)
 				&& !qpnp_chg_is_usb_chg_plugged_in(chip))
 				pr_warn_ratelimited("Battery 0, CHG absent\n");
 		}
-		return ret.intval;
+		return soc;
 	} else {
 		pr_debug("No BMS supply registered return 50\n");
 	}
diff --git a/drivers/staging/android/binder.c b/drivers/staging/android/binder.c
index 3abc3b9..b7bf74e 100644
--- a/drivers/staging/android/binder.c
+++ b/drivers/staging/android/binder.c
@@ -33,6 +33,7 @@
 #include <linux/uaccess.h>
 #include <linux/vmalloc.h>
 #include <linux/slab.h>
+#include <linux/security.h>
 
 #include "binder.h"
 
@@ -1488,6 +1489,10 @@
 			return_error = BR_DEAD_REPLY;
 			goto err_dead_binder;
 		}
+		if (security_binder_transaction(proc->tsk, target_proc->tsk) < 0) {
+			return_error = BR_FAILED_REPLY;
+			goto err_invalid_target_handle;
+		}
 		if (!(tr->flags & TF_ONE_WAY) && thread->transaction_stack) {
 			struct binder_transaction *tmp;
 			tmp = thread->transaction_stack;
@@ -1633,6 +1638,10 @@
 					fp->cookie, node->cookie);
 				goto err_binder_get_ref_for_node_failed;
 			}
+			if (security_binder_transfer_binder(proc->tsk, target_proc->tsk)) {
+				return_error = BR_FAILED_REPLY;
+				goto err_binder_get_ref_for_node_failed;
+			}
 			ref = binder_get_ref_for_node(target_proc, node);
 			if (ref == NULL) {
 				return_error = BR_FAILED_REPLY;
@@ -1662,6 +1671,10 @@
 				return_error = BR_FAILED_REPLY;
 				goto err_binder_get_ref_failed;
 			}
+			if (security_binder_transfer_binder(proc->tsk, target_proc->tsk)) {
+				return_error = BR_FAILED_REPLY;
+				goto err_binder_get_ref_failed;
+			}
 			if (ref->node->proc == target_proc) {
 				if (fp->type == BINDER_TYPE_HANDLE)
 					fp->type = BINDER_TYPE_BINDER;
@@ -1715,6 +1728,11 @@
 				return_error = BR_FAILED_REPLY;
 				goto err_fget_failed;
 			}
+			if (security_binder_transfer_file(proc->tsk, target_proc->tsk, file) < 0) {
+				fput(file);
+				return_error = BR_FAILED_REPLY;
+				goto err_get_unused_fd_failed;
+			}
 			target_fd = task_get_unused_fd_flags(target_proc, O_CLOEXEC);
 			if (target_fd < 0) {
 				fput(file);
@@ -2748,6 +2766,9 @@
 			ret = -EBUSY;
 			goto err;
 		}
+		ret = security_binder_set_context_mgr(proc->tsk);
+		if (ret < 0)
+			goto err;
 		if (binder_context_mgr_uid != -1) {
 			if (binder_context_mgr_uid != current->cred->euid) {
 				binder_debug(BINDER_DEBUG_TOP_ERRORS,
diff --git a/drivers/thermal/qpnp-adc-tm.c b/drivers/thermal/qpnp-adc-tm.c
index 7dcd45f..cf1801b 100644
--- a/drivers/thermal/qpnp-adc-tm.c
+++ b/drivers/thermal/qpnp-adc-tm.c
@@ -169,6 +169,19 @@
 #define QPNP_MIN_TIME			2000
 #define QPNP_MAX_TIME			2100
 
+struct qpnp_adc_thr_client_info {
+	struct list_head		list;
+	struct qpnp_adc_tm_btm_param	*btm_param;
+	int32_t				low_thr_requested;
+	int32_t				high_thr_requested;
+	enum qpnp_state_request		state_requested;
+	enum qpnp_state_request		state_req_copy;
+	bool				low_thr_set;
+	bool				high_thr_set;
+	bool				notify_low_thr;
+	bool				notify_high_thr;
+};
+
 struct qpnp_adc_tm_sensor {
 	struct thermal_zone_device	*tz_dev;
 	struct qpnp_adc_tm_chip		*chip;
@@ -181,14 +194,13 @@
 	uint32_t			btm_channel_num;
 	uint32_t			vadc_channel_num;
 	struct work_struct		work;
-	struct qpnp_adc_tm_btm_param	*btm_param;
 	bool				thermal_node;
-	bool				low_thr_notify;
-	bool				high_thr_notify;
 	uint32_t			scale_type;
+	struct list_head		thr_list;
 };
 
 struct qpnp_adc_tm_chip {
+	struct device			*dev;
 	struct qpnp_adc_drv		*adc;
 	struct list_head		list;
 	bool				adc_tm_initialized;
@@ -202,53 +214,62 @@
 LIST_HEAD(qpnp_adc_tm_device_list);
 
 struct qpnp_adc_tm_trip_reg_type {
-	uint16_t low_thr_lsb_addr;
-	uint16_t low_thr_msb_addr;
-	uint16_t high_thr_lsb_addr;
-	uint16_t high_thr_msb_addr;
-	u8 multi_meas_en;
-	u8 low_thr_int_chan_en;
-	u8 high_thr_int_chan_en;
-	u8 meas_interval_ctl;
+	enum qpnp_adc_tm_channel_select	btm_amux_chan;
+	uint16_t			low_thr_lsb_addr;
+	uint16_t			low_thr_msb_addr;
+	uint16_t			high_thr_lsb_addr;
+	uint16_t			high_thr_msb_addr;
+	u8				multi_meas_en;
+	u8				low_thr_int_chan_en;
+	u8				high_thr_int_chan_en;
+	u8				meas_interval_ctl;
 };
 
 static struct qpnp_adc_tm_trip_reg_type adc_tm_data[] = {
-	[QPNP_ADC_TM_M0_ADC_CH_SEL_CTL] = {QPNP_M0_LOW_THR_LSB,
+	[QPNP_ADC_TM_CHAN0] = {QPNP_ADC_TM_M0_ADC_CH_SEL_CTL,
+		QPNP_M0_LOW_THR_LSB,
 		QPNP_M0_LOW_THR_MSB, QPNP_M0_HIGH_THR_LSB,
 		QPNP_M0_HIGH_THR_MSB, QPNP_ADC_TM_MULTI_MEAS_EN_M0,
 		QPNP_ADC_TM_LOW_THR_INT_EN_M0, QPNP_ADC_TM_HIGH_THR_INT_EN_M0,
 		QPNP_ADC_TM_M0_MEAS_INTERVAL_CTL},
-	[QPNP_ADC_TM_M1_ADC_CH_SEL_CTL] = {QPNP_M1_LOW_THR_LSB,
+	[QPNP_ADC_TM_CHAN1] = {QPNP_ADC_TM_M1_ADC_CH_SEL_CTL,
+		QPNP_M1_LOW_THR_LSB,
 		QPNP_M1_LOW_THR_MSB, QPNP_M1_HIGH_THR_LSB,
 		QPNP_M1_HIGH_THR_MSB, QPNP_ADC_TM_MULTI_MEAS_EN_M1,
 		QPNP_ADC_TM_LOW_THR_INT_EN_M1, QPNP_ADC_TM_HIGH_THR_INT_EN_M1,
 		QPNP_ADC_TM_M1_MEAS_INTERVAL_CTL},
-	[QPNP_ADC_TM_M2_ADC_CH_SEL_CTL] = {QPNP_M2_LOW_THR_LSB,
+	[QPNP_ADC_TM_CHAN2] = {QPNP_ADC_TM_M2_ADC_CH_SEL_CTL,
+		QPNP_M2_LOW_THR_LSB,
 		QPNP_M2_LOW_THR_MSB, QPNP_M2_HIGH_THR_LSB,
 		QPNP_M2_HIGH_THR_MSB, QPNP_ADC_TM_MULTI_MEAS_EN_M2,
 		QPNP_ADC_TM_LOW_THR_INT_EN_M2, QPNP_ADC_TM_HIGH_THR_INT_EN_M2,
 		QPNP_ADC_TM_M2_MEAS_INTERVAL_CTL},
-	[QPNP_ADC_TM_M3_ADC_CH_SEL_CTL] = {QPNP_M3_LOW_THR_LSB,
+	[QPNP_ADC_TM_CHAN3] = {QPNP_ADC_TM_M3_ADC_CH_SEL_CTL,
+		QPNP_M3_LOW_THR_LSB,
 		QPNP_M3_LOW_THR_MSB, QPNP_M3_HIGH_THR_LSB,
 		QPNP_M3_HIGH_THR_MSB, QPNP_ADC_TM_MULTI_MEAS_EN_M3,
 		QPNP_ADC_TM_LOW_THR_INT_EN_M3, QPNP_ADC_TM_HIGH_THR_INT_EN_M3,
 		QPNP_ADC_TM_M3_MEAS_INTERVAL_CTL},
-	[QPNP_ADC_TM_M4_ADC_CH_SEL_CTL] = {QPNP_M4_LOW_THR_LSB,
+	[QPNP_ADC_TM_CHAN4] = {QPNP_ADC_TM_M4_ADC_CH_SEL_CTL,
+		QPNP_M4_LOW_THR_LSB,
 		QPNP_M4_LOW_THR_MSB, QPNP_M4_HIGH_THR_LSB,
 		QPNP_M4_HIGH_THR_MSB, QPNP_ADC_TM_MULTI_MEAS_EN_M4,
 		QPNP_ADC_TM_LOW_THR_INT_EN_M4, QPNP_ADC_TM_HIGH_THR_INT_EN_M4,
 		QPNP_ADC_TM_M4_MEAS_INTERVAL_CTL},
-	[QPNP_ADC_TM_M5_ADC_CH_SEL_CTL] = {QPNP_M5_LOW_THR_LSB,
+	[QPNP_ADC_TM_CHAN5] = {QPNP_ADC_TM_M5_ADC_CH_SEL_CTL,
+		QPNP_M5_LOW_THR_LSB,
 		QPNP_M5_LOW_THR_MSB, QPNP_M5_HIGH_THR_LSB,
 		QPNP_M5_HIGH_THR_MSB, QPNP_ADC_TM_MULTI_MEAS_EN_M5,
 		QPNP_ADC_TM_LOW_THR_INT_EN_M5, QPNP_ADC_TM_HIGH_THR_INT_EN_M5,
 		QPNP_ADC_TM_M5_MEAS_INTERVAL_CTL},
-	[QPNP_ADC_TM_M6_ADC_CH_SEL_CTL] = {QPNP_M6_LOW_THR_LSB,
+	[QPNP_ADC_TM_CHAN6] = {QPNP_ADC_TM_M6_ADC_CH_SEL_CTL,
+		QPNP_M6_LOW_THR_LSB,
 		QPNP_M6_LOW_THR_MSB, QPNP_M6_HIGH_THR_LSB,
 		QPNP_M6_HIGH_THR_MSB, QPNP_ADC_TM_MULTI_MEAS_EN_M6,
 		QPNP_ADC_TM_LOW_THR_INT_EN_M6, QPNP_ADC_TM_HIGH_THR_INT_EN_M6,
 		QPNP_ADC_TM_M6_MEAS_INTERVAL_CTL},
-	[QPNP_ADC_TM_M7_ADC_CH_SEL_CTL] = {QPNP_M7_LOW_THR_LSB,
+	[QPNP_ADC_TM_CHAN7] = {QPNP_ADC_TM_M7_ADC_CH_SEL_CTL,
+		QPNP_M7_LOW_THR_LSB,
 		QPNP_M7_LOW_THR_MSB, QPNP_M7_HIGH_THR_LSB,
 		QPNP_M7_HIGH_THR_MSB, QPNP_ADC_TM_MULTI_MEAS_EN_M7,
 		QPNP_ADC_TM_LOW_THR_INT_EN_M7, QPNP_ADC_TM_HIGH_THR_INT_EN_M7,
@@ -384,6 +405,25 @@
 	return rc;
 }
 
+static int32_t qpnp_adc_tm_get_btm_idx(uint32_t btm_chan,
+						uint32_t *btm_chan_idx)
+{
+	int rc = 0, i;
+	bool chan_found = false;
+
+	for (i = 0; i < QPNP_ADC_TM_CHAN_NONE; i++) {
+		if (adc_tm_data[i].btm_amux_chan == btm_chan) {
+			*btm_chan_idx = i;
+			chan_found = true;
+		}
+	}
+
+	if (!chan_found)
+		return -EINVAL;
+
+	return rc;
+}
+
 static int32_t qpnp_adc_tm_check_revision(struct qpnp_adc_tm_chip *chip,
 							uint32_t btm_chan_num)
 {
@@ -433,6 +473,7 @@
 {
 	int rc;
 	u8 meas_interval_timer2 = 0;
+	uint32_t btm_chan_idx = 0;
 
 	/* Configure kernel clients to timer1 */
 	switch (chan_prop->timer_select) {
@@ -489,11 +530,60 @@
 	}
 
 	/* Select the timer to use for the corresponding channel */
-	adc_tm_data[btm_chan].meas_interval_ctl = chan_prop->timer_select;
+	rc = qpnp_adc_tm_get_btm_idx(btm_chan, &btm_chan_idx);
+	if (rc < 0) {
+		pr_err("Invalid btm channel idx\n");
+		return rc;
+	}
+	adc_tm_data[btm_chan_idx].meas_interval_ctl = chan_prop->timer_select;
 
 	return rc;
 }
 
+static int32_t qpnp_adc_tm_add_to_list(struct qpnp_adc_tm_chip *chip,
+				uint32_t dt_index,
+				struct qpnp_adc_tm_btm_param *param,
+				struct qpnp_vadc_chan_properties *chan_prop)
+{
+	struct qpnp_adc_thr_client_info *client_info = NULL;
+	bool client_info_exists = false;
+
+	list_for_each_entry(client_info,
+			&chip->sensor[dt_index].thr_list, list) {
+		if (client_info->btm_param == param) {
+			client_info->low_thr_requested = chan_prop->low_thr;
+			client_info->high_thr_requested = chan_prop->high_thr;
+			client_info->state_requested = param->state_request;
+			client_info->state_req_copy = param->state_request;
+			client_info->notify_low_thr = false;
+			client_info->notify_high_thr = false;
+			client_info_exists = true;
+			pr_debug("client found\n");
+		}
+	}
+
+	if (!client_info_exists) {
+		client_info = devm_kzalloc(chip->dev,
+			sizeof(struct qpnp_adc_thr_client_info), GFP_KERNEL);
+		if (!client_info) {
+			pr_err("%s: kzalloc() failed.\n", __func__);
+			return -ENOMEM;
+		}
+
+		pr_debug("new client\n");
+		client_info->btm_param = param;
+		client_info->low_thr_requested = chan_prop->low_thr;
+		client_info->high_thr_requested = chan_prop->high_thr;
+		client_info->state_requested = param->state_request;
+		client_info->state_req_copy = param->state_request;
+
+		list_add_tail(&client_info->list,
+					&chip->sensor[dt_index].thr_list);
+	}
+
+	return 0;
+}
+
 static int32_t qpnp_adc_tm_reg_update(struct qpnp_adc_tm_chip *chip,
 		uint16_t addr, u8 mask, bool state)
 {
@@ -522,55 +612,137 @@
 }
 
 static int32_t qpnp_adc_tm_thr_update(struct qpnp_adc_tm_chip *chip,
-			uint32_t btm_chan,
-			struct qpnp_vadc_chan_properties *chan_prop)
+			uint32_t btm_chan, int32_t high_thr, int32_t low_thr)
 {
 	int rc = 0;
+	uint32_t btm_chan_idx = 0;
+
+	rc = qpnp_adc_tm_get_btm_idx(btm_chan, &btm_chan_idx);
+	if (rc < 0) {
+		pr_err("Invalid btm channel idx\n");
+		return rc;
+	}
 
 	rc = qpnp_adc_tm_write_reg(chip,
-			adc_tm_data[btm_chan].low_thr_lsb_addr,
-			QPNP_ADC_TM_THR_LSB_MASK(chan_prop->low_thr));
+			adc_tm_data[btm_chan_idx].low_thr_lsb_addr,
+			QPNP_ADC_TM_THR_LSB_MASK(low_thr));
 	if (rc < 0) {
 		pr_err("low threshold lsb setting failed\n");
 		return rc;
 	}
 
 	rc = qpnp_adc_tm_write_reg(chip,
-		adc_tm_data[btm_chan].low_thr_msb_addr,
-		QPNP_ADC_TM_THR_MSB_MASK(chan_prop->low_thr));
+		adc_tm_data[btm_chan_idx].low_thr_msb_addr,
+		QPNP_ADC_TM_THR_MSB_MASK(low_thr));
 	if (rc < 0) {
 		pr_err("low threshold msb setting failed\n");
 		return rc;
 	}
 
 	rc = qpnp_adc_tm_write_reg(chip,
-		adc_tm_data[btm_chan].high_thr_lsb_addr,
-		QPNP_ADC_TM_THR_LSB_MASK(chan_prop->high_thr));
+		adc_tm_data[btm_chan_idx].high_thr_lsb_addr,
+		QPNP_ADC_TM_THR_LSB_MASK(high_thr));
 	if (rc < 0) {
 		pr_err("high threshold lsb setting failed\n");
 		return rc;
 	}
 
 	rc = qpnp_adc_tm_write_reg(chip,
-		adc_tm_data[btm_chan].high_thr_msb_addr,
-		QPNP_ADC_TM_THR_MSB_MASK(chan_prop->high_thr));
+		adc_tm_data[btm_chan_idx].high_thr_msb_addr,
+		QPNP_ADC_TM_THR_MSB_MASK(high_thr));
 	if (rc < 0)
 		pr_err("high threshold msb setting failed\n");
 
-	pr_debug("client requested low:%d and high:%d\n",
-		chan_prop->low_thr, chan_prop->high_thr);
+	pr_debug("client requested high:%d and low:%d\n",
+		high_thr, low_thr);
 
 	return rc;
 }
 
+static int32_t qpnp_adc_tm_manage_thresholds(struct qpnp_adc_tm_chip *chip,
+		uint32_t dt_index, uint32_t btm_chan)
+{
+	struct qpnp_adc_thr_client_info *client_info = NULL;
+	struct list_head *thr_list;
+	int high_thr = 0, low_thr = 0, rc = 0;
+
+
+	/* high_thr/low_thr starting point and reset the high_thr_set and
+		low_thr_set back to reset since the thresholds will be
+		recomputed */
+	list_for_each(thr_list,
+			&chip->sensor[dt_index].thr_list) {
+		client_info = list_entry(thr_list,
+					struct qpnp_adc_thr_client_info, list);
+		high_thr = client_info->high_thr_requested;
+		low_thr = client_info->low_thr_requested;
+		client_info->high_thr_set = false;
+		client_info->low_thr_set = false;
+	}
+
+	pr_debug("init threshold is high:%d and low:%d\n", high_thr, low_thr);
+
+	/* Find the min of high_thr and max of low_thr */
+	list_for_each(thr_list,
+			&chip->sensor[dt_index].thr_list) {
+		client_info = list_entry(thr_list,
+					struct qpnp_adc_thr_client_info, list);
+		if ((client_info->state_req_copy == ADC_TM_HIGH_THR_ENABLE) ||
+			(client_info->state_req_copy ==
+						ADC_TM_HIGH_LOW_THR_ENABLE))
+			if (client_info->high_thr_requested < high_thr)
+				high_thr = client_info->high_thr_requested;
+
+		if ((client_info->state_req_copy == ADC_TM_LOW_THR_ENABLE) ||
+			(client_info->state_req_copy ==
+						ADC_TM_HIGH_LOW_THR_ENABLE))
+			if (client_info->low_thr_requested > low_thr)
+				low_thr = client_info->low_thr_requested;
+
+		pr_debug("threshold compared is high:%d and low:%d\n",
+				client_info->high_thr_requested,
+				client_info->low_thr_requested);
+		pr_debug("current threshold is high:%d and low:%d\n",
+							high_thr, low_thr);
+	}
+
+	/* Check which of the high_thr and low_thr got set */
+	list_for_each(thr_list,
+			&chip->sensor[dt_index].thr_list) {
+		client_info = list_entry(thr_list,
+					struct qpnp_adc_thr_client_info, list);
+		if ((client_info->state_req_copy == ADC_TM_HIGH_THR_ENABLE) ||
+			(client_info->state_req_copy ==
+						ADC_TM_HIGH_LOW_THR_ENABLE))
+			if (high_thr == client_info->high_thr_requested)
+				client_info->high_thr_set = true;
+
+		if ((client_info->state_req_copy == ADC_TM_LOW_THR_ENABLE) ||
+			(client_info->state_req_copy ==
+						ADC_TM_HIGH_LOW_THR_ENABLE))
+			if (low_thr == client_info->low_thr_requested)
+				client_info->low_thr_set = true;
+	}
+
+	rc = qpnp_adc_tm_thr_update(chip, btm_chan, high_thr, low_thr);
+	if (rc < 0)
+		pr_err("setting chan:%d threshold failed\n", btm_chan);
+
+	pr_debug("threshold written is high:%d and low:%d\n",
+							high_thr, low_thr);
+
+	return 0;
+}
+
 static int32_t qpnp_adc_tm_channel_configure(struct qpnp_adc_tm_chip *chip,
 			uint32_t btm_chan,
 			struct qpnp_vadc_chan_properties *chan_prop,
 			uint32_t amux_channel)
 {
 	int rc = 0, i = 0, chan_idx = 0;
-	bool chan_found = false;
+	bool chan_found = false, high_thr_set = false, low_thr_set = false;
 	u8 sensor_mask = 0;
+	struct qpnp_adc_thr_client_info *client_info = NULL;
 
 	while (i < chip->max_channels_available) {
 		if (chip->sensor[i].btm_channel_num == btm_chan) {
@@ -589,17 +761,22 @@
 	sensor_mask = 1 << chan_idx;
 	if (!chip->sensor[chan_idx].thermal_node) {
 		/* Update low and high notification thresholds */
-		rc = qpnp_adc_tm_thr_update(chip, btm_chan,
-				chan_prop);
+		rc = qpnp_adc_tm_manage_thresholds(chip, chan_idx,
+				btm_chan);
 		if (rc < 0) {
 			pr_err("setting chan:%d threshold failed\n", btm_chan);
 			return rc;
 		}
 
-		if ((chan_prop->state_request ==
-					ADC_TM_LOW_THR_ENABLE) ||
-			(chan_prop->state_request ==
-					ADC_TM_HIGH_LOW_THR_ENABLE)) {
+		list_for_each_entry(client_info,
+				&chip->sensor[chan_idx].thr_list, list) {
+			if (client_info->high_thr_set == true)
+				high_thr_set = true;
+			if (client_info->low_thr_set == true)
+				low_thr_set = true;
+		}
+
+		if (low_thr_set) {
 			pr_debug("low sensor mask:%x with state:%d\n",
 					sensor_mask, chan_prop->state_request);
 			/* Enable low threshold's interrupt */
@@ -611,10 +788,7 @@
 			}
 		}
 
-		if ((chan_prop->state_request ==
-					ADC_TM_HIGH_THR_ENABLE) ||
-			(chan_prop->state_request ==
-					ADC_TM_HIGH_LOW_THR_ENABLE)) {
+		if (high_thr_set) {
 			/* Enable high threshold's interrupt */
 			pr_debug("high sensor mask:%x\n", sensor_mask);
 			rc = qpnp_adc_tm_reg_update(chip,
@@ -760,8 +934,10 @@
 	int rc = 0, channel;
 	u8 sensor_mask = 0;
 
-	if (qpnp_adc_tm_is_valid(chip))
+	if (qpnp_adc_tm_is_valid(chip)) {
+		pr_err("invalid device\n");
 		return -ENODEV;
+	}
 
 	if (qpnp_adc_tm_check_revision(chip, adc_tm->btm_channel_num))
 		return -EINVAL;
@@ -860,9 +1036,10 @@
 	struct qpnp_adc_tm_chip *chip = adc_tm_sensor->chip;
 	int64_t result = 0;
 	u8 trip_cool_thr0, trip_cool_thr1, trip_warm_thr0, trip_warm_thr1;
-	unsigned int reg, rc = 0, btm_channel_num;
+	unsigned int reg, rc = 0;
 	uint16_t reg_low_thr_lsb, reg_low_thr_msb;
 	uint16_t reg_high_thr_lsb, reg_high_thr_msb;
+	uint32_t btm_chan_idx = 0, btm_chan = 0;
 
 	if (qpnp_adc_tm_is_valid(chip))
 		return -ENODEV;
@@ -870,11 +1047,17 @@
 	if (qpnp_adc_tm_check_revision(chip, adc_tm_sensor->btm_channel_num))
 		return -EINVAL;
 
-	btm_channel_num = adc_tm_sensor->btm_channel_num;
-	reg_low_thr_lsb = adc_tm_data[btm_channel_num].low_thr_lsb_addr;
-	reg_low_thr_msb = adc_tm_data[btm_channel_num].low_thr_msb_addr;
-	reg_high_thr_lsb = adc_tm_data[btm_channel_num].high_thr_lsb_addr;
-	reg_high_thr_msb = adc_tm_data[btm_channel_num].high_thr_msb_addr;
+	btm_chan = adc_tm_sensor->btm_channel_num;
+	rc = qpnp_adc_tm_get_btm_idx(btm_chan, &btm_chan_idx);
+	if (rc < 0) {
+		pr_err("Invalid btm channel idx\n");
+		return rc;
+	}
+
+	reg_low_thr_lsb = adc_tm_data[btm_chan_idx].low_thr_lsb_addr;
+	reg_low_thr_msb = adc_tm_data[btm_chan_idx].low_thr_msb_addr;
+	reg_high_thr_lsb = adc_tm_data[btm_chan_idx].high_thr_lsb_addr;
+	reg_high_thr_msb = adc_tm_data[btm_chan_idx].high_thr_msb_addr;
 
 	switch (trip) {
 	case ADC_TM_TRIP_HIGH_WARM:
@@ -934,7 +1117,8 @@
 	u8 trip_cool_thr0, trip_cool_thr1, trip_warm_thr0, trip_warm_thr1;
 	uint16_t reg_low_thr_lsb, reg_low_thr_msb;
 	uint16_t reg_high_thr_lsb, reg_high_thr_msb;
-	int rc = 0, btm_channel_num;
+	int rc = 0;
+	uint32_t btm_chan = 0, btm_chan_idx = 0;
 
 	if (qpnp_adc_tm_is_valid(chip))
 		return -ENODEV;
@@ -967,11 +1151,17 @@
 	trip_cool_thr0 = ((tm_config.high_thr_voltage << 24) >> 24);
 	trip_cool_thr1 = ((tm_config.high_thr_voltage << 16) >> 24);
 
-	btm_channel_num = adc_tm->btm_channel_num;
-	reg_low_thr_lsb = adc_tm_data[btm_channel_num].low_thr_lsb_addr;
-	reg_low_thr_msb = adc_tm_data[btm_channel_num].low_thr_msb_addr;
-	reg_high_thr_lsb = adc_tm_data[btm_channel_num].high_thr_lsb_addr;
-	reg_high_thr_msb = adc_tm_data[btm_channel_num].high_thr_msb_addr;
+	btm_chan = adc_tm->btm_channel_num;
+	rc = qpnp_adc_tm_get_btm_idx(btm_chan, &btm_chan_idx);
+	if (rc < 0) {
+		pr_err("Invalid btm channel idx\n");
+		return rc;
+	}
+
+	reg_low_thr_lsb = adc_tm_data[btm_chan_idx].low_thr_lsb_addr;
+	reg_low_thr_msb = adc_tm_data[btm_chan_idx].low_thr_msb_addr;
+	reg_high_thr_lsb = adc_tm_data[btm_chan_idx].high_thr_lsb_addr;
+	reg_high_thr_msb = adc_tm_data[btm_chan_idx].high_thr_msb_addr;
 
 	switch (trip) {
 	case ADC_TM_TRIP_HIGH_WARM:
@@ -1015,20 +1205,25 @@
 
 static void notify_battery_therm(struct qpnp_adc_tm_sensor *adc_tm)
 {
-	/* Battery therm's warm temperature translates to low voltage */
-	if (adc_tm->low_thr_notify) {
-		/* HIGH_STATE = WARM_TEMP for battery client */
-		adc_tm->btm_param->threshold_notification(
-		ADC_TM_WARM_STATE, adc_tm->btm_param->btm_ctx);
-		adc_tm->low_thr_notify = false;
-	}
+	struct qpnp_adc_thr_client_info *client_info = NULL;
 
-	/* Battery therm's cool temperature translates to high voltage */
-	if (adc_tm->high_thr_notify) {
-		/* LOW_STATE = COOL_TEMP for battery client */
-		adc_tm->btm_param->threshold_notification(
-		ADC_TM_COOL_STATE, adc_tm->btm_param->btm_ctx);
-		adc_tm->high_thr_notify = false;
+	list_for_each_entry(client_info,
+			&adc_tm->thr_list, list) {
+		/* Batt therm's warm temperature translates to low voltage */
+		if (client_info->notify_low_thr) {
+			/* HIGH_STATE = WARM_TEMP for battery client */
+			client_info->btm_param->threshold_notification(
+			ADC_TM_WARM_STATE, client_info->btm_param->btm_ctx);
+			client_info->notify_low_thr = false;
+		}
+
+		/* Batt therm's cool temperature translates to high voltage */
+		if (client_info->notify_high_thr) {
+			/* LOW_STATE = COOL_TEMP for battery client */
+			client_info->btm_param->threshold_notification(
+			ADC_TM_COOL_STATE, client_info->btm_param->btm_ctx);
+			client_info->notify_high_thr = false;
+		}
 	}
 
 	return;
@@ -1036,19 +1231,32 @@
 
 static void notify_clients(struct qpnp_adc_tm_sensor *adc_tm)
 {
-	/* For non batt therm clients */
-	if (adc_tm->low_thr_notify) {
-		pr_debug("notify kernel with low state\n");
-		adc_tm->btm_param->threshold_notification(
-		ADC_TM_LOW_STATE, adc_tm->btm_param->btm_ctx);
-		adc_tm->low_thr_notify = false;
-	}
+	struct qpnp_adc_thr_client_info *client_info = NULL;
 
-	if (adc_tm->high_thr_notify) {
-		pr_debug("notify kernel with high state\n");
-		adc_tm->btm_param->threshold_notification(
-		ADC_TM_HIGH_STATE, adc_tm->btm_param->btm_ctx);
-		adc_tm->high_thr_notify = false;
+	list_for_each_entry(client_info,
+			&adc_tm->thr_list, list) {
+		/* For non batt therm clients */
+		if (client_info->notify_low_thr) {
+			if (client_info->btm_param->threshold_notification
+								!= NULL) {
+				pr_debug("notify kernel with low state\n");
+				client_info->btm_param->threshold_notification(
+					ADC_TM_LOW_STATE,
+					client_info->btm_param->btm_ctx);
+				client_info->notify_low_thr = false;
+			}
+		}
+
+		if (client_info->notify_high_thr) {
+			if (client_info->btm_param->threshold_notification
+								!= NULL) {
+				pr_debug("notify kernel with high state\n");
+				client_info->btm_param->threshold_notification(
+					ADC_TM_HIGH_STATE,
+					client_info->btm_param->btm_ctx);
+				client_info->notify_high_thr = false;
+			}
+		}
 	}
 
 	return;
@@ -1064,12 +1272,10 @@
 					NULL, "btm");
 		pr_debug("notifying uspace client\n");
 	} else {
-		if (adc_tm->btm_param->threshold_notification != NULL) {
-			if (adc_tm->scale_type == SCALE_RBATT_THERM)
-				notify_battery_therm(adc_tm);
-			else
-				notify_clients(adc_tm);
-		}
+		if (adc_tm->scale_type == SCALE_RBATT_THERM)
+			notify_battery_therm(adc_tm);
+		else
+			notify_clients(adc_tm);
 	}
 
 	return;
@@ -1083,6 +1289,7 @@
 	int rc = 0, sensor_mask = 0;
 	u8 thr_int_en = 0;
 	bool state = false;
+	uint32_t btm_chan_idx = 0, btm_chan = 0;
 
 	if (qpnp_adc_tm_is_valid(chip))
 		return -ENODEV;
@@ -1097,24 +1304,29 @@
 
 	pr_debug("Sensor number:%x with state:%d\n", adc_tm->sensor_num, state);
 
+	btm_chan = adc_tm->btm_channel_num;
+	rc = qpnp_adc_tm_get_btm_idx(btm_chan, &btm_chan_idx);
+	if (rc < 0) {
+		pr_err("Invalid btm channel idx\n");
+		return rc;
+	}
+
 	switch (trip) {
 	case ADC_TM_TRIP_HIGH_WARM:
 		/* low_thr (lower voltage) for higher temp */
-		thr_int_en = adc_tm_data[adc_tm->btm_channel_num].
-							low_thr_int_chan_en;
+		thr_int_en = adc_tm_data[btm_chan_idx].low_thr_int_chan_en;
 		rc = qpnp_adc_tm_reg_update(chip, QPNP_ADC_TM_LOW_THR_INT_EN,
 				sensor_mask, state);
 		if (rc)
-			pr_err("channel:%x failed\n", adc_tm->btm_channel_num);
+			pr_err("channel:%x failed\n", btm_chan);
 	break;
 	case ADC_TM_TRIP_LOW_COOL:
 		/* high_thr (higher voltage) for cooler temp */
-		thr_int_en = adc_tm_data[adc_tm->btm_channel_num].
-							high_thr_int_chan_en;
+		thr_int_en = adc_tm_data[btm_chan_idx].high_thr_int_chan_en;
 		rc = qpnp_adc_tm_reg_update(chip, QPNP_ADC_TM_HIGH_THR_INT_EN,
 				sensor_mask, state);
 		if (rc)
-			pr_err("channel:%x failed\n", adc_tm->btm_channel_num);
+			pr_err("channel:%x failed\n", btm_chan);
 	break;
 	default:
 		return -EINVAL;
@@ -1128,7 +1340,10 @@
 	u8 status_low = 0, status_high = 0, qpnp_adc_tm_meas_en = 0;
 	u8 adc_tm_low_enable = 0, adc_tm_high_enable = 0;
 	u8 sensor_mask = 0;
-	int rc = 0, sensor_notify_num = 0, i = 0, sensor_num = 0, btm_chan_num;
+	int rc = 0, sensor_notify_num = 0, i = 0, sensor_num = 0;
+	uint32_t btm_chan_num = 0;
+	struct qpnp_adc_thr_client_info *client_info = NULL;
+	struct list_head *thr_list;
 
 	if (qpnp_adc_tm_is_valid(chip))
 		return -ENODEV;
@@ -1190,7 +1405,6 @@
 				pr_err("high threshold int read failed\n");
 				goto fail;
 			}
-			chip->sensor[sensor_num].high_thr_notify = true;
 		} else {
 			/* Uses the thermal sysfs registered device to disable
 				the corresponding high voltage threshold which
@@ -1205,6 +1419,21 @@
 				goto fail;
 			}
 		}
+		list_for_each(thr_list, &chip->sensor[sensor_num].thr_list) {
+			client_info = list_entry(thr_list,
+					struct qpnp_adc_thr_client_info, list);
+			if (client_info->high_thr_set) {
+				client_info->high_thr_set = false;
+				client_info->notify_high_thr = true;
+				if (client_info->state_req_copy ==
+						ADC_TM_HIGH_LOW_THR_ENABLE)
+					client_info->state_req_copy =
+							ADC_TM_LOW_THR_ENABLE;
+				else
+					client_info->state_req_copy =
+							ADC_TM_HIGH_THR_DISABLE;
+			}
+		}
 	}
 
 	if (adc_tm_low_enable) {
@@ -1233,7 +1462,6 @@
 				pr_err("low threshold int read failed\n");
 				goto fail;
 			}
-			chip->sensor[sensor_num].low_thr_notify = true;
 		} else {
 			/* Uses the thermal sysfs registered device to disable
 				the corresponding low voltage threshold which
@@ -1248,8 +1476,27 @@
 				goto fail;
 			}
 		}
+		list_for_each(thr_list, &chip->sensor[sensor_num].thr_list) {
+			client_info = list_entry(thr_list,
+					struct qpnp_adc_thr_client_info, list);
+			if (client_info->low_thr_set) {
+				/* mark the corresponding clients threshold
+					as not set */
+				client_info->low_thr_set = false;
+				client_info->notify_low_thr = true;
+				if (client_info->state_req_copy ==
+						ADC_TM_HIGH_LOW_THR_ENABLE)
+					client_info->state_req_copy =
+							ADC_TM_HIGH_THR_ENABLE;
+				else
+					client_info->state_req_copy =
+							ADC_TM_LOW_THR_DISABLE;
+			}
+		}
 	}
 
+	qpnp_adc_tm_manage_thresholds(chip, sensor_num, btm_chan_num);
+
 	if (adc_tm_high_enable || adc_tm_low_enable) {
 		rc = qpnp_adc_tm_reg_update(chip, QPNP_ADC_TM_MULTI_MEAS_EN,
 			sensor_mask, false);
@@ -1359,8 +1606,10 @@
 	int rc = 0, i = 0;
 	bool chan_found = false;
 
-	if (qpnp_adc_tm_is_valid(chip))
+	if (qpnp_adc_tm_is_valid(chip)) {
+		pr_err("chip not valid\n");
 		return -ENODEV;
+	}
 
 	if (param->threshold_notification == NULL) {
 		pr_debug("No notification for high/low temp??\n");
@@ -1413,6 +1662,8 @@
 	adc_tm_rscale_fn[scale_type].chan(chip->vadc_dev, param,
 			&chip->adc->amux_prop->chan_prop->low_thr,
 			&chip->adc->amux_prop->chan_prop->high_thr);
+	qpnp_adc_tm_add_to_list(chip, dt_index, param,
+				chip->adc->amux_prop->chan_prop);
 	chip->adc->amux_prop->chan_prop->tm_channel_select =
 				chip->sensor[dt_index].btm_channel_num;
 	chip->adc->amux_prop->chan_prop->timer_select =
@@ -1425,7 +1676,6 @@
 		goto fail_unlock;
 	}
 
-	chip->sensor[dt_index].btm_param = param;
 	chip->sensor[dt_index].scale_type = scale_type;
 
 fail_unlock:
@@ -1577,6 +1827,7 @@
 		goto fail;
 	}
 
+	chip->dev = &(spmi->dev);
 	chip->adc = adc_qpnp;
 
 	rc = qpnp_adc_get_devicetree_data(spmi, chip->adc);
@@ -1652,6 +1903,7 @@
 				pr_err("thermal device register failed.\n");
 		}
 		INIT_WORK(&chip->sensor[sen_idx].work, notify_adc_tm_fn);
+		INIT_LIST_HEAD(&chip->sensor[sen_idx].thr_list);
 		sen_idx++;
 	}
 	chip->max_channels_available = count_adc_channel_list;
diff --git a/drivers/usb/dwc3/dwc3-msm.c b/drivers/usb/dwc3/dwc3-msm.c
index f43affb..60d7119 100644
--- a/drivers/usb/dwc3/dwc3-msm.c
+++ b/drivers/usb/dwc3/dwc3-msm.c
@@ -201,6 +201,7 @@
 	bool			lpm_irq_seen;
 	struct delayed_work	resume_work;
 	struct work_struct	restart_usb_work;
+	struct work_struct	usb_block_reset_work;
 	struct dwc3_charger	charger;
 	struct usb_phy		*otg_xceiv;
 	struct delayed_work	chg_work;
@@ -1495,6 +1496,11 @@
 	case DWC3_CONTROLLER_ERROR_EVENT:
 		dev_info(mdwc->dev, "DWC3_CONTROLLER_ERROR_EVENT received\n");
 		dwc3_msm_dump_phy_info(mdwc);
+		/*
+		 * schedule work for doing block reset for recovery from erratic
+		 * error event.
+		 */
+		queue_work(system_nrt_wq, &mdwc->usb_block_reset_work);
 		break;
 	case DWC3_CONTROLLER_RESET_EVENT:
 		dev_dbg(mdwc->dev, "DWC3_CONTROLLER_RESET_EVENT received\n");
@@ -1537,6 +1543,16 @@
 	dwc3_msm_dbm_soft_reset(mdwc, 0);
 }
 
+static void dwc3_block_reset_usb_work(struct work_struct *w)
+{
+	struct dwc3_msm *mdwc = container_of(w, struct dwc3_msm,
+						usb_block_reset_work);
+
+	dev_dbg(mdwc->dev, "%s\n", __func__);
+
+	dwc3_msm_block_reset(&mdwc->ext_xceiv, true);
+}
+
 static void dwc3_chg_enable_secondary_det(struct dwc3_msm *mdwc)
 {
 	u32 chg_ctrl;
@@ -2692,6 +2708,7 @@
 	INIT_DELAYED_WORK(&mdwc->chg_work, dwc3_chg_detect_work);
 	INIT_DELAYED_WORK(&mdwc->resume_work, dwc3_resume_work);
 	INIT_WORK(&mdwc->restart_usb_work, dwc3_restart_usb_work);
+	INIT_WORK(&mdwc->usb_block_reset_work, dwc3_block_reset_usb_work);
 	INIT_WORK(&mdwc->id_work, dwc3_id_work);
 	INIT_DELAYED_WORK(&mdwc->init_adc_work, dwc3_init_adc_work);
 	init_completion(&mdwc->ext_chg_wait);
diff --git a/drivers/usb/dwc3/dwc3_otg.c b/drivers/usb/dwc3/dwc3_otg.c
index e912e86..5348eb5 100644
--- a/drivers/usb/dwc3/dwc3_otg.c
+++ b/drivers/usb/dwc3/dwc3_otg.c
@@ -24,6 +24,7 @@
 #include "io.h"
 #include "xhci.h"
 
+#define VBUS_REG_CHECK_DELAY	(jiffies + msecs_to_jiffies(1000))
 #define MAX_INVALID_CHRGR_RETRY 3
 static int max_chgr_retry_count = MAX_INVALID_CHRGR_RETRY;
 module_param(max_chgr_retry_count, int, S_IRUGO | S_IWUSR);
@@ -336,13 +337,13 @@
 		dev_dbg(otg->phy->dev, "%s: set gadget %s\n",
 					__func__, gadget->name);
 		otg->gadget = gadget;
-		schedule_work(&dotg->sm_work);
+		queue_delayed_work(system_nrt_wq, &dotg->sm_work, 0);
 	} else {
 		if (otg->phy->state == OTG_STATE_B_PERIPHERAL) {
 			dwc3_otg_start_peripheral(otg, 0);
 			otg->gadget = NULL;
 			otg->phy->state = OTG_STATE_UNDEFINED;
-			schedule_work(&dotg->sm_work);
+			queue_delayed_work(system_nrt_wq, &dotg->sm_work, 0);
 		} else {
 			otg->gadget = NULL;
 		}
@@ -367,7 +368,7 @@
 	 * STOP chg_det as part of !BSV handling would reset the chg_det flags
 	 */
 	if (test_bit(B_SESS_VLD, &dotg->inputs))
-		schedule_work(&dotg->sm_work);
+		queue_delayed_work(system_nrt_wq, &dotg->sm_work, 0);
 }
 
 /**
@@ -406,7 +407,7 @@
 
 	/* Flush processing any pending events before handling new ones */
 	if (init)
-		flush_work(&dotg->sm_work);
+		flush_delayed_work(&dotg->sm_work);
 
 	if (event == DWC3_EVENT_PHY_RESUME) {
 		if (!pm_runtime_status_suspended(phy->dev)) {
@@ -453,15 +454,16 @@
 
 		if (!init) {
 			init = true;
-			if (!work_busy(&dotg->sm_work))
-				schedule_work(&dotg->sm_work);
+			if (!work_busy(&dotg->sm_work.work))
+				queue_delayed_work(system_nrt_wq,
+							&dotg->sm_work, 0);
 
 			complete(&dotg->dwc3_xcvr_vbus_init);
 			dev_dbg(phy->dev, "XCVR: BSV init complete\n");
 			return;
 		}
 
-		schedule_work(&dotg->sm_work);
+		queue_delayed_work(system_nrt_wq, &dotg->sm_work, 0);
 	}
 }
 
@@ -610,7 +612,7 @@
 			handled_irqs |= DWC3_OEVTEN_OTGBDEVVBUSCHNGEVNT;
 		}
 
-		schedule_work(&dotg->sm_work);
+		queue_delayed_work(system_nrt_wq, &dotg->sm_work, 0);
 
 		ret = IRQ_HANDLED;
 
@@ -671,10 +673,12 @@
  */
 static void dwc3_otg_sm_work(struct work_struct *w)
 {
-	struct dwc3_otg *dotg = container_of(w, struct dwc3_otg, sm_work);
+	struct dwc3_otg *dotg = container_of(w, struct dwc3_otg, sm_work.work);
 	struct usb_phy *phy = dotg->otg.phy;
 	struct dwc3_charger *charger = dotg->charger;
 	bool work = 0;
+	int ret = 0;
+	int delay = 0;
 
 	pm_runtime_resume(phy->dev);
 	dev_dbg(phy->dev, "%s state\n", otg_state_string(phy->state));
@@ -817,10 +821,23 @@
 		if (test_bit(ID, &dotg->inputs)) {
 			dev_dbg(phy->dev, "id\n");
 			phy->state = OTG_STATE_B_IDLE;
+			dotg->vbus_retry_count = 0;
 			work = 1;
 		} else {
 			phy->state = OTG_STATE_A_HOST;
-			if (dwc3_otg_start_host(&dotg->otg, 1)) {
+			ret = dwc3_otg_start_host(&dotg->otg, 1);
+			if ((ret == -EPROBE_DEFER) &&
+						dotg->vbus_retry_count < 3) {
+				/*
+				 * Get regulator failed as regulator driver is
+				 * not up yet. Will try to start host after 1sec
+				 */
+				phy->state = OTG_STATE_A_IDLE;
+				dev_dbg(phy->dev, "Unable to get vbus regulator. Retrying...\n");
+				delay = VBUS_REG_CHECK_DELAY;
+				work = 1;
+				dotg->vbus_retry_count++;
+			} else if (ret) {
 				/*
 				 * Probably set_host was not called yet.
 				 * We will re-try as soon as it will be called
@@ -839,6 +856,7 @@
 			dev_dbg(phy->dev, "id\n");
 			dwc3_otg_start_host(&dotg->otg, 0);
 			phy->state = OTG_STATE_B_IDLE;
+			dotg->vbus_retry_count = 0;
 			work = 1;
 		}
 		break;
@@ -849,7 +867,7 @@
 	}
 
 	if (work)
-		schedule_work(&dotg->sm_work);
+		queue_delayed_work(system_nrt_wq, &dotg->sm_work, delay);
 }
 
 
@@ -973,7 +991,7 @@
 	dotg->otg.phy->state = OTG_STATE_UNDEFINED;
 
 	init_completion(&dotg->dwc3_xcvr_vbus_init);
-	INIT_WORK(&dotg->sm_work, dwc3_otg_sm_work);
+	INIT_DELAYED_WORK(&dotg->sm_work, dwc3_otg_sm_work);
 
 	ret = request_irq(dotg->irq, dwc3_otg_interrupt, IRQF_SHARED,
 				"dwc3_otg", dotg);
@@ -988,7 +1006,7 @@
 	return 0;
 
 err3:
-	cancel_work_sync(&dotg->sm_work);
+	cancel_delayed_work_sync(&dotg->sm_work);
 	usb_set_transceiver(NULL);
 err2:
 	kfree(dotg->otg.phy);
@@ -1013,7 +1031,7 @@
 	if (dotg) {
 		if (dotg->charger)
 			dotg->charger->start_detection(dotg->charger, false);
-		cancel_work_sync(&dotg->sm_work);
+		cancel_delayed_work_sync(&dotg->sm_work);
 		usb_set_transceiver(NULL);
 		pm_runtime_put(dwc->dev);
 		free_irq(dotg->irq, dotg);
diff --git a/drivers/usb/dwc3/dwc3_otg.h b/drivers/usb/dwc3/dwc3_otg.h
index 7adf874..3a75b0a 100644
--- a/drivers/usb/dwc3/dwc3_otg.h
+++ b/drivers/usb/dwc3/dwc3_otg.h
@@ -41,7 +41,7 @@
 	struct dwc3		*dwc;
 	void __iomem		*regs;
 	struct regulator	*vbus_otg;
-	struct work_struct	sm_work;
+	struct delayed_work	sm_work;
 	struct dwc3_charger	*charger;
 	struct dwc3_ext_xceiv	*ext_xceiv;
 #define ID		0
@@ -51,6 +51,7 @@
 	struct completion	dwc3_xcvr_vbus_init;
 	int			host_bus_suspend;
 	int			charger_retry_count;
+	int			vbus_retry_count;
 };
 
 /**
diff --git a/drivers/usb/dwc3/gadget.c b/drivers/usb/dwc3/gadget.c
index aaa22f3..8fa4774 100644
--- a/drivers/usb/dwc3/gadget.c
+++ b/drivers/usb/dwc3/gadget.c
@@ -2656,9 +2656,6 @@
 	dbg_print_reg("OSTS", dwc3_readl(dwc->regs, DWC3_OSTS));
 
 	dwc3_notify_event(dwc, DWC3_CONTROLLER_ERROR_EVENT);
-
-	panic("DWC3 Erratic error\n");
-
 }
 
 static void dwc3_gadget_interrupt(struct dwc3 *dwc,
diff --git a/drivers/usb/gadget/u_ether.c b/drivers/usb/gadget/u_ether.c
index 325c2b5..9e789c5 100644
--- a/drivers/usb/gadget/u_ether.c
+++ b/drivers/usb/gadget/u_ether.c
@@ -553,6 +553,7 @@
 				}
 
 				new_req->length = length;
+				new_req->complete = tx_complete;
 				retval = usb_ep_queue(in, new_req, GFP_ATOMIC);
 				switch (retval) {
 				default:
diff --git a/drivers/usb/host/ehci-msm-hsic.c b/drivers/usb/host/ehci-msm-hsic.c
index d102c22..5d58f16 100644
--- a/drivers/usb/host/ehci-msm-hsic.c
+++ b/drivers/usb/host/ehci-msm-hsic.c
@@ -342,7 +342,7 @@
 
 #define HSIC_DBG1_REG		0x38
 
-static const int vdd_val[VDD_TYPE_MAX][VDD_VAL_MAX] = {
+static int vdd_val[VDD_TYPE_MAX][VDD_VAL_MAX] = {
 		{   /* VDD_CX CORNER Voting */
 			[VDD_NONE]	= RPM_VREG_CORNER_NONE,
 			[VDD_MIN]	= RPM_VREG_CORNER_NOMINAL,
@@ -359,6 +359,8 @@
 {
 	int ret = 0;
 	int none_vol, min_vol, max_vol;
+	u32 tmp[3];
+	int len = 0;
 
 	if (!mehci->hsic_vddcx) {
 		mehci->vdd_type = VDDCX_CORNER;
@@ -373,6 +375,22 @@
 			}
 			mehci->vdd_type = VDDCX;
 		}
+
+		if (mehci->dev->of_node) {
+			of_get_property(mehci->dev->of_node,
+					"hsic,vdd-voltage-level",
+					&len);
+			if (len == sizeof(tmp)) {
+				of_property_read_u32_array(mehci->dev->of_node,
+						"hsic,vdd-voltage-level",
+						tmp, len/sizeof(*tmp));
+				vdd_val[mehci->vdd_type][VDD_NONE] = tmp[0];
+				vdd_val[mehci->vdd_type][VDD_MIN] = tmp[1];
+				vdd_val[mehci->vdd_type][VDD_MAX] = tmp[2];
+			} else {
+				dev_dbg(mehci->dev, "Use default vdd config\n");
+			}
+		}
 	}
 
 	none_vol = vdd_val[mehci->vdd_type][VDD_NONE];
diff --git a/drivers/usb/host/ehci-msm2.c b/drivers/usb/host/ehci-msm2.c
index 0aecaad..dd04f49 100644
--- a/drivers/usb/host/ehci-msm2.c
+++ b/drivers/usb/host/ehci-msm2.c
@@ -40,6 +40,7 @@
 #include <mach/msm_xo.h>
 #include <mach/msm_iomap.h>
 #include <linux/debugfs.h>
+#include <mach/rpm-regulator.h>
 
 #define MSM_USB_BASE (hcd->regs)
 
@@ -76,6 +77,7 @@
 	int					wakeup_int_cnt;
 	bool					wakeup_irq_enabled;
 	int					wakeup_irq;
+	enum usb_vdd_type			vdd_type;
 };
 
 static inline struct msm_hcd *hcd_to_mhcd(struct usb_hcd *hcd)
@@ -96,26 +98,87 @@
 #define HSUSB_PHY_1P8_VOL_MAX		1800000 /* uV */
 #define HSUSB_PHY_1P8_HPM_LOAD		50000	/* uA */
 
+#define HSUSB_PHY_VDD_DIG_VOL_NONE	0	/* uV */
 #define HSUSB_PHY_VDD_DIG_VOL_MIN	1045000	/* uV */
 #define HSUSB_PHY_VDD_DIG_VOL_MAX	1320000	/* uV */
 #define HSUSB_PHY_VDD_DIG_LOAD		49360	/* uA */
 
+#define HSUSB_PHY_SUSP_DIG_VOL_P50  500000
+#define HSUSB_PHY_SUSP_DIG_VOL_P75  750000
+enum hsusb_vdd_value {
+	VDD_MIN_NONE = 0,
+	VDD_MIN_P50,
+	VDD_MIN_P75,
+	VDD_MIN_OP,
+	VDD_MAX_OP,
+	VDD_VAL_MAX_OP,
+};
+
+static int hsusb_vdd_val[VDD_TYPE_MAX][VDD_VAL_MAX_OP] = {
+		{   /* VDD_CX CORNER Voting */
+			[VDD_MIN_NONE]	= RPM_VREG_CORNER_NONE,
+			[VDD_MIN_P50]	= RPM_VREG_CORNER_NONE,
+			[VDD_MIN_P75]	= RPM_VREG_CORNER_NONE,
+			[VDD_MIN_OP]	= RPM_VREG_CORNER_NOMINAL,
+			[VDD_MAX_OP]	= RPM_VREG_CORNER_HIGH,
+		},
+		{   /* VDD_CX Voltage Voting */
+			[VDD_MIN_NONE]	= HSUSB_PHY_VDD_DIG_VOL_NONE,
+			[VDD_MIN_P50]	= HSUSB_PHY_SUSP_DIG_VOL_P50,
+			[VDD_MIN_P75]	= HSUSB_PHY_SUSP_DIG_VOL_P75,
+			[VDD_MIN_OP]	= HSUSB_PHY_VDD_DIG_VOL_MIN,
+			[VDD_MAX_OP]	= HSUSB_PHY_VDD_DIG_VOL_MAX,
+		},
+};
+
 static int msm_ehci_init_vddcx(struct msm_hcd *mhcd, int init)
 {
 	int ret = 0;
+	int none_vol, min_vol, max_vol;
+	u32 tmp[5];
+	int len = 0;
 
-	if (!init)
+	if (!init) {
+		none_vol = hsusb_vdd_val[mhcd->vdd_type][VDD_MIN_NONE];
+		max_vol = hsusb_vdd_val[mhcd->vdd_type][VDD_MAX_OP];
 		goto disable_reg;
-
-	mhcd->hsusb_vddcx = devm_regulator_get(mhcd->dev, "HSUSB_VDDCX");
-	if (IS_ERR(mhcd->hsusb_vddcx)) {
-		dev_err(mhcd->dev, "unable to get ehci vddcx\n");
-		return PTR_ERR(mhcd->hsusb_vddcx);
 	}
 
-	ret = regulator_set_voltage(mhcd->hsusb_vddcx,
-			HSUSB_PHY_VDD_DIG_VOL_MIN,
-			HSUSB_PHY_VDD_DIG_VOL_MAX);
+	mhcd->vdd_type = VDDCX_CORNER;
+	mhcd->hsusb_vddcx = devm_regulator_get(mhcd->dev, "hsusb_vdd_dig");
+	if (IS_ERR(mhcd->hsusb_vddcx)) {
+		mhcd->hsusb_vddcx = devm_regulator_get(mhcd->dev,
+							"HSUSB_VDDCX");
+		if (IS_ERR(mhcd->hsusb_vddcx)) {
+			dev_err(mhcd->dev, "unable to get ehci vddcx\n");
+			return PTR_ERR(mhcd->hsusb_vddcx);
+		}
+		mhcd->vdd_type = VDDCX;
+	}
+
+	if (mhcd->dev->of_node) {
+		of_get_property(mhcd->dev->of_node,
+				"qcom,vdd-voltage-level",
+				&len);
+		if (len == sizeof(tmp)) {
+			of_property_read_u32_array(mhcd->dev->of_node,
+					"qcom,vdd-voltage-level",
+					tmp, len/sizeof(*tmp));
+			hsusb_vdd_val[mhcd->vdd_type][VDD_MIN_NONE] = tmp[0];
+			hsusb_vdd_val[mhcd->vdd_type][VDD_MIN_P50] = tmp[1];
+			hsusb_vdd_val[mhcd->vdd_type][VDD_MIN_P75] = tmp[2];
+			hsusb_vdd_val[mhcd->vdd_type][VDD_MIN_OP] = tmp[3];
+			hsusb_vdd_val[mhcd->vdd_type][VDD_MAX_OP] = tmp[4];
+		} else {
+			dev_dbg(mhcd->dev, "Use default vdd config\n");
+		}
+	}
+
+	none_vol = hsusb_vdd_val[mhcd->vdd_type][VDD_MIN_NONE];
+	min_vol = hsusb_vdd_val[mhcd->vdd_type][VDD_MIN_OP];
+	max_vol = hsusb_vdd_val[mhcd->vdd_type][VDD_MAX_OP];
+
+	ret = regulator_set_voltage(mhcd->hsusb_vddcx, min_vol, max_vol);
 	if (ret) {
 		dev_err(mhcd->dev, "unable to set the voltage"
 				"for ehci vddcx\n");
@@ -143,8 +206,7 @@
 reg_enable_err:
 	regulator_set_optimum_mode(mhcd->hsusb_vddcx, 0);
 reg_optimum_mode_err:
-	regulator_set_voltage(mhcd->hsusb_vddcx, 0,
-				HSUSB_PHY_VDD_DIG_VOL_MIN);
+	regulator_set_voltage(mhcd->hsusb_vddcx, none_vol, max_vol);
 	return ret;
 
 }
@@ -194,24 +256,22 @@
 }
 
 #ifdef CONFIG_PM_SLEEP
-#define HSUSB_PHY_SUSP_DIG_VOL_P50  500000
-#define HSUSB_PHY_SUSP_DIG_VOL_P75  750000
 static int msm_ehci_config_vddcx(struct msm_hcd *mhcd, int high)
 {
 	struct msm_usb_host_platform_data *pdata;
-	int max_vol = HSUSB_PHY_VDD_DIG_VOL_MAX;
+	int max_vol = hsusb_vdd_val[mhcd->vdd_type][VDD_MAX_OP];
 	int min_vol;
 	int ret;
 
 	pdata = mhcd->dev->platform_data;
 
 	if (high)
-		min_vol = HSUSB_PHY_VDD_DIG_VOL_MIN;
+		min_vol = hsusb_vdd_val[mhcd->vdd_type][VDD_MIN_OP];
 	else if (pdata && pdata->dock_connect_irq &&
 			!irq_read_line(pdata->dock_connect_irq))
-		min_vol = HSUSB_PHY_SUSP_DIG_VOL_P75;
+		min_vol = hsusb_vdd_val[mhcd->vdd_type][VDD_MIN_P75];
 	else
-		min_vol = HSUSB_PHY_SUSP_DIG_VOL_P50;
+		min_vol = hsusb_vdd_val[mhcd->vdd_type][VDD_MIN_P50];
 
 	ret = regulator_set_voltage(mhcd->hsusb_vddcx, min_vol, max_vol);
 	if (ret) {
diff --git a/drivers/video/msm/mdss/mdp3.c b/drivers/video/msm/mdss/mdp3.c
index 8a5f1ee..eff60a3 100644
--- a/drivers/video/msm/mdss/mdp3.c
+++ b/drivers/video/msm/mdss/mdp3.c
@@ -35,6 +35,9 @@
 #include <linux/uaccess.h>
 #include <linux/file.h>
 #include <linux/msm_kgsl.h>
+#include <linux/major.h>
+#include <linux/bootmem.h>
+#include <linux/memblock.h>
 
 #include <mach/board.h>
 #include <mach/clk.h>
@@ -583,6 +586,41 @@
 	return 0;
 }
 
+struct reg_dump {
+	int start_addr;
+	int num_reads;
+};
+
+struct reg_dump ppp_reg[] = {
+	{0x10108, 3},
+	{0x10118, 6},
+	{0x10138, 9},
+	{0x10158, 1},
+	{0x10164, 7},
+	{0x1019C, 1},
+	{0x101b8, 2},
+	{0x101c0, 8},
+};
+
+static int mdp3_iommu_fault_handler(struct iommu_domain *domain,
+		struct device *dev, unsigned long iova, int flags, void *token)
+{
+	unsigned int addr, val;
+	int i, j;
+	pr_err("MDP IOMMU page fault: iova 0x%lx\n", iova);
+	for (i = 0; i < ARRAY_SIZE(ppp_reg); i++) {
+		for (j = 0; j < ppp_reg[i].num_reads; j++) {
+			addr = ppp_reg[i].start_addr + (j*4);
+			val = MDP3_REG_READ(addr);
+			pr_err("TMsg: Addr= 0x%08x, val= 0x%08x\n",
+				(unsigned int)addr, (unsigned int)val);
+		}
+	}
+	panic("PPP pagefault, shutting down for easier debugging\n");
+	return 0;
+}
+
+
 int mdp3_iommu_attach(int context)
 {
 	struct mdp3_iommu_ctx_map *context_map;
@@ -658,6 +696,9 @@
 			else
 				return PTR_ERR(mdp3_iommu_domains[i].domain);
 		}
+		iommu_set_fault_handler(mdp3_iommu_domains[i].domain,
+			mdp3_iommu_fault_handler,
+			NULL);
 	}
 
 	mdp3_res->domains = mdp3_iommu_domains;
@@ -1594,6 +1635,45 @@
 	}
 }
 
+int mdp3_parse_dt_splash(struct msm_fb_data_type *mfd)
+{
+	struct platform_device *pdev = mfd->pdev;
+	int rc;
+	u32 offsets[2];
+
+	rc = of_property_read_u32_array(pdev->dev.of_node,
+				"qcom,memblock-reserve", offsets, 2);
+
+	if (rc) {
+		pr_err("fail to get memblock-reserve property\n");
+		return rc;
+	}
+
+	if (mdp3_res->splash_mem_addr != offsets[0])
+		rc = -EINVAL;
+
+	mdp3_res->splash_mem_addr = offsets[0];
+	mdp3_res->splash_mem_size = offsets[1];
+
+	pr_debug("memaddr=%x size=%x\n", mdp3_res->splash_mem_addr,
+		mdp3_res->splash_mem_size);
+
+	return rc;
+}
+
+void mdp3_release_splash_memory(void)
+{
+	/* Give back the reserved memory to the system */
+	if (mdp3_res->splash_mem_addr) {
+		pr_debug("mdp3_release_splash_memory\n");
+		memblock_free(mdp3_res->splash_mem_addr,
+				mdp3_res->splash_mem_size);
+		free_bootmem_late(mdp3_res->splash_mem_addr,
+				mdp3_res->splash_mem_size);
+		mdp3_res->splash_mem_addr = 0;
+	}
+}
+
 struct mdp3_dma *mdp3_get_dma_pipe(int capability)
 {
 	int i;
@@ -1684,6 +1764,8 @@
 		rc = (status == 0x080000);
 	}
 
+	mdp3_res->splash_mem_addr = MDP3_REG_READ(MDP3_REG_DMA_S_IBUF_ADDR);
+
 	mdp3_clk_update(MDP3_CLK_AHB, 0);
 	mdp3_clk_update(MDP3_CLK_CORE, 0);
 	return rc;
@@ -1717,12 +1799,6 @@
 		goto splash_on_err;
 	}
 
-	rc = mdp3_continuous_splash_copy(pdata);
-	if (rc) {
-		pr_err("fail to copy continuous splash image\n");
-		goto splash_on_err;
-	}
-
 	mdp3_irq_register();
 
 	if (pdata->event_handler) {
diff --git a/drivers/video/msm/mdss/mdp3.h b/drivers/video/msm/mdss/mdp3.h
index 2f73c42..caee34f 100644
--- a/drivers/video/msm/mdss/mdp3.h
+++ b/drivers/video/msm/mdss/mdp3.h
@@ -149,6 +149,8 @@
 
 	struct early_suspend suspend_handler;
 	struct mdss_panel_cfg pan_cfg;
+	u32 splash_mem_addr;
+	u32 splash_mem_size;
 };
 
 struct mdp3_img_data {
@@ -181,6 +183,8 @@
 int mdp3_iommu_disable(int client);
 int mdp3_iommu_is_attached(int client);
 void mdp3_free(void);
+int mdp3_parse_dt_splash(struct msm_fb_data_type *mfd);
+void mdp3_release_splash_memory(void);
 
 #define MDP3_REG_WRITE(addr, val) writel_relaxed(val, mdp3_res->mdp_base + addr)
 #define MDP3_REG_READ(addr) readl_relaxed(mdp3_res->mdp_base + addr)
diff --git a/drivers/video/msm/mdss/mdp3_ctrl.c b/drivers/video/msm/mdss/mdp3_ctrl.c
index bf5b643..a888541 100644
--- a/drivers/video/msm/mdss/mdp3_ctrl.c
+++ b/drivers/video/msm/mdss/mdp3_ctrl.c
@@ -758,8 +758,8 @@
 	if (!mdp3_iommu_is_attached(MDP3_CLIENT_DMA_P)) {
 		pr_debug("continuous splash screen, IOMMU not attached\n");
 		mdp3_ctrl_reset(mfd);
-		mdp3_free();
 	}
+	mdp3_release_splash_memory();
 
 	mutex_lock(&mdp3_session->lock);
 
@@ -805,9 +805,9 @@
 
 	if (!mdp3_iommu_is_attached(MDP3_CLIENT_DMA_P)) {
 		pr_debug("continuous splash screen, IOMMU not attached\n");
-		mdp3_ctrl_off(mfd);
-		mdp3_ctrl_on(mfd);
+		mdp3_ctrl_reset(mfd);
 	}
+	mdp3_release_splash_memory();
 
 	mutex_lock(&mdp3_session->lock);
 
@@ -1219,7 +1219,8 @@
 	if (!mdp3_session->dma->config_lut)
 		return -EINVAL;
 
-	if (cmap->start + cmap->len > MDP_LUT_SIZE) {
+	if (cmap->start > MDP_LUT_SIZE || cmap->len > MDP_LUT_SIZE ||
+			(cmap->start + cmap->len > MDP_LUT_SIZE)) {
 		pr_err("mdp3_ctrl_lut_update invalid arguments\n");
 		return  -EINVAL;
 	}
@@ -1358,8 +1359,13 @@
 	struct mdp3_session_data *mdp3_session = NULL;
 	u32 intf_type = MDP3_DMA_OUTPUT_SEL_DSI_VIDEO;
 	int rc;
+	int splash_mismatch = 0;
 
 	pr_debug("mdp3_ctrl_init\n");
+	rc = mdp3_parse_dt_splash(mfd);
+	if (rc)
+		splash_mismatch = 1;
+
 	mdp3_interface->on_fnc = mdp3_ctrl_on;
 	mdp3_interface->off_fnc = mdp3_ctrl_off;
 	mdp3_interface->do_histogram = NULL;
@@ -1404,7 +1410,7 @@
 	mdp3_session->dma->output_config.out_sel = intf_type;
 	mdp3_session->mfd = mfd;
 	mdp3_session->panel = dev_get_platdata(&mfd->pdev->dev);
-	mdp3_session->status = 0;
+	mdp3_session->status = mdp3_session->intf->active;
 	mdp3_session->overlay.id = MSMFB_NEW_REQUEST;
 	mdp3_bufq_init(&mdp3_session->bufq_in);
 	mdp3_bufq_init(&mdp3_session->bufq_out);
@@ -1434,6 +1440,11 @@
 	kobject_uevent(&dev->kobj, KOBJ_ADD);
 	pr_debug("vsync kobject_uevent(KOBJ_ADD)\n");
 
+	if (splash_mismatch) {
+		pr_err("splash memory mismatch, stop splash\n");
+		mdp3_ctrl_off(mfd);
+	}
+
 init_done:
 	if (IS_ERR_VALUE(rc))
 		kfree(mdp3_session);
diff --git a/drivers/video/msm/mdss/mdp3_ppp.c b/drivers/video/msm/mdss/mdp3_ppp.c
index e1f2d10..6e62cc7 100644
--- a/drivers/video/msm/mdss/mdp3_ppp.c
+++ b/drivers/video/msm/mdss/mdp3_ppp.c
@@ -498,6 +498,7 @@
 
 	src_w = req->src_rect.w;
 	dst_h = blit_op->dst.roi.height;
+	pr_err("TMsg: In workaround. srcw= %d, dstH=%d\n", src_w, dst_h);
 	/* bg tile fetching HW workaround */
 	for (i = 0; i < (req->dst_rect.h / 16); i++) {
 		/* this tile size */
diff --git a/drivers/video/msm/mdss/mdss_dsi.c b/drivers/video/msm/mdss/mdss_dsi.c
index e156116..2d0497c 100644
--- a/drivers/video/msm/mdss/mdss_dsi.c
+++ b/drivers/video/msm/mdss/mdss_dsi.c
@@ -289,6 +289,7 @@
 {
 	int ret = 0;
 	struct mdss_dsi_ctrl_pdata *ctrl_pdata = NULL;
+	struct mdss_panel_info *panel_info = NULL;
 
 	if (pdata == NULL) {
 		pr_err("%s: Invalid input data\n", __func__);
@@ -305,6 +306,7 @@
 	ctrl_pdata = container_of(pdata, struct mdss_dsi_ctrl_pdata,
 				panel_data);
 
+	panel_info = &ctrl_pdata->panel_data.panel_info;
 	pr_debug("%s+: ctrl=%p ndx=%d\n", __func__,
 				ctrl_pdata, ctrl_pdata->ndx);
 
@@ -335,6 +337,11 @@
 		return ret;
 	}
 
+	if (panel_info->dynamic_fps
+	    && (panel_info->dfps_update == DFPS_SUSPEND_RESUME_MODE)
+	    && (panel_info->new_fps != panel_info->mipi.frame_rate))
+		panel_info->mipi.frame_rate = panel_info->new_fps;
+
 	pr_debug("%s-:\n", __func__);
 
 	return ret;
@@ -350,6 +357,7 @@
 	u32 ystride, bpp, data, dst_bpp;
 	u32 dummy_xres, dummy_yres;
 	struct mdss_dsi_ctrl_pdata *ctrl_pdata = NULL;
+	u32 hsync_period, vsync_period;
 
 	if (pdata == NULL) {
 		pr_err("%s: Invalid input data\n", __func__);
@@ -412,11 +420,16 @@
 			pdata->panel_info.bpp);
 	height = pdata->panel_info.yres;
 
-	mipi  = &pdata->panel_info.mipi;
 	if (pdata->panel_info.type == MIPI_VIDEO_PANEL) {
 		dummy_xres = pdata->panel_info.lcdc.xres_pad;
 		dummy_yres = pdata->panel_info.lcdc.yres_pad;
+	}
 
+	vsync_period = vspw + vbp + height + dummy_yres + vfp;
+	hsync_period = hspw + hbp + width + dummy_xres + hfp;
+
+	mipi  = &pdata->panel_info.mipi;
+	if (pdata->panel_info.type == MIPI_VIDEO_PANEL) {
 		MIPI_OUTP((ctrl_pdata->ctrl_base) + 0x24,
 			((hspw + hbp + width + dummy_xres) << 16 |
 			(hspw + hbp)));
@@ -424,9 +437,8 @@
 			((vspw + vbp + height + dummy_yres) << 16 |
 			(vspw + vbp)));
 		MIPI_OUTP((ctrl_pdata->ctrl_base) + 0x2C,
-			(vspw + vbp + height + dummy_yres +
-				vfp - 1) << 16 | (hspw + hbp +
-				width + dummy_xres + hfp - 1));
+				((vsync_period - 1) << 16)
+				| (hsync_period - 1));
 
 		MIPI_OUTP((ctrl_pdata->ctrl_base) + 0x30, (hspw << 16));
 		MIPI_OUTP((ctrl_pdata->ctrl_base) + 0x34, 0);
@@ -591,6 +603,65 @@
 	return ret;
 }
 
+static int mdss_dsi_dfps_config(struct mdss_panel_data *pdata, int new_fps)
+{
+	int rc = 0;
+	struct mdss_dsi_ctrl_pdata *ctrl_pdata = NULL;
+	u32 dsi_ctrl;
+
+	pr_debug("%s+:\n", __func__);
+
+	if (pdata == NULL) {
+		pr_err("%s: Invalid input data\n", __func__);
+		return -EINVAL;
+	}
+
+	ctrl_pdata = container_of(pdata, struct mdss_dsi_ctrl_pdata,
+				panel_data);
+
+	if (!ctrl_pdata->panel_data.panel_info.dynamic_fps) {
+		pr_err("%s: Dynamic fps not enabled for this panel\n",
+					__func__);
+		return -EINVAL;
+	}
+
+	if (new_fps !=
+		ctrl_pdata->panel_data.panel_info.mipi.frame_rate) {
+		rc = mdss_dsi_clk_div_config
+			(&ctrl_pdata->panel_data.panel_info, new_fps);
+		if (rc) {
+			pr_err("%s: unable to initialize the clk dividers\n",
+							__func__);
+			return rc;
+		}
+		ctrl_pdata->pclk_rate =
+			ctrl_pdata->panel_data.panel_info.mipi.dsi_pclk_rate;
+		ctrl_pdata->byte_clk_rate =
+			ctrl_pdata->panel_data.panel_info.clk_rate / 8;
+
+		if (pdata->panel_info.dfps_update
+				== DFPS_IMMEDIATE_CLK_UPDATE_MODE) {
+			dsi_ctrl = MIPI_INP((ctrl_pdata->ctrl_base) +
+					    0x0004);
+			ctrl_pdata->panel_data.panel_info.mipi.frame_rate =
+									new_fps;
+			dsi_ctrl &= ~0x2;
+			MIPI_OUTP((ctrl_pdata->ctrl_base) + 0x0004,
+							dsi_ctrl);
+			mdss_dsi_controller_cfg(true, pdata);
+			mdss_dsi_clk_ctrl(ctrl_pdata, 0);
+			mdss_dsi_clk_ctrl(ctrl_pdata, 1);
+			dsi_ctrl |= 0x2;
+			MIPI_OUTP((ctrl_pdata->ctrl_base) + 0x0004,
+							dsi_ctrl);
+		}
+	} else {
+		pr_debug("%s: Panel is already at this FPS\n", __func__);
+	}
+
+	return rc;
+}
+
 static int mdss_dsi_event_handler(struct mdss_panel_data *pdata,
 				  int event, void *arg)
 {
@@ -644,6 +715,12 @@
 		break;
 	case MDSS_EVENT_DSI_CMDLIST_KOFF:
 		mdss_dsi_cmdlist_commit(ctrl_pdata, 1);
+	case MDSS_EVENT_PANEL_UPDATE_FPS:
+		if (arg != NULL) {
+			rc = mdss_dsi_dfps_config(pdata, (int)arg);
+			pr_debug("%s:update fps to = %d\n",
+				__func__, (int)arg);
+		}
 		break;
 	case MDSS_EVENT_CONT_SPLASH_BEGIN:
 		if (ctrl_pdata->off_cmds.link_state == DSI_HS_MODE) {
@@ -952,77 +1029,25 @@
 {
 	struct mipi_panel_info *mipi;
 	int rc, i, len;
-	u8 lanes = 0, bpp;
-	u32 h_period, v_period, dsi_pclk_rate, tmp[9];
+	u32 tmp[9];
 	struct device_node *dsi_ctrl_np = NULL;
 	struct platform_device *ctrl_pdev = NULL;
+	bool dynamic_fps;
 	const char *data;
 	struct mdss_panel_info *pinfo = &(ctrl_pdata->panel_data.panel_info);
 
-	h_period = ((pinfo->lcdc.h_pulse_width)
-			+ (pinfo->lcdc.h_back_porch)
-			+ (pinfo->xres)
-			+ (pinfo->lcdc.h_front_porch));
-
-	v_period = ((pinfo->lcdc.v_pulse_width)
-			+ (pinfo->lcdc.v_back_porch)
-			+ (pinfo->yres)
-			+ (pinfo->lcdc.v_front_porch));
-
-	mipi  = &pinfo->mipi;
 	mipi  = &(pinfo->mipi);
 
 	pinfo->type =
 		((mipi->mode == DSI_VIDEO_MODE)
 			? MIPI_VIDEO_PANEL : MIPI_CMD_PANEL);
 
-	if (mipi->data_lane3)
-		lanes += 1;
-	if (mipi->data_lane2)
-		lanes += 1;
-	if (mipi->data_lane1)
-		lanes += 1;
-	if (mipi->data_lane0)
-		lanes += 1;
-
-
-	if ((mipi->dst_format == DSI_CMD_DST_FORMAT_RGB888)
-	    || (mipi->dst_format == DSI_VIDEO_DST_FORMAT_RGB888)
-	    || (mipi->dst_format == DSI_VIDEO_DST_FORMAT_RGB666_LOOSE))
-		bpp = 3;
-	else if ((mipi->dst_format == DSI_CMD_DST_FORMAT_RGB565)
-		 || (mipi->dst_format == DSI_VIDEO_DST_FORMAT_RGB565))
-		bpp = 2;
-	else
-		bpp = 3;		/* Default format set to RGB888 */
-
-	if (!pinfo->clk_rate) {
-		h_period += pinfo->lcdc.xres_pad;
-		v_period += pinfo->lcdc.yres_pad;
-
-		if (lanes > 0) {
-			pinfo->clk_rate =
-			((h_period * v_period * (mipi->frame_rate) * bpp * 8)
-			   / lanes);
-		} else {
-			pr_err("%s: forcing mdss_dsi lanes to 1\n", __func__);
-			pinfo->clk_rate =
-				(h_period * v_period
-					 * (mipi->frame_rate) * bpp * 8);
-		}
-	}
-	pll_divider_config.clk_rate = pinfo->clk_rate;
-
-	rc = mdss_dsi_clk_div_config(bpp, lanes, &dsi_pclk_rate);
+	rc = mdss_dsi_clk_div_config(pinfo, mipi->frame_rate);
 	if (rc) {
 		pr_err("%s: unable to initialize the clk dividers\n", __func__);
 		return rc;
 	}
 
-	if ((dsi_pclk_rate < 3300000) || (dsi_pclk_rate > 250000000))
-		dsi_pclk_rate = 35000000;
-	mipi->dsi_pclk_rate = dsi_pclk_rate;
-
 	dsi_ctrl_np = of_parse_phandle(pan_node,
 				"qcom,mdss-dsi-panel-controller", 0);
 	if (!dsi_ctrl_np) {
@@ -1088,6 +1113,43 @@
 	ctrl_pdata->shared_pdata.broadcast_enable = of_property_read_bool(
 		pan_node, "qcom,mdss-dsi-panel-broadcast-mode");
 
+	dynamic_fps = of_property_read_bool(pan_node,
+					  "qcom,mdss-dsi-pan-enable-dynamic-fps");
+	if (dynamic_fps) {
+		pinfo->dynamic_fps = true;
+		data = of_get_property(pan_node,
+					  "qcom,mdss-dsi-pan-fps-update", NULL);
+		if (data) {
+			if (!strcmp(data, "dfps_suspend_resume_mode")) {
+				pinfo->dfps_update =
+						DFPS_SUSPEND_RESUME_MODE;
+				pr_debug("%s: dfps mode: suspend/resume\n",
+								__func__);
+			} else if (!strcmp(data,
+					    "dfps_immediate_clk_mode")) {
+				pinfo->dfps_update =
+						DFPS_IMMEDIATE_CLK_UPDATE_MODE;
+				pr_debug("%s: dfps mode: Immediate clk\n",
+								__func__);
+			} else {
+				pr_debug("%s: dfps to default mode\n",
+								__func__);
+				pinfo->dfps_update =
+						DFPS_SUSPEND_RESUME_MODE;
+				pr_debug("%s: dfps mode: suspend/resume\n",
+								__func__);
+			}
+		} else {
+			pr_debug("%s: dfps update mode not configured\n",
+								__func__);
+				pinfo->dynamic_fps =
+								false;
+				pr_debug("%s: dynamic FPS disabled\n",
+								__func__);
+		}
+		pinfo->new_fps = pinfo->mipi.frame_rate;
+	}
+
 	ctrl_pdata->disp_en_gpio = of_get_named_gpio(ctrl_pdev->dev.of_node,
 		"qcom,platform-enable-gpio", 0);
 
@@ -1219,7 +1281,7 @@
 	 * register in mdp driver
 	 */
 
-	ctrl_pdata->pclk_rate = dsi_pclk_rate;
+	ctrl_pdata->pclk_rate = mipi->dsi_pclk_rate;
 	ctrl_pdata->byte_clk_rate = pinfo->clk_rate / 8;
 	pr_debug("%s: pclk=%d, bclk=%d\n", __func__,
 			ctrl_pdata->pclk_rate, ctrl_pdata->byte_clk_rate);
diff --git a/drivers/video/msm/mdss/mdss_dsi.h b/drivers/video/msm/mdss/mdss_dsi.h
index 2d63532..d538743 100644
--- a/drivers/video/msm/mdss/mdss_dsi.h
+++ b/drivers/video/msm/mdss/mdss_dsi.h
@@ -335,6 +335,7 @@
 	int pwm_pmic_gpio;
 	int pwm_lpg_chan;
 	int bklt_max;
+	int new_fps;
 	struct pwm_device *pwm_bl;
 	struct dsi_drv_cm_data shared_pdata;
 	u32 pclk_rate;
@@ -397,8 +398,8 @@
 void mdss_dsi_irq_handler_config(struct mdss_dsi_ctrl_pdata *ctrl_pdata);
 
 void mipi_set_tx_power_mode(int mode, struct mdss_panel_data *pdata);
-int mdss_dsi_clk_div_config(u8 bpp, u8 lanes,
-			    u32 *expected_dsi_pclk);
+int mdss_dsi_clk_div_config(struct mdss_panel_info *panel_info,
+			    int frame_rate);
 int mdss_dsi_clk_init(struct platform_device *pdev,
 		      struct mdss_dsi_ctrl_pdata *ctrl_pdata);
 void mdss_dsi_clk_deinit(struct mdss_dsi_ctrl_pdata *ctrl_pdata);
diff --git a/drivers/video/msm/mdss/mdss_fb.c b/drivers/video/msm/mdss/mdss_fb.c
index 17280ed..793cbd7 100644
--- a/drivers/video/msm/mdss/mdss_fb.c
+++ b/drivers/video/msm/mdss/mdss_fb.c
@@ -623,6 +623,7 @@
 void mdss_fb_set_backlight(struct msm_fb_data_type *mfd, u32 bkl_lvl)
 {
 	struct mdss_panel_data *pdata;
+	int (*update_ad_input)(struct msm_fb_data_type *mfd);
 	u32 temp = bkl_lvl;
 
 	if ((!mfd->panel_power_on || !bl_updated) && !IS_CALIB_MODE_BL(mfd)) {
@@ -654,9 +655,10 @@
 		bl_level_old = temp;
 
 		if (mfd->mdp.update_ad_input) {
+			update_ad_input = mfd->mdp.update_ad_input;
 			mutex_unlock(&mfd->bl_lock);
 			/* Will trigger ad_setup which will grab bl_lock */
-			mfd->mdp.update_ad_input(mfd);
+			update_ad_input(mfd);
 			mutex_lock(&mfd->bl_lock);
 		}
 	}
diff --git a/drivers/video/msm/mdss/mdss_mdp.h b/drivers/video/msm/mdss/mdss_mdp.h
index 351d52b..134ffea 100644
--- a/drivers/video/msm/mdss/mdss_mdp.h
+++ b/drivers/video/msm/mdss/mdss_mdp.h
@@ -153,6 +153,7 @@
 	u32 bus_ib_quota;
 	u32 clk_rate;
 	u32 perf_changed;
+	int force_screen_state;
 
 	struct mdss_data_type *mdata;
 	struct msm_fb_data_type *mfd;
@@ -175,7 +176,7 @@
 					struct mdss_mdp_vsync_handler *);
 	int (*remove_vsync_handler) (struct mdss_mdp_ctl *,
 					struct mdss_mdp_vsync_handler *);
-
+	int (*config_fps_fnc) (struct mdss_mdp_ctl *ctl, int new_fps);
 	void *priv_data;
 	u32 wb_type;
 };
@@ -387,6 +388,9 @@
 	struct mdss_mdp_data free_list[MAX_FREE_LIST_SIZE];
 	int free_list_size;
 	int ad_state;
+
+	u32 splash_mem_addr;
+	u32 splash_mem_size;
 };
 
 struct mdss_mdp_perf_params {
@@ -395,6 +399,17 @@
 	u32 mdp_clk_rate;
 };
 
+/**
+ * enum mdss_screen_state - Screen states that MDP can be forced into
+ *
+ * @MDSS_SCREEN_DEFAULT:	Do not force MDP into any screen state.
+ * @MDSS_SCREEN_FORCE_BLANK:	Force MDP to generate blank color fill screen.
+ */
+enum mdss_screen_state {
+	MDSS_SCREEN_DEFAULT,
+	MDSS_SCREEN_FORCE_BLANK,
+};
+
 #define is_vig_pipe(_pipe_id_) ((_pipe_id_) <= MDSS_MDP_SSPP_VIG2)
 static inline void mdss_mdp_ctl_write(struct mdss_mdp_ctl *ctl,
 				      u32 reg, u32 val)
@@ -420,7 +435,6 @@
 
 irqreturn_t mdss_mdp_isr(int irq, void *ptr);
 int mdss_iommu_attach(struct mdss_data_type *mdata);
-int mdss_mdp_video_copy_splash_screen(struct mdss_panel_data *pdata);
 void mdss_mdp_irq_clear(struct mdss_data_type *mdata,
 		u32 intr_type, u32 intf_num);
 int mdss_mdp_irq_enable(u32 intr_type, u32 intf_num);
@@ -452,8 +466,6 @@
 					struct msm_fb_data_type *mfd);
 int mdss_mdp_video_reconfigure_splash_done(struct mdss_mdp_ctl *ctl);
 int mdss_mdp_cmd_reconfigure_splash_done(struct mdss_mdp_ctl *ctl);
-int mdss_mdp_video_copy_splash_screen(struct mdss_panel_data *pdata);
-void mdss_mdp_ctl_splash_start(struct mdss_panel_data *pdata);
 int mdss_mdp_ctl_splash_finish(struct mdss_mdp_ctl *ctl);
 int mdss_mdp_ctl_setup(struct mdss_mdp_ctl *ctl);
 int mdss_mdp_ctl_split_display_setup(struct mdss_mdp_ctl *ctl,
@@ -583,7 +595,7 @@
 int mdss_mdp_calib_config(struct mdp_calib_config_data *cfg, u32 *copyback);
 int mdss_mdp_calib_config_buffer(struct mdp_calib_config_buffer *cfg,
 						u32 *copyback);
-
+int mdss_mdp_ctl_update_fps(struct mdss_mdp_ctl *ctl, int fps);
 int mdss_mdp_pipe_is_staged(struct mdss_mdp_pipe *pipe);
 int mdss_mdp_writeback_display_commit(struct mdss_mdp_ctl *ctl, void *arg);
 struct mdss_mdp_ctl *mdss_mdp_ctl_mixer_switch(struct mdss_mdp_ctl *ctl,
diff --git a/drivers/video/msm/mdss/mdss_mdp_ctl.c b/drivers/video/msm/mdss/mdss_mdp_ctl.c
index 7b36f2c..bce4248 100644
--- a/drivers/video/msm/mdss/mdss_mdp_ctl.c
+++ b/drivers/video/msm/mdss/mdss_mdp_ctl.c
@@ -212,7 +212,14 @@
 
 	quota = fps * pipe->src.w * src_h;
 	if (pipe->src_fmt->chroma_sample == MDSS_MDP_CHROMA_420)
-		quota = (quota * 3) / 2;
+		/*
+		 * with decimation, chroma is not downsampled, this means we
+		 * need to allocate bw for extra lines that will be fetched
+		 */
+		if (pipe->vert_deci)
+			quota *= 2;
+		else
+			quota = (quota * 3) / 2;
 	else
 		quota *= pipe->src_fmt->bpp;
 
@@ -421,6 +428,7 @@
 	ctl->add_vsync_handler = NULL;
 	ctl->remove_vsync_handler = NULL;
 	ctl->panel_data = NULL;
+	ctl->config_fps_fnc = NULL;
 	mutex_unlock(&mdss_mdp_ctl_lock);
 
 	return 0;
@@ -595,18 +603,6 @@
 	return 0;
 }
 
-void mdss_mdp_ctl_splash_start(struct mdss_panel_data *pdata)
-{
-	switch (pdata->panel_info.type) {
-	case MIPI_VIDEO_PANEL:
-		mdss_mdp_video_copy_splash_screen(pdata);
-		break;
-	case MIPI_CMD_PANEL:
-	default:
-		break;
-	}
-}
-
 int mdss_mdp_ctl_splash_finish(struct mdss_mdp_ctl *ctl)
 {
 	switch (ctl->panel_data->panel_info.type) {
@@ -1220,12 +1216,20 @@
 	u32 mixercfg = 0, blend_color_out = 0, bg_alpha_enable = 0;
 	u32 fg_alpha = 0, bg_alpha = 0;
 	int stage, secure = 0;
+	int screen_state;
+
+	screen_state = ctl->force_screen_state;
 
 	if (!mixer)
 		return -ENODEV;
 
 	pr_debug("setup mixer=%d\n", mixer->num);
 
+	if (screen_state == MDSS_SCREEN_FORCE_BLANK) {
+		mixercfg = MDSS_MDP_LM_BORDER_COLOR;
+		goto update_mixer;
+	}
+
 	pipe = mixer->stage_pipe[MDSS_MDP_STAGE_BASE];
 	if (pipe == NULL) {
 		mixercfg = MDSS_MDP_LM_BORDER_COLOR;
@@ -1333,6 +1337,7 @@
 	if (mixer->cursor_enabled)
 		mixercfg |= MDSS_MDP_LM_CURSOR_OUT;
 
+update_mixer:
 	pr_debug("mixer=%d mixer_cfg=%x\n", mixer->num, mixercfg);
 
 	if (mixer->num == MDSS_MDP_INTF_LAYERMIXER3)
@@ -1594,6 +1599,16 @@
 	return 0;
 }
 
+int mdss_mdp_ctl_update_fps(struct mdss_mdp_ctl *ctl, int fps)
+{
+	int ret = 0;
+
+	if (ctl->config_fps_fnc)
+		ret = ctl->config_fps_fnc(ctl, fps);
+
+	return ret;
+}
+
 int mdss_mdp_display_wakeup_time(struct mdss_mdp_ctl *ctl,
 				 ktime_t *wakeup_time)
 {
@@ -1732,7 +1747,8 @@
 	mixer2_changed = (ctl->mixer_right && ctl->mixer_right->params_changed);
 
 	mdss_mdp_clk_ctrl(MDP_BLOCK_POWER_ON, false);
-	if (mixer1_changed || mixer2_changed) {
+	if (mixer1_changed || mixer2_changed
+			|| ctl->force_screen_state) {
 		perf_update = mdss_mdp_ctl_perf_update(ctl);
 
 		if (ctl->prepare_fnc)
diff --git a/drivers/video/msm/mdss/mdss_mdp_intf_video.c b/drivers/video/msm/mdss/mdss_mdp_intf_video.c
index c78339a..8d4ca2b 100644
--- a/drivers/video/msm/mdss/mdss_mdp_intf_video.c
+++ b/drivers/video/msm/mdss/mdss_mdp_intf_video.c
@@ -16,6 +16,8 @@
 #include <linux/iopoll.h>
 #include <linux/delay.h>
 #include <linux/dma-mapping.h>
+#include <linux/bootmem.h>
+#include <linux/memblock.h>
 
 #include "mdss_fb.h"
 #include "mdss_mdp.h"
@@ -109,7 +111,7 @@
 	return 0;
 }
 
-static int mdss_mdp_video_timegen_setup(struct mdss_mdp_video_ctx *ctx,
+static int mdss_mdp_video_timegen_setup(struct mdss_mdp_ctl *ctl,
 					struct intf_timing_params *p)
 {
 	u32 hsync_period, vsync_period;
@@ -117,7 +119,9 @@
 	u32 active_h_start, active_h_end, active_v_start, active_v_end;
 	u32 den_polarity, hsync_polarity, vsync_polarity;
 	u32 display_hctl, active_hctl, hsync_ctl, polarity_ctl;
+	struct mdss_mdp_video_ctx *ctx;
 
+	ctx = ctl->priv_data;
 	hsync_period = p->hsync_pulse_width + p->h_back_porch +
 			p->width + p->h_front_porch;
 	vsync_period = p->vsync_pulse_width + p->v_back_porch +
@@ -180,7 +184,7 @@
 
 	mdp_video_write(ctx, MDSS_MDP_REG_INTF_HSYNC_CTL, hsync_ctl);
 	mdp_video_write(ctx, MDSS_MDP_REG_INTF_VSYNC_PERIOD_F0,
-			   vsync_period * hsync_period);
+			vsync_period * hsync_period);
 	mdp_video_write(ctx, MDSS_MDP_REG_INTF_VSYNC_PULSE_WIDTH_F0,
 			   p->vsync_pulse_width * hsync_period);
 	mdp_video_write(ctx, MDSS_MDP_REG_INTF_DISPLAY_HCTL, display_hctl);
@@ -440,6 +444,88 @@
 			ctl->underrun_cnt);
 }
 
+static int mdss_mdp_video_config_fps(struct mdss_mdp_ctl *ctl, int new_fps)
+{
+	struct mdss_mdp_video_ctx *ctx;
+	struct mdss_panel_data *pdata;
+	int rc = 0;
+	u32 hsync_period, vsync_period;
+
+	pr_debug("Updating fps for ctl=%d\n", ctl->num);
+
+	ctx = (struct mdss_mdp_video_ctx *) ctl->priv_data;
+	if (!ctx) {
+		pr_err("invalid ctx\n");
+		return -ENODEV;
+	}
+
+	pdata = ctl->panel_data;
+	if (pdata == NULL) {
+		pr_err("%s: Invalid panel data\n", __func__);
+		return -EINVAL;
+	}
+
+	if (!pdata->panel_info.dynamic_fps) {
+		pr_err("%s: Dynamic fps not enabled for this panel\n",
+						__func__);
+		return -EINVAL;
+	}
+
+	vsync_period = mdss_panel_get_vtotal(&pdata->panel_info);
+	hsync_period = mdss_panel_get_htotal(&pdata->panel_info);
+
+	if (pdata->panel_info.dfps_update
+			!= DFPS_SUSPEND_RESUME_MODE) {
+		if (pdata->panel_info.dfps_update
+				== DFPS_IMMEDIATE_CLK_UPDATE_MODE) {
+			if (!ctx->timegen_en) {
+				pr_err("TG is OFF. DFPS mode invalid\n");
+				return -EINVAL;
+			}
+			ctl->force_screen_state = MDSS_SCREEN_FORCE_BLANK;
+			mdss_mdp_display_commit(ctl, NULL);
+			mdss_mdp_display_wait4comp(ctl);
+			mdp_video_write(ctx,
+					MDSS_MDP_REG_INTF_TIMING_ENGINE_EN, 0);
+			/*
+			 * Need to wait for atleast one vsync time for proper
+			 * TG OFF before doing changes on interfaces
+			 */
+			msleep(20);
+			rc = mdss_mdp_ctl_intf_event(ctl,
+						MDSS_EVENT_PANEL_UPDATE_FPS,
+						(void *)new_fps);
+			WARN(rc, "intf %d panel fps update error (%d)\n",
+							ctl->intf_num, rc);
+			mdp_video_write(ctx,
+					MDSS_MDP_REG_INTF_TIMING_ENGINE_EN, 1);
+			/*
+			 * Add memory barrier to make sure the MDP Video
+			 * mode engine is enabled before next frame is sent
+			 */
+			mb();
+			ctl->force_screen_state = MDSS_SCREEN_DEFAULT;
+			mdss_mdp_display_commit(ctl, NULL);
+			mdss_mdp_display_wait4comp(ctl);
+		} else {
+			pr_err("intf %d panel, unknown FPS mode\n",
+							ctl->intf_num);
+			return -EINVAL;
+		}
+	} else {
+		rc = mdss_mdp_ctl_intf_event(ctl,
+					MDSS_EVENT_PANEL_UPDATE_FPS,
+					(void *)new_fps);
+		WARN(rc, "intf %d panel fps update error (%d)\n",
+						ctl->intf_num, rc);
+	}
+
+	return rc;
+}
+
+
+
+
 static int mdss_mdp_video_display(struct mdss_mdp_ctl *ctl, void *arg)
 {
 	struct mdss_mdp_video_ctx *ctx;
@@ -492,67 +578,13 @@
 	return 0;
 }
 
-int mdss_mdp_video_copy_splash_screen(struct mdss_panel_data *pdata)
-{
-	void *virt = NULL;
-	unsigned long bl_fb_addr = 0;
-	unsigned long *bl_fb_addr_va;
-	unsigned long  pipe_addr, pipe_src_size;
-	u32 height, width, rgb_size, bpp;
-	size_t size;
-	static struct ion_handle *ihdl;
-	struct ion_client *iclient = mdss_get_ionclient();
-	static ion_phys_addr_t phys;
-
-	pipe_addr = MDSS_MDP_REG_SSPP_OFFSET(3) +
-		MDSS_MDP_REG_SSPP_SRC0_ADDR;
-	pipe_src_size =
-		MDSS_MDP_REG_SSPP_OFFSET(3) + MDSS_MDP_REG_SSPP_SRC_SIZE;
-
-	bpp        = 3;
-	rgb_size   = MDSS_MDP_REG_READ(pipe_src_size);
-	bl_fb_addr = MDSS_MDP_REG_READ(pipe_addr);
-
-	height = (rgb_size >> 16) & 0xffff;
-	width  = rgb_size & 0xffff;
-	size = PAGE_ALIGN(height * width * bpp);
-	pr_debug("%s:%d splash_height=%d splash_width=%d Buffer size=%d\n",
-			__func__, __LINE__, height, width, size);
-
-	ihdl = ion_alloc(iclient, size, SZ_1M,
-			ION_HEAP(ION_QSECOM_HEAP_ID), 0);
-	if (IS_ERR_OR_NULL(ihdl)) {
-		pr_err("unable to alloc fbmem from ion (%p)\n", ihdl);
-		return -ENOMEM;
-	}
-
-	pdata->panel_info.splash_ihdl = ihdl;
-
-	virt = ion_map_kernel(iclient, ihdl);
-	ion_phys(iclient, ihdl, &phys, &size);
-
-	pr_debug("%s %d Allocating %u bytes at 0x%lx (%pa phys)\n",
-			__func__, __LINE__, size,
-			(unsigned long int)virt, &phys);
-
-	bl_fb_addr_va = (unsigned long *)ioremap(bl_fb_addr, size);
-	memcpy(virt, bl_fb_addr_va, size);
-	iounmap(bl_fb_addr_va);
-
-	MDSS_MDP_REG_WRITE(pipe_addr, phys);
-	MDSS_MDP_REG_WRITE(MDSS_MDP_REG_CTL_FLUSH + MDSS_MDP_REG_CTL_OFFSET(0),
-			0x48);
-
-	return 0;
-}
-
 int mdss_mdp_video_reconfigure_splash_done(struct mdss_mdp_ctl *ctl)
 {
-	struct ion_client *iclient = mdss_get_ionclient();
 	struct mdss_panel_data *pdata;
 	int ret = 0, off;
 	int mdss_mdp_rev = MDSS_MDP_REG_READ(MDSS_MDP_REG_HW_VERSION);
 	int mdss_v2_intf_off = 0;
+	struct mdss_overlay_private *mdp5_data = mfd_to_mdp5_data(ctl->mfd);
 
 	off = 0;
 
@@ -578,7 +610,12 @@
 			mdss_v2_intf_off, 0);
 	/* wait for 1 VSYNC for the pipe to be unstaged */
 	msleep(20);
-	ion_free(iclient, pdata->panel_info.splash_ihdl);
+
+	/* Give back the reserved memory to the system */
+	memblock_free(mdp5_data->splash_mem_addr, mdp5_data->splash_mem_size);
+	free_bootmem_late(mdp5_data->splash_mem_addr,
+				 mdp5_data->splash_mem_size);
+
 	ret = mdss_mdp_ctl_intf_event(ctl, MDSS_EVENT_CONT_SPLASH_FINISH,
 			NULL);
 	mdss_mdp_clk_ctrl(MDP_BLOCK_POWER_OFF, false);
@@ -654,7 +691,7 @@
 			pinfo->bpp);
 	itp.vsync_pulse_width = pinfo->lcdc.v_pulse_width;
 
-	if (mdss_mdp_video_timegen_setup(ctx, &itp)) {
+	if (mdss_mdp_video_timegen_setup(ctl, &itp)) {
 		pr_err("unable to get timing parameters\n");
 		return -EINVAL;
 	}
@@ -666,6 +703,7 @@
 	ctl->read_line_cnt_fnc = mdss_mdp_video_line_count;
 	ctl->add_vsync_handler = mdss_mdp_video_add_vsync_handler;
 	ctl->remove_vsync_handler = mdss_mdp_video_remove_vsync_handler;
+	ctl->config_fps_fnc = mdss_mdp_video_config_fps;
 
 	return 0;
 }
diff --git a/drivers/video/msm/mdss/mdss_mdp_overlay.c b/drivers/video/msm/mdss/mdss_mdp_overlay.c
index 8e805da..5f0d646 100644
--- a/drivers/video/msm/mdss/mdss_mdp_overlay.c
+++ b/drivers/video/msm/mdss/mdss_mdp_overlay.c
@@ -22,6 +22,7 @@
 #include <linux/uaccess.h>
 #include <linux/delay.h>
 #include <linux/msm_mdp.h>
+#include <linux/memblock.h>
 
 #include <mach/iommu_domains.h>
 #include <mach/event_timer.h>
@@ -45,6 +46,7 @@
 static int mdss_mdp_overlay_free_fb_pipe(struct msm_fb_data_type *mfd);
 static int mdss_mdp_overlay_fb_parse_dt(struct msm_fb_data_type *mfd);
 static int mdss_mdp_overlay_off(struct msm_fb_data_type *mfd);
+static int mdss_mdp_overlay_splash_parse_dt(struct msm_fb_data_type *mfd);
 
 static int mdss_mdp_overlay_get(struct msm_fb_data_type *mfd,
 				struct mdp_overlay *req)
@@ -827,7 +829,7 @@
 int mdss_mdp_overlay_kickoff(struct msm_fb_data_type *mfd)
 {
 	struct mdss_overlay_private *mdp5_data = mfd_to_mdp5_data(mfd);
-	struct mdss_mdp_pipe *pipe, *next;
+	struct mdss_mdp_pipe *pipe;
 	struct mdss_mdp_ctl *ctl = mfd_to_ctl(mfd);
 	struct mdss_mdp_ctl *tmp;
 	int ret;
@@ -847,8 +849,7 @@
 		return ret;
 	}
 
-	list_for_each_entry_safe(pipe, next, &mdp5_data->pipes_used,
-			used_list) {
+	list_for_each_entry(pipe, &mdp5_data->pipes_used, used_list) {
 		struct mdss_mdp_data *buf;
 		/*
 		 * When external is connected and no dedicated wfd is present,
@@ -886,12 +887,6 @@
 			pipe->params_changed++;
 			buf = &pipe->front_buf;
 		} else if (!pipe->params_changed) {
-			if (pipe->mixer && !mdss_mdp_pipe_is_staged(pipe) &&
-			    !list_empty(&pipe->used_list)) {
-				list_del_init(&pipe->used_list);
-				list_add(&pipe->cleanup_list,
-					&mdp5_data->pipes_cleanup);
-			}
 			continue;
 		} else if (pipe->front_buf.num_planes) {
 			buf = &pipe->front_buf;
@@ -1454,14 +1449,9 @@
 	if (!ctl->add_vsync_handler || !ctl->remove_vsync_handler)
 		return -EOPNOTSUPP;
 
-	rc = mutex_lock_interruptible(&ctl->lock);
-	if (rc)
-		return rc;
-
 	if (!ctl->power_on) {
 		pr_debug("fb%d vsync pending first update en=%d\n",
 				mfd->index, en);
-		mutex_unlock(&ctl->lock);
 		return -EPERM;
 	}
 
@@ -1474,11 +1464,99 @@
 		rc = ctl->remove_vsync_handler(ctl, &ctl->vsync_handler);
 	mdss_mdp_clk_ctrl(MDP_BLOCK_POWER_OFF, false);
 
-	mutex_unlock(&ctl->lock);
-
 	return rc;
 }
 
+static ssize_t dynamic_fps_sysfs_rda_dfps(struct device *dev,
+	struct device_attribute *attr, char *buf)
+{
+	ssize_t ret;
+	struct mdss_panel_data *pdata;
+	struct fb_info *fbi = dev_get_drvdata(dev);
+	struct msm_fb_data_type *mfd = (struct msm_fb_data_type *)fbi->par;
+	struct mdss_overlay_private *mdp5_data = mfd_to_mdp5_data(mfd);
+
+	if (!mdp5_data->ctl || !mdp5_data->ctl->power_on)
+		return 0;
+
+	pdata = dev_get_platdata(&mfd->pdev->dev);
+	if (!pdata) {
+		pr_err("no panel connected for fb%d\n", mfd->index);
+		return -ENODEV;
+	}
+
+	ret = snprintf(buf, PAGE_SIZE, "%d\n",
+		       pdata->panel_info.mipi.frame_rate);
+	pr_debug("%s: '%d'\n", __func__,
+		pdata->panel_info.mipi.frame_rate);
+
+	return ret;
+} /* dynamic_fps_sysfs_rda_dfps */
+
+static ssize_t dynamic_fps_sysfs_wta_dfps(struct device *dev,
+	struct device_attribute *attr, const char *buf, size_t count)
+{
+	int dfps, rc = 0;
+	struct mdss_panel_data *pdata;
+	struct fb_info *fbi = dev_get_drvdata(dev);
+	struct msm_fb_data_type *mfd = (struct msm_fb_data_type *)fbi->par;
+	struct mdss_overlay_private *mdp5_data = mfd_to_mdp5_data(mfd);
+
+	rc = kstrtoint(buf, 10, &dfps);
+	if (rc) {
+		pr_err("%s: kstrtoint failed. rc=%d\n", __func__, rc);
+		return rc;
+	}
+
+	if (!mdp5_data->ctl || !mdp5_data->ctl->power_on)
+		return 0;
+
+	pdata = dev_get_platdata(&mfd->pdev->dev);
+	if (!pdata) {
+		pr_err("no panel connected for fb%d\n", mfd->index);
+		return -ENODEV;
+	}
+
+	if (dfps == pdata->panel_info.mipi.frame_rate) {
+		pr_debug("%s: FPS is already %d\n",
+			__func__, dfps);
+		return count;
+	}
+
+	if (dfps < 30) {
+		pr_err("Unsupported FPS. Configuring to min_fps = 30\n");
+		dfps = 30;
+		rc = mdss_mdp_ctl_update_fps(mdp5_data->ctl, dfps);
+	} else if (dfps > 60) {
+		pr_err("Unsupported FPS. Configuring to max_fps = 60\n");
+		dfps = 60;
+		rc = mdss_mdp_ctl_update_fps(mdp5_data->ctl, dfps);
+	} else {
+		rc = mdss_mdp_ctl_update_fps(mdp5_data->ctl, dfps);
+	}
+	if (!rc) {
+		pr_info("%s: configured to '%d' FPS\n", __func__, dfps);
+	} else {
+		pr_err("Failed to configure '%d' FPS. rc = %d\n",
+							dfps, rc);
+		return rc;
+	}
+	pdata->panel_info.new_fps = dfps;
+	return count;
+} /* dynamic_fps_sysfs_wta_dfps */
+
+
+static DEVICE_ATTR(dynamic_fps, S_IRUGO | S_IWUSR, dynamic_fps_sysfs_rda_dfps,
+	dynamic_fps_sysfs_wta_dfps);
+
+static struct attribute *dynamic_fps_fs_attrs[] = {
+	&dev_attr_dynamic_fps.attr,
+	NULL,
+};
+static struct attribute_group dynamic_fps_fs_attrs_group = {
+	.attrs = dynamic_fps_fs_attrs,
+};
+
 static ssize_t mdss_mdp_vsync_show_event(struct device *dev,
 		struct device_attribute *attr, char *buf)
 {
@@ -2244,7 +2322,6 @@
 	if (pdata->panel_info.cont_splash_enabled) {
 		mdss_mdp_clk_ctrl(MDP_BLOCK_POWER_ON, false);
 		mdss_mdp_footswitch_ctrl_splash(1);
-		mdss_mdp_ctl_splash_start(pdata);
 	}
 	return 0;
 }
@@ -2306,6 +2383,15 @@
 		goto init_fail;
 	}
 
+	if (mfd->panel_info->type == MIPI_VIDEO_PANEL) {
+		rc = sysfs_create_group(&dev->kobj,
+			&dynamic_fps_fs_attrs_group);
+		if (rc) {
+			pr_err("Error dfps sysfs creation ret=%d\n", rc);
+			goto init_fail;
+		}
+	}
+
 	pm_runtime_set_suspended(&mfd->pdev->dev);
 	pm_runtime_enable(&mfd->pdev->dev);
 
@@ -2322,8 +2408,48 @@
 	return rc;
 }
 
+static __ref int mdss_mdp_overlay_splash_parse_dt(struct msm_fb_data_type *mfd)
+{
+	struct platform_device *pdev = mfd->pdev;
+	struct mdss_overlay_private *mdp5_mdata = mfd_to_mdp5_data(mfd);
+	int len = 0, rc = 0;
+	u32 offsets[2];
+
+	of_find_property(pdev->dev.of_node, "qcom,memblock-reserve", &len);
+
+	if (len < 1) {
+		pr_debug("mem reservation for splash screen fb not present\n");
+		rc = -EINVAL;
+		goto error;
+	}
+
+	len = len/sizeof(u32);
+
+	rc = of_property_read_u32_array(pdev->dev.of_node,
+			"qcom,memblock-reserve", offsets, len);
+	if (rc) {
+		pr_debug("Error reading mem reserve settings for fb\n");
+		goto error;
+	}
+
+	if (!memblock_is_reserved(offsets[0])) {
+		pr_debug("failed to reserve memory for fb splash\n");
+		rc = -EINVAL;
+		goto error;
+	}
+
+	mdp5_mdata->splash_mem_addr = offsets[0];
+	mdp5_mdata->splash_mem_size = offsets[1];
+	pr_debug("memaddr=%x size=%x\n", mdp5_mdata->splash_mem_addr,
+		mdp5_mdata->splash_mem_size);
+
+error:
+	return rc;
+}
+
 static int mdss_mdp_overlay_fb_parse_dt(struct msm_fb_data_type *mfd)
 {
+	int rc = 0;
 	struct platform_device *pdev = mfd->pdev;
 	struct mdss_overlay_private *mdp5_mdata = mfd_to_mdp5_data(mfd);
 
@@ -2334,5 +2460,13 @@
 			pdev->name);
 	}
 
-	return 0;
+	rc = mdss_mdp_overlay_splash_parse_dt(mfd);
+	if (rc && mfd->panel_info->cont_splash_enabled) {
+		pr_err("No rsvd mem found in DT for splash screen\n");
+	} else {
+		pr_debug("Mem reservation not reqd if cont splash diasbled\n");
+		rc = 0;
+	}
+
+	return rc;
 }
diff --git a/drivers/video/msm/mdss/mdss_mdp_pipe.c b/drivers/video/msm/mdss/mdss_mdp_pipe.c
index 3f75053..16ea7dc 100644
--- a/drivers/video/msm/mdss/mdss_mdp_pipe.c
+++ b/drivers/video/msm/mdss/mdss_mdp_pipe.c
@@ -173,21 +173,39 @@
 			return rc;
 		pr_debug("BWC SMP strides ystride0=%x ystride1=%x\n",
 			ps.ystride[0], ps.ystride[1]);
-	} else if (mdata->has_decimation && pipe->src_fmt->is_yuv) {
-		ps.num_planes = 2;
-		ps.ystride[0] = width;
-		ps.ystride[1] = ps.ystride[0];
 	} else {
 		rc = mdss_mdp_get_plane_sizes(pipe->src_fmt->format,
 			width, pipe->src.h, &ps, 0);
 		if (rc)
 			return rc;
 
-		if (pipe->mixer && pipe->mixer->rotator_mode)
+		if (pipe->mixer && pipe->mixer->rotator_mode) {
 			rot_mode = 1;
-		else if (ps.num_planes == 1)
+		} else if (ps.num_planes == 1) {
 			ps.ystride[0] = MAX_BPP *
 				max(pipe->mixer->width, width);
+		} else if (mdata->has_decimation) {
+			/*
+			 * when decimation block is used, all chroma planes
+			 * are fetched on a single SMP plane for chroma pixels
+			 */
+			if (ps.num_planes == 3) {
+				ps.num_planes = 2;
+				ps.ystride[1] += ps.ystride[2];
+			}
+
+			/*
+			 * To avoid quailty loss, MDP does one less decimation
+			 * on chroma components if they are subsampled.
+			 * Account for this to have enough SMPs for latency
+			 */
+			switch (pipe->src_fmt->chroma_sample) {
+			case MDSS_MDP_CHROMA_H2V1:
+			case MDSS_MDP_CHROMA_420:
+				ps.ystride[1] <<= 1;
+				break;
+			}
+		}
 	}
 
 	nlines = pipe->bwc_mode ? 1 : 2;
diff --git a/drivers/video/msm/mdss/mdss_mdp_pp.c b/drivers/video/msm/mdss/mdss_mdp_pp.c
index 0b64870..09b789b 100644
--- a/drivers/video/msm/mdss/mdss_mdp_pp.c
+++ b/drivers/video/msm/mdss/mdss_mdp_pp.c
@@ -2836,7 +2836,7 @@
 		return -EHOSTDOWN;
 	}
 	if (mixer_num > MDSS_AD_MAX_MIXERS) {
-		pr_warn("too many mixers, not supported, %d", mixer_num);
+		pr_debug("too many mixers, not supported, %d", mixer_num);
 		return ret;
 	}
 
@@ -3195,6 +3195,7 @@
 	struct mdss_mdp_ctl *ctl = mfd_to_ctl(mfd);
 	struct msm_fb_data_type *bl_mfd;
 	char __iomem *base;
+	u32 temp;
 	u32 bypass = MDSS_PP_AD_BYPASS_DEF, bl;
 
 	ret = mdss_mdp_get_ad(mfd, &ad);
@@ -3263,6 +3264,21 @@
 		pp_ad_init_write(ad);
 	}
 
+	/* update ad screen size if it has changed since last configuration */
+	if (mfd->panel_info->type == WRITEBACK_PANEL &&
+		(ad->init.frame_w != ctl->width ||
+			ad->init.frame_h != ctl->height)) {
+		pr_debug("changing from %dx%d to %dx%d", ad->init.frame_w,
+							ad->init.frame_h,
+							ctl->width,
+							ctl->height);
+		ad->init.frame_w = ctl->width;
+		ad->init.frame_h = ctl->height;
+		temp = ad->init.frame_w << 16;
+		temp |= ad->init.frame_h & 0xFFFF;
+		writel_relaxed(temp, base + MDSS_MDP_REG_AD_FRAME_SIZE);
+	}
+
 	if ((ad->sts & PP_STS_ENABLE) && PP_AD_STATE_IS_READY(ad->state)) {
 		bypass = 0;
 		ret = 1;
diff --git a/drivers/video/msm/mdss/mdss_mdp_wb.c b/drivers/video/msm/mdss/mdss_mdp_wb.c
index 72288c2..a9f3e35 100644
--- a/drivers/video/msm/mdss/mdss_mdp_wb.c
+++ b/drivers/video/msm/mdss/mdss_mdp_wb.c
@@ -675,7 +675,8 @@
 		break;
 	case MSMFB_WRITEBACK_QUEUE_BUFFER:
 		if (!copy_from_user(&data, arg, sizeof(data))) {
-			ret = mdss_mdp_wb_queue(mfd, arg, false);
+			ret = mdss_mdp_wb_queue(mfd, &data, false);
+			ret = copy_to_user(arg, &data, sizeof(data));
 		} else {
 			pr_err("wb queue buf failed on copy_from_user\n");
 			ret = -EFAULT;
@@ -683,7 +684,8 @@
 		break;
 	case MSMFB_WRITEBACK_DEQUEUE_BUFFER:
 		if (!copy_from_user(&data, arg, sizeof(data))) {
-			ret = mdss_mdp_wb_dequeue(mfd, arg);
+			ret = mdss_mdp_wb_dequeue(mfd, &data);
+			ret = copy_to_user(arg, &data, sizeof(data));
 		} else {
 			pr_err("wb dequeue buf failed on copy_from_user\n");
 			ret = -EFAULT;
diff --git a/drivers/video/msm/mdss/mdss_panel.h b/drivers/video/msm/mdss/mdss_panel.h
index d05ca66..c7a219b 100644
--- a/drivers/video/msm/mdss/mdss_panel.h
+++ b/drivers/video/msm/mdss/mdss_panel.h
@@ -112,6 +112,7 @@
  *				display state from boot loader to panel driver.
  *				The event handler will enable the panel and
  *				vote for the display clocks.
+ * @MDSS_EVENT_PANEL_UPDATE_FPS: Event to update the frame rate of the panel.
  * @MDSS_EVENT_FB_REGISTERED:	Called after fb dev driver has been registered,
  *				panel driver gets ptr to struct fb_info which
  *				holds fb dev information.
@@ -132,6 +133,7 @@
 	MDSS_EVENT_CHECK_PARAMS,
 	MDSS_EVENT_CONT_SPLASH_BEGIN,
 	MDSS_EVENT_CONT_SPLASH_FINISH,
+	MDSS_EVENT_PANEL_UPDATE_FPS,
 	MDSS_EVENT_FB_REGISTERED,
 	MDSS_EVENT_PANEL_CLK_CTRL,
 	MDSS_EVENT_DSI_CMDLIST_KOFF,
@@ -214,6 +216,11 @@
 	char hw_vsync_mode;
 };
 
+enum dynamic_fps_update {
+	DFPS_SUSPEND_RESUME_MODE,
+	DFPS_IMMEDIATE_CLK_UPDATE_MODE,
+};
+
 enum lvds_mode {
 	LVDS_SINGLE_CHANNEL_MODE,
 	LVDS_DUAL_CHANNEL_MODE,
@@ -269,6 +276,9 @@
 	int pwm_lpg_chan;
 	int pwm_period;
 	u32 mode_gpio_state;
+	bool dynamic_fps;
+	char dfps_update;
+	int new_fps;
 
 	u32 cont_splash_enabled;
 	struct ion_handle *splash_ihdl;
@@ -354,6 +364,20 @@
 			pinfo->lcdc.v_pulse_width;
 }
 
+/*
+ * mdss_panel_get_htotal() - return panel horizontal width
+ * @pinfo:	Pointer to panel info containing all panel information
+ *
+ * Returns the total width of the panel including any blanking regions
+ * which are not visible to user but used for calculations.
+ */
+static inline int mdss_panel_get_htotal(struct mdss_panel_info *pinfo)
+{
+	return pinfo->xres + pinfo->lcdc.h_back_porch +
+			pinfo->lcdc.h_front_porch +
+			pinfo->lcdc.h_pulse_width;
+}
+
 int mdss_register_panel(struct platform_device *pdev,
 	struct mdss_panel_data *pdata);
 
diff --git a/drivers/video/msm/mdss/msm_mdss_io_8974.c b/drivers/video/msm/mdss/msm_mdss_io_8974.c
index d24daab..f7ea557 100644
--- a/drivers/video/msm/mdss/msm_mdss_io_8974.c
+++ b/drivers/video/msm/mdss/msm_mdss_io_8974.c
@@ -106,13 +106,64 @@
 #define PREF_DIV_RATIO 27
 struct dsiphy_pll_divider_config pll_divider_config;
 
-int mdss_dsi_clk_div_config(u8 bpp, u8 lanes,
-			    u32 *expected_dsi_pclk)
+int mdss_dsi_clk_div_config(struct mdss_panel_info *panel_info,
+			    int frame_rate)
 {
 	u32 fb_divider, rate, vco;
 	u32 div_ratio = 0;
 	u32 pll_analog_posDiv = 1;
+	u32 h_period, v_period;
+	u32 dsi_pclk_rate;
+	u8 lanes = 0, bpp;
 	struct dsi_clk_mnd_table const *mnd_entry = mnd_table;
+
+	if (panel_info->mipi.data_lane3)
+		lanes += 1;
+	if (panel_info->mipi.data_lane2)
+		lanes += 1;
+	if (panel_info->mipi.data_lane1)
+		lanes += 1;
+	if (panel_info->mipi.data_lane0)
+		lanes += 1;
+
+	switch (panel_info->mipi.dst_format) {
+	case DSI_CMD_DST_FORMAT_RGB888:
+	case DSI_VIDEO_DST_FORMAT_RGB888:
+	case DSI_VIDEO_DST_FORMAT_RGB666_LOOSE:
+		bpp = 3;
+		break;
+	case DSI_CMD_DST_FORMAT_RGB565:
+	case DSI_VIDEO_DST_FORMAT_RGB565:
+		bpp = 2;
+		break;
+	default:
+		bpp = 3;	/* Default format set to RGB888 */
+		break;
+	}
+
+	h_period = mdss_panel_get_htotal(panel_info);
+	v_period = mdss_panel_get_vtotal(panel_info);
+
+	if ((frame_rate !=
+	     panel_info->mipi.frame_rate) ||
+	    (!panel_info->clk_rate)) {
+		h_period += panel_info->lcdc.xres_pad;
+		v_period += panel_info->lcdc.yres_pad;
+
+		if (lanes > 0) {
+			panel_info->clk_rate =
+			((h_period * v_period *
+			  frame_rate * bpp * 8)
+			   / lanes);
+		} else {
+			pr_err("%s: forcing mdss_dsi lanes to 1\n", __func__);
+			panel_info->clk_rate =
+				(h_period * v_period * frame_rate * bpp * 8);
+		}
+	}
+	pll_divider_config.clk_rate = panel_info->clk_rate;
+
+
 	if (pll_divider_config.clk_rate == 0)
 		pll_divider_config.clk_rate = 454000000;
 
@@ -176,9 +227,13 @@
 		dsi_pclk.n = mnd_entry->pclk_n;
 		dsi_pclk.d = mnd_entry->pclk_d;
 	}
-	*expected_dsi_pclk = (((pll_divider_config.clk_rate) * lanes)
+	dsi_pclk_rate = (((pll_divider_config.clk_rate) * lanes)
 				      / (8 * bpp));
 
+	if ((dsi_pclk_rate < 3300000) || (dsi_pclk_rate > 250000000))
+		dsi_pclk_rate = 35000000;
+	panel_info->mipi.dsi_pclk_rate = dsi_pclk_rate;
+
 	return 0;
 }
 
diff --git a/include/linux/msm_audio_acdb.h b/include/linux/msm_audio_acdb.h
index e8ca1cd..853899e 100644
--- a/include/linux/msm_audio_acdb.h
+++ b/include/linux/msm_audio_acdb.h
@@ -63,6 +63,10 @@
 			(AUDIO_MAX_COMMON_IOCTL_NUM+28), unsigned)
 #define AUDIO_DEREGISTER_VOCPROC_VOL_TABLE	_IOW(AUDIO_IOCTL_MAGIC, \
 			(AUDIO_MAX_COMMON_IOCTL_NUM+29), unsigned)
+#define AUDIO_SET_HW_DELAY_RX	_IOW(AUDIO_IOCTL_MAGIC, \
+			(AUDIO_MAX_COMMON_IOCTL_NUM+30), struct hw_delay)
+#define AUDIO_SET_HW_DELAY_TX	_IOW(AUDIO_IOCTL_MAGIC, \
+			(AUDIO_MAX_COMMON_IOCTL_NUM+31), struct hw_delay)
 #define	AUDIO_MAX_ACDB_IOCTL	(AUDIO_MAX_COMMON_IOCTL_NUM+40)
 
 /* ACDB structures */
@@ -96,6 +100,11 @@
 	int status;
 };
 
+struct hw_delay {
+	uint32_t num_entries;
+	void *delay_info;
+};
+
 /* For Real-Time Audio Calibration */
 #define AUDIO_GET_RTAC_ADM_INFO		_IOR(AUDIO_IOCTL_MAGIC, \
 			(AUDIO_MAX_ACDB_IOCTL+1), unsigned)
diff --git a/include/linux/qpnp/qpnp-adc.h b/include/linux/qpnp/qpnp-adc.h
index 13bef66..6e711c2 100644
--- a/include/linux/qpnp/qpnp-adc.h
+++ b/include/linux/qpnp/qpnp-adc.h
@@ -615,6 +615,21 @@
 	QPNP_ADC_TM_CH_SELECT_NONE
 };
 
+/**
+ * Channel index for the corresponding index to qpnp_adc_tm_channel_selec
+ */
+enum qpnp_adc_tm_channel_num {
+	QPNP_ADC_TM_CHAN0 = 0,
+	QPNP_ADC_TM_CHAN1,
+	QPNP_ADC_TM_CHAN2,
+	QPNP_ADC_TM_CHAN3,
+	QPNP_ADC_TM_CHAN4,
+	QPNP_ADC_TM_CHAN5,
+	QPNP_ADC_TM_CHAN6,
+	QPNP_ADC_TM_CHAN7,
+	QPNP_ADC_TM_CHAN_NONE
+};
+
 enum qpnp_comp_scheme_type {
 	COMP_ID_GF = 0,
 	COMP_ID_SMIC,
diff --git a/include/linux/security.h b/include/linux/security.h
index 673afbb..b62f396 100644
--- a/include/linux/security.h
+++ b/include/linux/security.h
@@ -1381,6 +1381,11 @@
 struct security_operations {
 	char name[SECURITY_NAME_MAX + 1];
 
+	int (*binder_set_context_mgr) (struct task_struct *mgr);
+	int (*binder_transaction) (struct task_struct *from, struct task_struct *to);
+	int (*binder_transfer_binder) (struct task_struct *from, struct task_struct *to);
+	int (*binder_transfer_file) (struct task_struct *from, struct task_struct *to, struct file *file);
+
 	int (*ptrace_access_check) (struct task_struct *child, unsigned int mode);
 	int (*ptrace_traceme) (struct task_struct *parent);
 	int (*capget) (struct task_struct *target,
@@ -1664,6 +1669,10 @@
 
 
 /* Security operations */
+int security_binder_set_context_mgr(struct task_struct *mgr);
+int security_binder_transaction(struct task_struct *from, struct task_struct *to);
+int security_binder_transfer_binder(struct task_struct *from, struct task_struct *to);
+int security_binder_transfer_file(struct task_struct *from, struct task_struct *to, struct file *file);
 int security_ptrace_access_check(struct task_struct *child, unsigned int mode);
 int security_ptrace_traceme(struct task_struct *parent);
 int security_capget(struct task_struct *target,
@@ -1842,6 +1851,26 @@
 	return 0;
 }
 
+static inline int security_binder_set_context_mgr(struct task_struct *mgr)
+{
+	return 0;
+}
+
+static inline int security_binder_transaction(struct task_struct *from, struct task_struct *to)
+{
+	return 0;
+}
+
+static inline int security_binder_transfer_binder(struct task_struct *from, struct task_struct *to)
+{
+	return 0;
+}
+
+static inline int security_binder_transfer_file(struct task_struct *from, struct task_struct *to, struct file *file)
+{
+	return 0;
+}
+
 static inline int security_ptrace_access_check(struct task_struct *child,
 					     unsigned int mode)
 {
diff --git a/include/linux/vmalloc.h b/include/linux/vmalloc.h
index 6071e91..663bc05 100644
--- a/include/linux/vmalloc.h
+++ b/include/linux/vmalloc.h
@@ -134,6 +134,7 @@
 extern struct vm_struct *vmlist;
 extern __init void vm_area_add_early(struct vm_struct *vm);
 extern __init void vm_area_register_early(struct vm_struct *vm, size_t align);
+extern __init int vm_area_check_early(struct vm_struct *vm);
 
 #ifdef CONFIG_SMP
 # ifdef CONFIG_MMU
diff --git a/include/media/msm_cam_sensor.h b/include/media/msm_cam_sensor.h
index 540fd2c..326e8bf 100644
--- a/include/media/msm_cam_sensor.h
+++ b/include/media/msm_cam_sensor.h
@@ -231,6 +231,7 @@
 struct msm_camera_i2c_reg_array {
 	uint16_t reg_addr;
 	uint16_t reg_data;
+	uint32_t delay;
 };
 
 struct msm_camera_i2c_reg_setting {
diff --git a/include/sound/apr_audio-v2.h b/include/sound/apr_audio-v2.h
index fb58d12..bbda72e 100644
--- a/include/sound/apr_audio-v2.h
+++ b/include/sound/apr_audio-v2.h
@@ -1968,6 +1968,14 @@
 	 */
 } __packed;
 
+#define AFE_PARAM_ID_DEVICE_HW_DELAY     0x00010243
+#define AFE_API_VERSION_DEVICE_HW_DELAY  0x1
+
+struct afe_param_id_device_hw_delay_cfg {
+	uint32_t    device_hw_delay_minor_version;
+	uint32_t    delay_in_us;
+} __packed;
+
 union afe_port_config {
 	struct afe_param_id_pcm_cfg               pcm;
 	struct afe_param_id_i2s_cfg               i2s;
@@ -1976,6 +1984,7 @@
 	struct afe_param_id_rt_proxy_port_cfg     rtproxy;
 	struct afe_param_id_internal_bt_fm_cfg    int_bt_fm;
 	struct afe_param_id_pseudo_port_cfg       pseudo_port;
+	struct afe_param_id_device_hw_delay_cfg   hw_delay;
 } __packed;
 
 struct afe_audioif_config_command_no_payload {
@@ -2481,6 +2490,8 @@
 
 #define ASM_STREAM_POSTPROC_TOPO_ID_DEFAULT 0x00010BE4
 
+#define ASM_STREAM_POSTPROC_TOPO_ID_NONE 0x00010C68
+
 #define ASM_MEDIA_FMT_EVRCB_FS 0x00010BEF
 
 #define ASM_MEDIA_FMT_EVRCWB_FS 0x00010BF0
@@ -4298,7 +4309,6 @@
 struct asm_aac_dual_mono_mapping_param {
 	struct apr_hdr							hdr;
 	struct asm_stream_cmd_set_encdec_param	encdec;
-	struct asm_enc_cfg_blk_param_v2			encblk;
 	u16    left_channel_sce;
 	u16    right_channel_sce;
 
diff --git a/kernel/smp.c b/kernel/smp.c
index 2f8b10e..3cbd828 100644
--- a/kernel/smp.c
+++ b/kernel/smp.c
@@ -310,20 +310,20 @@
 	 */
 	this_cpu = get_cpu();
 
-	/*
-	 * Can deadlock when called with interrupts disabled.
-	 * We allow cpu's that are not yet online though, as no one else can
-	 * send smp call function interrupt to this cpu and as such deadlocks
-	 * can't happen.
-	 */
-	WARN_ON_ONCE(cpu_online(this_cpu) && irqs_disabled()
-		     && !oops_in_progress);
-
 	if (cpu == this_cpu) {
 		local_irq_save(flags);
 		func(info);
 		local_irq_restore(flags);
 	} else {
+		/*
+		 * Can deadlock when called with interrupts disabled.
+		 * We allow cpu's that are not yet online though, as no one else
+		 * can send smp call function interrupt to this cpu and as such
+		 * deadlocks can't happen.
+		 */
+		WARN_ON_ONCE(cpu_online(this_cpu) && irqs_disabled()
+			     && !oops_in_progress);
+
 		if ((unsigned)cpu < nr_cpu_ids && cpu_online(cpu)) {
 			struct call_single_data *data = &d;
 
@@ -408,20 +408,21 @@
 	unsigned long flags;
 
 	this_cpu = get_cpu();
-	/*
-	 * Can deadlock when called with interrupts disabled.
-	 * We allow cpu's that are not yet online though, as no one else can
-	 * send smp call function interrupt to this cpu and as such deadlocks
-	 * can't happen.
-	 */
-	WARN_ON_ONCE(cpu_online(smp_processor_id()) && wait && irqs_disabled()
-		     && !oops_in_progress);
 
 	if (cpu == this_cpu) {
 		local_irq_save(flags);
 		data->func(data->info);
 		local_irq_restore(flags);
 	} else {
+		/*
+		 * Can deadlock when called with interrupts disabled.
+		 * We allow cpu's that are not yet online though, as no one else
+		 * can send smp call function interrupt to this cpu and as such
+		 * deadlocks can't happen.
+		 */
+		WARN_ON_ONCE(cpu_online(smp_processor_id()) && wait
+			     && irqs_disabled() && !oops_in_progress);
+
 		csd_lock(data);
 		generic_exec_single(cpu, data, wait);
 	}
diff --git a/kernel/watchdog.c b/kernel/watchdog.c
index df30ee0..818920f 100644
--- a/kernel/watchdog.c
+++ b/kernel/watchdog.c
@@ -127,7 +127,7 @@
 /* Commands for resetting the watchdog */
 static void __touch_watchdog(void)
 {
-	int this_cpu = smp_processor_id();
+	int this_cpu = raw_smp_processor_id();
 
 	__this_cpu_write(watchdog_touch_ts, get_timestamp(this_cpu));
 }
diff --git a/mm/bootmem.c b/mm/bootmem.c
index 0131170..3db5820 100644
--- a/mm/bootmem.c
+++ b/mm/bootmem.c
@@ -154,7 +154,7 @@
  * down, but we are still initializing the system.  Pages are given directly
  * to the page allocator, no bootmem metadata is updated because it is gone.
  */
-void __init free_bootmem_late(unsigned long addr, unsigned long size)
+void free_bootmem_late(unsigned long addr, unsigned long size)
 {
 	unsigned long cursor, end;
 
diff --git a/mm/memory.c b/mm/memory.c
index b6ab040..acc9aa6 100644
--- a/mm/memory.c
+++ b/mm/memory.c
@@ -58,6 +58,7 @@
 #include <linux/swapops.h>
 #include <linux/elf.h>
 #include <linux/gfp.h>
+#include <linux/bug.h>
 
 #include <asm/io.h>
 #include <asm/pgalloc.h>
@@ -705,6 +706,9 @@
 	if (vma->vm_file && vma->vm_file->f_op)
 		print_symbol(KERN_ALERT "vma->vm_file->f_op->mmap: %s\n",
 				(unsigned long)vma->vm_file->f_op->mmap);
+
+	BUG_ON(PANIC_CORRUPTION);
+
 	dump_stack();
 	add_taint(TAINT_BAD_PAGE);
 }
diff --git a/mm/page_alloc.c b/mm/page_alloc.c
index 9cc2f45..46ccd2f 100644
--- a/mm/page_alloc.c
+++ b/mm/page_alloc.c
@@ -745,7 +745,7 @@
 	local_irq_restore(flags);
 }
 
-void __meminit __free_pages_bootmem(struct page *page, unsigned int order)
+void __free_pages_bootmem(struct page *page, unsigned int order)
 {
 	unsigned int nr_pages = 1 << order;
 	unsigned int loop;
diff --git a/mm/vmalloc.c b/mm/vmalloc.c
index 5065adb..a2ab2ab 100644
--- a/mm/vmalloc.c
+++ b/mm/vmalloc.c
@@ -1116,7 +1116,31 @@
 	return mem;
 }
 EXPORT_SYMBOL(vm_map_ram);
+/**
+ * vm_area_check_early - check if vmap area is already mapped
+ * @vm: vm_struct to be checked
+ *
+ * This function is used to check if the vmap area has been
+ * mapped already. @vm->addr, @vm->size and @vm->flags should
+ * contain proper values.
+ *
+ */
+int __init vm_area_check_early(struct vm_struct *vm)
+{
+	struct vm_struct *tmp, **p;
 
+	BUG_ON(vmap_initialized);
+	for (p = &vmlist; (tmp = *p) != NULL; p = &tmp->next) {
+		if (tmp->addr >= vm->addr) {
+			if (tmp->addr < vm->addr + vm->size)
+				return 1;
+		} else {
+			if (tmp->addr + tmp->size > vm->addr)
+				return 1;
+		}
+	}
+	return 0;
+}
 /**
  * vm_area_add_early - add vmap area early during boot
  * @vm: vm_struct to add
@@ -1392,15 +1416,26 @@
  */
 struct vm_struct *get_vm_area(unsigned long size, unsigned long flags)
 {
+#ifdef CONFIG_ENABLE_VMALLOC_SAVING
+	return __get_vm_area_node(size, 1, flags, PAGE_OFFSET, VMALLOC_END,
+				-1, GFP_KERNEL, __builtin_return_address(0));
+#else
 	return __get_vm_area_node(size, 1, flags, VMALLOC_START, VMALLOC_END,
 				-1, GFP_KERNEL, __builtin_return_address(0));
+#endif
+
 }
 
 struct vm_struct *get_vm_area_caller(unsigned long size, unsigned long flags,
 				const void *caller)
 {
-	return __get_vm_area_node(size, 1, flags, VMALLOC_START, VMALLOC_END,
+#ifdef CONFIG_ENABLE_VMALLOC_SAVING
+	return __get_vm_area_node(size, 1, flags, PAGE_OFFSET, VMALLOC_END,
 						-1, GFP_KERNEL, caller);
+#else
+	return __get_vm_area_node(size, 1, flags, VMALLOC_START, VMALLOC_END,
+				-1, GFP_KERNEL, __builtin_return_address(0));
+#endif
 }
 
 /**
diff --git a/security/capability.c b/security/capability.c
index 5bb21b1..fc991bc 100644
--- a/security/capability.c
+++ b/security/capability.c
@@ -12,6 +12,26 @@
 
 #include <linux/security.h>
 
+static int cap_binder_set_context_mgr(struct task_struct *mgr)
+{
+	return 0;
+}
+
+static int cap_binder_transaction(struct task_struct *from, struct task_struct *to)
+{
+	return 0;
+}
+
+static int cap_binder_transfer_binder(struct task_struct *from, struct task_struct *to)
+{
+	return 0;
+}
+
+static int cap_binder_transfer_file(struct task_struct *from, struct task_struct *to, struct file *file)
+{
+	return 0;
+}
+
 static int cap_syslog(int type)
 {
 	return 0;
@@ -877,6 +897,10 @@
 
 void __init security_fixup_ops(struct security_operations *ops)
 {
+	set_to_cap_if_null(ops, binder_set_context_mgr);
+	set_to_cap_if_null(ops, binder_transaction);
+	set_to_cap_if_null(ops, binder_transfer_binder);
+	set_to_cap_if_null(ops, binder_transfer_file);
 	set_to_cap_if_null(ops, ptrace_access_check);
 	set_to_cap_if_null(ops, ptrace_traceme);
 	set_to_cap_if_null(ops, capget);
diff --git a/security/security.c b/security/security.c
index bf619ff..cecd55e 100644
--- a/security/security.c
+++ b/security/security.c
@@ -130,6 +130,26 @@
 
 /* Security operations */
 
+int security_binder_set_context_mgr(struct task_struct *mgr)
+{
+	return security_ops->binder_set_context_mgr(mgr);
+}
+
+int security_binder_transaction(struct task_struct *from, struct task_struct *to)
+{
+	return security_ops->binder_transaction(from, to);
+}
+
+int security_binder_transfer_binder(struct task_struct *from, struct task_struct *to)
+{
+	return security_ops->binder_transfer_binder(from, to);
+}
+
+int security_binder_transfer_file(struct task_struct *from, struct task_struct *to, struct file *file)
+{
+	return security_ops->binder_transfer_file(from, to, file);
+}
+
 int security_ptrace_access_check(struct task_struct *child, unsigned int mode)
 {
 	return security_ops->ptrace_access_check(child, mode);
diff --git a/security/selinux/hooks.c b/security/selinux/hooks.c
index d85b793..b28b7eb 100644
--- a/security/selinux/hooks.c
+++ b/security/selinux/hooks.c
@@ -1818,6 +1818,67 @@
 
 /* Hook functions begin here. */
 
+static int selinux_binder_set_context_mgr(struct task_struct *mgr)
+{
+	u32 mysid = current_sid();
+	u32 mgrsid = task_sid(mgr);
+
+	return avc_has_perm(mysid, mgrsid, SECCLASS_BINDER, BINDER__SET_CONTEXT_MGR, NULL);
+}
+
+static int selinux_binder_transaction(struct task_struct *from, struct task_struct *to)
+{
+	u32 mysid = current_sid();
+	u32 fromsid = task_sid(from);
+	u32 tosid = task_sid(to);
+	int rc;
+
+	if (mysid != fromsid) {
+		rc = avc_has_perm(mysid, fromsid, SECCLASS_BINDER, BINDER__IMPERSONATE, NULL);
+		if (rc)
+			return rc;
+	}
+
+	return avc_has_perm(fromsid, tosid, SECCLASS_BINDER, BINDER__CALL, NULL);
+}
+
+static int selinux_binder_transfer_binder(struct task_struct *from, struct task_struct *to)
+{
+	u32 fromsid = task_sid(from);
+	u32 tosid = task_sid(to);
+	return avc_has_perm(fromsid, tosid, SECCLASS_BINDER, BINDER__TRANSFER, NULL);
+}
+
+static int selinux_binder_transfer_file(struct task_struct *from, struct task_struct *to, struct file *file)
+{
+	u32 sid = task_sid(to);
+	struct file_security_struct *fsec = file->f_security;
+	struct inode *inode = file->f_path.dentry->d_inode;
+	struct inode_security_struct *isec = inode->i_security;
+	struct common_audit_data ad;
+	struct selinux_audit_data sad = {0,};
+	int rc;
+
+	COMMON_AUDIT_DATA_INIT(&ad, PATH);
+	ad.u.path = file->f_path;
+	ad.selinux_audit_data = &sad;
+
+	if (sid != fsec->sid) {
+		rc = avc_has_perm(sid, fsec->sid,
+				  SECCLASS_FD,
+				  FD__USE,
+				  &ad);
+		if (rc)
+			return rc;
+	}
+
+	if (unlikely(IS_PRIVATE(inode)))
+		return 0;
+
+	return avc_has_perm(sid, isec->sid, isec->sclass, file_to_av(file),
+			    &ad);
+}
+
 static int selinux_ptrace_access_check(struct task_struct *child,
 				     unsigned int mode)
 {
@@ -5523,6 +5584,11 @@
 static struct security_operations selinux_ops = {
 	.name =				"selinux",
 
+	.binder_set_context_mgr =	selinux_binder_set_context_mgr,
+	.binder_transaction =		selinux_binder_transaction,
+	.binder_transfer_binder =	selinux_binder_transfer_binder,
+	.binder_transfer_file =		selinux_binder_transfer_file,
+
 	.ptrace_access_check =		selinux_ptrace_access_check,
 	.ptrace_traceme =		selinux_ptrace_traceme,
 	.capget =			selinux_capget,
diff --git a/security/selinux/include/classmap.h b/security/selinux/include/classmap.h
index b8c5372..4a4a9ae 100644
--- a/security/selinux/include/classmap.h
+++ b/security/selinux/include/classmap.h
@@ -149,5 +149,6 @@
 	{ "kernel_service", { "use_as_override", "create_files_as", NULL } },
 	{ "tun_socket",
 	  { COMMON_SOCK_PERMS, NULL } },
+	{ "binder", { "impersonate", "call", "set_context_mgr", "transfer", NULL } },
 	{ NULL }
   };
diff --git a/sound/soc/codecs/msm8x10-wcd.c b/sound/soc/codecs/msm8x10-wcd.c
index fb115e7..4e3df21 100644
--- a/sound/soc/codecs/msm8x10-wcd.c
+++ b/sound/soc/codecs/msm8x10-wcd.c
@@ -1136,9 +1136,6 @@
 			  MSM8X10_WCD_A_CDC_IIR1_GAIN_B4_CTL,
 			  -84,	40, digital_gain),
 
-	SOC_SINGLE("MICBIAS1 CAPLESS Switch",
-		   MSM8X10_WCD_A_MICB_1_CTL, 4, 1, 1),
-
 	SOC_ENUM("TX1 HPF cut off", cf_dec1_enum),
 	SOC_ENUM("TX2 HPF cut off", cf_dec2_enum),
 
@@ -1431,13 +1428,8 @@
 		snd_soc_update_bits(codec,
 				    MSM8X10_WCD_A_CDC_ANA_CLK_CTL,
 				    0x20, 0x20);
-	} else {
+	} else
 		wcd8x10->adc_count--;
-		if (!wcd8x10->adc_count)
-			snd_soc_update_bits(codec,
-					    MSM8X10_WCD_A_CDC_ANA_CLK_CTL,
-					    0x20, 0x0);
-	}
 }
 
 static int msm8x10_wcd_codec_enable_adc(struct snd_soc_dapm_widget *w,
@@ -1577,15 +1569,20 @@
 	struct snd_kcontrol *kcontrol, int event)
 {
 	struct snd_soc_codec *codec = w->codec;
+	struct msm8x10_wcd_priv *msm8x10_wcd = snd_soc_codec_get_drvdata(codec);
 	u16 micb_int_reg;
 	char *internal1_text = "Internal1";
 	char *internal2_text = "Internal2";
 	char *internal3_text = "Internal3";
+	enum wcd9xxx_notify_event e_post_off, e_pre_on, e_post_on;
 
 	dev_dbg(codec->dev, "%s %d\n", __func__, event);
 	switch (w->reg) {
 	case MSM8X10_WCD_A_MICB_1_CTL:
 		micb_int_reg = MSM8X10_WCD_A_MICB_1_INT_RBIAS;
+		e_pre_on = WCD9XXX_EVENT_PRE_MICBIAS_1_ON;
+		e_post_on = WCD9XXX_EVENT_POST_MICBIAS_1_ON;
+		e_post_off = WCD9XXX_EVENT_POST_MICBIAS_1_OFF;
 		break;
 	default:
 		dev_err(codec->dev,
@@ -1596,17 +1593,28 @@
 
 	switch (event) {
 	case SND_SOC_DAPM_PRE_PMU:
+		/* Let MBHC module know micbias is about to turn ON */
+		wcd9xxx_resmgr_notifier_call(&msm8x10_wcd->resmgr, e_pre_on);
+
 		if (strnstr(w->name, internal1_text, 30))
 			snd_soc_update_bits(codec, micb_int_reg, 0x80, 0x80);
 		else if (strnstr(w->name, internal2_text, 30))
 			snd_soc_update_bits(codec, micb_int_reg, 0x10, 0x10);
 		else if (strnstr(w->name, internal3_text, 30))
 			snd_soc_update_bits(codec, micb_int_reg, 0x2, 0x2);
+
+		/* Always pull up TxFe for TX2 to Micbias */
+		snd_soc_update_bits(codec, micb_int_reg, 0x04, 0x04);
 		break;
 	case SND_SOC_DAPM_POST_PMU:
 		usleep_range(20000, 20100);
+		/* Let MBHC module know so micbias is on */
+		wcd9xxx_resmgr_notifier_call(&msm8x10_wcd->resmgr, e_post_on);
 		break;
 	case SND_SOC_DAPM_POST_PMD:
+		/* Let MBHC module know so micbias switch to be off */
+		wcd9xxx_resmgr_notifier_call(&msm8x10_wcd->resmgr, e_post_off);
+
 		if (strnstr(w->name, internal1_text, 30))
 			snd_soc_update_bits(codec, micb_int_reg, 0x80, 0x00);
 		else if (strnstr(w->name, internal2_text, 30))
@@ -1614,6 +1622,8 @@
 		else if (strnstr(w->name, internal3_text, 30))
 			snd_soc_update_bits(codec, micb_int_reg, 0x2, 0x0);
 
+		/* Disable pull up TxFe for TX2 to Micbias */
+		snd_soc_update_bits(codec, micb_int_reg, 0x04, 0x00);
 		break;
 	}
 	return 0;
@@ -2647,6 +2657,48 @@
 	snd_soc_update_bits(codec, MSM8X10_WCD_A_CDC_TOP_CLK_CTL, 0x10, 0x10);
 }
 
+static void msm8x10_wcd_mbhc_txfe(struct snd_soc_codec *codec, bool on)
+{
+	snd_soc_update_bits(codec, MSM8X10_WCD_A_TX_7_MBHC_EN_ATEST_CTRL,
+			    0x80, on ? 0x80 : 0x00);
+}
+
+static int msm8x10_wcd_enable_ext_mb_source(struct snd_soc_codec *codec,
+	bool turn_on)
+{
+	int ret = 0;
+
+	if (turn_on)
+		ret = snd_soc_dapm_force_enable_pin(&codec->dapm,
+				"MICBIAS_REGULATOR");
+	else
+		ret = snd_soc_dapm_disable_pin(&codec->dapm,
+				"MICBIAS_REGULATOR");
+
+	snd_soc_dapm_sync(&codec->dapm);
+
+	if (ret)
+		dev_err(codec->dev, "%s: Failed to %s external micbias source\n",
+			__func__, turn_on ? "enable" : "disabled");
+	else
+		dev_dbg(codec->dev, "%s: %s external micbias source\n",
+			 __func__, turn_on ? "Enabled" : "Disabled");
+
+	return ret;
+}
+
+static void msm8x10_wcd_micb_internal(struct snd_soc_codec *codec, bool on)
+{
+	snd_soc_update_bits(codec, MSM8X10_WCD_A_MICB_1_INT_RBIAS,
+			    0x1C, on ? 0x14 : 0x00);
+}
+
+static void msm8x10_wcd_enable_mb_vddio(struct snd_soc_codec *codec, bool on)
+{
+	snd_soc_update_bits(codec, MSM8X10_WCD_A_MICB_CFILT_1_CTL,
+			    0x40, on ? 0x40 : 0x00);
+}
+
 static const struct wcd9xxx_mbhc_cb mbhc_cb = {
 	.enable_mux_bias_block = msm8x10_wcd_enable_mux_bias_block,
 	.cfilt_fast_mode = msm8x10_wcd_put_cfilt_fast_mode,
@@ -2657,6 +2709,10 @@
 	.free_irq = msm8x10_wcd_free_irq,
 	.get_cdc_type = msm8x10_wcd_get_cdc_type,
 	.enable_clock_gate = msm8x10_wcd_mbhc_clk_gate,
+	.enable_mbhc_txfe = msm8x10_wcd_mbhc_txfe,
+	.enable_mb_source = msm8x10_wcd_enable_ext_mb_source,
+	.setup_int_rbias = msm8x10_wcd_micb_internal,
+	.pull_mb_to_vddio = msm8x10_wcd_enable_mb_vddio,
 };
 
 static void delayed_hs_detect_fn(struct work_struct *work)
@@ -2766,6 +2822,7 @@
 	struct msm8x10_wcd *msm8x10_wcd;
 	struct wcd9xxx_core_resource *core_res;
 	int i, ret = 0;
+	struct msm8x10_wcd_pdata *pdata;
 
 	dev_dbg(codec->dev, "%s()\n", __func__);
 
@@ -2811,6 +2868,17 @@
 	msm8x10_wcd_bringup(codec);
 	msm8x10_wcd_codec_init_reg(codec);
 	msm8x10_wcd_update_reg_defaults(codec);
+
+	pdata = dev_get_platdata(msm8x10_wcd->dev);
+	if (!pdata) {
+		dev_err(msm8x10_wcd->dev, "%s: platform data not found\n",
+			__func__);
+	}
+
+	/* update micbias capless mode */
+	snd_soc_update_bits(codec, MSM8X10_WCD_A_MICB_1_CTL, 0x10,
+			    pdata->micbias.bias1_cap_mode << 4);
+
 	msm8x10_wcd_priv->on_demand_list[ON_DEMAND_CP].supply =
 				wcd8x10_wcd_codec_find_regulator(
 				codec->control_data,
diff --git a/sound/soc/codecs/wcd9xxx-mbhc.c b/sound/soc/codecs/wcd9xxx-mbhc.c
index a9e0c43..c2d626b 100644
--- a/sound/soc/codecs/wcd9xxx-mbhc.c
+++ b/sound/soc/codecs/wcd9xxx-mbhc.c
@@ -184,9 +184,11 @@
 	return mbhc->polling_active;
 }
 
-static void wcd9xxx_turn_onoff_override(struct snd_soc_codec *codec, bool on)
+static void wcd9xxx_turn_onoff_override(struct wcd9xxx_mbhc *mbhc, bool on)
 {
-	snd_soc_update_bits(codec, WCD9XXX_A_CDC_MBHC_B1_CTL, 0x04, on << 2);
+	struct snd_soc_codec *codec = mbhc->codec;
+	snd_soc_update_bits(codec, WCD9XXX_A_CDC_MBHC_B1_CTL,
+			    0x04, on ? 0x04 : 0x00);
 }
 
 /* called under codec_resource_lock acquisition */
@@ -296,7 +298,7 @@
 		override = snd_soc_read(codec, WCD9XXX_A_CDC_MBHC_B1_CTL) &
 			   0x04;
 		if (!override)
-			wcd9xxx_turn_onoff_override(codec, true);
+			wcd9xxx_turn_onoff_override(mbhc, true);
 		/* Adjust threshold if Mic Bias voltage changes */
 		if (d->micb_mv != VDDIO_MICBIAS_MV) {
 			cfilt_k_val = __wcd9xxx_resmgr_get_k_val(mbhc,
@@ -338,7 +340,7 @@
 		snd_soc_update_bits(codec, mbhc->mbhc_bias_regs.mbhc_reg,
 				    0x10, 0x00);
 		if (!override)
-			wcd9xxx_turn_onoff_override(codec, false);
+			wcd9xxx_turn_onoff_override(mbhc, false);
 		if (restartpolling)
 			wcd9xxx_start_hs_polling(mbhc);
 
@@ -1070,6 +1072,9 @@
 	}
 
 	btn_det = WCD9XXX_MBHC_CAL_BTN_DET_PTR(mbhc->mbhc_cfg->calibration);
+	/* Enable external voltage source to micbias if present */
+	if (mbhc->mbhc_cb && mbhc->mbhc_cb->enable_mb_source)
+		mbhc->mbhc_cb->enable_mb_source(codec, true);
 
 	/*
 	 * Request BG and clock.
@@ -1184,6 +1189,8 @@
 
 static void wcd9xxx_cleanup_hs_polling(struct wcd9xxx_mbhc *mbhc)
 {
+
+	pr_debug("%s: enter\n", __func__);
 	WCD9XXX_BCL_ASSERT_LOCKED(mbhc->resmgr);
 
 	wcd9xxx_shutdown_hs_removal_detect(mbhc);
@@ -1194,8 +1201,13 @@
 	wcd9xxx_resmgr_put_bandgap(mbhc->resmgr, WCD9XXX_BANDGAP_MBHC_MODE);
 	WCD9XXX_BG_CLK_UNLOCK(mbhc->resmgr);
 
+	/* Disable external voltage source to micbias if present */
+	if (mbhc->mbhc_cb && mbhc->mbhc_cb->enable_mb_source)
+		mbhc->mbhc_cb->enable_mb_source(mbhc->codec, false);
+
 	mbhc->polling_active = false;
 	mbhc->mbhc_state = MBHC_STATE_NONE;
+	pr_debug("%s: leave\n", __func__);
 }
 
 /* called under codec_resource_lock acquisition */
@@ -1209,6 +1221,12 @@
 static void wcd9xxx_onoff_vddio_switch(struct wcd9xxx_mbhc *mbhc, bool on)
 {
 	pr_debug("%s: vddio %d\n", __func__, on);
+
+	if (mbhc->mbhc_cb && mbhc->mbhc_cb->pull_mb_to_vddio) {
+		mbhc->mbhc_cb->pull_mb_to_vddio(mbhc->codec, on);
+		goto exit;
+	}
+
 	if (on) {
 		snd_soc_update_bits(mbhc->codec, mbhc->mbhc_bias_regs.mbhc_reg,
 				    1 << 7, 1 << 7);
@@ -1220,6 +1238,12 @@
 		snd_soc_update_bits(mbhc->codec, mbhc->mbhc_bias_regs.mbhc_reg,
 				    1 << 7, 0);
 	}
+
+exit:
+	/*
+	 * Wait for the micbias to settle down to vddio
+	 * when the micbias to vddio switch is enabled.
+	 */
 	if (on)
 		usleep_range(10000, 10000);
 }
@@ -1988,7 +2012,6 @@
 static void wcd9xxx_mbhc_decide_swch_plug(struct wcd9xxx_mbhc *mbhc)
 {
 	enum wcd9xxx_mbhc_plug_type plug_type;
-	struct snd_soc_codec *codec = mbhc->codec;
 	bool current_source_enable;
 
 	pr_debug("%s: enter\n", __func__);
@@ -2002,9 +2025,9 @@
 		plug_type = wcd9xxx_codec_cs_get_plug_type(mbhc, false);
 		wcd9xxx_turn_onoff_current_source(mbhc, false, false);
 	} else {
-		wcd9xxx_turn_onoff_override(codec, true);
+		wcd9xxx_turn_onoff_override(mbhc, true);
 		plug_type = wcd9xxx_codec_get_plug_type(mbhc, true);
-		wcd9xxx_turn_onoff_override(codec, false);
+		wcd9xxx_turn_onoff_override(mbhc, false);
 	}
 
 	if (wcd9xxx_swch_level_remove(mbhc)) {
@@ -2015,13 +2038,16 @@
 
 	if (plug_type == PLUG_TYPE_INVALID ||
 	    plug_type == PLUG_TYPE_GND_MIC_SWAP) {
+		wcd9xxx_cleanup_hs_polling(mbhc);
 		wcd9xxx_schedule_hs_detect_plug(mbhc,
 						&mbhc->correct_plug_swch);
 	} else if (plug_type == PLUG_TYPE_HEADPHONE) {
 		wcd9xxx_report_plug(mbhc, 1, SND_JACK_HEADPHONE);
+		wcd9xxx_cleanup_hs_polling(mbhc);
 		wcd9xxx_schedule_hs_detect_plug(mbhc,
 						&mbhc->correct_plug_swch);
 	} else if (plug_type == PLUG_TYPE_HIGH_HPH) {
+		wcd9xxx_cleanup_hs_polling(mbhc);
 		wcd9xxx_schedule_hs_detect_plug(mbhc,
 						&mbhc->correct_plug_swch);
 	} else {
@@ -2643,7 +2669,7 @@
 		wcd9xxx_turn_onoff_current_source(mbhc, true,
 						  false);
 	else
-		wcd9xxx_turn_onoff_override(codec, true);
+		wcd9xxx_turn_onoff_override(mbhc, true);
 
 	timeout = jiffies + msecs_to_jiffies(HS_DETECT_PLUG_TIME_MS);
 	while (!time_after(jiffies, timeout)) {
@@ -2728,7 +2754,7 @@
 				wcd9xxx_turn_onoff_current_source(mbhc, false,
 								  false);
 			else
-				wcd9xxx_turn_onoff_override(codec, false);
+				wcd9xxx_turn_onoff_override(mbhc, false);
 			/*
 			 * The valid plug also includes PLUG_TYPE_GND_MIC_SWAP
 			 */
@@ -2754,7 +2780,7 @@
 	if (!correction && current_source_enable)
 		wcd9xxx_turn_onoff_current_source(mbhc, false, highhph);
 	else if (!correction)
-		wcd9xxx_turn_onoff_override(codec, false);
+		wcd9xxx_turn_onoff_override(mbhc, false);
 
 	wcd9xxx_onoff_ext_mclk(mbhc, false);
 
@@ -2853,7 +2879,7 @@
 			snd_soc_update_bits(codec, WCD9XXX_A_CDC_MBHC_CLK_CTL,
 					    0x08, 0x00);
 			/* Turn off override */
-			wcd9xxx_turn_onoff_override(codec, false);
+			wcd9xxx_turn_onoff_override(mbhc, false);
 		}
 	}
 
@@ -3443,7 +3469,13 @@
 	 * LDOH and CFILT are already configured during pdata handling.
 	 * Only need to make sure CFILT and bandgap are in Fast mode.
 	 * Need to restore defaults once calculation is done.
+	 *
+	 * In case when Micbias is powered by external source, request
+	 * turn on the external voltage source for Calibration.
 	 */
+	if (mbhc->mbhc_cb && mbhc->mbhc_cb->enable_mb_source)
+		mbhc->mbhc_cb->enable_mb_source(codec, true);
+
 	cfilt_mode = snd_soc_read(codec, mbhc->mbhc_bias_regs.cfilt_ctl);
 	if (mbhc->mbhc_cb && mbhc->mbhc_cb->cfilt_fast_mode)
 		mbhc->mbhc_cb->cfilt_fast_mode(codec, mbhc);
@@ -3563,6 +3595,9 @@
 				    0x80, 0x80);
 	usleep_range(100, 100);
 
+	if (mbhc->mbhc_cb && mbhc->mbhc_cb->enable_mb_source)
+		mbhc->mbhc_cb->enable_mb_source(codec, false);
+
 	wcd9xxx_enable_irq(mbhc->resmgr->core_res, WCD9XXX_IRQ_MBHC_POTENTIAL);
 	wcd9xxx_turn_onoff_rel_detection(codec, true);
 
@@ -3923,6 +3958,18 @@
 		0x40, WCD9XXX_CFILT_FAST_MODE);
 
 	/*
+	 * setup internal micbias if codec uses internal micbias for
+	 * headset detection
+	 */
+	if (mbhc->mbhc_cfg->use_int_rbias) {
+		if (mbhc->mbhc_cb && mbhc->mbhc_cb->setup_int_rbias)
+			mbhc->mbhc_cb->setup_int_rbias(codec, true);
+		else
+			pr_info("%s: internal bias is requested but codec did not provide callback\n",
+				__func__);
+	}
+
+	/*
 	 * If codec has specific clock gating for MBHC,
 	 * remove the clock gate
 	 */
@@ -4047,6 +4094,15 @@
 	return cfilt;
 }
 
+static void wcd9xxx_enable_mbhc_txfe(struct wcd9xxx_mbhc *mbhc, bool on)
+{
+	if (mbhc->mbhc_cb && mbhc->mbhc_cb->enable_mbhc_txfe)
+		mbhc->mbhc_cb->enable_mbhc_txfe(mbhc->codec, on);
+	else
+		snd_soc_update_bits(mbhc->codec, WCD9XXX_A_TX_7_MBHC_TEST_CTL,
+				    0x40, on ? 0x40 : 0x00);
+}
+
 static int wcd9xxx_event_notify(struct notifier_block *self, unsigned long val,
 				void *data)
 {
@@ -4064,14 +4120,22 @@
 	case WCD9XXX_EVENT_PRE_MICBIAS_2_ON:
 	case WCD9XXX_EVENT_PRE_MICBIAS_3_ON:
 	case WCD9XXX_EVENT_PRE_MICBIAS_4_ON:
-		if (mbhc->mbhc_cfg->micbias == wcd9xxx_event_to_micbias(event))
+		if (mbhc->mbhc_cfg && mbhc->mbhc_cfg->micbias ==
+		    wcd9xxx_event_to_micbias(event)) {
 			wcd9xxx_switch_micbias(mbhc, 0);
+			/*
+			 * Enable MBHC TxFE whenever  micbias is
+			 * turned ON and polling is active
+			 */
+			if (mbhc->polling_active)
+				wcd9xxx_enable_mbhc_txfe(mbhc, true);
+		}
 		break;
 	case WCD9XXX_EVENT_POST_MICBIAS_1_ON:
 	case WCD9XXX_EVENT_POST_MICBIAS_2_ON:
 	case WCD9XXX_EVENT_POST_MICBIAS_3_ON:
 	case WCD9XXX_EVENT_POST_MICBIAS_4_ON:
-		if (mbhc->mbhc_cfg->micbias ==
+		if (mbhc->mbhc_cfg && mbhc->mbhc_cfg->micbias ==
 		    wcd9xxx_event_to_micbias(event) &&
 		    wcd9xxx_mbhc_polling(mbhc)) {
 			/* if polling is on, restart it */
@@ -4083,11 +4147,17 @@
 	case WCD9XXX_EVENT_POST_MICBIAS_2_OFF:
 	case WCD9XXX_EVENT_POST_MICBIAS_3_OFF:
 	case WCD9XXX_EVENT_POST_MICBIAS_4_OFF:
-		if (mbhc->mbhc_cfg->micbias ==
-		    wcd9xxx_event_to_micbias(event) &&
-		    (mbhc->event_state &
-		     (1 << MBHC_EVENT_PA_HPHL | 1 << MBHC_EVENT_PA_HPHR)))
-			wcd9xxx_switch_micbias(mbhc, 1);
+		if (mbhc->mbhc_cfg && mbhc->mbhc_cfg->micbias ==
+		    wcd9xxx_event_to_micbias(event)) {
+			if (mbhc->event_state &
+			   (1 << MBHC_EVENT_PA_HPHL | 1 << MBHC_EVENT_PA_HPHR))
+				wcd9xxx_switch_micbias(mbhc, 1);
+			/*
+			 * Disable MBHC TxFE, in case it was enabled
+			 * earlier when micbias was enabled.
+			 */
+			wcd9xxx_enable_mbhc_txfe(mbhc, false);
+		}
 		break;
 	/* PA usage change */
 	case WCD9XXX_EVENT_PRE_HPHL_PA_ON:
@@ -4264,7 +4334,7 @@
 	wcd9xxx_resmgr_get_clk_block(mbhc->resmgr, WCD9XXX_CLK_RCO);
 	WCD9XXX_BG_CLK_UNLOCK(mbhc->resmgr);
 
-	wcd9xxx_turn_onoff_override(codec, true);
+	wcd9xxx_turn_onoff_override(mbhc, true);
 	pr_debug("%s: Setting impedance detection\n", __func__);
 
 	/* Codec specific setup for L0, R0, L1 and R1 measurements */
@@ -4315,7 +4385,7 @@
 	wcd9xxx_resmgr_put_clk_block(mbhc->resmgr, WCD9XXX_CLK_RCO);
 	WCD9XXX_BG_CLK_UNLOCK(mbhc->resmgr);
 
-	wcd9xxx_turn_onoff_override(codec, false);
+	wcd9xxx_turn_onoff_override(mbhc, false);
 	mbhc->mbhc_cb->compute_impedance(l, r, zl, zr);
 
 	pr_debug("%s: L0: 0x%x(%d), L1: 0x%x(%d), L2: 0x%x(%d)\n",
diff --git a/sound/soc/codecs/wcd9xxx-mbhc.h b/sound/soc/codecs/wcd9xxx-mbhc.h
index e5259c3..91280e4 100644
--- a/sound/soc/codecs/wcd9xxx-mbhc.h
+++ b/sound/soc/codecs/wcd9xxx-mbhc.h
@@ -227,6 +227,7 @@
 	/* swap_gnd_mic returns true if extern GND/MIC swap switch toggled */
 	bool (*swap_gnd_mic) (struct snd_soc_codec *);
 	unsigned long cs_enable_flags;
+	bool use_int_rbias;
 };
 
 struct wcd9xxx_cfilt_mode {
@@ -250,6 +251,10 @@
 	int (*setup_zdet) (struct wcd9xxx_mbhc *,
 			   enum mbhc_impedance_detect_stages stage);
 	void (*compute_impedance) (s16 *, s16 *, uint32_t *, uint32_t *);
+	void (*enable_mbhc_txfe) (struct snd_soc_codec *, bool);
+	int (*enable_mb_source) (struct snd_soc_codec *, bool);
+	void (*setup_int_rbias) (struct snd_soc_codec *, bool);
+	void (*pull_mb_to_vddio) (struct snd_soc_codec *, bool);
 };
 
 struct wcd9xxx_mbhc {
diff --git a/sound/soc/msm/msm8226.c b/sound/soc/msm/msm8226.c
index 9460ec0..d1ddfae 100644
--- a/sound/soc/msm/msm8226.c
+++ b/sound/soc/msm/msm8226.c
@@ -2003,7 +2003,7 @@
 	mutex_init(&cdc_mclk_mutex);
 
 	mbhc_cfg.gpio_level_insert = of_property_read_bool(pdev->dev.of_node,
-					"qcom,headset-jack-type-NO");
+					"qcom,headset-jack-type-NC");
 
 	ret = snd_soc_register_card(card);
 	if (ret == -EPROBE_DEFER)
diff --git a/sound/soc/msm/msm8x10.c b/sound/soc/msm/msm8x10.c
index 23577ed..4b61db6 100644
--- a/sound/soc/msm/msm8x10.c
+++ b/sound/soc/msm/msm8x10.c
@@ -72,6 +72,7 @@
 	.detect_extn_cable = false,
 	.insert_detect = true,
 	.swap_gnd_mic = NULL,
+	.use_int_rbias = false,
 };
 
 /*
@@ -1024,6 +1025,8 @@
 	atomic_set(&mclk_rsc_ref, 0);
 	mbhc_cfg.gpio_level_insert = of_property_read_bool(pdev->dev.of_node,
 						"qcom,headset-jack-type-NC");
+	mbhc_cfg.use_int_rbias = of_property_read_bool(pdev->dev.of_node,
+						"qcom,mbhc-bias-internal");
 
 	spdev = pdev;
 
diff --git a/sound/soc/msm/qdsp6v2/audio_acdb.c b/sound/soc/msm/qdsp6v2/audio_acdb.c
index c9e38e0..9a2d4d3 100644
--- a/sound/soc/msm/qdsp6v2/audio_acdb.c
+++ b/sound/soc/msm/qdsp6v2/audio_acdb.c
@@ -36,6 +36,7 @@
 #define NUM_VOCPROC_BLOCKS		(6 * MAX_NETWORKS)
 #define ACDB_TOTAL_VOICE_ALLOCATION	(ACDB_BLOCK_SIZE * NUM_VOCPROC_BLOCKS)
 
+#define MAX_HW_DELAY_ENTRIES	25
 
 struct sidetone_atomic_cal {
 	atomic_t	enable;
@@ -98,6 +99,10 @@
 
 	/* Speaker protection */
 	struct msm_spk_prot_cfg spk_prot_cfg;
+
+	/* Av sync delay info */
+	struct hw_delay hw_delay_rx;
+	struct hw_delay hw_delay_tx;
 };
 
 static struct acdb_data		acdb_data;
@@ -371,6 +376,122 @@
 	return result;
 }
 
+int get_hw_delay(int32_t path, struct hw_delay_entry *entry)
+{
+	int i, result = 0;
+	struct hw_delay *delay = NULL;
+	struct hw_delay_entry *info = NULL;
+	pr_debug("%s,\n", __func__);
+
+	if (entry == NULL) {
+		pr_err("ACDB=> NULL pointer sent to %s\n", __func__);
+		result = -EINVAL;
+		goto ret;
+	}
+	if ((path >= MAX_AUDPROC_TYPES) || (path < 0)) {
+		pr_err("ACDB=> Bad path sent to %s, path: %d\n",
+		       __func__, path);
+		result = -EINVAL;
+		goto ret;
+	}
+	mutex_lock(&acdb_data.acdb_mutex);
+	if (path == RX_CAL)
+		delay = &acdb_data.hw_delay_rx;
+	else if (path == TX_CAL)
+		delay = &acdb_data.hw_delay_tx;
+
+	if ((delay == NULL) || ((delay != NULL) && delay->num_entries == 0)) {
+		pr_err("ACDB=> %s Invalid delay/ delay entries\n", __func__);
+		result = -EINVAL;
+		goto done;
+	}
+
+	info = (struct hw_delay_entry *)(delay->delay_info);
+	if (info == NULL) {
+		pr_err("ACDB=> %s Delay entries info is NULL\n", __func__);
+		result = -EFAULT;
+		goto done;
+	}
+	for (i = 0; i < delay->num_entries; i++) {
+		if (info[i].sample_rate == entry->sample_rate) {
+			entry->delay_usec = info[i].delay_usec;
+			break;
+		}
+	}
+	if (i == delay->num_entries) {
+		pr_err("ACDB=> %s: Unable to find delay for sample rate %d\n",
+		       __func__, entry->sample_rate);
+		result = -EFAULT;
+	}
+
+done:
+	mutex_unlock(&acdb_data.acdb_mutex);
+ret:
+	pr_debug("ACDB=> %s: Path = %d samplerate = %u usec = %u status %d\n",
+		 __func__, path, entry->sample_rate, entry->delay_usec, result);
+	return result;
+}
+
+int store_hw_delay(int32_t path, void *arg)
+{
+	int result = 0;
+	struct hw_delay delay;
+	struct hw_delay *delay_dest = NULL;
+	pr_debug("%s,\n", __func__);
+
+	if ((path >= MAX_AUDPROC_TYPES) || (path < 0) || (arg == NULL)) {
+		pr_err("ACDB=> Bad path/ pointer sent to %s, path: %d\n",
+		      __func__, path);
+		result = -EINVAL;
+		goto done;
+	}
+	result = copy_from_user((void *)&delay, (void *)arg,
+				sizeof(struct hw_delay));
+	if (result) {
+		pr_err("ACDB=> %s failed to copy hw delay: result=%d path=%d\n",
+		       __func__, result, path);
+		result = -EFAULT;
+		goto done;
+	}
+	if ((delay.num_entries <= 0) ||
+		(delay.num_entries > MAX_HW_DELAY_ENTRIES)) {
+		pr_err("ACDB=> %s incorrect no of hw delay entries: %d\n",
+		       __func__, delay.num_entries);
+		result = -EINVAL;
+		goto done;
+	}
+	if ((path >= MAX_AUDPROC_TYPES) || (path < 0)) {
+		pr_err("ACDB=> Bad path sent to %s, path: %d\n",
+		__func__, path);
+		result = -EINVAL;
+		goto done;
+	}
+
+	pr_debug("ACDB=> %s : Path = %d num_entries = %d\n",
+		 __func__, path, delay.num_entries);
+
+	mutex_lock(&acdb_data.acdb_mutex);
+	if (path == RX_CAL)
+		delay_dest = &acdb_data.hw_delay_rx;
+	else if (path == TX_CAL)
+		delay_dest = &acdb_data.hw_delay_tx;
+
+	delay_dest->num_entries = delay.num_entries;
+
+	result = copy_from_user(delay_dest->delay_info,
+				delay.delay_info,
+				(sizeof(struct hw_delay_entry)*
+				delay.num_entries));
+	if (result) {
+		pr_err("ACDB=> %s failed to copy hw delay info res=%d path=%d",
+		       __func__, result, path);
+		result = -EFAULT;
+	}
+	mutex_unlock(&acdb_data.acdb_mutex);
+done:
+	return result;
+}
+
 int get_anc_cal(struct acdb_cal_block *cal_block)
 {
 	int result = 0;
@@ -998,6 +1119,29 @@
 	atomic_set(&acdb_data.valid_adm_custom_top, 1);
 	atomic_set(&acdb_data.valid_asm_custom_top, 1);
 	atomic_inc(&usage_count);
+
+	/* Allocate memory for hw delay entries */
+	mutex_lock(&acdb_data.acdb_mutex);
+	acdb_data.hw_delay_rx.num_entries = 0;
+	acdb_data.hw_delay_tx.num_entries = 0;
+	acdb_data.hw_delay_rx.delay_info =
+				kmalloc(sizeof(struct hw_delay_entry)*
+					MAX_HW_DELAY_ENTRIES,
+					GFP_KERNEL);
+	if (acdb_data.hw_delay_rx.delay_info == NULL) {
+		pr_err("%s : Failed to allocate av sync delay entries rx\n",
+			__func__);
+	}
+	acdb_data.hw_delay_tx.delay_info =
+				kmalloc(sizeof(struct hw_delay_entry)*
+					MAX_HW_DELAY_ENTRIES,
+					GFP_KERNEL);
+	if (acdb_data.hw_delay_tx.delay_info == NULL) {
+		pr_err("%s : Failed to allocate av sync delay entries tx\n",
+			__func__);
+	}
+	mutex_unlock(&acdb_data.acdb_mutex);
+
 	return result;
 }
 
@@ -1238,6 +1382,12 @@
 	case AUDIO_DEREGISTER_VOCPROC_VOL_TABLE:
 		result = deregister_vocvol_table();
 		goto done;
+	case AUDIO_SET_HW_DELAY_RX:
+		result = store_hw_delay(RX_CAL, (void *)arg);
+		goto done;
+	case AUDIO_SET_HW_DELAY_TX:
+		result = store_hw_delay(TX_CAL, (void *)arg);
+		goto done;
 	}
 
 	if (copy_from_user(&size, (void *) arg, sizeof(size))) {
@@ -1393,6 +1543,9 @@
 	else
 		result = deregister_memory();
 
+	kfree(acdb_data.hw_delay_rx.delay_info);
+	kfree(acdb_data.hw_delay_tx.delay_info);
+
 	return result;
 }
 
diff --git a/sound/soc/msm/qdsp6v2/audio_acdb.h b/sound/soc/msm/qdsp6v2/audio_acdb.h
index d9c1210..e2ca395 100644
--- a/sound/soc/msm/qdsp6v2/audio_acdb.h
+++ b/sound/soc/msm/qdsp6v2/audio_acdb.h
@@ -41,6 +41,11 @@
 	atomic_t		cal_paddr;
 };
 
+struct hw_delay_entry {
+	uint32_t sample_rate;
+	uint32_t delay_usec;
+};
+
 uint32_t get_voice_rx_topology(void);
 uint32_t get_voice_tx_topology(void);
 uint32_t get_adm_rx_topology(void);
@@ -65,5 +70,6 @@
 int get_sidetone_cal(struct sidetone_cal *cal_data);
 int get_spk_protection_cfg(struct msm_spk_prot_cfg *prot_cfg);
 int get_aanc_cal(struct acdb_cal_block *cal_block);
+int get_hw_delay(int32_t path, struct hw_delay_entry *delay_info);
 
 #endif
diff --git a/sound/soc/msm/qdsp6v2/msm-dolby-dap-config.c b/sound/soc/msm/qdsp6v2/msm-dolby-dap-config.c
index cd08b39..307d63e 100644
--- a/sound/soc/msm/qdsp6v2/msm-dolby-dap-config.c
+++ b/sound/soc/msm/qdsp6v2/msm-dolby-dap-config.c
@@ -43,75 +43,190 @@
 
 const struct dolby_dap_endp_params_s
 			dolby_dap_endp_params[NUM_DOLBY_ENDP_DEVICE] = {
-	{EARPIECE,			2, DOLBY_ENDP_EXT_SPEAKERS,
-		{DOLBY_PARAM_ID_DVLO}, {DOLBY_ENDDEP_PARAM_DVLO_LENGTH},
-		{DOLBY_ENDDEP_PARAM_DVLO_OFFSET}, {-320} },
-	{SPEAKER,			2, DOLBY_ENDP_INT_SPEAKERS,
-		{DOLBY_PARAM_ID_DVLO}, {DOLBY_ENDDEP_PARAM_DVLO_LENGTH},
-		{DOLBY_ENDDEP_PARAM_DVLO_OFFSET}, {-320} },
-	{WIRED_HEADSET,			2, DOLBY_ENDP_HEADPHONES,
-		{DOLBY_PARAM_ID_DVLO}, {DOLBY_ENDDEP_PARAM_DVLO_LENGTH},
-		{DOLBY_ENDDEP_PARAM_DVLO_OFFSET}, {-320} },
-	{WIRED_HEADPHONE,		2, DOLBY_ENDP_HEADPHONES,
-		{DOLBY_PARAM_ID_DVLO}, {DOLBY_ENDDEP_PARAM_DVLO_LENGTH},
-		{DOLBY_ENDDEP_PARAM_DVLO_OFFSET}, {-320} },
-	{BLUETOOTH_SCO,			2, DOLBY_ENDP_EXT_SPEAKERS,
-		{DOLBY_PARAM_ID_DVLO}, {DOLBY_ENDDEP_PARAM_DVLO_LENGTH},
-		{DOLBY_ENDDEP_PARAM_DVLO_OFFSET}, {-320} },
-	{BLUETOOTH_SCO_HEADSET,		2, DOLBY_ENDP_EXT_SPEAKERS,
-		{DOLBY_PARAM_ID_DVLO}, {DOLBY_ENDDEP_PARAM_DVLO_LENGTH},
-		{DOLBY_ENDDEP_PARAM_DVLO_OFFSET}, {-320} },
-	{BLUETOOTH_SCO_CARKIT,		2, DOLBY_ENDP_EXT_SPEAKERS,
-		{DOLBY_PARAM_ID_DVLO}, {DOLBY_ENDDEP_PARAM_DVLO_LENGTH},
-		{DOLBY_ENDDEP_PARAM_DVLO_OFFSET}, {-320} },
-	{BLUETOOTH_A2DP,		2, DOLBY_ENDP_EXT_SPEAKERS,
-		{DOLBY_PARAM_ID_DVLO}, {DOLBY_ENDDEP_PARAM_DVLO_LENGTH},
-		{DOLBY_ENDDEP_PARAM_DVLO_OFFSET}, {-320} },
-	{BLUETOOTH_A2DP_HEADPHONES,	2, DOLBY_ENDP_HEADPHONES,
-		{DOLBY_PARAM_ID_DVLO}, {DOLBY_ENDDEP_PARAM_DVLO_LENGTH},
-		{DOLBY_ENDDEP_PARAM_DVLO_OFFSET}, {-320} },
-	{BLUETOOTH_A2DP_SPEAKER,	2, DOLBY_ENDP_EXT_SPEAKERS,
-		{DOLBY_PARAM_ID_DVLO}, {DOLBY_ENDDEP_PARAM_DVLO_LENGTH},
-		{DOLBY_ENDDEP_PARAM_DVLO_OFFSET}, {-320} },
-	{AUX_DIGITAL,			2, DOLBY_ENDP_HDMI,
-		{DOLBY_PARAM_ID_DVLO}, {DOLBY_ENDDEP_PARAM_DVLO_LENGTH},
-		{DOLBY_ENDDEP_PARAM_DVLO_OFFSET}, {-640} },
-	{AUX_DIGITAL,			6, DOLBY_ENDP_HDMI,
-		{DOLBY_PARAM_ID_DVLO}, {DOLBY_ENDDEP_PARAM_DVLO_LENGTH},
-		{DOLBY_ENDDEP_PARAM_DVLO_OFFSET}, {-640} },
-	{AUX_DIGITAL,			8, DOLBY_ENDP_HDMI,
-		{DOLBY_PARAM_ID_DVLO}, {DOLBY_ENDDEP_PARAM_DVLO_LENGTH},
-		{DOLBY_ENDDEP_PARAM_DVLO_OFFSET}, {-640} },
-	{ANLG_DOCK_HEADSET,		2, DOLBY_ENDP_HEADPHONES,
-		{DOLBY_PARAM_ID_DVLO}, {DOLBY_ENDDEP_PARAM_DVLO_LENGTH},
-		{DOLBY_ENDDEP_PARAM_DVLO_OFFSET}, {-320} },
-	{DGTL_DOCK_HEADSET,		2, DOLBY_ENDP_HEADPHONES,
-		{DOLBY_PARAM_ID_DVLO}, {DOLBY_ENDDEP_PARAM_DVLO_LENGTH},
-		{DOLBY_ENDDEP_PARAM_DVLO_OFFSET}, {-320} },
-	{USB_ACCESSORY,			2, DOLBY_ENDP_EXT_SPEAKERS,
-		{DOLBY_PARAM_ID_DVLO}, {DOLBY_ENDDEP_PARAM_DVLO_LENGTH},
-		{DOLBY_ENDDEP_PARAM_DVLO_OFFSET}, {-320} },
-	{USB_DEVICE,			2, DOLBY_ENDP_EXT_SPEAKERS,
-		{DOLBY_PARAM_ID_DVLO}, {DOLBY_ENDDEP_PARAM_DVLO_LENGTH},
-		{DOLBY_ENDDEP_PARAM_DVLO_OFFSET}, {-320} },
-	{REMOTE_SUBMIX,			2, DOLBY_ENDP_EXT_SPEAKERS,
-		{DOLBY_PARAM_ID_DVLO}, {DOLBY_ENDDEP_PARAM_DVLO_LENGTH},
-		{DOLBY_ENDDEP_PARAM_DVLO_OFFSET}, {-320} },
-	{ANC_HEADSET,			2, DOLBY_ENDP_HEADPHONES,
-		{DOLBY_PARAM_ID_DVLO}, {DOLBY_ENDDEP_PARAM_DVLO_LENGTH},
-		{DOLBY_ENDDEP_PARAM_DVLO_OFFSET}, {-320} },
-	{ANC_HEADPHONE,			2, DOLBY_ENDP_HEADPHONES,
-		{DOLBY_PARAM_ID_DVLO}, {DOLBY_ENDDEP_PARAM_DVLO_LENGTH},
-		{DOLBY_ENDDEP_PARAM_DVLO_OFFSET}, {-320} },
-	{PROXY,				2, DOLBY_ENDP_EXT_SPEAKERS,
-		{DOLBY_PARAM_ID_DVLO}, {DOLBY_ENDDEP_PARAM_DVLO_LENGTH},
-		{DOLBY_ENDDEP_PARAM_DVLO_OFFSET}, {-320} },
-	{FM,				2, DOLBY_ENDP_EXT_SPEAKERS,
-		{DOLBY_PARAM_ID_DVLO}, {DOLBY_ENDDEP_PARAM_DVLO_LENGTH},
-		{DOLBY_ENDDEP_PARAM_DVLO_OFFSET}, {-320} },
-	{FM_TX,				2, DOLBY_ENDP_EXT_SPEAKERS,
-		{DOLBY_PARAM_ID_DVLO}, {DOLBY_ENDDEP_PARAM_DVLO_LENGTH},
-		{DOLBY_ENDDEP_PARAM_DVLO_OFFSET}, {-320} },
+	{EARPIECE, 2, DOLBY_ENDP_EXT_SPEAKERS,
+		{DOLBY_PARAM_ID_DVLO, DOLBY_PARAM_ID_DVLI, DOLBY_PARAM_ID_VMB},
+		{DOLBY_ENDDEP_PARAM_DVLO_LENGTH, DOLBY_ENDDEP_PARAM_DVLI_LENGTH,
+		 DOLBY_ENDDEP_PARAM_VMB_LENGTH},
+		{DOLBY_ENDDEP_PARAM_DVLO_OFFSET, DOLBY_ENDDEP_PARAM_DVLI_OFFSET,
+		 DOLBY_ENDDEP_PARAM_VMB_OFFSET},
+		{-320, -320, 144}
+	},
+	{SPEAKER, 2, DOLBY_ENDP_INT_SPEAKERS,
+		{DOLBY_PARAM_ID_DVLO, DOLBY_PARAM_ID_DVLI, DOLBY_PARAM_ID_VMB},
+		{DOLBY_ENDDEP_PARAM_DVLO_LENGTH, DOLBY_ENDDEP_PARAM_DVLI_LENGTH,
+		 DOLBY_ENDDEP_PARAM_VMB_LENGTH},
+		{DOLBY_ENDDEP_PARAM_DVLO_OFFSET, DOLBY_ENDDEP_PARAM_DVLI_OFFSET,
+		 DOLBY_ENDDEP_PARAM_VMB_OFFSET},
+		{-320, -320, 144}
+	},
+	{WIRED_HEADSET,	2, DOLBY_ENDP_HEADPHONES,
+		{DOLBY_PARAM_ID_DVLO, DOLBY_PARAM_ID_DVLI, DOLBY_PARAM_ID_VMB},
+		{DOLBY_ENDDEP_PARAM_DVLO_LENGTH, DOLBY_ENDDEP_PARAM_DVLI_LENGTH,
+		 DOLBY_ENDDEP_PARAM_VMB_LENGTH},
+		{DOLBY_ENDDEP_PARAM_DVLO_OFFSET, DOLBY_ENDDEP_PARAM_DVLI_OFFSET,
+		 DOLBY_ENDDEP_PARAM_VMB_OFFSET},
+		{-320, -320, 144}
+	},
+	{WIRED_HEADPHONE, 2, DOLBY_ENDP_HEADPHONES,
+		{DOLBY_PARAM_ID_DVLO, DOLBY_PARAM_ID_DVLI, DOLBY_PARAM_ID_VMB},
+		{DOLBY_ENDDEP_PARAM_DVLO_LENGTH, DOLBY_ENDDEP_PARAM_DVLI_LENGTH,
+		 DOLBY_ENDDEP_PARAM_VMB_LENGTH},
+		{DOLBY_ENDDEP_PARAM_DVLO_OFFSET, DOLBY_ENDDEP_PARAM_DVLI_OFFSET,
+		 DOLBY_ENDDEP_PARAM_VMB_OFFSET},
+		{-320, -320, 144}
+	},
+	{BLUETOOTH_SCO,	2, DOLBY_ENDP_EXT_SPEAKERS,
+		{DOLBY_PARAM_ID_DVLO, DOLBY_PARAM_ID_DVLI, DOLBY_PARAM_ID_VMB},
+		{DOLBY_ENDDEP_PARAM_DVLO_LENGTH, DOLBY_ENDDEP_PARAM_DVLI_LENGTH,
+		 DOLBY_ENDDEP_PARAM_VMB_LENGTH},
+		{DOLBY_ENDDEP_PARAM_DVLO_OFFSET, DOLBY_ENDDEP_PARAM_DVLI_OFFSET,
+		 DOLBY_ENDDEP_PARAM_VMB_OFFSET},
+		{-320, -320, 144}
+	},
+	{BLUETOOTH_SCO_HEADSET,	2, DOLBY_ENDP_EXT_SPEAKERS,
+		{DOLBY_PARAM_ID_DVLO, DOLBY_PARAM_ID_DVLI, DOLBY_PARAM_ID_VMB},
+		{DOLBY_ENDDEP_PARAM_DVLO_LENGTH, DOLBY_ENDDEP_PARAM_DVLI_LENGTH,
+		 DOLBY_ENDDEP_PARAM_VMB_LENGTH},
+		{DOLBY_ENDDEP_PARAM_DVLO_OFFSET, DOLBY_ENDDEP_PARAM_DVLI_OFFSET,
+		 DOLBY_ENDDEP_PARAM_VMB_OFFSET},
+		{-320, -320, 144}
+	},
+	{BLUETOOTH_SCO_CARKIT, 2, DOLBY_ENDP_EXT_SPEAKERS,
+		{DOLBY_PARAM_ID_DVLO, DOLBY_PARAM_ID_DVLI, DOLBY_PARAM_ID_VMB},
+		{DOLBY_ENDDEP_PARAM_DVLO_LENGTH, DOLBY_ENDDEP_PARAM_DVLI_LENGTH,
+		 DOLBY_ENDDEP_PARAM_VMB_LENGTH},
+		{DOLBY_ENDDEP_PARAM_DVLO_OFFSET, DOLBY_ENDDEP_PARAM_DVLI_OFFSET,
+		 DOLBY_ENDDEP_PARAM_VMB_OFFSET},
+		{-320, -320, 144}
+	},
+	{BLUETOOTH_A2DP, 2, DOLBY_ENDP_EXT_SPEAKERS,
+		{DOLBY_PARAM_ID_DVLO, DOLBY_PARAM_ID_DVLI, DOLBY_PARAM_ID_VMB},
+		{DOLBY_ENDDEP_PARAM_DVLO_LENGTH, DOLBY_ENDDEP_PARAM_DVLI_LENGTH,
+		 DOLBY_ENDDEP_PARAM_VMB_LENGTH},
+		{DOLBY_ENDDEP_PARAM_DVLO_OFFSET, DOLBY_ENDDEP_PARAM_DVLI_OFFSET,
+		 DOLBY_ENDDEP_PARAM_VMB_OFFSET},
+		{-320, -320, 144}
+	},
+	{BLUETOOTH_A2DP_HEADPHONES, 2, DOLBY_ENDP_HEADPHONES,
+		{DOLBY_PARAM_ID_DVLO, DOLBY_PARAM_ID_DVLI, DOLBY_PARAM_ID_VMB},
+		{DOLBY_ENDDEP_PARAM_DVLO_LENGTH, DOLBY_ENDDEP_PARAM_DVLI_LENGTH,
+		 DOLBY_ENDDEP_PARAM_VMB_LENGTH},
+		{DOLBY_ENDDEP_PARAM_DVLO_OFFSET, DOLBY_ENDDEP_PARAM_DVLI_OFFSET,
+		 DOLBY_ENDDEP_PARAM_VMB_OFFSET},
+		{-320, -320, 144}
+	},
+	{BLUETOOTH_A2DP_SPEAKER, 2, DOLBY_ENDP_EXT_SPEAKERS,
+		{DOLBY_PARAM_ID_DVLO, DOLBY_PARAM_ID_DVLI, DOLBY_PARAM_ID_VMB},
+		{DOLBY_ENDDEP_PARAM_DVLO_LENGTH, DOLBY_ENDDEP_PARAM_DVLI_LENGTH,
+		 DOLBY_ENDDEP_PARAM_VMB_LENGTH},
+		{DOLBY_ENDDEP_PARAM_DVLO_OFFSET, DOLBY_ENDDEP_PARAM_DVLI_OFFSET,
+		 DOLBY_ENDDEP_PARAM_VMB_OFFSET},
+		{-320, -320, 144}
+	},
+	{AUX_DIGITAL, 2, DOLBY_ENDP_HDMI,
+		{DOLBY_PARAM_ID_DVLO, DOLBY_PARAM_ID_DVLI, DOLBY_PARAM_ID_VMB},
+		{DOLBY_ENDDEP_PARAM_DVLO_LENGTH, DOLBY_ENDDEP_PARAM_DVLI_LENGTH,
+		 DOLBY_ENDDEP_PARAM_VMB_LENGTH},
+		{DOLBY_ENDDEP_PARAM_DVLO_OFFSET, DOLBY_ENDDEP_PARAM_DVLI_OFFSET,
+		 DOLBY_ENDDEP_PARAM_VMB_OFFSET},
+		{-496, -496, 0}
+	},
+	{AUX_DIGITAL, 6, DOLBY_ENDP_HDMI,
+		{DOLBY_PARAM_ID_DVLO, DOLBY_PARAM_ID_DVLI, DOLBY_PARAM_ID_VMB},
+		{DOLBY_ENDDEP_PARAM_DVLO_LENGTH, DOLBY_ENDDEP_PARAM_DVLI_LENGTH,
+		 DOLBY_ENDDEP_PARAM_VMB_LENGTH},
+		{DOLBY_ENDDEP_PARAM_DVLO_OFFSET, DOLBY_ENDDEP_PARAM_DVLI_OFFSET,
+		 DOLBY_ENDDEP_PARAM_VMB_OFFSET},
+		{-496, -496, 0}
+	},
+	{AUX_DIGITAL, 8, DOLBY_ENDP_HDMI,
+		{DOLBY_PARAM_ID_DVLO, DOLBY_PARAM_ID_DVLI, DOLBY_PARAM_ID_VMB},
+		{DOLBY_ENDDEP_PARAM_DVLO_LENGTH, DOLBY_ENDDEP_PARAM_DVLI_LENGTH,
+		 DOLBY_ENDDEP_PARAM_VMB_LENGTH},
+		{DOLBY_ENDDEP_PARAM_DVLO_OFFSET, DOLBY_ENDDEP_PARAM_DVLI_OFFSET,
+		 DOLBY_ENDDEP_PARAM_VMB_OFFSET},
+		{-496, -496, 0}
+	},
+	{ANLG_DOCK_HEADSET, 2, DOLBY_ENDP_HEADPHONES,
+		{DOLBY_PARAM_ID_DVLO, DOLBY_PARAM_ID_DVLI, DOLBY_PARAM_ID_VMB},
+		{DOLBY_ENDDEP_PARAM_DVLO_LENGTH, DOLBY_ENDDEP_PARAM_DVLI_LENGTH,
+		 DOLBY_ENDDEP_PARAM_VMB_LENGTH},
+		{DOLBY_ENDDEP_PARAM_DVLO_OFFSET, DOLBY_ENDDEP_PARAM_DVLI_OFFSET,
+		 DOLBY_ENDDEP_PARAM_VMB_OFFSET},
+		{-320, -320, 144}
+	},
+	{DGTL_DOCK_HEADSET, 2, DOLBY_ENDP_HEADPHONES,
+		{DOLBY_PARAM_ID_DVLO, DOLBY_PARAM_ID_DVLI, DOLBY_PARAM_ID_VMB},
+		{DOLBY_ENDDEP_PARAM_DVLO_LENGTH, DOLBY_ENDDEP_PARAM_DVLI_LENGTH,
+		 DOLBY_ENDDEP_PARAM_VMB_LENGTH},
+		{DOLBY_ENDDEP_PARAM_DVLO_OFFSET, DOLBY_ENDDEP_PARAM_DVLI_OFFSET,
+		 DOLBY_ENDDEP_PARAM_VMB_OFFSET},
+		{-320, -320, 144}
+	},
+	{USB_ACCESSORY,	2, DOLBY_ENDP_EXT_SPEAKERS,
+		{DOLBY_PARAM_ID_DVLO, DOLBY_PARAM_ID_DVLI, DOLBY_PARAM_ID_VMB},
+		{DOLBY_ENDDEP_PARAM_DVLO_LENGTH, DOLBY_ENDDEP_PARAM_DVLI_LENGTH,
+		 DOLBY_ENDDEP_PARAM_VMB_LENGTH},
+		{DOLBY_ENDDEP_PARAM_DVLO_OFFSET, DOLBY_ENDDEP_PARAM_DVLI_OFFSET,
+		 DOLBY_ENDDEP_PARAM_VMB_OFFSET},
+		{-320, -320, 144}
+	},
+	{USB_DEVICE, 2, DOLBY_ENDP_EXT_SPEAKERS,
+		{DOLBY_PARAM_ID_DVLO, DOLBY_PARAM_ID_DVLI, DOLBY_PARAM_ID_VMB},
+		{DOLBY_ENDDEP_PARAM_DVLO_LENGTH, DOLBY_ENDDEP_PARAM_DVLI_LENGTH,
+		 DOLBY_ENDDEP_PARAM_VMB_LENGTH},
+		{DOLBY_ENDDEP_PARAM_DVLO_OFFSET, DOLBY_ENDDEP_PARAM_DVLI_OFFSET,
+		 DOLBY_ENDDEP_PARAM_VMB_OFFSET},
+		{-320, -320, 144}
+	},
+	{REMOTE_SUBMIX,	2, DOLBY_ENDP_EXT_SPEAKERS,
+		{DOLBY_PARAM_ID_DVLO, DOLBY_PARAM_ID_DVLI, DOLBY_PARAM_ID_VMB},
+		{DOLBY_ENDDEP_PARAM_DVLO_LENGTH, DOLBY_ENDDEP_PARAM_DVLI_LENGTH,
+		 DOLBY_ENDDEP_PARAM_VMB_LENGTH},
+		{DOLBY_ENDDEP_PARAM_DVLO_OFFSET, DOLBY_ENDDEP_PARAM_DVLI_OFFSET,
+		 DOLBY_ENDDEP_PARAM_VMB_OFFSET},
+		{-320, -320, 144}
+	},
+	{ANC_HEADSET, 2, DOLBY_ENDP_HEADPHONES,
+		{DOLBY_PARAM_ID_DVLO, DOLBY_PARAM_ID_DVLI, DOLBY_PARAM_ID_VMB},
+		{DOLBY_ENDDEP_PARAM_DVLO_LENGTH, DOLBY_ENDDEP_PARAM_DVLI_LENGTH,
+		 DOLBY_ENDDEP_PARAM_VMB_LENGTH},
+		{DOLBY_ENDDEP_PARAM_DVLO_OFFSET, DOLBY_ENDDEP_PARAM_DVLI_OFFSET,
+		 DOLBY_ENDDEP_PARAM_VMB_OFFSET},
+		{-320, -320, 144}
+	},
+	{ANC_HEADPHONE,	2, DOLBY_ENDP_HEADPHONES,
+		{DOLBY_PARAM_ID_DVLO, DOLBY_PARAM_ID_DVLI, DOLBY_PARAM_ID_VMB},
+		{DOLBY_ENDDEP_PARAM_DVLO_LENGTH, DOLBY_ENDDEP_PARAM_DVLI_LENGTH,
+		 DOLBY_ENDDEP_PARAM_VMB_LENGTH},
+		{DOLBY_ENDDEP_PARAM_DVLO_OFFSET, DOLBY_ENDDEP_PARAM_DVLI_OFFSET,
+		 DOLBY_ENDDEP_PARAM_VMB_OFFSET},
+		{-320, -320, 144}
+	},
+	{PROXY,	2, DOLBY_ENDP_EXT_SPEAKERS,
+		{DOLBY_PARAM_ID_DVLO, DOLBY_PARAM_ID_DVLI, DOLBY_PARAM_ID_VMB},
+		{DOLBY_ENDDEP_PARAM_DVLO_LENGTH, DOLBY_ENDDEP_PARAM_DVLI_LENGTH,
+		 DOLBY_ENDDEP_PARAM_VMB_LENGTH},
+		{DOLBY_ENDDEP_PARAM_DVLO_OFFSET, DOLBY_ENDDEP_PARAM_DVLI_OFFSET,
+		 DOLBY_ENDDEP_PARAM_VMB_OFFSET},
+		{-320, -320, 144}
+	},
+	{FM, 2, DOLBY_ENDP_EXT_SPEAKERS,
+		{DOLBY_PARAM_ID_DVLO, DOLBY_PARAM_ID_DVLI, DOLBY_PARAM_ID_VMB},
+		{DOLBY_ENDDEP_PARAM_DVLO_LENGTH, DOLBY_ENDDEP_PARAM_DVLI_LENGTH,
+		 DOLBY_ENDDEP_PARAM_VMB_LENGTH},
+		{DOLBY_ENDDEP_PARAM_DVLO_OFFSET, DOLBY_ENDDEP_PARAM_DVLI_OFFSET,
+		 DOLBY_ENDDEP_PARAM_VMB_OFFSET},
+		{-320, -320, 144}
+	},
+	{FM_TX,	2, DOLBY_ENDP_EXT_SPEAKERS,
+		{DOLBY_PARAM_ID_DVLO, DOLBY_PARAM_ID_DVLI, DOLBY_PARAM_ID_VMB},
+		{DOLBY_ENDDEP_PARAM_DVLO_LENGTH, DOLBY_ENDDEP_PARAM_DVLI_LENGTH,
+		 DOLBY_ENDDEP_PARAM_VMB_LENGTH},
+		{DOLBY_ENDDEP_PARAM_DVLO_OFFSET, DOLBY_ENDDEP_PARAM_DVLI_OFFSET,
+		 DOLBY_ENDDEP_PARAM_VMB_OFFSET},
+		{-320, -320, 144}
+	},
 };
 
 /* dolby param ids to/from dsp */
diff --git a/sound/soc/msm/qdsp6v2/msm-dolby-dap-config.h b/sound/soc/msm/qdsp6v2/msm-dolby-dap-config.h
index 113d85f..4544fea 100644
--- a/sound/soc/msm/qdsp6v2/msm-dolby-dap-config.h
+++ b/sound/soc/msm/qdsp6v2/msm-dolby-dap-config.h
@@ -226,10 +226,17 @@
 #define DOLBY_PARAM_PAYLOAD_SIZE		3
 #define DOLBY_MAX_LENGTH_INDIVIDUAL_PARAM	329
 
-#define DOLBY_NUM_ENDP_DEPENDENT_PARAMS		1
-#define DOLBY_ENDDEP_PARAM_DVLO_OFFSET		0
-#define DOLBY_ENDDEP_PARAM_DVLO_LENGTH		1
-#define DOLBY_ENDDEP_PARAM_LENGTH		DOLBY_ENDDEP_PARAM_DVLO_LENGTH
+#define DOLBY_NUM_ENDP_DEPENDENT_PARAMS	  3
+#define DOLBY_ENDDEP_PARAM_DVLO_OFFSET	  0
+#define DOLBY_ENDDEP_PARAM_DVLO_LENGTH	  1
+#define DOLBY_ENDDEP_PARAM_DVLI_OFFSET    (DOLBY_ENDDEP_PARAM_DVLO_OFFSET + \
+						DOLBY_ENDDEP_PARAM_DVLO_LENGTH)
+#define DOLBY_ENDDEP_PARAM_DVLI_LENGTH    1
+#define DOLBY_ENDDEP_PARAM_VMB_OFFSET     (DOLBY_ENDDEP_PARAM_DVLI_OFFSET + \
+						DOLBY_ENDDEP_PARAM_DVLI_LENGTH)
+#define DOLBY_ENDDEP_PARAM_VMB_LENGTH     1
+#define DOLBY_ENDDEP_PARAM_LENGTH         (DOLBY_ENDDEP_PARAM_DVLO_LENGTH + \
+		DOLBY_ENDDEP_PARAM_DVLI_LENGTH + DOLBY_ENDDEP_PARAM_VMB_LENGTH)
 
 #define MAX_DOLBY_PARAMS			47
 #define MAX_DOLBY_CTRL_PARAMS			5
diff --git a/sound/soc/msm/qdsp6v2/msm-pcm-afe-v2.c b/sound/soc/msm/qdsp6v2/msm-pcm-afe-v2.c
index c4b44fe..d80ca19 100644
--- a/sound/soc/msm/qdsp6v2/msm-pcm-afe-v2.c
+++ b/sound/soc/msm/qdsp6v2/msm-pcm-afe-v2.c
@@ -35,8 +35,8 @@
 
 #define MIN_PLAYBACK_PERIOD_SIZE (128 * 2)
 #define MAX_PLAYBACK_PERIOD_SIZE (128 * 2 * 2 * 6)
-#define MIN_PLAYBACK_NUM_PERIODS (32)
-#define MAX_PLAYBACK_NUM_PERIODS (384)
+#define MIN_PLAYBACK_NUM_PERIODS (64)
+#define MAX_PLAYBACK_NUM_PERIODS (768)
 
 #define MIN_CAPTURE_PERIOD_SIZE (128 * 2 * 4)
 #define MAX_CAPTURE_PERIOD_SIZE (128 * 2 * 2 * 6 * 4)
diff --git a/sound/soc/msm/qdsp6v2/msm-pcm-routing-v2.c b/sound/soc/msm/qdsp6v2/msm-pcm-routing-v2.c
index 62cc5db..f6ea266 100644
--- a/sound/soc/msm/qdsp6v2/msm-pcm-routing-v2.c
+++ b/sound/soc/msm/qdsp6v2/msm-pcm-routing-v2.c
@@ -192,7 +192,7 @@
 		topology_id = get_adm_tx_topology();
 
 	if (topology_id  == 0)
-		topology_id = DEFAULT_COPP_TOPOLOGY;
+		topology_id = NULL_COPP_TOPOLOGY;
 
 	return topology_id;
 }
@@ -1344,7 +1344,7 @@
 		break;
 	case 1:
 		msm_route_ec_ref_rx = 1;
-		ec_ref_port_id = PRIMARY_I2S_RX;
+		ec_ref_port_id = AFE_PORT_ID_PRIMARY_MI2S_RX;
 		break;
 	default:
 		msm_route_ec_ref_rx = 3; /* NONE */
diff --git a/sound/soc/msm/qdsp6v2/q6afe.c b/sound/soc/msm/qdsp6v2/q6afe.c
index f7be34c..59113fe 100644
--- a/sound/soc/msm/qdsp6v2/q6afe.c
+++ b/sound/soc/msm/qdsp6v2/q6afe.c
@@ -632,6 +632,71 @@
 	}
 }
 
+static int afe_send_hw_delay(u16 port_id, u32 rate)
+{
+	struct hw_delay_entry delay_entry;
+	struct afe_audioif_config_command config;
+	int index = 0;
+	int ret = -EINVAL;
+
+	pr_debug("%s\n", __func__);
+
+	delay_entry.sample_rate = rate;
+	if (afe_get_port_type(port_id) == MSM_AFE_PORT_TYPE_TX)
+		ret = get_hw_delay(TX_CAL, &delay_entry);
+	else if (afe_get_port_type(port_id) == MSM_AFE_PORT_TYPE_RX)
+		ret = get_hw_delay(RX_CAL, &delay_entry);
+
+	if (ret != 0) {
+		pr_warn("%s: Failed to get hw delay info\n", __func__);
+		goto fail_cmd;
+	}
+	index = q6audio_get_port_index(port_id);
+	if (index < 0) {
+		pr_debug("%s: AFE port index invalid!\n", __func__);
+		goto fail_cmd;
+	}
+
+	config.hdr.hdr_field = APR_HDR_FIELD(APR_MSG_TYPE_SEQ_CMD,
+				APR_HDR_LEN(APR_HDR_SIZE), APR_PKT_VER);
+	config.hdr.pkt_size = sizeof(config);
+	config.hdr.src_port = 0;
+	config.hdr.dest_port = 0;
+	config.hdr.token = index;
+
+	config.hdr.opcode = AFE_PORT_CMD_SET_PARAM_V2;
+	config.param.port_id = q6audio_get_port_id(port_id);
+	config.param.payload_size = sizeof(config) - sizeof(struct apr_hdr) -
+				    sizeof(config.param);
+	config.param.payload_address_lsw = 0x00;
+	config.param.payload_address_msw = 0x00;
+	config.param.mem_map_handle = 0x00;
+	config.pdata.module_id = AFE_MODULE_AUDIO_DEV_INTERFACE;
+	config.pdata.param_id = AFE_PARAM_ID_DEVICE_HW_DELAY;
+	config.pdata.param_size = sizeof(config.port);
+
+	config.port.hw_delay.delay_in_us = delay_entry.delay_usec;
+	config.port.hw_delay.device_hw_delay_minor_version =
+				AFE_API_VERSION_DEVICE_HW_DELAY;
+
+	ret = afe_apr_send_pkt(&config, &this_afe.wait[index]);
+	if (ret) {
+		pr_err("%s: AFE hw delay for port %#x failed\n",
+		       __func__, port_id);
+		goto fail_cmd;
+	} else if (atomic_read(&this_afe.status) != 0) {
+		pr_err("%s: config cmd failed\n", __func__);
+		ret = -EINVAL;
+		goto fail_cmd;
+	}
+
+fail_cmd:
+	pr_debug("%s port_id %u rate %u delay_usec %d status %d\n",
+	__func__, port_id, rate, delay_entry.delay_usec, ret);
+	return ret;
+
+}
+
 void afe_send_cal(u16 port_id)
 {
 	pr_debug("%s\n", __func__);
@@ -1248,6 +1313,7 @@
 		return ret;
 
 	afe_send_cal(port_id);
+	afe_send_hw_delay(port_id, rate);
 
 	/* Start SW MAD module */
 	mad_type = afe_port_get_mad_type(port_id);
diff --git a/sound/soc/msm/qdsp6v2/q6asm.c b/sound/soc/msm/qdsp6v2/q6asm.c
index 76812f1..9c0c362 100644
--- a/sound/soc/msm/qdsp6v2/q6asm.c
+++ b/sound/soc/msm/qdsp6v2/q6asm.c
@@ -1607,7 +1607,7 @@
 
 	open.preprocopo_id = get_asm_topology();
 	if (open.preprocopo_id == 0)
-		open.preprocopo_id = ASM_STREAM_POSTPROC_TOPO_ID_DEFAULT;
+		open.preprocopo_id = ASM_STREAM_POSTPROC_TOPO_ID_NONE;
 	open.bits_per_sample = bits_per_sample;
 	open.mode_flags = 0x0;
 
@@ -1706,7 +1706,7 @@
 
 	open.postprocopo_id = get_asm_topology();
 	if (open.postprocopo_id == 0)
-		open.postprocopo_id = ASM_STREAM_POSTPROC_TOPO_ID_DEFAULT;
+		open.postprocopo_id = ASM_STREAM_POSTPROC_TOPO_ID_NONE;
 
 	switch (format) {
 	case FORMAT_LINEAR_PCM:
@@ -1790,7 +1790,7 @@
 	/* source endpoint : matrix */
 	open.postprocopo_id = get_asm_topology();
 	if (open.postprocopo_id == 0)
-		open.postprocopo_id = ASM_STREAM_POSTPROC_TOPO_ID_DEFAULT;
+		open.postprocopo_id = ASM_STREAM_POSTPROC_TOPO_ID_NONE;
 
 	switch (wr_format) {
 	case FORMAT_LINEAR_PCM:
@@ -2237,7 +2237,6 @@
 			uint16_t sce_left, uint16_t sce_right)
 {
 	struct asm_aac_dual_mono_mapping_param dual_mono;
-	u32 frames_per_buf = 0;
 
 	int rc = 0;
 
@@ -2248,11 +2247,8 @@
 
 	dual_mono.hdr.opcode = ASM_STREAM_CMD_SET_ENCDEC_PARAM;
 	dual_mono.encdec.param_id = ASM_PARAM_ID_AAC_DUAL_MONO_MAPPING;
-	dual_mono.encdec.param_size = sizeof(struct asm_aac_enc_cfg_v2) -
-				sizeof(struct asm_stream_cmd_set_encdec_param);
-	dual_mono.encblk.frames_per_buf = frames_per_buf;
-	dual_mono.encblk.enc_cfg_blk_size  = dual_mono.encdec.param_size -
-				sizeof(struct asm_enc_cfg_blk_param_v2);
+	dual_mono.encdec.param_size = sizeof(dual_mono.left_channel_sce) +
+				sizeof(dual_mono.right_channel_sce);
 	dual_mono.left_channel_sce = sce_left;
 	dual_mono.right_channel_sce = sce_right;
 
diff --git a/sound/soc/soc-core.c b/sound/soc/soc-core.c
index de98feb..55f8dc8 100644
--- a/sound/soc/soc-core.c
+++ b/sound/soc/soc-core.c
@@ -3231,8 +3231,11 @@
 	mutex_init(&card->dapm_power_mutex);
 
 	ret = snd_soc_instantiate_card(card);
-	if (ret != 0)
+	if (ret != 0) {
 		soc_cleanup_card_debugfs(card);
+		if (card->rtd)
+			kfree(card->rtd);
+	}
 
 
 	return ret;