Merge "msm: vidc: Add AFD and CC metadata support to extradata"
diff --git a/Documentation/devicetree/bindings/arm/msm/cpr-regulator.txt b/Documentation/devicetree/bindings/arm/msm/cpr-regulator.txt
index aa24dc6..bba4cf7 100644
--- a/Documentation/devicetree/bindings/arm/msm/cpr-regulator.txt
+++ b/Documentation/devicetree/bindings/arm/msm/cpr-regulator.txt
@@ -251,6 +251,8 @@
 				corresponds to 'scaling' in this equation:
 				quot_adjust = (freq_turbo - freq_corner) * scaling / 1000.
 				This property is required if qcom,cpr-speed-bin-max-corners is present.
+- mem-acc-supply:		Regulator to vote for the memory accelerator configuration.
+				Not Present: memory accelerator configuration not supported.
 
 Example:
 	apc_vreg_corner: regulator@f9018000 {
diff --git a/Documentation/devicetree/bindings/fb/mdss-dsi-panel.txt b/Documentation/devicetree/bindings/fb/mdss-dsi-panel.txt
index 02d6df9..f6b4923 100644
--- a/Documentation/devicetree/bindings/fb/mdss-dsi-panel.txt
+++ b/Documentation/devicetree/bindings/fb/mdss-dsi-panel.txt
@@ -257,6 +257,37 @@
 - qcom,mdss-dsi-rx-eot-ignore:		Boolean used to enable ignoring end of transmission packets.
 - qcom,mdss-dsi-tx-eot-append:		Boolean used to enable appending end of transmission packets.
 - qcom,ulps-enabled:			Boolean to enable support for Ultra Low Power State (ULPS) mode.
+- qcom,mdss-tear-check-disable:		Boolean to disable mdp tear check. Tear check is enabled by default to avoid
+					tearing. Other tear-check properties are ignored if this property is present.
+					The below tear check configuration properties can be individually tuned if
+					tear check is enabled.
+- qcom,mdss-tear-check-sync-cfg-height: Specifies the vertical total number of lines.
+					The default value is 0xfff0.
+- qcom,mdss-tear-check-sync-init-val:	Specifies the init value at which the read pointer gets loaded
+					at vsync edge. The reader pointer refers to the line number of
+					panel buffer that is currently being updated.
+					The default value is panel height.
+- qcom,mdss-tear-check-sync-threshold-start:
+					Allows the first ROI line write to an panel when read pointer is
+					between the range of ROI start line and ROI start line plus this
+					setting.
+					The default value is 4.
+- qcom,mdss-tear-check-sync-threshold-continue:
+					The minimum number of lines the write pointer needs to be
+					above the read pointer so that it is safe to write to the panel.
+					(This check is not done for the first ROI line write of an update)
+					The default value is 4.
+- qcom,mdss-tear-check-start-pos:	Specify the y position from which the start_threshold value is
+					added and write is kicked off if the read pointer falls within that
+					region.
+					The default value is panel height.
+- qcom,mdss-tear-check-rd-ptr-trigger-intr:
+					Specify the read pointer value at which an interrupt has to be
+					generated.
+					The default value is panel height + 1.
+- qcom,mdss-tear-check-frame-rate:	Specify the value to be a real frame rate(fps) x 100 factor to tune the
+					timing of TE simulation with more precision.
+					The default value is 6000 with 60 fps.
 
 Note, if a given optional qcom,* binding is not present, then the driver will configure
 the default values specified.
@@ -354,5 +385,12 @@
 		mdss-dsi-rx-eot-ignore;
 		mdss-dsi-tx-eot-append;
 		qcom,ulps-enabled;
+		qcom,mdss-tear-check-sync-cfg-height = <0xfff0>;
+		qcom,mdss-tear-check-sync-init-val = <1280>;
+		qcom,mdss-tear-check-sync-threshold-start = <4>;
+		qcom,mdss-tear-check-sync-threshold-continue = <4>;
+		qcom,mdss-tear-check-start-pos = <1280>;
+		qcom,mdss-tear-check-rd-ptr-trigger-intr = <1281>;
+		qcom,mdss-tear-check-frame-rate = <6000>;
 	};
 };
diff --git a/Documentation/devicetree/bindings/fb/mdss-mdp.txt b/Documentation/devicetree/bindings/fb/mdss-mdp.txt
index cfcc48b..bd11551 100644
--- a/Documentation/devicetree/bindings/fb/mdss-mdp.txt
+++ b/Documentation/devicetree/bindings/fb/mdss-mdp.txt
@@ -246,6 +246,8 @@
 - qcom,mdss-has-wfd-blk: Boolean property to indicate the presence of dedicated
 			writeback wfd block in MDSS as opposed to writeback
 			block that is shared between rotator and wfd.
+- qcom,mdss-no-lut-read: 	Boolean property to indicate reading of LUT is
+				not supported.
 - qcom,mdss-smp-mb-per-pipe:	Maximum number of shared memory pool blocks
 				restricted for a source surface pipe. If this
 				property is not specified, no such restriction
@@ -273,6 +275,12 @@
 				used to reduce the pending writes limit dynamically
 				and can be tuned to match performance requirements
 				depending upon system state.
+- qcom,mdss-clk-levels:		This array indicates the mdp core clock level selection
+				array. Core clock is calculated for each frame and
+				hence depending upon calculated value, clock rate
+				will be rounded up to the next level according to
+				this table. Order of entries need to be ordered in
+				ascending order.
 
 Fudge Factors:			Fudge factors are used to boost demand for
 				resources like bus bandswidth, clk rate etc. to
@@ -288,6 +296,10 @@
 				FUDGE(x, a, b) = ((x * a) / b)
 - qcom,mdss-ib-factor:		This fudge factor is applied to calculated ib
 				values in default conditions.
+- qcom,mdss-ib-factor-overlap:	This fudge factor is applied to calculated ib
+				values when the overlap bandwidth is the
+				predominant value compared to prefill bandwidth
+				value.
 - qcom,mdss-clk-factor:		This fudge factor is applied to calculated mdp
 				clk rate in default conditions.
 - qcom,mdss-highest-bank-bit: Property to indicate tile format as opposed to usual
@@ -357,6 +369,9 @@
 		qcom,mdss-ib-factor = <3 2>;		/* 1.5 times  */
 		qcom,mdss-clk-factor = <5 4>;		/* 1.25 times */
 
+		/* Clock levels */
+		qcom,mdss-clk-levels = <92310000, 177780000, 200000000>;
+
 		qcom,max-clk-rate = <320000000>;
 		qcom,vbif-settings = <0x0004 0x00000001>,
 				     <0x00D8 0x00000707>;
@@ -387,6 +402,7 @@
 		qcom,mdss-has-bwc;
 		qcom,mdss-has-decimation;
 		qcom,mdss-has-wfd-blk;
+		qcom,mdss-no-lut-read;
 
 		qcom,mdss-pipe-vig-clk-ctrl-offsets = <0x3AC 0 0>,
 						      <0x3B4 0 0>,
diff --git a/Documentation/devicetree/bindings/hwmon/qpnp-adc-current.txt b/Documentation/devicetree/bindings/hwmon/qpnp-adc-current.txt
index 9acf54a..3e6d060 100644
--- a/Documentation/devicetree/bindings/hwmon/qpnp-adc-current.txt
+++ b/Documentation/devicetree/bindings/hwmon/qpnp-adc-current.txt
@@ -29,10 +29,12 @@
 - qcom,use-default-rds-trim : Add this property to check if certain conditions are to be checked
 			      reading the SMBB_BAT_IF_CNST_RDS, IADC_RDS trim register and
 			      manufacturer type. Check the driver for conditions that each of the type.
-			      0 : Select this type to read the IADC and SMBB trim register and
+			      0 : Select the TypeA to read the IADC and SMBB trim register and
 				  apply the default RSENSE if conditions are met.
-			      1 : Select this type to read the IADC, SMBB trim register and
+			      1 : Select the TypeB to read the IADC, SMBB trim register and
 				  manufacturer type and apply the default RSENSE if conditions are met.
+			      2 : Select the TypeC to read the IADC, SMBB trim register and
+				  apply the default RSENSE if conditions are met.
 - qcom,pmic-revid : Phandle pointing to the revision peripheral node. Use it to query the
 		    PMIC type and revision for applying the appropriate temperature
 		    compensation parameters.
diff --git a/Documentation/devicetree/bindings/power/smb358-charger.txt b/Documentation/devicetree/bindings/power/smb358-charger.txt
new file mode 100644
index 0000000..9d5dc6a
--- /dev/null
+++ b/Documentation/devicetree/bindings/power/smb358-charger.txt
@@ -0,0 +1,71 @@
+Summit smb358 battery charger
+
+SMB358 is a single-cell battery charger. It can charge
+the battery and power the system via the USB/AC adapter input.
+
+The smb358 interface is via I2C bus.
+
+Required Properties:
+- compatible			Must be "qcom,smb358-charger".
+- reg				The device 7-bit I2C address.
+- interrupt-parent		parent of interrupt.
+- interrupts			This indicates the IRQ number of the GPIO
+				connected to the STAT pin.
+- qcom,irq-gpio			GPIO which receives interrupts from STAT output.
+- qcom,bms-psy-name		This is a string and it points to the bms
+				power supply name.
+- qcom,float-voltage-mv		Float Voltage in mV - the maximum voltage up to which
+				the battery is charged. Supported range 3500mV to 4500mV
+- qcom,vcc-i2c-supply		Power source required to power up i2c bus.
+- qcom,chg-vadc			Corresponding VADC device's phandle.
+
+Optional Properties:
+
+- qcom,fastchg-current-max-ma	Fast Charging current in mA. Supported range is
+				from 200mA to 2000mA.
+- qcom,chg-valid-gpio		GPIO which indicates the charger presence.
+				This GPIO is connected to the SYSOK pin.
+- qcom,chg-autonomous-mode	This is a bool property and it indicates that the
+				charger is configured for autonomous operation and
+				does not require any software configuration.
+- qcom,disable-apsd		This is a bool property which disables automatic
+				power source detection (APSD). If this is set
+				charger detection is done by DCIN UV irq.
+- qcom,charger-disabled		This is a bool property which disables charging.
+- qcom,using-pmic-therm		This property indicates thermal pin connected to pmic or smb.
+- qcom,iterm-ma			Specifies the termination current to indicate end-of-charge.
+				Possible values in mA - 30, 40, 60, 80, 100, 125, 150, 200.
+- qcom,iterm-disabled		Disables the termination current feature. This is a bool
+				property.
+- qcom,recharge-mv		Recharge threshold in mV - the offset from the float-volatge
+				as which the charger restarts charging. Possible
+				values are 50mV to 300mV.
+- qcom,recharge-disabled	Boolean value which disables the auto-recharge.
+- qcom,chg-adc_tm		phandle to the corresponding VADC device to read the ADC channels.
+- qcom,cold-bat-decidegc	Cold battery temperature in decidegC.
+- qcom,hot-bat-decidegc		Hot battery temperature in decidegC.
+- qcom,bat-present-decidegc	This is a property indicating battery present temperature, if
+				higher than it, battery should exist. Default value is negative,
+				if this property is 200, it stands for -200 decidegC.
+
+Example:
+	i2c@f9967000 {
+		smb358-charger@1b {
+			compatible = "qcom,smb358-charger";
+			reg = <0x1b>;
+			interrupt-parent = <&msmgpio>;
+			interrupts = <17 0x0>;
+			qcom,irq-gpio = <&msmgpio 17 0x00>;
+			qcom,vcc-i2c-supply = <&pm8226_lvs1>;
+			qcom,float-voltage-mv = <4350>;
+			qcom,disable-apsd;
+			qcom,fastchg-current-max-ma = <1500>;
+			qcom,bms-psy-name = "bms";
+			qcom,chg-vadc = <&pm8226_vadc>;
+			qcom,chg-adc_tm = <&pm8226_adc_tm>;
+			qcom,hot-bat-decidegc = <500>;
+			qcom,cold-bat-decidegc = <0>;
+			qcom,bat-present-decidegc = <200>;
+		};
+	};
+
diff --git a/Documentation/devicetree/bindings/regulator/mem-acc-regulator.txt b/Documentation/devicetree/bindings/regulator/mem-acc-regulator.txt
new file mode 100644
index 0000000..8eaa3a1
--- /dev/null
+++ b/Documentation/devicetree/bindings/regulator/mem-acc-regulator.txt
@@ -0,0 +1,52 @@
+Qualcomm Technologies Memory Accelerator
+
+Memory accelerator configures the power-mode (corner) for the
+accelerator.
+
+Required properties:
+- compatible:			Must be "qcom,mem-acc-regulator"
+- regulator-name:		A string used to describe the regulator
+- regulator-min-microvolt:	Minimum corner value as min constraint, which
+				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,corner-acc-map		Array which maps the APC (application processor)
+				corner value to the accelerator corner.
+				[0] maps APC SVS corner (1) to accelerator SVS corner
+				[1] maps APC NOMINAL corner (2) to accelerator NOMINAL corner
+				[2] maps APC TURBO corner (3) to accelerator TURBO corner
+
+Optional properties:
+- reg:				Register addresses for acc-en and acc-sel-l1 acc-sel-l2 control.
+- reg-names:			Register names. Must be "acc-sel-l1", "acc-sel-l2", "acc-en".
+				A given mem-acc-regulator driver must have "acc-sel-l1" or
+				"acc-sel-l2" reg-names property and related register address
+				property.
+- qcom,acc-en-bit-pos		Array which specifies bit positions in the
+				'acc-en' register. Setting these bits forces the
+				the acclerator to use the corner value specified
+				in the 'acc-sel-l1' and 'acc-sel-l2' register.
+- qcom,acc-sel-l1-bit-pos	Array which specifies bit positions in the
+				'acc-sel-l1' register. Each element in this array
+				is the LSB of a 2-bit value. This 2-bit value
+				specifies the corner value used by the
+				accelerator for L1 cache.
+- qcom,acc-sel-l2-bit-pos	Array which specifies bit positions in the
+				'acc-sel-l2' register. Each element in this array
+				is the LSB of a 2-bit value. This 2-bit value
+				specifies the corner value used by the
+				accelerator for L2 cache.
+
+mem_acc_vreg_corner: regulator@fd4aa044 {
+	compatible = "qcom,mem-acc-regulator";
+	reg = <0xfd4aa048 0x1>, <0xfd4aa044 0x1>, <0xfd4af000 0x1>;
+	reg-names = "acc-en", "acc-sel-l1" , "acc-sel-l2";
+	regulator-name = "mem_acc_corner";
+	regulator-min-microvolt = <1>;
+	regulator-max-microvolt = <3>;
+
+	qcom,acc-en-bit-pos = <0>;
+	qcom,acc-sel-l1-bit-pos = <0>;
+	qcom,acc-sel-l2-bit-pos = <0>;
+	qcom,corner-acc-map = <0 1 3>;
+};
diff --git a/Documentation/devicetree/bindings/slimbus/slim-msm-ctrl.txt b/Documentation/devicetree/bindings/slimbus/slim-msm-ctrl.txt
index e199e55..d25b456 100644
--- a/Documentation/devicetree/bindings/slimbus/slim-msm-ctrl.txt
+++ b/Documentation/devicetree/bindings/slimbus/slim-msm-ctrl.txt
@@ -54,11 +54,11 @@
 		 are to be used, so that application processor can query
 		 logical address of the ported generic device to be used.
 		 Other than PC, fields of EA are same across platforms.
- -qcom,slim-mdm: This value indicates presence of slimbus component on
+ - qcom,slim-mdm: This value provides the identifier of slimbus component on
 		 external mdm. This property enables the slimbus driver to
-		 receive subsytem restart notification from mdm and follow
-		 appropriate steps to ensure communication on the bus can be
-		 resumed after mdm-restart.
+		 register and receive subsytem restart notification from mdm
+		 and follow appropriate steps to ensure communication on the bus
+		 can be resumed after mdm-restart.
 Example:
 	slim@fe12f000 {
 		cell-index = <1>;
diff --git a/Documentation/devicetree/bindings/spi/spi_qsd.txt b/Documentation/devicetree/bindings/spi/spi_qsd.txt
index 1504dc0..da71e19 100644
--- a/Documentation/devicetree/bindings/spi/spi_qsd.txt
+++ b/Documentation/devicetree/bindings/spi/spi_qsd.txt
@@ -33,6 +33,9 @@
   When this entry is not present, voting is done by the runtime-pm callbacks.
  - qcom,master-id : Master endpoint number used for voting on clocks using the
   bus-scaling driver.
+ - qcom,rt-priority : whether spi message queue is set to run as a realtime task.
+  With this spi transaction message pump with high (realtime) priority to reduce
+  the transfer latency on the bus by minimising the delay between a transfer request
 
 Optional properties which are required for support of BAM-mode:
 - qcom,ver-reg-exists : Boolean. When present, allows driver to verify if HW
@@ -92,4 +95,5 @@
 		qcom,bam-producer-pipe-index = <13>;
 		qcom,ver-reg-exists;
 		qcom,master-id = <86>;
+		qcom,rt-priority;
 	};
diff --git a/Documentation/devicetree/bindings/usb/msm-hsusb.txt b/Documentation/devicetree/bindings/usb/msm-hsusb.txt
index fcafe11..979819f 100644
--- a/Documentation/devicetree/bindings/usb/msm-hsusb.txt
+++ b/Documentation/devicetree/bindings/usb/msm-hsusb.txt
@@ -196,12 +196,15 @@
   turnaround timeout is observed on enabling streaming. Hence it is required
   to see these errors and number of erros on enabling this at USB level to make
   final decision to enable this feature or not.
+- qcom,android-usb-uicc-nluns : Number of mass storage LUNs required for
+  the UICC card.
 Example Android USB device node :
 	android_usb@fc42b0c8 {
 		compatible = "qcom,android-usb";
 		reg = <0xfc42b0c8 0xc8>;
 		qcom,android-usb-swfi-latency = <1>;
 		qcom,streaming-func = "rndis","mtp";
+		qcom,android-usb-uicc-nluns = <1>;
 	};
 
 
diff --git a/Documentation/devicetree/bindings/usb/msm-ssusb.txt b/Documentation/devicetree/bindings/usb/msm-ssusb.txt
index bfa9abe..d2f03ea 100644
--- a/Documentation/devicetree/bindings/usb/msm-ssusb.txt
+++ b/Documentation/devicetree/bindings/usb/msm-ssusb.txt
@@ -60,6 +60,8 @@
   deemphasis value to be used for overriding into SSPHY register.
 - qcom,usbin-vadc: Corresponding vadc device's phandle to read usbin voltage using VADC.
 	This will be used to get value of usb power supply's VOLTAGE_NOW property,
+- qcom,utmi-clk-rate: Indicates refclk frequency (in Hz) to the core. If not
+  specified, default of 19.2MHz is assumed.
 
 Sub nodes:
 - Sub node for "DWC3- USB3 controller".
diff --git a/arch/arm/Kconfig.debug b/arch/arm/Kconfig.debug
index 344b57e..969ddcb 100644
--- a/arch/arm/Kconfig.debug
+++ b/arch/arm/Kconfig.debug
@@ -63,6 +63,29 @@
 	      8 - SIGSEGV faults
 	     16 - SIGBUS faults
 
+config FORCE_PAGES
+	bool "Force lowmem to be mapped with 4K pages"
+        help
+          There are some advanced debug features that can only be done when
+          memory is mapped with pages instead of sections. Enable this option
+          to always map lowmem pages with pages. This may have a performance
+          cost due to increased TLB pressure.
+
+          If unsure say N.
+
+config FREE_PAGES_RDONLY
+	bool "Set pages as read only while on the buddy list"
+	select FORCE_PAGES
+	select PAGE_POISONING
+	help
+          Pages are always mapped in the kernel. This means that anyone
+          can write to the page if they have the address. Enable this option
+          to mark pages as read only to trigger a fault if any code attempts
+          to write to a page on the buddy list. This may have a performance
+          impact.
+
+          If unsure, say N.
+
 # These options are only for real kernel hackers who want to get their hands dirty.
 config DEBUG_LL
 	bool "Kernel low-level debugging functions (read help!)"
diff --git a/arch/arm/boot/dts/apq8074-v1.dtsi b/arch/arm/boot/dts/apq8074-v1.dtsi
index a74674b..be7dee8 100644
--- a/arch/arm/boot/dts/apq8074-v1.dtsi
+++ b/arch/arm/boot/dts/apq8074-v1.dtsi
@@ -27,6 +27,7 @@
 		qcom,disk-encrypt-pipe-pair = <2>;
 		qcom,hlos-ce-hw-instance = <1>;
 		qcom,qsee-ce-hw-instance = <0>;
+		qcom,support-bus-scaling;
 		qcom,msm-bus,name = "qseecom-noc";
 		qcom,msm-bus,num-cases = <4>;
 		qcom,msm-bus,active-only = <0>;
@@ -34,9 +35,9 @@
 		qcom,support-fde;
 		qcom,msm-bus,vectors-KBps =
 				<55 512 0 0>,
-				<55 512 3936000 393600>,
-				<55 512 3936000 393600>,
-				<55 512 3936000 393600>;
+				<55 512 0 0>,
+				<55 512 120000 1200000>,
+				<55 512 393600 3936000>;
 	};
 };
 
diff --git a/arch/arm/boot/dts/apq8074-v2.0-1.dtsi b/arch/arm/boot/dts/apq8074-v2.0-1.dtsi
index 2b2af09..064a28c 100644
--- a/arch/arm/boot/dts/apq8074-v2.0-1.dtsi
+++ b/arch/arm/boot/dts/apq8074-v2.0-1.dtsi
@@ -32,11 +32,12 @@
 		qcom,msm-bus,active-only = <0>;
 		qcom,msm-bus,num-paths = <1>;
 		qcom,support-fde;
+		qcom,support-bus-scaling;
 		qcom,msm-bus,vectors-KBps =
 				<55 512 0 0>,
-				<55 512 3936000 393600>,
-				<55 512 3936000 393600>,
-				<55 512 3936000 393600>;
+				<55 512 0 0>,
+				<55 512 120000 1200000>,
+				<55 512 393600 3936000>;
 	};
 
 	sound {
diff --git a/arch/arm/boot/dts/apq8074-v2.2.dtsi b/arch/arm/boot/dts/apq8074-v2.2.dtsi
index 8f46270..010d574 100644
--- a/arch/arm/boot/dts/apq8074-v2.2.dtsi
+++ b/arch/arm/boot/dts/apq8074-v2.2.dtsi
@@ -32,11 +32,12 @@
 		qcom,msm-bus,active-only = <0>;
 		qcom,msm-bus,num-paths = <1>;
 		qcom,support-fde;
+		qcom,support-bus-scaling;
 		qcom,msm-bus,vectors-KBps =
 				<55 512 0 0>,
-				<55 512 3936000 393600>,
-				<55 512 3936000 393600>,
-				<55 512 3936000 393600>;
+				<55 512 0 0>,
+				<55 512 120000 1200000>,
+				<55 512 393600 3936000>;
 	};
 
 	sound {
diff --git a/arch/arm/boot/dts/dsi-panel-jdi-720p-cmd.dtsi b/arch/arm/boot/dts/dsi-panel-jdi-720p-cmd.dtsi
new file mode 100755
index 0000000..d465a6f
--- /dev/null
+++ b/arch/arm/boot/dts/dsi-panel-jdi-720p-cmd.dtsi
@@ -0,0 +1,89 @@
+/* Copyright (c) 2014, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+/*---------------------------------------------------------------------------
+ * This file is autogenerated file using gcdb parser. Please do not edit it.
+ * Update input XML file to add a new entry or update variable in this file
+ * VERSION = "1.0"
+ *---------------------------------------------------------------------------*/
+&mdss_mdp {
+	dsi_jdi_720p_cmd: qcom,mdss_dsi_jdi_720p_cmd {
+		qcom,mdss-dsi-panel-name = "JDI 720p command mode dsi panel";
+		qcom,mdss-dsi-panel-controller = <&mdss_dsi0>;
+		qcom,mdss-dsi-panel-type = "dsi_cmd_mode";
+		qcom,mdss-dsi-panel-destination = "display_1";
+		qcom,mdss-dsi-panel-framerate = <50>;
+		qcom,mdss-dsi-virtual-channel-id = <0>;
+		qcom,mdss-dsi-stream = <0>;
+		qcom,mdss-dsi-panel-width = <720>;
+		qcom,mdss-dsi-panel-height = <1280>;
+		qcom,mdss-dsi-h-front-porch = <130>;
+		qcom,mdss-dsi-h-back-porch = <130>;
+		qcom,mdss-dsi-h-pulse-width = <8>;
+		qcom,mdss-dsi-h-sync-skew = <0>;
+		qcom,mdss-dsi-v-back-porch = <32>;
+		qcom,mdss-dsi-v-front-porch = <32>;
+		qcom,mdss-dsi-v-pulse-width = <4>;
+		qcom,mdss-dsi-h-left-border = <0>;
+		qcom,mdss-dsi-h-right-border = <0>;
+		qcom,mdss-dsi-v-top-border = <0>;
+		qcom,mdss-dsi-v-bottom-border = <0>;
+		qcom,mdss-dsi-bpp = <24>;
+		qcom,mdss-dsi-underflow-color = <0xff>;
+		qcom,mdss-dsi-border-color = <0>;
+		qcom,mdss-dsi-on-command = [05 01 00 00 78 00 02 28 00
+				05 01 00 00 78 00 02 10 00
+				05 01 00 00 64 00 02 01 00
+				05 01 00 00 64 00 02 11 00
+				05 01 00 00 64 00 02 29 00
+				15 01 00 00 0a 00 02 35 00
+				39 01 00 00 0a 00 04 ff 12 82 01
+				15 01 00 00 0a 00 02 00 80
+				15 01 00 00 0a 00 02 ff 12
+				15 01 00 00 0a 00 02 00 81
+				15 01 00 00 0a 00 02 ff 82
+				15 01 00 00 0a 00 02 00 b4
+				15 01 00 00 0a 00 02 c0 40
+				39 01 00 00 0a 00 08 00 80 ff 00 00 81 ff 00
+				39 01 00 00 0a 00 06 00 00 ff 00 00 00];
+		qcom,mdss-dsi-off-command = [05 01 00 00 0a 00 01 34
+				05 01 00 00 0a 00 02 28 00
+				05 01 00 00 78 00 02 10 00];
+		qcom,mdss-dsi-on-command-state = "dsi_lp_mode";
+		qcom,mdss-dsi-off-command-state = "dsi_hs_mode";
+		qcom,mdss-dsi-h-sync-pulse = <0>;
+		qcom,mdss-dsi-traffic-mode = "non_burst_sync_event";
+		qcom,mdss-dsi-pan-enable-dynamic-fps;
+		qcom,mdss-dsi-fps-update = "dfps_suspend_resume_mode";
+		qcom,mdss-dsi-bllp-eof-power-mode;
+		qcom,mdss-dsi-bllp-power-mode;
+		qcom,mdss-dsi-lane-0-state;
+		qcom,mdss-dsi-lane-1-state;
+		qcom,mdss-dsi-lane-2-state;
+		qcom,mdss-dsi-lane-3-state;
+		qcom,mdss-dsi-te-pin-select = <1>;
+		qcom,mdss-dsi-te-v-sync-rd-ptr-irq-line = <0x2c>;
+		qcom,mdss-dsi-te-dcs-command = <1>;
+		qcom,mdss-dsi-te-check-enable;
+		qcom,mdss-dsi-te-using-te-pin;
+		qcom,mdss-dsi-panel-timings = [6e 26 1b 00 35 34
+					20 28 17 03 04 00];
+		qcom,mdss-dsi-t-clk-post = <0x20>;
+		qcom,mdss-dsi-t-clk-pre = <0x2a>;
+		qcom,mdss-dsi-bl-min-level = <1>;
+		qcom,mdss-dsi-bl-max-level = <4095>;
+		qcom,mdss-dsi-dma-trigger = "trigger_sw";
+		qcom,mdss-dsi-mdp-trigger = "none";
+		qcom,mdss-dsi-bl-pmic-control-type = "bl_ctrl_wled";
+		qcom,mdss-dsi-reset-sequence = <1 20>, <0 200>, <1 20>;
+	};
+};
diff --git a/arch/arm/boot/dts/dsi-panel-truly-wvga-cmd.dtsi b/arch/arm/boot/dts/dsi-panel-truly-wvga-cmd.dtsi
index 3106cd4..e6aaa41 100644
--- a/arch/arm/boot/dts/dsi-panel-truly-wvga-cmd.dtsi
+++ b/arch/arm/boot/dts/dsi-panel-truly-wvga-cmd.dtsi
@@ -167,5 +167,9 @@
 		qcom,mdss-dsi-reset-sequence = <1 20>, <0 2>, <1 20>;
 		qcom,mdss-pan-physical-width-dimension = <52>;
 		qcom,mdss-pan-physical-height-dimension = <86>;
+		qcom,mdss-tear-check-rd-ptr-trigger-intr = <0x5>;
+		qcom,mdss-tear-check-sync-threshold-start = <0x2>;
+		qcom,mdss-tear-check-sync-threshold-continue = <0x4>;
+		qcom,mdss-tear-check-start-pos = <0x18>;
 	};
 };
diff --git a/arch/arm/boot/dts/msm-pm8110.dtsi b/arch/arm/boot/dts/msm-pm8110.dtsi
index 7a60861..5ccecfa 100644
--- a/arch/arm/boot/dts/msm-pm8110.dtsi
+++ b/arch/arm/boot/dts/msm-pm8110.dtsi
@@ -339,6 +339,10 @@
 			qcom,bms-iadc = <&pm8110_iadc>;
 			qcom,bms-adc_tm = <&pm8110_adc_tm>;
 
+			qcom,batt-pres-status@1208 {
+				reg = <0x1208 0x1>;
+			};
+
 			qcom,bms-iadc@3800 {
 				reg = <0x3800 0x100>;
 			};
diff --git a/arch/arm/boot/dts/msm-pm8226.dtsi b/arch/arm/boot/dts/msm-pm8226.dtsi
index 08d3d05..6e1b985 100644
--- a/arch/arm/boot/dts/msm-pm8226.dtsi
+++ b/arch/arm/boot/dts/msm-pm8226.dtsi
@@ -210,6 +210,10 @@
 			qcom,bms-iadc = <&pm8226_iadc>;
 			qcom,bms-adc_tm = <&pm8226_adc_tm>;
 
+			qcom,batt-pres-status@1208 {
+				reg = <0x1208 0x1>;
+			};
+
 			qcom,bms-iadc@3800 {
 				reg = <0x3800 0x100>;
 			};
@@ -424,7 +428,7 @@
 			qcom,adc-vdd-reference = <1800>;
 			qcom,iadc-vadc = <&pm8226_vadc>;
 			qcom,iadc-poll-eoc;
-			qcom,use-default-rds-trim = <0>;
+			qcom,use-default-rds-trim = <2>;
 			qcom,pmic-revid = <&pm8226_revid>;
 
 			chan@0 {
diff --git a/arch/arm/boot/dts/msm-pm8941.dtsi b/arch/arm/boot/dts/msm-pm8941.dtsi
index a0e02f7..d8046c5 100644
--- a/arch/arm/boot/dts/msm-pm8941.dtsi
+++ b/arch/arm/boot/dts/msm-pm8941.dtsi
@@ -141,6 +141,10 @@
 		qcom,bms-iadc = <&pm8941_iadc>;
 		qcom,bms-adc_tm = <&pm8941_adc_tm>;
 
+		qcom,batt-pres-status@1208 {
+			reg = <0x1208 0x1>;
+		};
+
 		qcom,bms-iadc@3800 {
 			reg = <0x3800 0x100>;
 		};
diff --git a/arch/arm/boot/dts/msm-pma8084.dtsi b/arch/arm/boot/dts/msm-pma8084.dtsi
index c070443..93f05c4 100644
--- a/arch/arm/boot/dts/msm-pma8084.dtsi
+++ b/arch/arm/boot/dts/msm-pma8084.dtsi
@@ -837,5 +837,53 @@
 				status = "disabled";
 			};
 		};
+
+		pma8084_lpg1: pwm@b100 {
+			compatible = "qcom,qpnp-pwm";
+			reg = <0xb100 0x100>,
+			      <0xb042 0x7e>;
+			reg-names = "qpnp-lpg-channel-base", "qpnp-lpg-lut-base";
+			qcom,channel-id = <0>;
+		};
+
+		pma8084_lpg2: pwm@b200 {
+			compatible = "qcom,qpnp-pwm";
+			reg = <0xb200 0x100>,
+			      <0xb042 0x7e>;
+			reg-names = "qpnp-lpg-channel-base", "qpnp-lpg-lut-base";
+			qcom,channel-id = <1>;
+		};
+
+		pma8084_lpg3: pwm@b300 {
+			compatible = "qcom,qpnp-pwm";
+			reg = <0xb300 0x100>,
+			      <0xb042 0x7e>;
+			reg-names = "qpnp-lpg-channel-base", "qpnp-lpg-lut-base";
+			qcom,channel-id = <2>;
+		};
+
+		pma8084_lpg4: pwm@b400 {
+			compatible = "qcom,qpnp-pwm";
+			reg = <0xb400 0x100>,
+			      <0xb042 0x7e>;
+			reg-names = "qpnp-lpg-channel-base", "qpnp-lpg-lut-base";
+			qcom,channel-id = <3>;
+		};
+
+		pma8084_lpg5: pwm@b500 {
+			compatible = "qcom,qpnp-pwm";
+			reg = <0xb500 0x100>,
+			      <0xb042 0x7e>;
+			reg-names = "qpnp-lpg-channel-base", "qpnp-lpg-lut-base";
+			qcom,channel-id = <4>;
+		};
+
+		pma8084_lpg6: pwm@b600 {
+			compatible = "qcom,qpnp-pwm";
+			reg = <0xb600 0x100>,
+			      <0xb042 0x7e>;
+			reg-names = "qpnp-lpg-channel-base", "qpnp-lpg-lut-base";
+			qcom,channel-id = <5>;
+		};
 	};
 };
diff --git a/arch/arm/boot/dts/msm8226-bus.dtsi b/arch/arm/boot/dts/msm8226-bus.dtsi
index a2f91cf..8abe795 100644
--- a/arch/arm/boot/dts/msm8226-bus.dtsi
+++ b/arch/arm/boot/dts/msm8226-bus.dtsi
@@ -1,4 +1,4 @@
-/* Copyright (c) 2013, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2013-2014, The Linux Foundation. All rights reserved.
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 and
@@ -22,6 +22,7 @@
 		qcom,qos-freq = <4800>;
 		qcom,hw-sel = "NoC";
 		qcom,rpm-en;
+		qcom,nfab = <6>;
 
 		mas-gfx3d {
 			cell-id = <26>;
@@ -261,6 +262,7 @@
 		qcom,qos-freq = <4800>;
 		qcom,hw-sel = "NoC";
 		qcom,rpm-en;
+		qcom,nfab = <6>;
 
 		mas-lpass-ahb {
 			cell-id = <52>;
@@ -473,6 +475,7 @@
 		qcom,ntieredslaves = <0>;
 		qcom,hw-sel = "NoC";
 		qcom,rpm-en;
+		qcom,nfab = <6>;
 
 		mas-pnoc-cfg {
 			cell-id = <88>;
@@ -678,6 +681,7 @@
 		qcom,ntieredslaves = <0>;
 		qcom,hw-sel = "NoC";
 		qcom,rpm-en;
+		qcom,nfab = <6>;
 
 		mas-rpm-inst {
 			cell-id = <72>;
@@ -1001,6 +1005,7 @@
 		qcom,qos-freq = <19200>;
 		qcom,hw-sel = "BIMC";
 		qcom,rpm-en;
+		qcom,nfab = <6>;
 
 		mas-ampss-m0 {
 			cell-id = <1>;
@@ -1088,6 +1093,7 @@
 		qcom,hw-sel = "NoC";
 		qcom,rpm-en;
 		qcom,virt;
+		qcom,nfab = <6>;
 
 		mas-v-ocmem-gfx3d {
 			cell-id = <89>;
diff --git a/arch/arm/boot/dts/msm8226-mdss.dtsi b/arch/arm/boot/dts/msm8226-mdss.dtsi
index 5edc43b..5776926 100644
--- a/arch/arm/boot/dts/msm8226-mdss.dtsi
+++ b/arch/arm/boot/dts/msm8226-mdss.dtsi
@@ -36,6 +36,10 @@
 		qcom,mdss-ib-factor = <2 1>;		/* 2 times  */
 		qcom,mdss-clk-factor = <5 4>;		/* 1.25 times */
 
+		/* Clock levels */
+		qcom,mdss-clk-levels = <92310000 100000000
+				    133330000 177780000 200000000>;
+
 		qcom,max-clk-rate = <200000000>;
 		qcom,mdss-pipe-vig-off = <0x00001200>;
 		qcom,mdss-pipe-rgb-off = <0x00001E00>;
@@ -54,6 +58,8 @@
 
 		qcom,mdss-smp-data = <7 4096>;
 
+		qcom,mdss-no-lut-read;
+
 		qcom,mdss-ctl-off = <0x00000600 0x00000700>;
 		qcom,mdss-mixer-intf-off = <0x00003200>;
 		qcom,mdss-mixer-wb-off = <0x00003E00>;
diff --git a/arch/arm/boot/dts/msm8226-v2.dtsi b/arch/arm/boot/dts/msm8226-v2.dtsi
index 14fe237..787c9fb 100644
--- a/arch/arm/boot/dts/msm8226-v2.dtsi
+++ b/arch/arm/boot/dts/msm8226-v2.dtsi
@@ -80,11 +80,18 @@
 			<         0 0>,
 			< 384000000 2>,
 			< 787200000 4>,
+			< 998400000 5>,
+			<1094400000 6>,
 			<1190400000 7>;
 		qcom,speed2-bin-v2 =
 			<         0 0>,
 			< 384000000 2>,
 			< 787200000 4>,
+			< 998400000 5>,
+			<1094400000 6>,
+			<1190400000 7>,
+			<1305600000 8>,
+			<1344000000 9>,
 			<1401600000 10>;
 		qcom,speed1-bin-v2 =
 			<         0 0>,
diff --git a/arch/arm/boot/dts/msm8226.dtsi b/arch/arm/boot/dts/msm8226.dtsi
index c31f2d3..8d2414c 100644
--- a/arch/arm/boot/dts/msm8226.dtsi
+++ b/arch/arm/boot/dts/msm8226.dtsi
@@ -300,6 +300,7 @@
 		reg = <0xfe8050c8 0xc8>;
 		qcom,android-usb-swfi-latency = <1>;
 		qcom,streaming-func = "rndis";
+		qcom,android-usb-uicc-nluns = <1>;
 	};
 
 	smsc_hub: hsic_hub {
@@ -1060,7 +1061,7 @@
 			<  300000 1525 >,
 			<  384000 1525 >,
 			<  600000 1525 >,
-			<  787200 3051 >,
+			<  787200 1525 >,
 			<  998400 4066 >,
 			< 1094400 4066 >,
 			< 1190400 4066 >,
@@ -1386,6 +1387,12 @@
 		qcom,irq-is-percpu;
 		interrupts = <1 7 0xf00>;
 	};
+
+	bimc_sharedmem {
+		compatible = "qcom,sharedmem-uio";
+		reg = <0xfc380000 0x00100000>;
+		reg-names = "bimc";
+	};
 };
 
 &gdsc_venus {
diff --git a/arch/arm/boot/dts/msm8610-cdp.dtsi b/arch/arm/boot/dts/msm8610-cdp.dtsi
index 04eca14..9344e89 100644
--- a/arch/arm/boot/dts/msm8610-cdp.dtsi
+++ b/arch/arm/boot/dts/msm8610-cdp.dtsi
@@ -1,4 +1,4 @@
-/* Copyright (c) 2013, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2013-2014, 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
@@ -39,15 +39,15 @@
 				/* Object 6, Instance = 0 */
 				00 00 00 00 00 00
 				/* Object 38, Instance = 0 */
-				1D 03 00 1E 07 0D 00 00
+				1D 05 00 1D 0B 0D 00 00
 				/* Object 7, Instance = 0 */
-				20 08 32
+				20 0A 32
 				/* Object 8, Instance = 0 */
-				19 00 14 14 FF 00 FF 00 00 00
+				19 00 14 14 FF 00 05 00 32 19
 				/* Object 9, Instance = 0 */
 				83 00 00 13 0B 00 20 32 01 03
-				00 32 05 30 0A 05 0A 00 70 03
-				FC 01 04 2F F8 DC 00 00 40 00
+				00 0A 05 30 0A 05 0A 00 70 03
+				FC 01 04 2F 08 24 00 00 40 00
 				00 0A 00 00 02
 				/* Object 18, Instance = 0 */
 				00 00
@@ -59,16 +59,16 @@
 				00 00 00 00 00 00 00 00 00 00
 				00
 				/* Object 42, Instance = 0 */
-				00 00 00 00 00 00 00 00
+				03 19 1E 14 80 05 00 00
 				/* Object 46, Instance = 0 */
 				04 03 08 10 00 00 00 00 00
 				/* Object 47, Instance = 0 */
 				00 00 00 00 00 00 00 00 00 00
 				/* Object 48, Instance = 0 */
-				00 00 00 00 00 00 00 00 00 00
-				00 00 00 00 00 00 00 00 00 00
-				00 00 00 00 00 00 00 00 00 00
-				00 00 00 00 00 00 00 00 00 00
+				1D C0 22 00 00 00 00 00 00 00
+				20 19 00 06 06 00 00 64 04 40
+				00 00 00 05 00 2A 00 00 00 19
+				34 0C 00 00 00 00 00 00 00 00
 				00 00 00 00 00 00 00 00 00 00
 				00 00 00 00
 				/* Object 55, Instance = 0 */
diff --git a/arch/arm/boot/dts/msm8610-mdss.dtsi b/arch/arm/boot/dts/msm8610-mdss.dtsi
index 929659e..70d53e9 100644
--- a/arch/arm/boot/dts/msm8610-mdss.dtsi
+++ b/arch/arm/boot/dts/msm8610-mdss.dtsi
@@ -1,4 +1,4 @@
-/* Copyright (c) 2012-2013, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2012-2014, 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
@@ -16,6 +16,7 @@
 		reg = <0xfd900000 0x100000>;
 		reg-names = "mdp_phys";
 		interrupts = <0 72 0>;
+		vdd-cx-supply = <&pm8110_s1_corner>;
 
 		mdss_fb0: qcom,mdss_fb_primary {
 			cell-index = <0>;
diff --git a/arch/arm/boot/dts/msm8610-mtp.dtsi b/arch/arm/boot/dts/msm8610-mtp.dtsi
index aad838e..d88aba6 100644
--- a/arch/arm/boot/dts/msm8610-mtp.dtsi
+++ b/arch/arm/boot/dts/msm8610-mtp.dtsi
@@ -1,4 +1,4 @@
-/* Copyright (c) 2013-14, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2013-2014, 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
@@ -39,15 +39,15 @@
 				/* Object 6, Instance = 0 */
 				00 00 00 00 00 00
 				/* Object 38, Instance = 0 */
-				1D 05 01 0D 01 0E 00 00
+				1D 05 00 1D 0B 0D 00 00
 				/* Object 7, Instance = 0 */
-				20 08 32
+				20 0A 32
 				/* Object 8, Instance = 0 */
-				19 00 14 14 FF 00 FF 00 00 00
+				19 00 14 14 FF 00 05 00 32 19
 				/* Object 9, Instance = 0 */
 				83 00 00 13 0B 00 20 32 01 03
-				00 32 05 30 05 05 0A 00 70 03
-				FC 01 04 2F F8 DC 00 00 40 00
+				00 0A 05 30 0A 05 0A 00 70 03
+				FC 01 04 2F 08 24 00 00 40 00
 				00 0A 00 00 02
 				/* Object 18, Instance = 0 */
 				00 00
@@ -59,16 +59,16 @@
 				00 00 00 00 00 00 00 00 00 00
 				00
 				/* Object 42, Instance = 0 */
-				00 00 00 00 00 00 00 00
+				03 19 1E 14 80 05 00 00
 				/* Object 46, Instance = 0 */
 				04 03 08 10 00 00 00 00 00
 				/* Object 47, Instance = 0 */
 				00 00 00 00 00 00 00 00 00 00
 				/* Object 48, Instance = 0 */
-				00 00 00 00 00 00 00 00 00 00
-				00 00 00 00 00 00 00 00 00 00
-				00 00 00 00 00 00 00 00 00 00
-				00 00 00 00 00 00 00 00 00 00
+				1D C0 22 00 00 00 00 00 00 00
+				20 19 00 06 06 00 00 64 04 40
+				00 00 00 05 00 2A 00 00 00 19
+				34 0C 00 00 00 00 00 00 00 00
 				00 00 00 00 00 00 00 00 00 00
 				00 00 00 00
 				/* Object 55, Instance = 0 */
diff --git a/arch/arm/boot/dts/msm8610-qrd-skuaa.dtsi b/arch/arm/boot/dts/msm8610-qrd-skuaa.dtsi
index 53abb95..d731ce0 100644
--- a/arch/arm/boot/dts/msm8610-qrd-skuaa.dtsi
+++ b/arch/arm/boot/dts/msm8610-qrd-skuaa.dtsi
@@ -96,3 +96,14 @@
 		qcom,master-en = <1>;
 	};
 };
+
+&sdhc_2 {
+        qcom,nonremovable;
+
+        interrupts = <0 1>;
+        interrupt-map = <0 &intc 0 125 0
+                        1 &intc 0 221 0>;
+        interrupt-names = "hc_irq", "pwr_irq";
+        /delete-property/ cd-gpios;
+};
+
diff --git a/arch/arm/boot/dts/msm8610-qrd-skuab.dtsi b/arch/arm/boot/dts/msm8610-qrd-skuab.dtsi
index 1554575..336553a 100644
--- a/arch/arm/boot/dts/msm8610-qrd-skuab.dtsi
+++ b/arch/arm/boot/dts/msm8610-qrd-skuab.dtsi
@@ -183,3 +183,14 @@
 &dsi_otm8018b_fwvga_vid {
 	qcom,cont-splash-enabled;
 };
+
+&sdhc_2 {
+        qcom,nonremovable;
+
+        interrupts = <0 1>;
+        interrupt-map = <0 &intc 0 125 0
+                        1 &intc 0 221 0>;
+        interrupt-names = "hc_irq", "pwr_irq";
+        /delete-property/ cd-gpios;
+};
+
diff --git a/arch/arm/boot/dts/msm8610-v2-mtp.dts b/arch/arm/boot/dts/msm8610-v2-mtp.dts
index 77f5276..debfc23 100644
--- a/arch/arm/boot/dts/msm8610-v2-mtp.dts
+++ b/arch/arm/boot/dts/msm8610-v2-mtp.dts
@@ -1,4 +1,4 @@
-/* Copyright (c) 2013, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2013-2014, The Linux Foundation. All rights reserved.
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 and
@@ -22,4 +22,6 @@
 	qcom,board-id = <8 0>;
 };
 
-
+&sdhc_2 {
+	qcom,pad-drv-on = <0x5 0x4 0x4>; /* 12mA, 10mA, 10mA */
+};
diff --git a/arch/arm/boot/dts/msm8610.dtsi b/arch/arm/boot/dts/msm8610.dtsi
index 2938c69..90dae06 100644
--- a/arch/arm/boot/dts/msm8610.dtsi
+++ b/arch/arm/boot/dts/msm8610.dtsi
@@ -256,6 +256,7 @@
 		reg = <0xfe8050c8 0xc8>;
 		qcom,android-usb-swfi-latency = <1>;
 		qcom,streaming-func = "rndis";
+		qcom,android-usb-uicc-nluns = <1>;
 	};
 
 	rmtfs_sharedmem {
@@ -592,6 +593,7 @@
                 qcom,i2c-src-freq = <19200000>;
                 qcom,sda-gpio = <&msmgpio 10 0>;
                 qcom,scl-gpio = <&msmgpio 11 0>;
+		qcom,clk-ctl-xfer;
                 qcom,master-id = <86>;
 	};
 
@@ -929,15 +931,16 @@
 		qcom,disk-encrypt-pipe-pair = <2>;
 		qcom,hlos-ce-hw-instance = <0>;
 		qcom,qsee-ce-hw-instance = <0>;
+		qcom,support-bus-scaling;
 		qcom,msm-bus,name = "qseecom-noc";
 		qcom,msm-bus,num-cases = <4>;
 		qcom,msm-bus,active-only = <0>;
 		qcom,msm-bus,num-paths = <1>;
 		qcom,msm-bus,vectors-KBps =
 				<55 512 0 0>,
-				<55 512 3936000 393600>,
-				<55 512 3936000 393600>,
-				<55 512 3936000 393600>;
+				<55 512 0 0>,
+				<55 512 120000 1200000>,
+				<55 512 393600 3936000>;
 	};
 
         qcom,msm-rng@f9bff000 {
@@ -1040,6 +1043,12 @@
 		qcom,irq-is-percpu;
 		interrupts = <1 7 0xf00>;
 	};
+
+	bimc_sharedmem {
+		compatible = "qcom,sharedmem-uio";
+		reg = <0xfc380000 0x00100000>;
+		reg-names = "bimc";
+	};
 };
 
 &gdsc_vfe {
diff --git a/arch/arm/boot/dts/msm8926-qrd-skug.dtsi b/arch/arm/boot/dts/msm8926-qrd-skug.dtsi
index c93ea12..dabadda 100644
--- a/arch/arm/boot/dts/msm8926-qrd-skug.dtsi
+++ b/arch/arm/boot/dts/msm8926-qrd-skug.dtsi
@@ -98,3 +98,13 @@
 &dsi_ssd2080m_720_vid {
 	qcom,cont-splash-enabled;
 };
+
+&sdhc_2 {
+	qcom,nonremovable;
+
+	interrupts = <0 1>;
+	interrupt-map = <0 &intc 0 125 0
+			1 &intc 0 221 0>;
+	interrupt-names = "hc_irq", "pwr_irq";
+	/delete-property/ cd-gpios;
+};
diff --git a/arch/arm/boot/dts/msm8926-v1-1080p-mtp.dts b/arch/arm/boot/dts/msm8926-v1-1080p-mtp.dts
index 0812c54..d94b40c9 100644
--- a/arch/arm/boot/dts/msm8926-v1-1080p-mtp.dts
+++ b/arch/arm/boot/dts/msm8926-v1-1080p-mtp.dts
@@ -21,3 +21,7 @@
 	compatible = "qcom,msm8926-mtp", "qcom,msm8926", "qcom,mtp";
 	qcom,board-id = <8 2>;
 };
+
+&sdhc_2 {
+       qcom,pad-drv-on = <0x7 0x4 0x4>; /* 16mA, 10mA, 10mA */
+};
diff --git a/arch/arm/boot/dts/msm8926-v1-720p-mtp.dts b/arch/arm/boot/dts/msm8926-v1-720p-mtp.dts
index 7b49930..74fe06f 100644
--- a/arch/arm/boot/dts/msm8926-v1-720p-mtp.dts
+++ b/arch/arm/boot/dts/msm8926-v1-720p-mtp.dts
@@ -21,3 +21,7 @@
 	compatible = "qcom,msm8926-mtp", "qcom,msm8926", "qcom,mtp";
 	qcom,board-id = <8 0>;
 };
+
+&sdhc_2 {
+       qcom,pad-drv-on = <0x7 0x4 0x4>; /* 16mA, 10mA, 10mA */
+};
diff --git a/arch/arm/boot/dts/msm8926-v2.dtsi b/arch/arm/boot/dts/msm8926-v2.dtsi
index 1322573..c443ba6 100644
--- a/arch/arm/boot/dts/msm8926-v2.dtsi
+++ b/arch/arm/boot/dts/msm8926-v2.dtsi
@@ -66,6 +66,22 @@
 	};
 };
 
+&soc {
+	mem_acc_vreg_corner: regulator@fd4aa044 {
+		compatible = "qcom,mem-acc-regulator";
+		reg = <0xfd4aa048 0x4>, <0xfd4aa044 0x4>, <0xfd4af000 0x4>;
+		reg-names = "acc-en", "acc-sel-l1", "acc-sel-l2";
+		regulator-name = "mem_acc_corner";
+		regulator-min-microvolt = <1>;
+		regulator-max-microvolt = <3>;
+
+		qcom,acc-en-bit-pos = <0>;
+		qcom,acc-sel-l1-bit-pos = <0>;
+		qcom,acc-sel-l2-bit-pos = <0>;
+		qcom,corner-acc-map = <0 1 3>;
+	};
+};
+
 &pm8226_l3 {
 	regulator-max-microvolt = <1287500>;
 };
@@ -90,4 +106,5 @@
 	qcom,vdd-mx-vmax = <1287500>;
 	qcom,vdd-mx-vmin-method = <4>;
 	qcom,vdd-mx-corner-map = <1050000 1150000 1280000>;
+	mem-acc-supply = <&mem_acc_vreg_corner>;
 };
diff --git a/arch/arm/boot/dts/msm8926.dtsi b/arch/arm/boot/dts/msm8926.dtsi
index 394f4a9..1919022 100644
--- a/arch/arm/boot/dts/msm8926.dtsi
+++ b/arch/arm/boot/dts/msm8926.dtsi
@@ -53,11 +53,18 @@
 			<         0 0>,
 			< 384000000 2>,
 			< 787200000 4>,
+			< 998400000 5>,
+			<1094400000 6>,
 			<1190400000 7>;
 		qcom,speed2-bin-v1 =
 			<         0 0>,
 			< 384000000 2>,
 			< 787200000 4>,
+			< 998400000 5>,
+			<1094400000 6>,
+			<1190400000 7>,
+			<1305600000 8>,
+			<1344000000 9>,
 			<1401600000 10>;
 		qcom,speed1-bin-v1 =
 			<         0 0>,
diff --git a/arch/arm/boot/dts/msm8974-camera-sensor-cdp.dtsi b/arch/arm/boot/dts/msm8974-camera-sensor-cdp.dtsi
index 157c136..2e58167 100644
--- a/arch/arm/boot/dts/msm8974-camera-sensor-cdp.dtsi
+++ b/arch/arm/boot/dts/msm8974-camera-sensor-cdp.dtsi
@@ -27,130 +27,13 @@
 		qcom,cci-master = <0>;
 	};
 
-	qcom,camera@6e {
-		compatible = "qcom,s5k3l1yx";
-		reg = <0x6e>;
-		qcom,slave-id = <0x6e 0x0 0x3121>;
-		qcom,csiphy-sd-index = <0>;
-		qcom,csid-sd-index = <0>;
-		qcom,actuator-src = <&actuator0>;
-		qcom,mount-angle = <90>;
-		qcom,sensor-name = "s5k3l1yx";
-		cam_vdig-supply = <&pm8941_l3>;
-		cam_vana-supply = <&pm8941_l17>;
-		cam_vio-supply = <&pm8941_lvs3>;
-		cam_vaf-supply = <&pm8941_l23>;
-		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 = <1225000 0 2850000 3000000>;
-		qcom,cam-vreg-max-voltage = <1225000 0 2850000 3000000>;
-		qcom,cam-vreg-op-mode = <105000 0 80000 100000>;
-		qcom,gpio-no-mux = <0>;
-		gpios = <&msmgpio 15 0>,
-			<&msmgpio 90 0>,
-			<&msmgpio 89 0>;
-		qcom,gpio-reset = <1>;
-		qcom,gpio-standby = <2>;
-		qcom,gpio-req-tbl-num = <0 1 2>;
-		qcom,gpio-req-tbl-flags = <1 0 0>;
-		qcom,gpio-req-tbl-label = "CAMIF_MCLK",
-					  "CAM_RESET1",
-					  "CAM_STANDBY";
-		qcom,gpio-set-tbl-num = <1 1>;
-		qcom,gpio-set-tbl-flags = <0 2>;
-		qcom,gpio-set-tbl-delay = <1000 30000>;
-		qcom,csi-lane-assign = <0x4320>;
-		qcom,csi-lane-mask = <0x1F>;
-		qcom,sensor-position = <0>;
-		qcom,sensor-mode = <1>;
-		qcom,cci-master = <0>;
-		status = "ok";
-	};
-
-    qcom,camera@20 {
-		compatible = "qcom,imx135";
-		reg = <0x20>;
-		qcom,slave-id = <0x20 0x0016 0x0135>;
-		qcom,csiphy-sd-index = <0>;
-		qcom,csid-sd-index = <0>;
-		qcom,mount-angle = <90>;
-		qcom,sensor-name = "imx135";
-		qcom,actuator-src = <&actuator1>;
-		cam_vdig-supply = <&pm8941_l3>;
-		cam_vana-supply = <&pm8941_l17>;
-		cam_vio-supply = <&pm8941_lvs3>;
-		cam_vaf-supply = <&pm8941_l23>;
-		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 = <1225000 0 2850000 3000000>;
-		qcom,cam-vreg-max-voltage = <1225000 0 2850000 3000000>;
-		qcom,cam-vreg-op-mode = <105000 0 80000 100000>;
-		qcom,gpio-no-mux = <0>;
-		gpios = <&msmgpio 15 0>,
-			<&msmgpio 90 0>,
-			<&msmgpio 89 0>;
-		qcom,gpio-reset = <1>;
-		qcom,gpio-standby = <2>;
-		qcom,gpio-req-tbl-num = <0 1 2>;
-		qcom,gpio-req-tbl-flags = <1 0 0>;
-		qcom,gpio-req-tbl-label = "CAMIF_MCLK",
-					  "CAM_RESET1",
-					  "CAM_STANDBY";
-		qcom,gpio-set-tbl-num = <1 1>;
-		qcom,gpio-set-tbl-flags = <0 2>;
-		qcom,gpio-set-tbl-delay = <1000 30000>;
-		qcom,csi-lane-assign = <0x4320>;
-		qcom,csi-lane-mask = <0x1F>;
-		qcom,sensor-position = <0>;
-		qcom,sensor-mode = <0>;
-	        qcom,sensor-type = <0>;
-		qcom,cci-master = <0>;
-		status = "ok";
-	};
-
-	qcom,camera@6c {
-		compatible = "qcom,ov2720";
-		reg = <0x6c>;
-		qcom,slave-id = <0x6c 0x300A 0x2720>;
-		qcom,csiphy-sd-index = <2>;
-		qcom,csid-sd-index = <2>;
-		qcom,mount-angle = <90>;
-		qcom,sensor-name = "ov2720";
-		cam_vdig-supply = <&pm8941_l3>;
-		cam_vana-supply = <&pm8941_l17>;
-		cam_vio-supply = <&pm8941_lvs3>;
-		qcom,cam-vreg-name = "cam_vdig", "cam_vana", "cam_vio";
-		qcom,cam-vreg-type = <0 0 1>;
-		qcom,cam-vreg-min-voltage = <1225000 2850000 0>;
-		qcom,cam-vreg-max-voltage = <1225000 2850000 0>;
-		qcom,cam-vreg-op-mode = <105000 80000 0>;
-		qcom,gpio-no-mux = <0>;
-		gpios = <&msmgpio 17 0>,
-			<&msmgpio 18 0>;
-		qcom,gpio-reset = <1>;
-		qcom,gpio-req-tbl-num = <0 1>;
-		qcom,gpio-req-tbl-flags = <1 0>;
-		qcom,gpio-req-tbl-label = "CAMIF_MCLK",
-					  "CAM_RESET1";
-		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 = <0x7>;
-		qcom,sensor-position = <1>;
-		qcom,sensor-mode = <1>;
-		qcom,cci-master = <0>;
-		status = "ok";
-	};
 
 	qcom,camera@90 {
 		compatible = "qcom,mt9m114";
 		reg = <0x90>;
 		qcom,slave-id = <0x90 0x0 0x2481>;
 		qcom,csiphy-sd-index = <1>;
-		qcom,csid-sd-index = <0>;
+		qcom,csid-sd-index = <1>;
 		qcom,mount-angle = <0>;
 		qcom,sensor-name = "mt9m114";
 		cam_vdig-supply = <&pm8941_l3>;
@@ -178,16 +61,15 @@
 		qcom,sensor-mode = <1>;
 		qcom,cci-master = <0>;
 	};
+
 	qcom,camera@0 {
 		cell-index = <0>;
 		compatible = "qcom,camera";
 		reg = <0x0>;
 		qcom,csiphy-sd-index = <0>;
 		qcom,csid-sd-index = <0>;
-		qcom,actuator-src = <&actuator0>;
-		qcom,vdd-cx-supply = <&pm8841_s2>;
 		qcom,mount-angle = <90>;
-		qcom,vdd-cx-name = "qcom,vdd-cx";
+		qcom,actuator-src = <&actuator0>;
 		cam_vdig-supply = <&pm8941_l3>;
 		cam_vana-supply = <&pm8941_l17>;
 		cam_vio-supply = <&pm8941_lvs3>;
@@ -206,9 +88,9 @@
 		qcom,gpio-standby = <2>;
 		qcom,gpio-req-tbl-num = <0 1 2>;
 		qcom,gpio-req-tbl-flags = <1 0 0>;
-		qcom,gpio-req-tbl-label = "CAMIF_MCLK",
-					  "CAM_RESET1",
-					  "CAM_STANDBY";
+		qcom,gpio-req-tbl-label = "CAMIF_MCLK0",
+					  "CAM_RESET0",
+					  "CAM_STANDBY0";
 		qcom,sensor-position = <0>;
 		qcom,sensor-mode = <0>;
 		qcom,cci-master = <0>;
@@ -221,9 +103,7 @@
 		reg = <0x1>;
 		qcom,csiphy-sd-index = <1>;
 		qcom,csid-sd-index = <0>;
-		qcom,vdd-cx-supply = <&pm8841_s2>;
 		qcom,mount-angle = <90>;
-		qcom,vdd-cx-name = "qcom,vdd-cx";
 		cam_vdig-supply = <&pm8941_l3>;
 		cam_vana-supply = <&pm8941_l17>;
 		cam_vio-supply = <&pm8941_lvs3>;
@@ -241,10 +121,10 @@
 		qcom,gpio-standby = <2>;
 		qcom,gpio-req-tbl-num = <0 1 2>;
 		qcom,gpio-req-tbl-flags = <1 0 0>;
-		qcom,gpio-req-tbl-label = "CAMIF_MCLK",
+		qcom,gpio-req-tbl-label = "CAMIF_MCLK1",
 					  "CAM_RESET1",
-					  "CAM_STANDBY";
-		qcom,sensor-position = <1>;
+					  "CAM_STANDBY1";
+		qcom,sensor-position = <0>;
 		qcom,sensor-mode = <0>;
 		qcom,cci-master = <0>;
 		status = "ok";
@@ -253,28 +133,29 @@
 	qcom,camera@2 {
 		cell-index = <2>;
 		compatible = "qcom,camera";
-		reg = <0x2>;
+		reg = <0x02>;
 		qcom,csiphy-sd-index = <2>;
 		qcom,csid-sd-index = <2>;
 		qcom,mount-angle = <90>;
-		qcom,vdd-cx-supply = <&pm8841_s2>;
-		qcom,vdd-cx-name = "qcom,vdd-cx";
 		cam_vdig-supply = <&pm8941_l3>;
 		cam_vana-supply = <&pm8941_l17>;
 		cam_vio-supply = <&pm8941_lvs3>;
-		qcom,cam-vreg-name = "cam_vdig", "cam_vana", "cam_vio";
-		qcom,cam-vreg-type = <0 0 1>;
-		qcom,cam-vreg-min-voltage = <1225000 2850000 0>;
-		qcom,cam-vreg-max-voltage = <1225000 2850000 0>;
-		qcom,cam-vreg-op-mode = <105000 80000 0>;
+		qcom,cam-vreg-name = "cam_vdig", "cam_vio", "cam_vana";
+		qcom,cam-vreg-type = <0 1 0>;
+		qcom,cam-vreg-min-voltage = <1225000 0 2850000>;
+		qcom,cam-vreg-max-voltage = <1225000 0 2850000>;
+		qcom,cam-vreg-op-mode = <105000 0 80000>;
 		qcom,gpio-no-mux = <0>;
 		gpios = <&msmgpio 17 0>,
-			<&msmgpio 18 0>;
+			<&msmgpio 18 0>,
+			<&msmgpio 28 0>;
 		qcom,gpio-reset = <1>;
-		qcom,gpio-req-tbl-num = <0 1>;
-		qcom,gpio-req-tbl-flags = <1 0>;
-		qcom,gpio-req-tbl-label = "CAMIF_MCLK",
-					  "CAM_RESET1";
+		qcom,gpio-standby = <2>;
+		qcom,gpio-req-tbl-num = <0 1 2>;
+		qcom,gpio-req-tbl-flags = <1 0 0>;
+		qcom,gpio-req-tbl-label = "CAMIF_MCLK2",
+					  "CAM_RESET2",
+					  "CAM_STANDBY2";
 		qcom,sensor-position = <1>;
 		qcom,sensor-mode = <0>;
 		qcom,cci-master = <0>;
diff --git a/arch/arm/boot/dts/msm8974-camera-sensor-liquid.dtsi b/arch/arm/boot/dts/msm8974-camera-sensor-liquid.dtsi
index 1b70557..a22355a 100644
--- a/arch/arm/boot/dts/msm8974-camera-sensor-liquid.dtsi
+++ b/arch/arm/boot/dts/msm8974-camera-sensor-liquid.dtsi
@@ -28,124 +28,6 @@
 		qcom,cci-master = <0>;
 	};
 
-	qcom,camera@6e {
-		compatible = "qcom,s5k3l1yx";
-		reg = <0x6e>;
-		qcom,slave-id = <0x6e 0x0 0x3121>;
-		qcom,csiphy-sd-index = <0>;
-		qcom,csid-sd-index = <0>;
-		qcom,mount-angle = <0>;
-		qcom,actuator-src = <&actuator0>;
-		qcom,sensor-name = "s5k3l1yx";
-		cam_vdig-supply = <&pm8941_l3>;
-		cam_vana-supply = <&pm8941_l17>;
-		cam_vio-supply = <&pm8941_lvs2>;
-		cam_vaf-supply = <&pm8941_l23>;
-		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 = <1225000 0 2850000 3000000>;
-		qcom,cam-vreg-max-voltage = <1225000 0 2850000 3000000>;
-		qcom,cam-vreg-op-mode = <105000 0 80000 100000>;
-		qcom,gpio-no-mux = <0>;
-		gpios = <&msmgpio 15 0>,
-			<&msmgpio 90 0>,
-			<&msmgpio 89 0>;
-		qcom,gpio-reset = <1>;
-		qcom,gpio-standby = <2>;
-		qcom,gpio-req-tbl-num = <0 1 2>;
-		qcom,gpio-req-tbl-flags = <1 0 0>;
-		qcom,gpio-req-tbl-label = "CAMIF_MCLK",
-					  "CAM_RESET1",
-					  "CAM_STANDBY";
-		qcom,gpio-set-tbl-num = <1 1>;
-		qcom,gpio-set-tbl-flags = <0 2>;
-		qcom,gpio-set-tbl-delay = <1000 30000>;
-		qcom,csi-lane-assign = <0x4320>;
-		qcom,csi-lane-mask = <0x1F>;
-		qcom,sensor-position = <0>;
-		qcom,sensor-mode = <1>;
-		qcom,cci-master = <0>;
-		status = "ok";
-	};
-
-    qcom,camera@20 {
-		compatible = "qcom,imx135";
-		reg = <0x20>;
-		qcom,slave-id = <0x20 0x0016 0x0135>;
-		qcom,csiphy-sd-index = <0>;
-		qcom,csid-sd-index = <0>;
-		qcom,mount-angle = <0>;
-		qcom,sensor-name = "imx135";
-		qcom,actuator-src = <&actuator1>;
-		cam_vdig-supply = <&pm8941_l3>;
-		cam_vana-supply = <&pm8941_l17>;
-		cam_vio-supply = <&pm8941_lvs2>;
-		cam_vaf-supply = <&pm8941_l23>;
-		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 = <1225000 0 2850000 3000000>;
-		qcom,cam-vreg-max-voltage = <1225000 0 2850000 3000000>;
-		qcom,cam-vreg-op-mode = <105000 0 80000 100000>;
-		qcom,gpio-no-mux = <0>;
-		gpios = <&msmgpio 15 0>,
-			<&msmgpio 90 0>,
-			<&msmgpio 89 0>;
-		qcom,gpio-reset = <1>;
-		qcom,gpio-standby = <2>;
-		qcom,gpio-req-tbl-num = <0 1 2>;
-		qcom,gpio-req-tbl-flags = <1 0 0>;
-		qcom,gpio-req-tbl-label = "CAMIF_MCLK",
-					  "CAM_RESET1",
-					  "CAM_STANDBY";
-		qcom,gpio-set-tbl-num = <1 1>;
-		qcom,gpio-set-tbl-flags = <0 2>;
-		qcom,gpio-set-tbl-delay = <1000 30000>;
-		qcom,csi-lane-assign = <0x4320>;
-		qcom,csi-lane-mask = <0x1F>;
-		qcom,sensor-position = <0>;
-		qcom,sensor-mode = <0>;
-	        qcom,sensor-type = <0>;
-		qcom,cci-master = <0>;
-		status = "ok";
-	};
-
-	qcom,camera@6c {
-		compatible = "qcom,ov2720";
-		reg = <0x6c>;
-		qcom,slave-id = <0x6c 0x300A 0x2720>;
-		qcom,csiphy-sd-index = <2>;
-		qcom,csid-sd-index = <0>;
-		qcom,mount-angle = <180>;
-		qcom,sensor-name = "ov2720";
-		cam_vdig-supply = <&pm8941_l3>;
-		cam_vana-supply = <&pm8941_l17>;
-		cam_vio-supply = <&pm8941_lvs2>;
-		qcom,cam-vreg-name = "cam_vdig", "cam_vana", "cam_vio";
-		qcom,cam-vreg-type = <0 0 1>;
-		qcom,cam-vreg-min-voltage = <1225000 2850000 0>;
-		qcom,cam-vreg-max-voltage = <1225000 2850000 0>;
-		qcom,cam-vreg-op-mode = <105000 80000 0>;
-		qcom,gpio-no-mux = <0>;
-		gpios = <&msmgpio 17 0>,
-			<&msmgpio 18 0>;
-		qcom,gpio-reset = <1>;
-		qcom,gpio-req-tbl-num = <0 1>;
-		qcom,gpio-req-tbl-flags = <1 0>;
-		qcom,gpio-req-tbl-label = "CAMIF_MCLK",
-					  "CAM_RESET1";
-		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 = <0x7>;
-		qcom,sensor-position = <1>;
-		qcom,sensor-mode = <1>;
-		qcom,cci-master = <0>;
-		status = "ok";
-	};
-
 	qcom,camera@90 {
 		compatible = "qcom,mt9m114";
 		reg = <0x90>;
@@ -179,16 +61,15 @@
 		qcom,sensor-mode = <1>;
 		qcom,cci-master = <0>;
 	};
+
 	qcom,camera@0 {
 		cell-index = <0>;
 		compatible = "qcom,camera";
 		reg = <0x0>;
 		qcom,csiphy-sd-index = <0>;
 		qcom,csid-sd-index = <0>;
-		qcom,mount-angle = <0>;
+		qcom,mount-angle = <90>;
 		qcom,actuator-src = <&actuator0>;
-		qcom,vdd-cx-supply = <&pm8841_s2>;
-		qcom,vdd-cx-name = "qcom,vdd-cx";
 		cam_vdig-supply = <&pm8941_l3>;
 		cam_vana-supply = <&pm8941_l17>;
 		cam_vio-supply = <&pm8941_lvs2>;
@@ -199,6 +80,7 @@
 		qcom,cam-vreg-min-voltage = <1225000 0 2850000 3000000>;
 		qcom,cam-vreg-max-voltage = <1225000 0 2850000 3000000>;
 		qcom,cam-vreg-op-mode = <105000 0 80000 100000>;
+		qcom,gpio-no-mux = <0>;
 		gpios = <&msmgpio 15 0>,
 			<&msmgpio 90 0>,
 			<&msmgpio 89 0>;
@@ -206,9 +88,9 @@
 		qcom,gpio-standby = <2>;
 		qcom,gpio-req-tbl-num = <0 1 2>;
 		qcom,gpio-req-tbl-flags = <1 0 0>;
-		qcom,gpio-req-tbl-label = "CAMIF_MCLK",
-					  "CAM_RESET1",
-					  "CAM_STANDBY";
+		qcom,gpio-req-tbl-label = "CAMIF_MCLK0",
+					  "CAM_RESET0",
+					  "CAM_STANDBY0";
 		qcom,sensor-position = <0>;
 		qcom,sensor-mode = <0>;
 		qcom,cci-master = <0>;
@@ -220,10 +102,8 @@
 		compatible = "qcom,camera";
 		reg = <0x1>;
 		qcom,csiphy-sd-index = <1>;
-		qcom,csid-sd-index = <1>;
-		qcom,mount-angle = <180>;
-		qcom,vdd-cx-supply = <&pm8841_s2>;
-		qcom,vdd-cx-name = "qcom,vdd-cx";
+		qcom,csid-sd-index = <0>;
+		qcom,mount-angle = <90>;
 		cam_vdig-supply = <&pm8941_l3>;
 		cam_vana-supply = <&pm8941_l17>;
 		cam_vio-supply = <&pm8941_lvs2>;
@@ -232,15 +112,17 @@
 		qcom,cam-vreg-min-voltage = <1225000 2850000 0>;
 		qcom,cam-vreg-max-voltage = <1225000 2850000 0>;
 		qcom,cam-vreg-op-mode = <105000 80000 0>;
-		qcom,gpio-no-mux = <0>;
-		gpios = <&msmgpio 17 0>,
-			<&msmgpio 18 0>;
+		gpios = <&msmgpio 16 0>,
+			<&msmgpio 92 0>,
+			<&msmgpio 91 0>;
 		qcom,gpio-reset = <1>;
-		qcom,gpio-req-tbl-num = <0 1>;
-		qcom,gpio-req-tbl-flags = <1 0>;
-		qcom,gpio-req-tbl-label = "CAMIF_MCLK",
-					  "CAM_RESET1";
-		qcom,sensor-position = <1>;
+		qcom,gpio-standby = <2>;
+		qcom,gpio-req-tbl-num = <0 1 2>;
+		qcom,gpio-req-tbl-flags = <1 0 0>;
+		qcom,gpio-req-tbl-label = "CAMIF_MCLK1",
+					  "CAM_RESET1",
+					  "CAM_STANDBY1";
+		qcom,sensor-position = <0>;
 		qcom,sensor-mode = <0>;
 		qcom,cci-master = <0>;
 		status = "ok";
@@ -249,12 +131,10 @@
 	qcom,camera@2 {
 		cell-index = <2>;
 		compatible = "qcom,camera";
-		reg = <0x2>;
+		reg = <0x02>;
 		qcom,csiphy-sd-index = <2>;
 		qcom,csid-sd-index = <2>;
-		qcom,mount-angle = <180>;
-		qcom,vdd-cx-supply = <&pm8841_s2>;
-		qcom,vdd-cx-name = "qcom,vdd-cx";
+		qcom,mount-angle = <90>;
 		cam_vdig-supply = <&pm8941_l3>;
 		cam_vana-supply = <&pm8941_l17>;
 		cam_vio-supply = <&pm8941_lvs3>;
@@ -265,6 +145,7 @@
 		qcom,cam-vreg-min-voltage = <1225000 0 2850000 3000000>;
 		qcom,cam-vreg-max-voltage = <1225000 0 2850000 3000000>;
 		qcom,cam-vreg-op-mode = <105000 0 80000 100000>;
+		qcom,gpio-no-mux = <0>;
 		gpios = <&msmgpio 17 0>,
 			<&msmgpio 18 0>,
 			<&msmgpio 28 0>;
@@ -272,9 +153,9 @@
 		qcom,gpio-standby = <2>;
 		qcom,gpio-req-tbl-num = <0 1 2>;
 		qcom,gpio-req-tbl-flags = <1 0 0>;
-		qcom,gpio-req-tbl-label = "CAMIF_MCLK",
-					  "CAM_RESET1",
-					  "CAM_STANDBY";
+		qcom,gpio-req-tbl-label = "CAMIF_MCLK2",
+					  "CAM_RESET2",
+					  "CAM_STANDBY2";
 		qcom,sensor-position = <1>;
 		qcom,sensor-mode = <0>;
 		qcom,cci-master = <0>;
diff --git a/arch/arm/boot/dts/msm8974-camera-sensor-mtp.dtsi b/arch/arm/boot/dts/msm8974-camera-sensor-mtp.dtsi
index f3dff1a..c3c0d47 100644
--- a/arch/arm/boot/dts/msm8974-camera-sensor-mtp.dtsi
+++ b/arch/arm/boot/dts/msm8974-camera-sensor-mtp.dtsi
@@ -37,127 +37,6 @@
 		qcom,cci-master = <0>;
 	};
 
-	qcom,camera@6e {
-		compatible = "qcom,s5k3l1yx";
-		reg = <0x6e>;
-		qcom,slave-id = <0x6e 0x0 0x3121>;
-		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 = "s5k3l1yx";
-		cam_vdig-supply = <&pm8941_l3>;
-		cam_vana-supply = <&pm8941_l17>;
-		cam_vio-supply = <&pm8941_lvs3>;
-		cam_vaf-supply = <&pm8941_l23>;
-		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 = <1225000 0 2850000 3000000>;
-		qcom,cam-vreg-max-voltage = <1225000 0 2850000 3000000>;
-		qcom,cam-vreg-op-mode = <105000 0 80000 100000>;
-		qcom,gpio-no-mux = <0>;
-		gpios = <&msmgpio 15 0>,
-			<&msmgpio 90 0>,
-			<&msmgpio 89 0>;
-		qcom,gpio-reset = <1>;
-		qcom,gpio-standby = <2>;
-		qcom,gpio-req-tbl-num = <0 1 2>;
-		qcom,gpio-req-tbl-flags = <1 0 0>;
-		qcom,gpio-req-tbl-label = "CAMIF_MCLK",
-					  "CAM_RESET1",
-					  "CAM_STANDBY";
-		qcom,gpio-set-tbl-num = <1 1>;
-		qcom,gpio-set-tbl-flags = <0 2>;
-		qcom,gpio-set-tbl-delay = <1000 30000>;
-		qcom,csi-lane-assign = <0x4320>;
-		qcom,csi-lane-mask = <0x1F>;
-		qcom,sensor-position = <0>;
-		qcom,sensor-mode = <1>;
-		qcom,cci-master = <0>;
-		status = "ok";
-	};
-
-    qcom,camera@20 {
-		compatible = "qcom,imx135";
-		reg = <0x20>;
-		qcom,slave-id = <0x20 0x0016 0x0135>;
-		qcom,csiphy-sd-index = <0>;
-		qcom,csid-sd-index = <0>;
-		qcom,mount-angle = <90>;
-		qcom,sensor-name = "imx135";
-		qcom,actuator-src = <&actuator1>;
-		qcom,led-flash-src = <&led_flash0>;
-		cam_vdig-supply = <&pm8941_l3>;
-		cam_vana-supply = <&pm8941_l17>;
-		cam_vio-supply = <&pm8941_lvs3>;
-		cam_vaf-supply = <&pm8941_l23>;
-		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 = <1225000 0 2850000 3000000>;
-		qcom,cam-vreg-max-voltage = <1225000 0 2850000 3000000>;
-		qcom,cam-vreg-op-mode = <105000 0 80000 100000>;
-		qcom,gpio-no-mux = <0>;
-		gpios = <&msmgpio 15 0>,
-			<&msmgpio 90 0>,
-			<&msmgpio 89 0>;
-		qcom,gpio-reset = <1>;
-		qcom,gpio-standby = <2>;
-		qcom,gpio-req-tbl-num = <0 1 2>;
-		qcom,gpio-req-tbl-flags = <1 0 0>;
-		qcom,gpio-req-tbl-label = "CAMIF_MCLK",
-					  "CAM_RESET1",
-					  "CAM_STANDBY";
-		qcom,gpio-set-tbl-num = <1 1>;
-		qcom,gpio-set-tbl-flags = <0 2>;
-		qcom,gpio-set-tbl-delay = <1000 30000>;
-		qcom,csi-lane-assign = <0x4320>;
-		qcom,csi-lane-mask = <0x1F>;
-		qcom,sensor-position = <0>;
-		qcom,sensor-mode = <0>;
-	        qcom,sensor-type = <0>;
-		qcom,cci-master = <0>;
-		status = "ok";
-	};
-
-
-	qcom,camera@6c {
-		compatible = "qcom,ov2720";
-		reg = <0x6c>;
-		qcom,slave-id = <0x6c 0x300A 0x2720>;
-		qcom,csiphy-sd-index = <2>;
-		qcom,csid-sd-index = <2>;
-		qcom,mount-angle = <90>;
-		qcom,sensor-name = "ov2720";
-		cam_vdig-supply = <&pm8941_l3>;
-		cam_vana-supply = <&pm8941_l17>;
-		cam_vio-supply = <&pm8941_lvs3>;
-		qcom,cam-vreg-name = "cam_vdig", "cam_vana", "cam_vio";
-		qcom,cam-vreg-type = <0 0 1>;
-		qcom,cam-vreg-min-voltage = <1225000 2850000 0>;
-		qcom,cam-vreg-max-voltage = <1225000 2850000 0>;
-		qcom,cam-vreg-op-mode = <105000 80000 0>;
-		qcom,gpio-no-mux = <0>;
-		gpios = <&msmgpio 17 0>,
-			<&msmgpio 18 0>;
-		qcom,gpio-reset = <1>;
-		qcom,gpio-req-tbl-num = <0 1>;
-		qcom,gpio-req-tbl-flags = <1 0>;
-		qcom,gpio-req-tbl-label = "CAMIF_MCLK",
-					  "CAM_RESET1";
-		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 = <0x7>;
-		qcom,sensor-position = <1>;
-		qcom,sensor-mode = <1>;
-		qcom,cci-master = <1>;
-		status = "ok";
-	};
-
 	qcom,camera@90 {
 		compatible = "qcom,mt9m114";
 		reg = <0x90>;
@@ -191,6 +70,7 @@
 		qcom,sensor-mode = <1>;
 		qcom,cci-master = <0>;
 	};
+
 	qcom,camera@0 {
 		cell-index = <0>;
 		compatible = "qcom,camera";
@@ -200,8 +80,6 @@
 		qcom,mount-angle = <90>;
 		qcom,actuator-src = <&actuator0>;
 		qcom,led-flash-src = <&led_flash0>;
-		qcom,vdd-cx-supply = <&pm8841_s2>;
-		qcom,vdd-cx-name = "qcom,vdd-cx";
 		cam_vdig-supply = <&pm8941_l3>;
 		cam_vana-supply = <&pm8941_l17>;
 		cam_vio-supply = <&pm8941_lvs3>;
@@ -212,6 +90,7 @@
 		qcom,cam-vreg-min-voltage = <1225000 0 2850000 3000000>;
 		qcom,cam-vreg-max-voltage = <1225000 0 2850000 3000000>;
 		qcom,cam-vreg-op-mode = <105000 0 80000 100000>;
+		qcom,gpio-no-mux = <0>;
 		gpios = <&msmgpio 15 0>,
 			<&msmgpio 90 0>,
 			<&msmgpio 89 0>;
@@ -219,9 +98,9 @@
 		qcom,gpio-standby = <2>;
 		qcom,gpio-req-tbl-num = <0 1 2>;
 		qcom,gpio-req-tbl-flags = <1 0 0>;
-		qcom,gpio-req-tbl-label = "CAMIF_MCLK",
-					  "CAM_RESET1",
-					  "CAM_STANDBY";
+		qcom,gpio-req-tbl-label = "CAMIF_MCLK0",
+					  "CAM_RESET0",
+					  "CAM_STANDBY0";
 		qcom,sensor-position = <0>;
 		qcom,sensor-mode = <0>;
 		qcom,cci-master = <0>;
@@ -233,10 +112,8 @@
 		compatible = "qcom,camera";
 		reg = <0x1>;
 		qcom,csiphy-sd-index = <1>;
-		qcom,csid-sd-index = <1>;
+		qcom,csid-sd-index = <0>;
 		qcom,mount-angle = <90>;
-		qcom,vdd-cx-supply = <&pm8841_s2>;
-		qcom,vdd-cx-name = "qcom,vdd-cx";
 		cam_vdig-supply = <&pm8941_l3>;
 		cam_vana-supply = <&pm8941_l17>;
 		cam_vio-supply = <&pm8941_lvs3>;
@@ -246,14 +123,17 @@
 		qcom,cam-vreg-min-voltage = <1225000 0 2850000 3000000>;
 		qcom,cam-vreg-max-voltage = <1225000 0 2850000 3000000>;
 		qcom,cam-vreg-op-mode = <105000 0 80000 100000>;
-		gpios = <&msmgpio 17 0>,
-			<&msmgpio 18 0>;
+		gpios = <&msmgpio 16 0>,
+			<&msmgpio 92 0>,
+			<&msmgpio 91 0>;
 		qcom,gpio-reset = <1>;
-		qcom,gpio-req-tbl-num = <0 1>;
-		qcom,gpio-req-tbl-flags = <1 0>;
-		qcom,gpio-req-tbl-label = "CAMIF_MCLK",
-					  "CAM_RESET1";
-		qcom,sensor-position = <1>;
+		qcom,gpio-standby = <2>;
+		qcom,gpio-req-tbl-num = <0 1 2>;
+		qcom,gpio-req-tbl-flags = <1 0 0>;
+		qcom,gpio-req-tbl-label = "CAMIF_MCLK1",
+					  "CAM_RESET1",
+					  "CAM_STANDBY1";
+		qcom,sensor-position = <0>;
 		qcom,sensor-mode = <0>;
 		qcom,cci-master = <0>;
 		status = "ok";
@@ -276,16 +156,18 @@
 		qcom,cam-vreg-op-mode = <105000 80000 0>;
 		qcom,gpio-no-mux = <0>;
 		gpios = <&msmgpio 17 0>,
-			<&msmgpio 18 0>;
+			<&msmgpio 18 0>,
+			<&msmgpio 28 0>;
 		qcom,gpio-reset = <1>;
-		qcom,gpio-req-tbl-num = <0 1>;
-		qcom,gpio-req-tbl-flags = <1 0>;
-		qcom,gpio-req-tbl-label = "CAMIF_MCLK",
-					  "CAM_RESET1";
+		qcom,gpio-standby = <2>;
+		qcom,gpio-req-tbl-num = <0 1 2>;
+		qcom,gpio-req-tbl-flags = <1 0 0>;
+		qcom,gpio-req-tbl-label = "CAMIF_MCLK2",
+					  "CAM_RESET2",
+					  "CAM_STANDBY2";
 		qcom,sensor-position = <1>;
 		qcom,sensor-mode = <0>;
 		qcom,cci-master = <1>;
 		status = "ok";
 	};
-
 };
diff --git a/arch/arm/boot/dts/msm8974-liquid.dtsi b/arch/arm/boot/dts/msm8974-liquid.dtsi
index 942aba4..5d1034b 100644
--- a/arch/arm/boot/dts/msm8974-liquid.dtsi
+++ b/arch/arm/boot/dts/msm8974-liquid.dtsi
@@ -318,7 +318,7 @@
 		compatible = "qca,ar3002";
 		qca,bt-reset-gpio = <&pm8941_gpios 34 0>;
 		qca,bt-chip-pwd-supply = <&ath_chip_pwd_l>;
-		qca,bt-vdd-io-supply = <&pm8941_l10>;
+		qca,bt-vdd-io-supply = <&pm8941_s3>;
 		qca,bt-vdd-pa-supply = <&pm8941_l19>;
 	};
 
@@ -380,34 +380,47 @@
 		qcom,prim-auxpcm-gpio-set = "prim-gpio-tert";
 	};
 
-	hsic_host: hsic@f9a00000 {
-		compatible = "qcom,hsic-host";
-		reg = <0xf9a00000 0x400>;
-		#address-cells = <0>;
-	        interrupt-parent = <&hsic_host>;
-		interrupts = <0 1 2>;
-		#interrupt-cells = <1>;
-		interrupt-map-mask = <0xffffffff>;
-		interrupt-map = <0 &intc 0 136 0
-	                1 &intc 0 148 0
-	                2 &msmgpio 144 0x8>;
-		interrupt-names = "core_irq", "async_irq", "wakeup";
-		hsic_vdd_dig-supply = <&pm8841_s2_corner>;
-		HSIC_GDSC-supply = <&gdsc_usb_hsic>;
-		hsic,strobe-gpio = <&msmgpio 144 0x00>;
-		hsic,data-gpio = <&msmgpio 145 0x00>;
-		hsic,ignore-cal-pad-config;
-		hsic,strobe-pad-offset = <0x2050>;
-		hsic,data-pad-offset = <0x2054>;
-		qcom,phy-susp-sof-workaround;
-		hsic,vdd-voltage-level = <1 5 7>;
+	hsic_hub {
+		compatible = "qcom,hsic-smsc-hub";
+		smsc,model-id = <3503>;
+		#address-cells = <1>;
+		#size-cells = <1>;
+		ranges;
+		smsc,reset-gpio = <&pm8941_gpios 8 0x00>;
+		smsc,refclk-gpio = <&pm8941_gpios 16 0x00>;
+		smsc,int-gpio = <&msmgpio 50 0x00>;
+		hub_int-supply = <&pm8941_l10>;
+		hub_vbus-supply = <&ext_5v>;
 
-		qcom,msm-bus,name = "hsic";
-		qcom,msm-bus,num-cases = <2>;
-		qcom,msm-bus,num-paths = <1>;
-		qcom,msm-bus,vectors-KBps =
-				<85 512 0 0>,
-				<85 512 40000 160000>;
+		hsic_host: hsic@f9a00000 {
+			compatible = "qcom,hsic-host";
+			reg = <0xf9a00000 0x400>;
+			#address-cells = <0>;
+			interrupt-parent = <&hsic_host>;
+			interrupts = <0 1 2>;
+			#interrupt-cells = <1>;
+			interrupt-map-mask = <0xffffffff>;
+			interrupt-map = <0 &intc 0 136 0
+			        1 &intc 0 148 0
+		                2 &msmgpio 144 0x8>;
+			interrupt-names = "core_irq", "async_irq", "wakeup";
+			hsic_vdd_dig-supply = <&pm8841_s2_corner>;
+			HSIC_GDSC-supply = <&gdsc_usb_hsic>;
+			hsic,strobe-gpio = <&msmgpio 144 0x00>;
+			hsic,data-gpio = <&msmgpio 145 0x00>;
+			hsic,ignore-cal-pad-config;
+			hsic,strobe-pad-offset = <0x2050>;
+			hsic,data-pad-offset = <0x2054>;
+			qcom,phy-susp-sof-workaround;
+			hsic,vdd-voltage-level = <1 5 7>;
+
+			qcom,msm-bus,name = "hsic";
+			qcom,msm-bus,num-cases = <2>;
+			qcom,msm-bus,num-paths = <1>;
+			qcom,msm-bus,vectors-KBps =
+					<85 512 0 0>,
+					<85 512 40000 160000>;
+		};
 	};
 
         wlan0: qca,wlan {
@@ -433,37 +446,6 @@
                 qca,wifi-chip-pwd-supply = <&ath_chip_pwd_l>;
         };
 
-	qcom,pronto@fb21b000 {
-		status = "disabled";
-	};
-
-	qcom,iris-fm {
-		status = "disabled";
-	};
-
-	qcom,wcnss-wlan@fb000000 {
-		status = "disabled";
-	};
-
-	qcom,smd-wcnss {
-		status = "disabled";
-	};
-
-	qcom,smsm-wcnss {
-		status = "disabled";
-	};
-};
-
-&pm8941_l19 {
-	regulator-min-microvolt = <3300000>;
-	regulator-max-microvolt = <3300000>;
-	qcom,init-voltage = <3300000>;
-};
-
-&pm8941_l10 {
-	regulator-min-microvolt = <1800000>;
-	regulator-max-microvolt = <1800000>;
-	qcom,init-voltage = <1800000>;
 };
 
 &mdss_fb0 {
diff --git a/arch/arm/boot/dts/msm8974-v2.dtsi b/arch/arm/boot/dts/msm8974-v2.dtsi
index 7e102fe..fd4221f 100644
--- a/arch/arm/boot/dts/msm8974-v2.dtsi
+++ b/arch/arm/boot/dts/msm8974-v2.dtsi
@@ -1,4 +1,4 @@
-/* Copyright (c) 2013, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2013-2014, 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
@@ -198,17 +198,17 @@
 
 &cci {
 
-	qcom,camera@6e {
+	qcom,camera@0 {
 		qcom,vdd-cx-supply = <&pm8841_s2>;
 		qcom,vdd-cx-name = "qcom,vdd-cx";
 	};
 
-	qcom,camera@20 {
+	qcom,camera@1 {
 		qcom,vdd-cx-supply = <&pm8841_s2>;
 		qcom,vdd-cx-name = "qcom,vdd-cx";
 	};
 
-	qcom,camera@6c {
+	qcom,camera@2 {
 		qcom,vdd-cx-supply = <&pm8841_s2>;
 		qcom,vdd-cx-name = "qcom,vdd-cx";
 	};
diff --git a/arch/arm/boot/dts/msm8974.dtsi b/arch/arm/boot/dts/msm8974.dtsi
index 60078ac..e0f2ef2 100644
--- a/arch/arm/boot/dts/msm8974.dtsi
+++ b/arch/arm/boot/dts/msm8974.dtsi
@@ -2142,7 +2142,7 @@
         qcom,qcedev@fd440000 {
 		compatible = "qcom,qcedev";
 		reg = <0xfd440000 0x20000>,
-		      <0xfd444000 0x8000>;
+		      <0xfd444000 0x1b000>;
 		reg-names = "crypto-base","crypto-bam-base";
 		interrupts = <0 236 0>;
 		qcom,bam-pipe-pair = <1>;
@@ -2156,10 +2156,10 @@
 				<56 512 3936000 393600>;
 	};
 
-        qcom,qcrypto@fd444000 {
+        qcom,qcrypto@fd440000 {
 		compatible = "qcom,qcrypto";
 		reg = <0xfd440000 0x20000>,
-		      <0xfd444000 0x8000>;
+		      <0xfd444000 0x1b000>;
 		reg-names = "crypto-base","crypto-bam-base";
 		interrupts = <0 236 0>;
 		qcom,bam-pipe-pair = <2>;
@@ -2177,6 +2177,27 @@
 				<56 512 3936000 393600>;
 	};
 
+        qcom,qcrypto1@fd440000 {
+		compatible = "qcom,qcrypto";
+		reg = <0xfd440000 0x20000>,
+		      <0xfd444000 0x1b000>;
+		reg-names = "crypto-base","crypto-bam-base";
+		interrupts = <0 236 0>;
+		qcom,bam-pipe-pair = <0>;
+		qcom,ce-hw-instance = <1>;
+		qcom,ce-device = <1>;
+		qcom,clk-mgmt-sus-res;
+                qcom,msm-bus,name = "qcrypto-noc";
+		qcom,msm-bus,num-cases = <2>;
+		qcom,msm-bus,num-paths = <1>;
+		qcom,use-sw-aes-cbc-ecb-ctr-algo;
+		qcom,use-sw-aes-xts-algo;
+		qcom,use-sw-ahash-algo;
+		qcom,msm-bus,vectors-KBps =
+				<56 512 0 0>,
+				<56 512 3936000 393600>;
+	};
+
 	qcom,usbbam@f9304000 {
 		compatible = "qcom,usb-bam-msm";
 		reg = <0xf9304000 0x5000>,
@@ -2427,6 +2448,12 @@
 		interrupts = <0 1 0>;
 	};
 
+	bimc_sharedmem {
+		compatible = "qcom,sharedmem-uio";
+		reg = <0xfc380000 0x00100000>;
+		reg-names = "bimc";
+	};
+
 	qcom,smdtty {
 		compatible = "qcom,smdtty";
 
diff --git a/arch/arm/boot/dts/msm8974pro-ab-pm8941-cdp.dts b/arch/arm/boot/dts/msm8974pro-ab-pm8941-cdp.dts
index 5a01945..b9f2574 100644
--- a/arch/arm/boot/dts/msm8974pro-ab-pm8941-cdp.dts
+++ b/arch/arm/boot/dts/msm8974pro-ab-pm8941-cdp.dts
@@ -25,3 +25,8 @@
 	qcom,pad-pull-on = <0x0 0x3 0x3 0x1>; /* no-pull, pull-up, pull-up, pull-down */
 	qcom,pad-pull-off = <0x0 0x3 0x3 0x1>; /* no-pull, pull-up, pull-up, pull-down */
 };
+
+&ehci {
+	hsusb_vdd_dig-supply = <&pm8841_s2_corner>;
+	qcom,vdd-voltage-level = <1 2 3 5 7>;
+};
diff --git a/arch/arm/boot/dts/msm8974pro-ab-pm8941-fluid-hbtp.dts b/arch/arm/boot/dts/msm8974pro-ab-pm8941-fluid-hbtp.dts
index 6ba8b5e..feefded 100644
--- a/arch/arm/boot/dts/msm8974pro-ab-pm8941-fluid-hbtp.dts
+++ b/arch/arm/boot/dts/msm8974pro-ab-pm8941-fluid-hbtp.dts
@@ -14,6 +14,7 @@
 
 /include/ "msm8974pro-ab-pm8941.dtsi"
 /include/ "msm8974-fluid.dtsi"
+/include/ "dsi-panel-jdi-720p-cmd.dtsi"
 
 / {
 	model = "Qualcomm MSM 8974Pro-AA/AB FLUID";
@@ -22,6 +23,10 @@
 };
 
 &soc {
+	qcom,mdss_dsi@fd922800{
+		qcom,dsi-pref-prim-pan = <&dsi_jdi_720p_cmd>;
+	};
+
 	spi@f9966000 { /* BLSP2 QUP4 */
 		/* Leave the SPI bus for QDSP to use */
 		status = "disabled";
diff --git a/arch/arm/boot/dts/msm8974pro-ab-pm8941-mtp.dts b/arch/arm/boot/dts/msm8974pro-ab-pm8941-mtp.dts
index f80551e..99c4ec7 100644
--- a/arch/arm/boot/dts/msm8974pro-ab-pm8941-mtp.dts
+++ b/arch/arm/boot/dts/msm8974pro-ab-pm8941-mtp.dts
@@ -26,3 +26,10 @@
 	qcom,pad-pull-off = <0x0 0x3 0x3 0x1>; /* no-pull, pull-up, pull-up, pull-down */
 	qcom,pad-drv-on = <0x4 0x4 0x4>; /* 10mA, 10mA, 10mA */
 };
+
+&ehci {
+	status = "ok";
+	qcom,usb2-enable-uicc;
+	hsusb_vdd_dig-supply = <&pm8841_s2_corner>;
+	qcom,vdd-voltage-level = <1 2 3 5 7>;
+};
diff --git a/arch/arm/boot/dts/msm8974pro-ac-pm8941-mtp.dts b/arch/arm/boot/dts/msm8974pro-ac-pm8941-mtp.dts
index 76d0121..a25b8ca 100644
--- a/arch/arm/boot/dts/msm8974pro-ac-pm8941-mtp.dts
+++ b/arch/arm/boot/dts/msm8974pro-ac-pm8941-mtp.dts
@@ -25,3 +25,8 @@
 	qcom,pad-pull-on = <0x0 0x3 0x3 0x1>; /* no-pull, pull-up, pull-up, pull-down */
 	qcom,pad-pull-off = <0x0 0x3 0x3 0x1>; /* no-pull, pull-up, pull-up, pull-down */
 };
+
+&ehci {
+	status = "ok";
+	qcom,usb2-enable-uicc;
+};
diff --git a/arch/arm/boot/dts/msm8974pro-ac-pma8084-pm8941-mtp.dts b/arch/arm/boot/dts/msm8974pro-ac-pma8084-pm8941-mtp.dts
index 8a4ad45..0fe8813 100644
--- a/arch/arm/boot/dts/msm8974pro-ac-pma8084-pm8941-mtp.dts
+++ b/arch/arm/boot/dts/msm8974pro-ac-pma8084-pm8941-mtp.dts
@@ -120,3 +120,8 @@
 		qcom,thermal-node;
 	};
 };
+
+&ehci {
+	status = "ok";
+	qcom,usb2-enable-uicc;
+};
diff --git a/arch/arm/boot/dts/msm8974pro-ac-pma8084-pm8941.dtsi b/arch/arm/boot/dts/msm8974pro-ac-pma8084-pm8941.dtsi
index bc7ecd2..df04f82 100644
--- a/arch/arm/boot/dts/msm8974pro-ac-pma8084-pm8941.dtsi
+++ b/arch/arm/boot/dts/msm8974pro-ac-pma8084-pm8941.dtsi
@@ -74,6 +74,54 @@
 		qcom,auto-mode-enable = <0>;
 		status = "okay";
 	};
+
+	pwm@b100 {
+		status = "disabled";
+	};
+
+	pwm@b200 {
+		status = "disabled";
+	};
+
+	pwm@b300 {
+		status = "disabled";
+	};
+
+	pwm@b400 {
+		status = "disabled";
+	};
+
+	pwm@b500 {
+		status = "disabled";
+	};
+
+	pwm@b600 {
+		status = "disabled";
+	};
+
+	pwm@b700 {
+		status = "disabled";
+	};
+
+	pwm@b800 {
+		status = "disabled";
+	};
+
+	pwm@e400 {
+		status = "disabled";
+	};
+
+	pwm@e500 {
+		status = "disabled";
+	};
+
+	pwm@e600 {
+		status = "disabled";
+	};
+
+	pwm@e700 {
+		status = "disabled";
+	};
 };
 
 &pma8084_mvs1 {
@@ -103,6 +151,7 @@
 	qcom,misc-ref = <&pm8941_misc>;
 	dwc_usb3-adc_tm = <&pm8941_adc_tm>;
 	qcom,usbin-vadc = <&pm8941_vadc>;
+	qcom,utmi-clk-rate = <24000000>;
 	interrupt-map-mask = <0x0 0xffffffff>;
 	interrupt-map = <0x0 0 &intc 0 133 0
 			0x0 1 &spmi_bus 0x0 0x2 0x9 0x0>;
@@ -240,6 +289,11 @@
 	vadc@3100 {
 		interrupts = <0x2 0x31 0x0>;
 		interrupt-names = "eoc-int-en-set";
+		/delete-node/ chan@b3;
+		/delete-node/ chan@b4;
+		/delete-node/ chan@b5;
+		/delete-node/ chan@b7;
+		/delete-node/ chan@b8;
 	};
 
 	iadc@3600 {
@@ -254,5 +308,9 @@
 		interrupt-names =	"eoc-int-en-set",
 					"high-thr-en-set",
 					"low-thr-en-set";
+		/delete-node/ chan@b3;
+		/delete-node/ chan@b4;
+		/delete-node/ chan@b5;
+		/delete-node/ chan@b7;
 	};
 };
diff --git a/arch/arm/boot/dts/msm8974pro-pm8941.dtsi b/arch/arm/boot/dts/msm8974pro-pm8941.dtsi
index 9c2be1a..b502078 100644
--- a/arch/arm/boot/dts/msm8974pro-pm8941.dtsi
+++ b/arch/arm/boot/dts/msm8974pro-pm8941.dtsi
@@ -68,6 +68,12 @@
 
 &usb3 {
 	qcom,usbin-vadc = <&pm8941_vadc>;
+	qcom,utmi-clk-rate = <24000000>;
+};
+
+&ehci {
+	hsusb_vdd_dig-supply = <&pm8841_s2_corner>;
+	qcom,vdd-voltage-level = <1 2 3 5 7>;
 };
 
 &krait_regulator_pmic {
diff --git a/arch/arm/boot/dts/msm8974pro-pma8084-mtp.dtsi b/arch/arm/boot/dts/msm8974pro-pma8084-mtp.dtsi
index 680674d..12ed7d4 100644
--- a/arch/arm/boot/dts/msm8974pro-pma8084-mtp.dtsi
+++ b/arch/arm/boot/dts/msm8974pro-pma8084-mtp.dtsi
@@ -200,9 +200,12 @@
 	};
 
 	gpio@c700 { /* GPIO 8 */
-		/* Unused */
-		qcom,mode = <0>;		/* Digital input */
-		qcom,pull = <0>;		/* Pull up 30 uA */
+		qcom,mode = <1>;		/* Digital output */
+		qcom,output-type = <0>;		/* CMOS logic */
+		qcom,invert = <0>;		/* Do not invert the output */
+		qcom,vin-sel = <2>;		/* PMA8084 S4 = 1.8V */
+		qcom,src-sel = <2>;		/* Special function 1=LPG 3 */
+		qcom,out-strength = <3>;	/* High drive Strength*/
 		qcom,master-en = <1>;
 	};
 
diff --git a/arch/arm/boot/dts/msm8974pro-pma8084.dtsi b/arch/arm/boot/dts/msm8974pro-pma8084.dtsi
index c06ebf8..28ddda2 100644
--- a/arch/arm/boot/dts/msm8974pro-pma8084.dtsi
+++ b/arch/arm/boot/dts/msm8974pro-pma8084.dtsi
@@ -118,6 +118,8 @@
 		HSUSB_VDDCX-supply = <&pma8084_s2>;
 		HSUSB_1p8-supply = <&pma8084_l6>;
 		HSUSB_3p3-supply = <&pma8084_l24>;
+		hsusb_vdd_dig-supply = <&pma8084_s2_corner>;
+		qcom,vdd-voltage-level = <1 2 3 5 7>;
 	};
 
 	qcom,gdsc@fd8c4024 {
@@ -210,3 +212,7 @@
 		status = "ok";
 	};
 };
+
+&dsi_generic_720p_cmd {
+	qcom,mdss-dsi-bl-pmic-bank-select = <3>;
+};
diff --git a/arch/arm/boot/dts/msm8974pro.dtsi b/arch/arm/boot/dts/msm8974pro.dtsi
index ae0547f..d398f72 100644
--- a/arch/arm/boot/dts/msm8974pro.dtsi
+++ b/arch/arm/boot/dts/msm8974pro.dtsi
@@ -1723,7 +1723,7 @@
 		<3240000 1600000>,
 		<4048000 1600000>,
 		<4264000 1600000>;
-	qcom,max-hw-load = <1281600>; /* max(4k X 2304 @ 24, 4k X 2160 @ 30) + 1080p @ 30 */
+	qcom,max-hw-load = <1216800>; /* 3840 X 2160 @ 30 fps + 1920 X 1088 @ 30 fps */
 	qcom,buffer-type-tz-usage-table = <0x241 0x1>,
 					<0x106 0x2>,
 					<0x480 0x3>;
diff --git a/arch/arm/configs/msm8226-perf_defconfig b/arch/arm/configs/msm8226-perf_defconfig
index ef7a5db..dd355af 100644
--- a/arch/arm/configs/msm8226-perf_defconfig
+++ b/arch/arm/configs/msm8226-perf_defconfig
@@ -304,6 +304,7 @@
 CONFIG_WCD9306_CODEC=y
 CONFIG_REGULATOR_FIXED_VOLTAGE=y
 CONFIG_REGULATOR_FAN53555=y
+CONFIG_REGULATOR_MEM_ACC=y
 CONFIG_REGULATOR_ONSEMI_NCP6335D=y
 CONFIG_REGULATOR_STUB=y
 CONFIG_REGULATOR_QPNP=y
diff --git a/arch/arm/configs/msm8226_defconfig b/arch/arm/configs/msm8226_defconfig
index d7719eb..5f008d5 100644
--- a/arch/arm/configs/msm8226_defconfig
+++ b/arch/arm/configs/msm8226_defconfig
@@ -306,6 +306,7 @@
 CONFIG_WCD9306_CODEC=y
 CONFIG_REGULATOR_FIXED_VOLTAGE=y
 CONFIG_REGULATOR_FAN53555=y
+CONFIG_REGULATOR_MEM_ACC=y
 CONFIG_REGULATOR_ONSEMI_NCP6335D=y
 CONFIG_REGULATOR_STUB=y
 CONFIG_REGULATOR_QPNP=y
@@ -467,7 +468,7 @@
 CONFIG_CORESIGHT_MODEM_ETM=y
 CONFIG_CORESIGHT_WCN_ETM=y
 CONFIG_CORESIGHT_RPM_ETM=y
-CONFIG_CORESIGHT_EVENT=m
+CONFIG_CORESIGHT_EVENT=y
 CONFIG_EXT2_FS=y
 CONFIG_EXT2_FS_XATTR=y
 CONFIG_EXT3_FS=y
@@ -486,6 +487,7 @@
 CONFIG_SCHEDSTATS=y
 CONFIG_TIMER_STATS=y
 CONFIG_DEBUG_KMEMLEAK=y
+CONFIG_DEBUG_KMEMLEAK_EARLY_LOG_SIZE=4000
 CONFIG_DEBUG_KMEMLEAK_DEFAULT_OFF=y
 CONFIG_DEBUG_SPINLOCK=y
 CONFIG_DEBUG_MUTEXES=y
diff --git a/arch/arm/configs/msm8610-perf_defconfig b/arch/arm/configs/msm8610-perf_defconfig
index 9c583e3..55bc185 100644
--- a/arch/arm/configs/msm8610-perf_defconfig
+++ b/arch/arm/configs/msm8610-perf_defconfig
@@ -345,6 +345,7 @@
 CONFIG_USB=y
 CONFIG_USB_ANNOUNCE_NEW_DEVICES=y
 CONFIG_USB_SUSPEND=y
+CONFIG_USB_MON=y
 CONFIG_USB_ICE40_HCD=m
 CONFIG_USB_CCID_BRIDGE=y
 CONFIG_USB_STORAGE=y
diff --git a/arch/arm/configs/msm8610_defconfig b/arch/arm/configs/msm8610_defconfig
index 6e86676..6874b28 100644
--- a/arch/arm/configs/msm8610_defconfig
+++ b/arch/arm/configs/msm8610_defconfig
@@ -368,6 +368,7 @@
 CONFIG_USB=y
 CONFIG_USB_ANNOUNCE_NEW_DEVICES=y
 CONFIG_USB_SUSPEND=y
+CONFIG_USB_MON=y
 CONFIG_USB_ICE40_HCD=m
 CONFIG_USB_CCID_BRIDGE=y
 CONFIG_USB_STORAGE=y
@@ -432,7 +433,7 @@
 CONFIG_CORESIGHT_MODEM_ETM=y
 CONFIG_CORESIGHT_WCN_ETM=y
 CONFIG_CORESIGHT_RPM_ETM=y
-CONFIG_CORESIGHT_EVENT=m
+CONFIG_CORESIGHT_EVENT=y
 CONFIG_SENSORS=y
 CONFIG_EXT2_FS=y
 CONFIG_EXT2_FS_XATTR=y
@@ -452,6 +453,7 @@
 CONFIG_SCHEDSTATS=y
 CONFIG_TIMER_STATS=y
 CONFIG_DEBUG_KMEMLEAK=y
+CONFIG_DEBUG_KMEMLEAK_EARLY_LOG_SIZE=4000
 CONFIG_DEBUG_KMEMLEAK_DEFAULT_OFF=y
 CONFIG_DEBUG_SPINLOCK=y
 CONFIG_DEBUG_MUTEXES=y
diff --git a/arch/arm/configs/msm8974-perf_defconfig b/arch/arm/configs/msm8974-perf_defconfig
index a749766..478e766 100755
--- a/arch/arm/configs/msm8974-perf_defconfig
+++ b/arch/arm/configs/msm8974-perf_defconfig
@@ -396,6 +396,7 @@
 CONFIG_USB_EHCI_MSM=y
 CONFIG_USB_EHCI_MSM_HSIC=y
 CONFIG_USB_ACM=y
+CONFIG_USB_CCID_BRIDGE=y
 CONFIG_USB_STORAGE=y
 CONFIG_USB_STORAGE_DATAFAB=y
 CONFIG_USB_STORAGE_FREECOM=y
diff --git a/arch/arm/configs/msm8974_defconfig b/arch/arm/configs/msm8974_defconfig
index b002e45..c5c16c2 100755
--- a/arch/arm/configs/msm8974_defconfig
+++ b/arch/arm/configs/msm8974_defconfig
@@ -420,6 +420,7 @@
 CONFIG_USB_EHCI_MSM=y
 CONFIG_USB_EHCI_MSM_HSIC=y
 CONFIG_USB_ACM=y
+CONFIG_USB_CCID_BRIDGE=y
 CONFIG_USB_STORAGE=y
 CONFIG_USB_STORAGE_DATAFAB=y
 CONFIG_USB_STORAGE_FREECOM=y
@@ -500,7 +501,7 @@
 CONFIG_CORESIGHT_MODEM_ETM=y
 CONFIG_CORESIGHT_WCN_ETM=y
 CONFIG_CORESIGHT_RPM_ETM=y
-CONFIG_CORESIGHT_EVENT=m
+CONFIG_CORESIGHT_EVENT=y
 CONFIG_BIF=y
 CONFIG_BIF_QPNP=y
 CONFIG_EXT2_FS=y
@@ -523,6 +524,7 @@
 CONFIG_SCHEDSTATS=y
 CONFIG_TIMER_STATS=y
 CONFIG_DEBUG_KMEMLEAK=y
+CONFIG_DEBUG_KMEMLEAK_EARLY_LOG_SIZE=4000
 CONFIG_DEBUG_KMEMLEAK_DEFAULT_OFF=y
 CONFIG_DEBUG_SPINLOCK=y
 CONFIG_DEBUG_MUTEXES=y
diff --git a/arch/arm/configs/msm9625_defconfig b/arch/arm/configs/msm9625_defconfig
index d6811df..59057f0 100644
--- a/arch/arm/configs/msm9625_defconfig
+++ b/arch/arm/configs/msm9625_defconfig
@@ -298,7 +298,7 @@
 CONFIG_CORESIGHT_AUDIO_ETM=y
 CONFIG_CORESIGHT_MODEM_ETM=y
 CONFIG_CORESIGHT_RPM_ETM=y
-CONFIG_CORESIGHT_EVENT=m
+CONFIG_CORESIGHT_EVENT=y
 CONFIG_EXT3_FS=y
 CONFIG_VFAT_FS=y
 CONFIG_TMPFS=y
diff --git a/arch/arm/include/asm/cacheflush.h b/arch/arm/include/asm/cacheflush.h
index 0e8f4916..0fd3191 100644
--- a/arch/arm/include/asm/cacheflush.h
+++ b/arch/arm/include/asm/cacheflush.h
@@ -385,4 +385,12 @@
 int set_memory_x(unsigned long addr, int numpages);
 int set_memory_nx(unsigned long addr, int numpages);
 
+#ifdef CONFIG_FREE_PAGES_RDONLY
+#define mark_addr_rdonly(a)	set_memory_ro((unsigned long)a, 1);
+#define mark_addr_rdwrite(a)	set_memory_rw((unsigned long)a, 1);
+#else
+#define mark_addr_rdonly(a)
+#define mark_addr_rdwrite(a)
+#endif
+
 #endif
diff --git a/arch/arm/kernel/process.c b/arch/arm/kernel/process.c
index c5fa883..4d24305 100644
--- a/arch/arm/kernel/process.c
+++ b/arch/arm/kernel/process.c
@@ -14,6 +14,7 @@
 #include <linux/sched.h>
 #include <linux/kernel.h>
 #include <linux/mm.h>
+#include <linux/vmalloc.h>
 #include <linux/stddef.h>
 #include <linux/unistd.h>
 #include <linux/user.h>
@@ -378,7 +379,12 @@
 		printk("%04lx ", (unsigned long)p & 0xffff);
 		for (j = 0; j < 8; j++) {
 			u32	data;
-			if (probe_kernel_address(p, data)) {
+			/*
+			 * vmalloc addresses may point to
+			 * memory-mapped peripherals
+			 */
+			if (is_vmalloc_addr(p) ||
+			    probe_kernel_address(p, data)) {
 				printk(" ********");
 			} else {
 				printk(" %08x", data);
diff --git a/arch/arm/mach-msm/batterydata-lib.c b/arch/arm/mach-msm/batterydata-lib.c
index 42a59d1..7ac7a45 100644
--- a/arch/arm/mach-msm/batterydata-lib.c
+++ b/arch/arm/mach-msm/batterydata-lib.c
@@ -34,32 +34,33 @@
 	return 0;
 }
 
-static int interpolate_single_lut(struct single_row_lut *lut, int x)
+static int interpolate_single_lut_scaled(struct single_row_lut *lut,
+						int x, int scale)
 {
 	int i, result;
 
-	if (x < lut->x[0]) {
+	if (x < lut->x[0] * scale) {
 		pr_debug("x %d less than known range return y = %d lut = %pS\n",
 							x, lut->y[0], lut);
 		return lut->y[0];
 	}
-	if (x > lut->x[lut->cols - 1]) {
+	if (x > lut->x[lut->cols - 1] * scale) {
 		pr_debug("x %d more than known range return y = %d lut = %pS\n",
 						x, lut->y[lut->cols - 1], lut);
 		return lut->y[lut->cols - 1];
 	}
 
 	for (i = 0; i < lut->cols; i++)
-		if (x <= lut->x[i])
+		if (x <= lut->x[i] * scale)
 			break;
-	if (x == lut->x[i]) {
+	if (x == lut->x[i] * scale) {
 		result = lut->y[i];
 	} else {
 		result = linear_interpolate(
 			lut->y[i - 1],
-			lut->x[i - 1],
+			lut->x[i - 1] * scale,
 			lut->y[i],
-			lut->x[i],
+			lut->x[i] * scale,
 			x);
 	}
 	return result;
@@ -67,9 +68,9 @@
 
 int interpolate_fcc(struct single_row_lut *fcc_temp_lut, int batt_temp)
 {
-	/* batt_temp is in tenths of degC - convert it to degC for lookups */
-	batt_temp = batt_temp/10;
-	return interpolate_single_lut(fcc_temp_lut, batt_temp);
+	return interpolate_single_lut_scaled(fcc_temp_lut,
+						batt_temp,
+						DEGC_SCALE);
 }
 
 int interpolate_scalingfactor_fcc(struct single_row_lut *fcc_sf_lut,
@@ -80,7 +81,7 @@
 	 * that case return 100%
 	 */
 	if (fcc_sf_lut)
-		return interpolate_single_lut(fcc_sf_lut, cycles);
+		return interpolate_single_lut_scaled(fcc_sf_lut, cycles, 1);
 	else
 		return 100;
 }
@@ -104,34 +105,34 @@
 		pr_debug("pc %d greater than known pc ranges for sfd\n", pc);
 		row1 = 0;
 		row2 = 0;
-	}
-	if (pc < sf_lut->percent[rows - 1]) {
+	} else if (pc < sf_lut->percent[rows - 1]) {
 		pr_debug("pc %d less than known pc ranges for sf\n", pc);
 		row1 = rows - 1;
 		row2 = rows - 1;
-	}
-	for (i = 0; i < rows; i++) {
-		if (pc == sf_lut->percent[i]) {
-			row1 = i;
-			row2 = i;
-			break;
-		}
-		if (pc > sf_lut->percent[i]) {
-			row1 = i - 1;
-			row2 = i;
-			break;
+	} else {
+		for (i = 0; i < rows; i++) {
+			if (pc == sf_lut->percent[i]) {
+				row1 = i;
+				row2 = i;
+				break;
+			}
+			if (pc > sf_lut->percent[i]) {
+				row1 = i - 1;
+				row2 = i;
+				break;
+			}
 		}
 	}
 
-	if (row_entry < sf_lut->row_entries[0])
-		row_entry = sf_lut->row_entries[0];
-	if (row_entry > sf_lut->row_entries[cols - 1])
-		row_entry = sf_lut->row_entries[cols - 1];
+	if (row_entry < sf_lut->row_entries[0] * DEGC_SCALE)
+		row_entry = sf_lut->row_entries[0] * DEGC_SCALE;
+	if (row_entry > sf_lut->row_entries[cols - 1] * DEGC_SCALE)
+		row_entry = sf_lut->row_entries[cols - 1] * DEGC_SCALE;
 
 	for (i = 0; i < cols; i++)
-		if (row_entry <= sf_lut->row_entries[i])
+		if (row_entry <= sf_lut->row_entries[i] * DEGC_SCALE)
 			break;
-	if (row_entry == sf_lut->row_entries[i]) {
+	if (row_entry == sf_lut->row_entries[i] * DEGC_SCALE) {
 		scalefactor = linear_interpolate(
 				sf_lut->sf[row1][i],
 				sf_lut->percent[row1],
@@ -143,16 +144,16 @@
 
 	scalefactorrow1 = linear_interpolate(
 				sf_lut->sf[row1][i - 1],
-				sf_lut->row_entries[i - 1],
+				sf_lut->row_entries[i - 1] * DEGC_SCALE,
 				sf_lut->sf[row1][i],
-				sf_lut->row_entries[i],
+				sf_lut->row_entries[i] * DEGC_SCALE,
 				row_entry);
 
 	scalefactorrow2 = linear_interpolate(
 				sf_lut->sf[row2][i - 1],
-				sf_lut->row_entries[i - 1],
+				sf_lut->row_entries[i - 1] * DEGC_SCALE,
 				sf_lut->sf[row2][i],
-				sf_lut->row_entries[i],
+				sf_lut->row_entries[i] * DEGC_SCALE,
 				row_entry);
 
 	scalefactor = linear_interpolate(
@@ -167,7 +168,7 @@
 
 /* get ocv given a soc  -- reverse lookup */
 int interpolate_ocv(struct pc_temp_ocv_lut *pc_temp_ocv,
-				int batt_temp_degc, int pc)
+				int batt_temp, int pc)
 {
 	int i, ocvrow1, ocvrow2, ocv, rows, cols;
 	int row1 = 0;
@@ -179,34 +180,34 @@
 		pr_debug("pc %d greater than known pc ranges for sfd\n", pc);
 		row1 = 0;
 		row2 = 0;
-	}
-	if (pc < pc_temp_ocv->percent[rows - 1]) {
+	} else if (pc < pc_temp_ocv->percent[rows - 1]) {
 		pr_debug("pc %d less than known pc ranges for sf\n", pc);
 		row1 = rows - 1;
 		row2 = rows - 1;
-	}
-	for (i = 0; i < rows; i++) {
-		if (pc == pc_temp_ocv->percent[i]) {
-			row1 = i;
-			row2 = i;
-			break;
-		}
-		if (pc > pc_temp_ocv->percent[i]) {
-			row1 = i - 1;
-			row2 = i;
-			break;
+	} else {
+		for (i = 0; i < rows; i++) {
+			if (pc == pc_temp_ocv->percent[i]) {
+				row1 = i;
+				row2 = i;
+				break;
+			}
+			if (pc > pc_temp_ocv->percent[i]) {
+				row1 = i - 1;
+				row2 = i;
+				break;
+			}
 		}
 	}
 
-	if (batt_temp_degc < pc_temp_ocv->temp[0])
-		batt_temp_degc = pc_temp_ocv->temp[0];
-	if (batt_temp_degc > pc_temp_ocv->temp[cols - 1])
-		batt_temp_degc = pc_temp_ocv->temp[cols - 1];
+	if (batt_temp < pc_temp_ocv->temp[0] * DEGC_SCALE)
+		batt_temp = pc_temp_ocv->temp[0] * DEGC_SCALE;
+	if (batt_temp > pc_temp_ocv->temp[cols - 1] * DEGC_SCALE)
+		batt_temp = pc_temp_ocv->temp[cols - 1] * DEGC_SCALE;
 
 	for (i = 0; i < cols; i++)
-		if (batt_temp_degc <= pc_temp_ocv->temp[i])
+		if (batt_temp <= pc_temp_ocv->temp[i] * DEGC_SCALE)
 			break;
-	if (batt_temp_degc == pc_temp_ocv->temp[i]) {
+	if (batt_temp == pc_temp_ocv->temp[i] * DEGC_SCALE) {
 		ocv = linear_interpolate(
 				pc_temp_ocv->ocv[row1][i],
 				pc_temp_ocv->percent[row1],
@@ -218,17 +219,17 @@
 
 	ocvrow1 = linear_interpolate(
 				pc_temp_ocv->ocv[row1][i - 1],
-				pc_temp_ocv->temp[i - 1],
+				pc_temp_ocv->temp[i - 1] * DEGC_SCALE,
 				pc_temp_ocv->ocv[row1][i],
-				pc_temp_ocv->temp[i],
-				batt_temp_degc);
+				pc_temp_ocv->temp[i] * DEGC_SCALE,
+				batt_temp);
 
 	ocvrow2 = linear_interpolate(
 				pc_temp_ocv->ocv[row2][i - 1],
-				pc_temp_ocv->temp[i - 1],
+				pc_temp_ocv->temp[i - 1] * DEGC_SCALE,
 				pc_temp_ocv->ocv[row2][i],
-				pc_temp_ocv->temp[i],
-				batt_temp_degc);
+				pc_temp_ocv->temp[i] * DEGC_SCALE,
+				batt_temp);
 
 	ocv = linear_interpolate(
 				ocvrow1,
@@ -241,26 +242,26 @@
 }
 
 int interpolate_pc(struct pc_temp_ocv_lut *pc_temp_ocv,
-				int batt_temp_degc, int ocv)
+				int batt_temp, int ocv)
 {
 	int i, j, pcj, pcj_minus_one, pc;
 	int rows = pc_temp_ocv->rows;
 	int cols = pc_temp_ocv->cols;
 
-	if (batt_temp_degc < pc_temp_ocv->temp[0]) {
-		pr_debug("batt_temp %d < known temp range\n", batt_temp_degc);
-		batt_temp_degc = pc_temp_ocv->temp[0];
+	if (batt_temp < pc_temp_ocv->temp[0] * DEGC_SCALE) {
+		pr_debug("batt_temp %d < known temp range\n", batt_temp);
+		batt_temp = pc_temp_ocv->temp[0] * DEGC_SCALE;
 	}
 
-	if (batt_temp_degc > pc_temp_ocv->temp[cols - 1]) {
-		pr_debug("batt_temp %d > known temp range\n", batt_temp_degc);
-		batt_temp_degc = pc_temp_ocv->temp[cols - 1];
+	if (batt_temp > pc_temp_ocv->temp[cols - 1] * DEGC_SCALE) {
+		pr_debug("batt_temp %d > known temp range\n", batt_temp);
+		batt_temp = pc_temp_ocv->temp[cols - 1] * DEGC_SCALE;
 	}
 
 	for (j = 0; j < cols; j++)
-		if (batt_temp_degc <= pc_temp_ocv->temp[j])
+		if (batt_temp <= pc_temp_ocv->temp[j] * DEGC_SCALE)
 			break;
-	if (batt_temp_degc == pc_temp_ocv->temp[j]) {
+	if (batt_temp == pc_temp_ocv->temp[j] * DEGC_SCALE) {
 		/* found an exact match for temp in the table */
 		if (ocv >= pc_temp_ocv->ocv[0][j])
 			return pc_temp_ocv->percent[0];
@@ -282,7 +283,7 @@
 	}
 
 	/*
-	 * batt_temp_degc is within temperature for
+	 * batt_temp is within temperature for
 	 * column j-1 and j
 	 */
 	if (ocv >= pc_temp_ocv->ocv[0][j])
@@ -318,10 +319,10 @@
 		if (pcj && pcj_minus_one) {
 			pc = linear_interpolate(
 				pcj_minus_one,
-				pc_temp_ocv->temp[j-1],
+				pc_temp_ocv->temp[j-1] * DEGC_SCALE,
 				pcj,
-				pc_temp_ocv->temp[j],
-				batt_temp_degc);
+				pc_temp_ocv->temp[j] * DEGC_SCALE,
+				batt_temp);
 			return pc;
 		}
 	}
@@ -333,6 +334,6 @@
 		return pcj_minus_one;
 
 	pr_debug("%d ocv wasn't found for temp %d in the LUT returning 100%%\n",
-							ocv, batt_temp_degc);
+							ocv, batt_temp);
 	return 100;
 }
diff --git a/arch/arm/mach-msm/board-8974.c b/arch/arm/mach-msm/board-8974.c
index 7b13bbc..a923846 100644
--- a/arch/arm/mach-msm/board-8974.c
+++ b/arch/arm/mach-msm/board-8974.c
@@ -149,8 +149,6 @@
 			"msm-tsens", NULL),
 	OF_DEV_AUXDATA("qcom,qcedev", 0xFD440000, \
 			"qcedev.0", NULL),
-	OF_DEV_AUXDATA("qcom,qcrypto", 0xFD440000, \
-			"qcrypto.0", NULL),
 	OF_DEV_AUXDATA("qcom,hsic-host", 0xF9A00000, \
 			"msm_hsic_host", NULL),
 	OF_DEV_AUXDATA("qcom,hsic-smsc-hub", 0, "msm_smsc_hub",
diff --git a/arch/arm/mach-msm/clock-8974.c b/arch/arm/mach-msm/clock-8974.c
old mode 100755
new mode 100644
index 1771090..1847bf4
--- a/arch/arm/mach-msm/clock-8974.c
+++ b/arch/arm/mach-msm/clock-8974.c
@@ -1653,6 +1653,7 @@
 };
 
 static struct clk_freq_tbl ftbl_gcc_usb30_mock_utmi_clk[] = {
+	F(48000000,  gpll0, 12.5,   0,   0),
 	F(60000000,  gpll0,   10,   0,   0),
 	F_END
 };
@@ -4870,13 +4871,7 @@
 	CLK_LOOKUP("gpll4", gpll4_clk_src.c, ""),
 	CLK_LOOKUP("sleep_clk", gcc_sdcc1_cdccal_sleep_clk.c, "msm_sdcc.1"),
 	CLK_LOOKUP("cal_clk", gcc_sdcc1_cdccal_ff_clk.c, "msm_sdcc.1"),
-	CLK_LOOKUP("cam_src_clk", mclk0_clk_src.c, "6e.qcom,camera"),
-	CLK_LOOKUP("cam_src_clk", mclk0_clk_src.c, "20.qcom,camera"),
-	CLK_LOOKUP("cam_src_clk", mclk2_clk_src.c, "6c.qcom,camera"),
 	CLK_LOOKUP("cam_src_clk", mclk1_clk_src.c, "90.qcom,camera"),
-	CLK_LOOKUP("cam_clk", camss_mclk0_clk.c, "6e.qcom,camera"),
-	CLK_LOOKUP("cam_clk", camss_mclk0_clk.c, "20.qcom,camera"),
-	CLK_LOOKUP("cam_clk", camss_mclk2_clk.c, "6c.qcom,camera"),
 	CLK_LOOKUP("cam_clk", camss_mclk1_clk.c, "90.qcom,camera"),
 	CLK_LOOKUP("cam_src_clk", mclk0_clk_src.c, "0.qcom,camera"),
 	CLK_LOOKUP("cam_src_clk", mclk1_clk_src.c, "1.qcom,camera"),
@@ -4887,20 +4882,14 @@
 };
 
 static struct clk_lookup msm_clocks_8974_only[] __initdata = {
-	CLK_LOOKUP("cam_src_clk", mmss_gp0_clk_src.c, "6e.qcom,camera"),
-	CLK_LOOKUP("cam_src_clk", mmss_gp0_clk_src.c, "20.qcom,camera"),
-	CLK_LOOKUP("cam_src_clk", gp1_clk_src.c, "6c.qcom,camera"),
 	CLK_LOOKUP("cam_src_clk", mmss_gp1_clk_src.c, "90.qcom,camera"),
-	CLK_LOOKUP("cam_clk", camss_gp0_clk.c, "6e.qcom,camera"),
-	CLK_LOOKUP("cam_clk", camss_gp0_clk.c, "20.qcom,camera"),
-	CLK_LOOKUP("cam_clk", gcc_gp1_clk.c, "6c.qcom,camera"),
 	CLK_LOOKUP("cam_clk", camss_gp1_clk.c, "90.qcom,camera"),
 	CLK_LOOKUP("cam_src_clk", mmss_gp0_clk_src.c, "0.qcom,camera"),
-	CLK_LOOKUP("cam_src_clk", gp1_clk_src.c, "2.qcom,camera"),
 	CLK_LOOKUP("cam_src_clk", mmss_gp1_clk_src.c, "1.qcom,camera"),
+	CLK_LOOKUP("cam_src_clk", gp1_clk_src.c, "2.qcom,camera"),
 	CLK_LOOKUP("cam_clk", camss_gp0_clk.c, "0.qcom,camera"),
-	CLK_LOOKUP("cam_clk", gcc_gp1_clk.c, "2.qcom,camera"),
 	CLK_LOOKUP("cam_clk", camss_gp1_clk.c, "1.qcom,camera"),
+	CLK_LOOKUP("cam_clk", gcc_gp1_clk.c, "2.qcom,camera"),
 };
 
 static struct clk_lookup msm_clocks_8974_common[] __initdata = {
@@ -4987,10 +4976,16 @@
 	CLK_LOOKUP("bus_clk",      gcc_ce2_axi_clk.c,     "qcedev.0"),
 	CLK_LOOKUP("core_clk_src", ce2_clk_src.c,         "qcedev.0"),
 
-	CLK_LOOKUP("core_clk",     gcc_ce2_clk.c,     "qcrypto.0"),
-	CLK_LOOKUP("iface_clk",    gcc_ce2_ahb_clk.c, "qcrypto.0"),
-	CLK_LOOKUP("bus_clk",      gcc_ce2_axi_clk.c, "qcrypto.0"),
-	CLK_LOOKUP("core_clk_src", ce2_clk_src.c,     "qcrypto.0"),
+
+	CLK_LOOKUP("core_clk",     gcc_ce2_clk.c,     "fd440000.qcom,qcrypto"),
+	CLK_LOOKUP("iface_clk",    gcc_ce2_ahb_clk.c, "fd440000.qcom,qcrypto"),
+	CLK_LOOKUP("bus_clk",      gcc_ce2_axi_clk.c, "fd440000.qcom,qcrypto"),
+	CLK_LOOKUP("core_clk_src", ce2_clk_src.c,     "fd440000.qcom,qcrypto"),
+
+	CLK_LOOKUP("core_clk",     gcc_ce2_clk.c,     "fd440000.qcom,qcrypto1"),
+	CLK_LOOKUP("iface_clk",    gcc_ce2_ahb_clk.c, "fd440000.qcom,qcrypto1"),
+	CLK_LOOKUP("bus_clk",      gcc_ce2_axi_clk.c, "fd440000.qcom,qcrypto1"),
+	CLK_LOOKUP("core_clk_src", ce2_clk_src.c,     "fd440000.qcom,qcrypto1"),
 
 	CLK_LOOKUP("core_clk",     gcc_ce1_clk.c,         "qseecom"),
 	CLK_LOOKUP("iface_clk",    gcc_ce1_ahb_clk.c,     "qseecom"),
@@ -5035,6 +5030,7 @@
 	CLK_LOOKUP("mem_clk", gcc_usb30_master_clk.c,           "usb_bam"),
 	CLK_LOOKUP("mem_iface_clk", gcc_sys_noc_usb3_axi_clk.c, "usb_bam"),
 	CLK_LOOKUP("core_clk", gcc_usb30_master_clk.c,    "msm_dwc3"),
+	CLK_LOOKUP("utmi_clk_src", usb30_mock_utmi_clk_src.c, "msm_dwc3"),
 	CLK_LOOKUP("utmi_clk", gcc_usb30_mock_utmi_clk.c, "msm_dwc3"),
 	CLK_LOOKUP("iface_clk", gcc_sys_noc_usb3_axi_clk.c, "msm_dwc3"),
 	CLK_LOOKUP("iface_clk", gcc_sys_noc_usb3_axi_clk.c, "msm_usb3"),
@@ -5766,6 +5762,8 @@
 
 	mdp_clk_src.c.fmax[VDD_DIG_NOMINAL] = 240000000;
 
+	gcc_usb30_mock_utmi_clk.max_div = 3;
+
 	/* The parent of each of the QUP I2C clocks is an RCG on V2 */
 	for (i = 0; i < ARRAY_SIZE(qup_i2c_clks); i++)
 		qup_i2c_clks[i][0]->parent =  qup_i2c_clks[i][1];
diff --git a/arch/arm/mach-msm/clock-local2.h b/arch/arm/mach-msm/clock-local2.h
index 35fb6fa..fb0402d 100644
--- a/arch/arm/mach-msm/clock-local2.h
+++ b/arch/arm/mach-msm/clock-local2.h
@@ -103,7 +103,7 @@
 	const u32 bcr_reg;
 	int has_sibling;
 	u32 cur_div;
-	const u32 max_div;
+	u32 max_div;
 	const u32 halt_check;
 	void *const __iomem *base;
 };
diff --git a/arch/arm/mach-msm/cpr-regulator.c b/arch/arm/mach-msm/cpr-regulator.c
index d15da59f..e50f865 100644
--- a/arch/arm/mach-msm/cpr-regulator.c
+++ b/arch/arm/mach-msm/cpr-regulator.c
@@ -183,6 +183,9 @@
 	int			vdd_mx_vmin;
 	int			vdd_mx_corner_map[CPR_FUSE_CORNER_MAX];
 
+	/* mem-acc regulator */
+	struct regulator	*mem_acc_vreg;
+
 	/* CPR parameters */
 	u64		cpr_fuse_bits;
 	bool		cpr_fuse_disable;
@@ -557,15 +560,15 @@
 			     int new_apc_volt, enum voltage_change_dir dir)
 {
 	int rc = 0, vdd_mx_vmin = 0;
+	int fuse_corner = cpr_vreg->corner_map[corner];
 
-	/* No MX scaling if no vdd_mx */
-	if (cpr_vreg->vdd_mx == NULL)
-		dir = NO_CHANGE;
-
-	if (dir != NO_CHANGE) {
-		/* Determine the vdd_mx voltage */
+	/* Determine the vdd_mx voltage */
+	if (dir != NO_CHANGE && cpr_vreg->vdd_mx != NULL)
 		vdd_mx_vmin = cpr_mx_get(cpr_vreg, corner, new_apc_volt);
-	}
+
+	if (cpr_vreg->mem_acc_vreg && dir == DOWN)
+		rc = regulator_set_voltage(cpr_vreg->mem_acc_vreg,
+					fuse_corner, fuse_corner);
 
 	if (vdd_mx_vmin && dir == UP) {
 		if (vdd_mx_vmin != cpr_vreg->vdd_mx_vmin)
@@ -575,6 +578,10 @@
 	if (!rc)
 		rc = cpr_apc_set(cpr_vreg, new_apc_volt);
 
+	if (!rc && cpr_vreg->mem_acc_vreg && dir == UP)
+		rc = regulator_set_voltage(cpr_vreg->mem_acc_vreg,
+					fuse_corner, fuse_corner);
+
 	if (!rc && vdd_mx_vmin && dir == DOWN) {
 		if (vdd_mx_vmin != cpr_vreg->vdd_mx_vmin)
 			rc = cpr_mx_set(cpr_vreg, corner, vdd_mx_vmin);
@@ -2014,6 +2021,25 @@
 	return 0;
 }
 
+static int cpr_mem_acc_init(struct platform_device *pdev,
+				struct cpr_regulator *cpr_vreg)
+{
+	int rc;
+
+	if (of_property_read_bool(pdev->dev.of_node, "mem-acc-supply")) {
+		cpr_vreg->mem_acc_vreg = devm_regulator_get(&pdev->dev,
+							"mem-acc");
+		if (IS_ERR_OR_NULL(cpr_vreg->mem_acc_vreg)) {
+			rc = PTR_RET(cpr_vreg->mem_acc_vreg);
+			if (rc != -EPROBE_DEFER)
+				pr_err("devm_regulator_get: mem-acc: rc=%d\n",
+				       rc);
+			return rc;
+		}
+	}
+	return 0;
+}
+
 static int __devinit cpr_regulator_probe(struct platform_device *pdev)
 {
 	struct cpr_regulator *cpr_vreg;
@@ -2044,6 +2070,12 @@
 		return -ENOMEM;
 	}
 
+	rc = cpr_mem_acc_init(pdev, cpr_vreg);
+	if (rc) {
+		pr_err("mem_acc intialization error rc=%d\n", rc);
+		return rc;
+	}
+
 	rc = cpr_efuse_init(pdev, cpr_vreg);
 	if (rc) {
 		pr_err("Wrong eFuse address specified: rc=%d\n", rc);
diff --git a/arch/arm/mach-msm/include/mach/msm_smem.h b/arch/arm/mach-msm/include/mach/msm_smem.h
index 19f9c0e..670efe6 100644
--- a/arch/arm/mach-msm/include/mach/msm_smem.h
+++ b/arch/arm/mach-msm/include/mach/msm_smem.h
@@ -40,6 +40,17 @@
 
 #define SMEM_NUM_SMD_STREAM_CHANNELS        64
 
+/**
+ * OVERFLOW_ADD_UNSIGNED() - check for unsigned overflow
+ *
+ * @type: type to check for overflow
+ * @a: left value to use
+ * @b: right value to use
+ * @returns: true if a + b will result in overflow; false otherwise
+ */
+#define OVERFLOW_ADD_UNSIGNED(type, a, b) \
+	(((type)~0 - (a)) < (b) ? true : false)
+
 enum {
 	/* fixed items */
 	SMEM_PROC_COMM = 0,
diff --git a/arch/arm/mach-msm/include/mach/msm_spi.h b/arch/arm/mach-msm/include/mach/msm_spi.h
index 608927c..52d88a1 100644
--- a/arch/arm/mach-msm/include/mach/msm_spi.h
+++ b/arch/arm/mach-msm/include/mach/msm_spi.h
@@ -22,6 +22,9 @@
  *       runtime pm (optimizes for power).
  * @master_id master id number of the controller's wrapper (BLSP or GSBI).
  *       When zero, clock path voting is disabled.
+ * @rt when set, spi will pump transaction messages with high (realtime)
+ *	priority to reduce the transfer latency on the bus by minimising
+ *	the delay between a transfer request.
  */
 struct msm_spi_platform_data {
 	u32 max_clock_speed;
@@ -37,4 +40,5 @@
 	bool use_bam;
 	u32  bam_consumer_pipe_index;
 	u32  bam_producer_pipe_index;
+	bool rt_priority;
 };
diff --git a/arch/arm/mach-msm/include/mach/qdsp6v2/apr.h b/arch/arm/mach-msm/include/mach/qdsp6v2/apr.h
index c21f6e5..9f4acca 100644
--- a/arch/arm/mach-msm/include/mach/qdsp6v2/apr.h
+++ b/arch/arm/mach-msm/include/mach/qdsp6v2/apr.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2010-2013, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2010-2014, 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
@@ -94,7 +94,7 @@
 #define APR_SVC_SRD		0x7
 
 /* APR Port IDs */
-#define APR_MAX_PORTS		0x40
+#define APR_MAX_PORTS		0x80
 
 #define APR_NAME_MAX		0x40
 
diff --git a/arch/arm/mach-msm/krait-regulator-pmic.c b/arch/arm/mach-msm/krait-regulator-pmic.c
index 5081e7b..2f4185e 100644
--- a/arch/arm/mach-msm/krait-regulator-pmic.c
+++ b/arch/arm/mach-msm/krait-regulator-pmic.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2013, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2013-2014, 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
@@ -58,7 +58,8 @@
 #define REG_GANG_CTL2		0xC1
 #define GANG_EN_BIT		BIT(7)
 
-#define REG_PWM_CL			0x60
+#define REG_PWM_CL		0x60
+#define REG_SEC_ACCESS		0xD0
 
 struct krait_vreg_pmic_chip {
 	struct spmi_device	*spmi;
@@ -89,11 +90,21 @@
 	return 0;
 }
 
-static int write_byte(struct spmi_device *spmi, u16 addr, u8 *val)
+static int write_secure_byte(struct spmi_device *spmi, u16 base,
+							u16 addr, u8 *val)
 {
 	int rc;
+	u8 sec_val = 0xA5;
 
-	rc = spmi_ext_register_writel(spmi->ctrl, spmi->sid, addr, val, 1);
+	rc = spmi_ext_register_writel(spmi->ctrl, spmi->sid,
+					base + REG_SEC_ACCESS, &sec_val, 1);
+	if (rc) {
+		pr_err("SPMI write failed [%d,0x%04x] val = 0x%02x rc=%d\n",
+				spmi->sid, base + REG_SEC_ACCESS, sec_val, rc);
+		return rc;
+	}
+	rc = spmi_ext_register_writel(spmi->ctrl, spmi->sid,
+					base + addr, val, 1);
 	if (rc) {
 		pr_err("SPMI write failed [%d,0x%04x] val = 0x%02x rc=%d\n",
 						spmi->sid, addr, *val, rc);
@@ -127,7 +138,7 @@
 bool krait_pmic_is_ready(void)
 {
 	if (the_chip == NULL) {
-		pr_debug("kait_regulator_pmic not ready yet\n");
+		pr_debug("krait_regulator_pmic not ready yet\n");
 		return false;
 	}
 	return true;
@@ -149,7 +160,7 @@
 	int rc;
 
 	if (the_chip == NULL) {
-		pr_debug("kait_regulator_pmic not ready yet\n");
+		pr_debug("krait_regulator_pmic not ready yet\n");
 		return -ENXIO;
 	}
 
@@ -157,8 +168,8 @@
 		return 0;
 
 	setpoint = (I_PFM_MA - IOFFSET_MA) / ISTEP_MA;
-	rc = write_byte(the_chip->spmi,
-			the_chip->ps_base + REG_PWM_CL, &setpoint);
+	rc = write_secure_byte(the_chip->spmi,
+			the_chip->ps_base, REG_PWM_CL, &setpoint);
 	pr_debug("wrote 0x%02x->[%d 0x%04x] rc = %d\n", setpoint,
 			the_chip->spmi->sid,
 			the_chip->ps_base + REG_PWM_CL, rc);
@@ -180,7 +191,7 @@
 	int rc;
 
 	if (the_chip == NULL) {
-		pr_debug("kait_regulator_pmic not ready yet\n");
+		pr_debug("krait_regulator_pmic not ready yet\n");
 		return -ENXIO;
 	}
 
@@ -190,8 +201,8 @@
 	udelay(50);
 	setpoint = (I_PWM_MA - IOFFSET_MA) / ISTEP_MA;
 
-	rc = write_byte(the_chip->spmi,
-			the_chip->ps_base + REG_PWM_CL, &setpoint);
+	rc = write_secure_byte(the_chip->spmi,
+			the_chip->ps_base, REG_PWM_CL, &setpoint);
 	pr_debug("wrote 0x%02x->[%d 0x%04x] rc = %d\n", setpoint,
 			the_chip->spmi->sid,
 			the_chip->ps_base + REG_PWM_CL, rc);
diff --git a/arch/arm/mach-msm/msm_rq_stats.c b/arch/arm/mach-msm/msm_rq_stats.c
index c99f0ec..af4a6d2 100644
--- a/arch/arm/mach-msm/msm_rq_stats.c
+++ b/arch/arm/mach-msm/msm_rq_stats.c
@@ -30,7 +30,6 @@
 #include <linux/kernel_stat.h>
 #include <linux/tick.h>
 #include <asm/smp_plat.h>
-#include "acpuclock.h"
 #include <linux/suspend.h>
 
 #define MAX_LONG_SIZE 24
@@ -199,7 +198,7 @@
 	switch (val) {
 	case CPU_ONLINE:
 		if (!this_cpu->cur_freq)
-			this_cpu->cur_freq = acpuclk_get_rate(cpu);
+			this_cpu->cur_freq = cpufreq_quick_get(cpu);
 	case CPU_ONLINE_FROZEN:
 		this_cpu->avg_load_maxfreq = 0;
 	}
@@ -402,7 +401,7 @@
 		cpufreq_get_policy(&cpu_policy, i);
 		pcpu->policy_max = cpu_policy.cpuinfo.max_freq;
 		if (cpu_online(i))
-			pcpu->cur_freq = acpuclk_get_rate(i);
+			pcpu->cur_freq = cpufreq_quick_get(i);
 		cpumask_copy(pcpu->related_cpus, cpu_policy.cpus);
 	}
 	freq_transition.notifier_call = cpufreq_transition_handler;
diff --git a/arch/arm/mach-msm/pil-pronto.c b/arch/arm/mach-msm/pil-pronto.c
index a7fc204..a91331e 100644
--- a/arch/arm/mach-msm/pil-pronto.c
+++ b/arch/arm/mach-msm/pil-pronto.c
@@ -62,6 +62,9 @@
 
 #define PRONTO_PMU_CCPU_BOOT_REMAP_ADDR			0x2004
 
+#define PRONTO_PMU_SPARE				0x1088
+#define PRONTO_PMU_SPARE_SSR_BIT			BIT(23)
+
 #define CLK_CTL_WCNSS_RESTART_BIT			BIT(0)
 
 #define AXI_HALTREQ					0x0
@@ -376,7 +379,15 @@
 	struct pronto_data *drv = subsys_to_drv(subsys);
 	struct platform_device *pdev = wcnss_get_platform_device();
 	struct wcnss_wlan_config *pwlanconfig = wcnss_get_wlan_config();
-	int    ret = -1;
+	void __iomem *base = drv->base;
+	u32 reg;
+	int ret = -1;
+
+	if (base) {
+		reg = readl_relaxed(base + PRONTO_PMU_SPARE);
+		reg |= PRONTO_PMU_SPARE_SSR_BIT;
+		writel_relaxed(reg, base + PRONTO_PMU_SPARE);
+	}
 
 	if (pdev && pwlanconfig)
 		ret = wcnss_wlan_power(&pdev->dev, pwlanconfig,
diff --git a/arch/arm/mach-msm/pm-boot.c b/arch/arm/mach-msm/pm-boot.c
index 3559510..0d4840f 100644
--- a/arch/arm/mach-msm/pm-boot.c
+++ b/arch/arm/mach-msm/pm-boot.c
@@ -343,4 +343,4 @@
 {
 	return platform_driver_register(&msm_pm_boot_driver);
 }
-module_init(msm_pm_boot_module_init);
+postcore_initcall(msm_pm_boot_module_init);
diff --git a/arch/arm/mach-msm/qdsp6v2/ultrasound/usf.c b/arch/arm/mach-msm/qdsp6v2/ultrasound/usf.c
index cf69e17..192aaf9 100644
--- a/arch/arm/mach-msm/qdsp6v2/ultrasound/usf.c
+++ b/arch/arm/mach-msm/qdsp6v2/ultrasound/usf.c
@@ -70,6 +70,7 @@
 	USF_OPENED_STATE,
 	USF_CONFIGURED_STATE,
 	USF_WORK_STATE,
+	USF_ADSP_RESTART_STATE,
 	USF_ERROR_STATE
 };
 
@@ -406,6 +407,13 @@
 	case Q6USM_EVENT_WRITE_DONE:
 		wake_up(&usf_xx->wait);
 		break;
+
+	case RESET_EVENTS:
+		pr_err("%s: received RESET_EVENTS\n", __func__);
+		usf_xx->usf_state = USF_ADSP_RESTART_STATE;
+		wake_up(&usf_xx->wait);
+		break;
+
 	default:
 		break;
 	}
@@ -445,6 +453,12 @@
 		}
 		break;
 
+	case RESET_EVENTS:
+		pr_err("%s: received RESET_EVENTS\n", __func__);
+		usf_xx->usf_state = USF_ADSP_RESTART_STATE;
+		wake_up(&usf_xx->wait);
+		break;
+
 	default:
 		break;
 	}
@@ -865,7 +879,9 @@
 	if (detect_info.detect_timeout == USF_INFINITIVE_TIMEOUT) {
 		rc = wait_event_interruptible(usf_xx->wait,
 						(usf_xx->us_detect_type !=
-						USF_US_DETECT_UNDEF));
+						USF_US_DETECT_UNDEF) ||
+						(usf_xx->usf_state ==
+						USF_ADSP_RESTART_STATE));
 	} else {
 		if (detect_info.detect_timeout == USF_DEFAULT_TIMEOUT)
 			timeout = USF_TIMEOUT_JIFFIES;
@@ -874,8 +890,14 @@
 	}
 	rc = wait_event_interruptible_timeout(usf_xx->wait,
 					(usf_xx->us_detect_type !=
-					 USF_US_DETECT_UNDEF),
-					timeout);
+					USF_US_DETECT_UNDEF) ||
+					(usf_xx->usf_state ==
+					USF_ADSP_RESTART_STATE), timeout);
+
+	/* In the case of aDSP restart, "no US" is assumed */
+	if (usf_xx->usf_state == USF_ADSP_RESTART_STATE) {
+		rc = -EFAULT;
+	}
 	/* In the case of timeout, "no US" is assumed */
 	if (rc < 0)
 		pr_err("%s: Getting US detection failed rc[%d]\n",
@@ -1336,7 +1358,8 @@
 
 	case US_STOP_TX: {
 		usf_xx = &usf->usf_tx;
-		if (usf_xx->usf_state == USF_WORK_STATE)
+		if ((usf_xx->usf_state == USF_WORK_STATE)
+			|| (usf_xx->usf_state == USF_ADSP_RESTART_STATE))
 			rc = usf_stop_tx(usf);
 		else {
 			pr_err("%s: stop_tx: wrong state[%d]\n",
@@ -1349,7 +1372,8 @@
 
 	case US_STOP_RX: {
 		usf_xx = &usf->usf_rx;
-		if (usf_xx->usf_state == USF_WORK_STATE)
+		if ((usf_xx->usf_state == USF_WORK_STATE)
+			|| (usf_xx->usf_state == USF_ADSP_RESTART_STATE))
 			usf_disable(usf_xx);
 		else {
 			pr_err("%s: stop_rx: wrong state[%d]\n",
diff --git a/arch/arm/mach-msm/qdsp6v2/ultrasound/version_b/q6usm_b.c b/arch/arm/mach-msm/qdsp6v2/ultrasound/version_b/q6usm_b.c
index 51a51c5..af3c1f5 100644
--- a/arch/arm/mach-msm/qdsp6v2/ultrasound/version_b/q6usm_b.c
+++ b/arch/arm/mach-msm/qdsp6v2/ultrasound/version_b/q6usm_b.c
@@ -488,6 +488,24 @@
 	}
 
 	switch (data->opcode) {
+	case RESET_EVENTS: {
+		pr_err("%s: Reset event is received: %d %d\n",
+				__func__,
+				data->reset_event,
+				data->reset_proc);
+
+		opcode = RESET_EVENTS;
+
+		apr_reset(this_mmap.apr);
+		this_mmap.apr = NULL;
+
+		apr_reset(usc->apr);
+		usc->apr = NULL;
+
+		break;
+	}
+
+
 	case USM_DATA_EVENT_READ_DONE: {
 		struct us_port_data *port = &usc->port[OUT];
 
diff --git a/arch/arm/mach-msm/rpm_log.c b/arch/arm/mach-msm/rpm_log.c
old mode 100644
new mode 100755
index 58e8588..1809cea
--- a/arch/arm/mach-msm/rpm_log.c
+++ b/arch/arm/mach-msm/rpm_log.c
@@ -52,6 +52,7 @@
 	char *data;
 	u32 len;
 	u32 pos;
+	struct mutex mutex;
 	u32 max_len;
 	u32 read_idx;
 	struct msm_rpm_log_platform_data *pdata;
@@ -218,6 +219,7 @@
 	if (!access_ok(VERIFY_WRITE, bufu, count))
 		return -EFAULT;
 
+	mutex_lock(&buf->mutex);
 	/* check for more messages if local buffer empty */
 	if (buf->pos == buf->len) {
 		buf->pos = 0;
@@ -226,6 +228,7 @@
 	}
 
 	if ((file->f_flags & O_NONBLOCK) && buf->len == 0)
+		mutex_unlock(&buf->mutex);
 		return -EAGAIN;
 
 	/* loop until new messages arrive */
@@ -241,6 +244,7 @@
 
 	remaining = __copy_to_user(bufu, &(buf->data[buf->pos]), out_len);
 	buf->pos += out_len - remaining;
+	mutex_unlock(&buf->mutex);
 
 	return out_len - remaining;
 }
@@ -287,6 +291,7 @@
 	buf->pdata = pdata;
 	buf->len = 0;
 	buf->pos = 0;
+	mutex_init(&buf->mutex);
 	buf->max_len = PRINTED_LENGTH(pdata->log_len);
 	buf->read_idx = msm_rpm_log_read(pdata, MSM_RPM_LOG_PAGE_INDICES,
 					 MSM_RPM_LOG_HEAD);
diff --git a/arch/arm/mach-msm/smd.c b/arch/arm/mach-msm/smd.c
index 1241e44..32f9b3b 100644
--- a/arch/arm/mach-msm/smd.c
+++ b/arch/arm/mach-msm/smd.c
@@ -1035,12 +1035,19 @@
 {
 	unsigned head = ch->half_ch->get_head(ch->recv);
 	unsigned tail = ch->half_ch->get_tail(ch->recv);
-	*ptr = (void *) (ch->recv_data + tail);
+	unsigned fifo_size = ch->fifo_size;
 
+	BUG_ON(fifo_size >= SZ_1M);
+	BUG_ON(head >= fifo_size);
+	BUG_ON(tail >= fifo_size);
+	BUG_ON(OVERFLOW_ADD_UNSIGNED(uintptr_t, (uintptr_t)ch->recv_data,
+								 tail));
+
+	*ptr = (void *) (ch->recv_data + tail);
 	if (tail <= head)
 		return head - tail;
 	else
-		return ch->fifo_size - tail;
+		return fifo_size - tail;
 }
 
 static int read_intr_blocked(struct smd_channel *ch)
@@ -1140,16 +1147,23 @@
 {
 	unsigned head = ch->half_ch->get_head(ch->send);
 	unsigned tail = ch->half_ch->get_tail(ch->send);
-	*ptr = (void *) (ch->send_data + head);
+	unsigned fifo_size = ch->fifo_size;
 
+	BUG_ON(fifo_size >= SZ_1M);
+	BUG_ON(head >= fifo_size);
+	BUG_ON(tail >= fifo_size);
+	BUG_ON(OVERFLOW_ADD_UNSIGNED(uintptr_t, (uintptr_t)ch->send_data,
+								head));
+
+	*ptr = (void *) (ch->send_data + head);
 	if (head < tail) {
 		return tail - head - SMD_FIFO_FULL_RESERVE;
 	} else {
 		if (tail < SMD_FIFO_FULL_RESERVE)
-			return ch->fifo_size + tail - head
+			return fifo_size + tail - head
 					- SMD_FIFO_FULL_RESERVE;
 		else
-			return ch->fifo_size - head;
+			return fifo_size - head;
 	}
 }
 
diff --git a/arch/arm/mach-msm/smem.c b/arch/arm/mach-msm/smem.c
index f41240a..3c7cbeb 100644
--- a/arch/arm/mach-msm/smem.c
+++ b/arch/arm/mach-msm/smem.c
@@ -27,17 +27,6 @@
 
 #include "smem_private.h"
 
-/**
- * OVERFLOW_ADD_UNSIGNED() - check for unsigned overflow
- *
- * @type: type to check for overflow
- * @a: left value to use
- * @b: right value to use
- * @returns: true if a + b will result in overflow; false otherwise
- */
-#define OVERFLOW_ADD_UNSIGNED(type, a, b) \
-	(((type)~0 - (a)) < (b) ? true : false)
-
 #define MODEM_SBL_VERSION_INDEX 7
 #define SMEM_VERSION_INFO_SIZE (32 * 4)
 #define SMEM_VERSION 0x000B
diff --git a/arch/arm/mach-msm/socinfo.c b/arch/arm/mach-msm/socinfo.c
index 8e7adba..795749b 100644
--- a/arch/arm/mach-msm/socinfo.c
+++ b/arch/arm/mach-msm/socinfo.c
@@ -176,6 +176,14 @@
 	uint32_t pmic_die_revision_2;
 };
 
+
+struct socinfo_v9 {
+	struct socinfo_v8 v8;
+
+	/* only valid when format==9*/
+	uint32_t foundry_id;
+};
+
 static union {
 	struct socinfo_v1 v1;
 	struct socinfo_v2 v2;
@@ -185,6 +193,7 @@
 	struct socinfo_v6 v6;
 	struct socinfo_v7 v7;
 	struct socinfo_v8 v8;
+	struct socinfo_v9 v9;
 } *socinfo;
 
 static struct msm_soc_info cpu_of_id[] = {
@@ -522,6 +531,14 @@
 		: 0;
 }
 
+static uint32_t socinfo_get_foundry_id(void)
+{
+	return socinfo ?
+		(socinfo->v1.format >= 9 ? socinfo->v9.foundry_id : 0)
+		: 0;
+}
+
+
 enum pmic_model socinfo_get_pmic_model(void)
 {
 	return socinfo ?
@@ -876,6 +893,15 @@
 }
 
 static ssize_t
+msm_get_foundry_id(struct device *dev,
+			struct device_attribute *attr,
+			char *buf)
+{
+	return snprintf(buf, PAGE_SIZE, "%u\n",
+		socinfo_get_foundry_id());
+}
+
+static ssize_t
 msm_get_pmic_model(struct device *dev,
 			struct device_attribute *attr,
 			char *buf)
@@ -1115,6 +1141,10 @@
 	__ATTR(platform_subtype_id, S_IRUGO,
 			msm_get_platform_subtype_id, NULL);
 
+static struct device_attribute msm_soc_attr_foundry_id =
+	__ATTR(foundry_id, S_IRUGO,
+			msm_get_foundry_id, NULL);
+
 static struct device_attribute msm_soc_attr_pmic_model =
 	__ATTR(pmic_model, S_IRUGO,
 			msm_get_pmic_model, NULL);
@@ -1199,6 +1229,9 @@
 	device_create_file(msm_soc_device, &select_image);
 
 	switch (legacy_format) {
+	case 9:
+		device_create_file(msm_soc_device,
+					&msm_soc_attr_foundry_id);
 	case 8:
 	case 7:
 		device_create_file(msm_soc_device,
@@ -1414,6 +1447,23 @@
 			socinfo->v7.pmic_model,
 			socinfo->v7.pmic_die_revision);
 		break;
+	case 9:
+		pr_info("%s: v%u, id=%u, ver=%u.%u, raw_id=%u, raw_ver=%u ,"
+			"hw_plat=%u, hw_plat_ver=%u\n accessory_chip=%u,"
+			"hw_plat_subtype=%u, pmic_model=%u, pmic_die_revision=%u,"
+			"foundry_id=%u\n", __func__,
+			socinfo->v1.format,
+			socinfo->v1.id,
+			SOCINFO_VERSION_MAJOR(socinfo->v1.version),
+			SOCINFO_VERSION_MINOR(socinfo->v1.version),
+			socinfo->v2.raw_id, socinfo->v2.raw_version,
+			socinfo->v3.hw_platform, socinfo->v4.platform_version,
+			socinfo->v5.accessory_chip,
+			socinfo->v6.hw_platform_subtype,
+			socinfo->v7.pmic_model,
+			socinfo->v7.pmic_die_revision,
+			socinfo->v9.foundry_id);
+		break;
 	default:
 		pr_err("%s: Unknown format found\n", __func__);
 		break;
@@ -1422,7 +1472,10 @@
 
 int __init socinfo_init(void)
 {
-	socinfo = smem_alloc(SMEM_HW_SW_BUILD_ID, sizeof(struct socinfo_v8));
+	socinfo = smem_alloc(SMEM_HW_SW_BUILD_ID, sizeof(struct socinfo_v9));
+	if (!socinfo)
+		socinfo = smem_alloc(SMEM_HW_SW_BUILD_ID,
+				sizeof(struct socinfo_v8));
 
 	if (!socinfo)
 		socinfo = smem_alloc(SMEM_HW_SW_BUILD_ID,
diff --git a/arch/arm/mm/fault.c b/arch/arm/mm/fault.c
index 235c386..698c93e 100644
--- a/arch/arm/mm/fault.c
+++ b/arch/arm/mm/fault.c
@@ -675,6 +675,8 @@
 	if (!inf->fn(addr, fsr & ~FSR_LNX_PF, regs))
 		return;
 
+	trace_unhandled_abort(regs, addr, fsr);
+
 	printk(KERN_ALERT "Unhandled fault: %s (0x%03x) at 0x%08lx\n",
 		inf->name, fsr, addr);
 
@@ -707,6 +709,8 @@
 	if (!inf->fn(addr, ifsr | FSR_LNX_PF, regs))
 		return;
 
+	trace_unhandled_abort(regs, addr, ifsr);
+
 	printk(KERN_ALERT "Unhandled prefetch abort: %s (0x%03x) at 0x%08lx\n",
 		inf->name, ifsr, addr);
 
diff --git a/arch/arm/mm/mmu.c b/arch/arm/mm/mmu.c
index 269ae80..3d52735 100644
--- a/arch/arm/mm/mmu.c
+++ b/arch/arm/mm/mmu.c
@@ -344,11 +344,13 @@
 	unsigned long size = PAGE_SIZE*numpages; \
 	unsigned end = start + size; \
 \
-	if (start < MODULES_VADDR || start >= MODULES_END) \
-		return -EINVAL;\
+	if (!IS_ENABLED(CONFIG_FORCE_PAGES)) { \
+		if (start < MODULES_VADDR || start >= MODULES_END) \
+			return -EINVAL;\
 \
-	if (end < MODULES_VADDR || end >= MODULES_END) \
-		return -EINVAL; \
+		if (end < MODULES_VADDR || end >= MODULES_END) \
+			return -EINVAL; \
+	} \
 \
 	apply_to_page_range(&init_mm, start, size, callback, NULL); \
 	flush_tlb_kernel_range(start, end); \
@@ -1507,6 +1509,100 @@
 	}
 }
 
+#ifdef CONFIG_FORCE_PAGES
+/*
+ * remap a PMD into pages
+ * We split a single pmd here none of this two pmd nonsense
+ */
+static noinline void split_pmd(pmd_t *pmd, unsigned long addr,
+				unsigned long end, unsigned long pfn,
+				const struct mem_type *type)
+{
+	pte_t *pte, *start_pte;
+
+	start_pte = early_alloc(PTE_HWTABLE_OFF + PTE_HWTABLE_SIZE);
+
+	pte = start_pte;
+
+	do {
+		set_pte_ext(pte, pfn_pte(pfn, type->prot_pte), 0);
+		pfn++;
+	} while (pte++, addr += PAGE_SIZE, addr != end);
+
+	*pmd = __pmd((__pa(start_pte) + PTE_HWTABLE_OFF) | type->prot_l1);
+	mb();
+	flush_pmd_entry(pmd);
+	flush_tlb_all();
+}
+
+/*
+ * It's significantly easier to remap as pages later after all memory is
+ * mapped. Everything is sections so all we have to do is split
+ */
+static void __init remap_pages(void)
+{
+	struct memblock_region *reg;
+
+	for_each_memblock(memory, reg) {
+		phys_addr_t phys_start = reg->base;
+		phys_addr_t phys_end = reg->base + reg->size;
+		unsigned long addr = (unsigned long)__va(phys_start);
+		unsigned long end = (unsigned long)__va(phys_end);
+		pmd_t *pmd = NULL;
+		unsigned long next;
+		unsigned long pfn = __phys_to_pfn(phys_start);
+		bool fixup = false;
+		unsigned long saved_start = addr;
+
+		if (phys_end > arm_lowmem_limit)
+			end = (unsigned long)__va(arm_lowmem_limit);
+		if (phys_start >= phys_end)
+			break;
+
+		pmd = pmd_offset(
+			pud_offset(pgd_offset(&init_mm, addr), addr), addr);
+
+#ifndef	CONFIG_ARM_LPAE
+		if (addr & SECTION_SIZE) {
+			fixup = true;
+			pmd_empty_section_gap((addr - SECTION_SIZE) & PMD_MASK);
+			pmd++;
+		}
+
+		if (end & SECTION_SIZE)
+			pmd_empty_section_gap(end);
+#endif
+
+		do {
+			next = addr + SECTION_SIZE;
+
+			if (pmd_none(*pmd) || pmd_bad(*pmd))
+				split_pmd(pmd, addr, next, pfn,
+						&mem_types[MT_MEMORY]);
+			pmd++;
+			pfn += SECTION_SIZE >> PAGE_SHIFT;
+
+		} while (addr = next, addr < end);
+
+		if (fixup) {
+			/*
+			 * Put a faulting page table here to avoid detecting no
+			 * pmd when accessing an odd section boundary. This
+			 * needs to be faulting to help catch errors and avoid
+			 * speculation
+			 */
+			pmd = pmd_off_k(saved_start);
+			pmd[0] = pmd[1] & ~1;
+		}
+	}
+}
+#else
+static void __init remap_pages(void)
+{
+
+}
+#endif
+
 /*
  * paging_init() sets up the page tables, initialises the zone memory
  * maps, and sets up the zero page, bad page and bad page tables.
@@ -1521,6 +1617,7 @@
 	prepare_page_table();
 	map_lowmem();
 	dma_contiguous_remap();
+	remap_pages();
 	devicemaps_init(mdesc);
 	kmap_init();
 
diff --git a/drivers/base/dma-contiguous.c b/drivers/base/dma-contiguous.c
index 6312bcd..2adcbbc 100644
--- a/drivers/base/dma-contiguous.c
+++ b/drivers/base/dma-contiguous.c
@@ -527,6 +527,7 @@
 			page = pfn_to_page(pfn);
 			break;
 		} else if (ret != -EBUSY) {
+			pfn = 0;
 			clear_cma_bitmap(cma, pfn, count);
 			break;
 		}
diff --git a/drivers/char/diag/diagchar.h b/drivers/char/diag/diagchar.h
index 99647a7..95d90b3 100644
--- a/drivers/char/diag/diagchar.h
+++ b/drivers/char/diag/diagchar.h
@@ -241,6 +241,7 @@
 
 	int in_busy_1;
 	int in_busy_2;
+	spinlock_t in_busy_lock;
 
 	unsigned char *buf_in_1;
 	unsigned char *buf_in_2;
@@ -383,6 +384,7 @@
 	struct work_struct diag_usb_disconnect_work;
 #endif
 	struct workqueue_struct *diag_wq;
+	struct workqueue_struct *diag_usb_wq;
 	struct work_struct diag_drain_work;
 	struct workqueue_struct *diag_cntl_wq;
 	uint8_t *msg_masks;
diff --git a/drivers/char/diag/diagchar_core.c b/drivers/char/diag/diagchar_core.c
index 0e475c9..ba13ec1 100644
--- a/drivers/char/diag/diagchar_core.c
+++ b/drivers/char/diag/diagchar_core.c
@@ -1171,6 +1171,7 @@
 	int remote_token;
 	int exit_stat;
 	int clear_read_wakelock;
+	unsigned long flags;
 
 	for (i = 0; i < driver->num_clients; i++)
 		if (driver->client_map[i].pid == current->tgid)
@@ -1250,7 +1251,10 @@
 					process_lock_on_copy(&data->nrt_lock);
 					clear_read_wakelock++;
 				}
+				spin_lock_irqsave(&data->in_busy_lock, flags);
 				data->in_busy_1 = 0;
+				spin_unlock_irqrestore(&data->in_busy_lock,
+						       flags);
 			}
 			if (data->in_busy_2 == 1) {
 				num_data++;
@@ -1265,7 +1269,10 @@
 					process_lock_on_copy(&data->nrt_lock);
 					clear_read_wakelock++;
 				}
+				spin_lock_irqsave(&data->in_busy_lock, flags);
 				data->in_busy_2 = 0;
+				spin_unlock_irqrestore(&data->in_busy_lock,
+						       flags);
 			}
 		}
 		if (driver->supports_separate_cmdrsp) {
diff --git a/drivers/char/diag/diagfwd.c b/drivers/char/diag/diagfwd.c
index 0bbb012..f7e720f 100644
--- a/drivers/char/diag/diagfwd.c
+++ b/drivers/char/diag/diagfwd.c
@@ -73,6 +73,8 @@
 	struct diag_send_desc_type send = { NULL, NULL, DIAG_STATE_START, 0 };
 	struct diag_hdlc_dest_type enc = { NULL, NULL, 0 };
 	struct diag_smd_info *data = &(driver->smd_data[MODEM_DATA]);
+	int err;
+	unsigned long flags;
 
 	if (buf_length > APPS_BUF_SIZE) {
 		pr_err("diag: In %s, invalid len %d, permissible len %d\n",
@@ -85,6 +87,7 @@
 	send.last = (void *)(driver->apps_rsp_buf + buf_length);
 	send.terminate = 1;
 	if (!data->in_busy_1) {
+		spin_lock_irqsave(&data->in_busy_lock, flags);
 		enc.dest = data->buf_in_1;
 		enc.dest_last = (void *)(data->buf_in_1 + APPS_BUF_SIZE - 1);
 		diag_hdlc_encode(&send, &enc);
@@ -92,9 +95,15 @@
 		data->write_ptr_1->length = (int)(enc.dest -
 						(void *)(data->buf_in_1));
 		data->in_busy_1 = 1;
-		diag_device_write(data->buf_in_1, data->peripheral,
+		err = diag_device_write(data->buf_in_1, data->peripheral,
 					data->write_ptr_1);
+		if (err) {
+			pr_err("diag: In %s, Unable to write to device, err: %d\n",
+			       __func__, err);
+			data->in_busy_1 = 0;
+		}
 		memset(driver->apps_rsp_buf, '\0', APPS_BUF_SIZE);
+		spin_unlock_irqrestore(&data->in_busy_lock, flags);
 	}
 }
 
@@ -462,6 +471,7 @@
 	struct diag_request *write_ptr_modem = NULL;
 	int *in_busy_ptr = 0;
 	int err = 0;
+	unsigned long flags;
 
 	/*
 	 * Do not process data on command channel if the
@@ -489,16 +499,16 @@
 		}
 
 		if (write_ptr_modem) {
+			spin_lock_irqsave(&smd_info->in_busy_lock, flags);
 			write_ptr_modem->length = total_recd;
 			*in_busy_ptr = 1;
 			err = diag_device_write(buf, smd_info->peripheral,
 						write_ptr_modem);
 			if (err) {
-				/* Free up the buffer for future use */
-				*in_busy_ptr = 0;
 				pr_err_ratelimited("diag: In %s, diag_device_write error: %d\n",
 					__func__, err);
 			}
+			spin_unlock_irqrestore(&smd_info->in_busy_lock, flags);
 		}
 	} else {
 		/* The data is raw and needs to be hdlc encoded */
@@ -526,6 +536,8 @@
 				success = diag_add_hdlc_encoding(smd_info, buf,
 							total_recd, write_buf,
 							&write_length);
+				spin_lock_irqsave(&smd_info->in_busy_lock,
+						  flags);
 				if (success) {
 					write_ptr_modem->length = write_length;
 					*in_busy_ptr = 1;
@@ -533,15 +545,12 @@
 							smd_info->peripheral,
 							write_ptr_modem);
 					if (err) {
-						/*
-						 * Free up the buffer for
-						 * future use
-						 */
-						*in_busy_ptr = 0;
 						pr_err_ratelimited("diag: In %s, diag_device_write error: %d\n",
 								__func__, err);
 					}
 				}
+				spin_unlock_irqrestore(&smd_info->in_busy_lock,
+						       flags);
 			}
 		}
 	}
@@ -814,6 +823,43 @@
 	diag_smd_send_req(smd_info);
 }
 
+#ifdef CONFIG_DIAG_OVER_USB
+static int diag_write_to_usb(struct usb_diag_ch *ch,
+			     struct diag_request *write_ptr)
+{
+	int err = 0;
+	uint8_t retry_count, max_retries;
+
+	if (!ch || !write_ptr)
+		return -EIO;
+
+	retry_count = 0;
+	max_retries = 3;
+
+	while (retry_count < max_retries) {
+		retry_count++;
+		/* If USB is not connected, don't try to write */
+		if (!driver->usb_connected) {
+			err = -ENODEV;
+			break;
+		}
+		err = usb_diag_write(ch, write_ptr);
+		if (err == -EAGAIN) {
+			/*
+			 * USB is not configured. Wait for sometime and
+			 * try again. The value 10000 was chosen empirically
+			 * as an optimum value for USB to be configured.
+			 */
+			usleep_range(10000, 10100);
+			continue;
+		} else {
+			break;
+		}
+	}
+	return err;
+}
+#endif
+
 int diag_device_write(void *buf, int data_type, struct diag_request *write_ptr)
 {
 	int i, err = 0, index;
@@ -919,7 +965,7 @@
 			if (driver->write_ptr_svc) {
 				driver->write_ptr_svc->length = driver->used;
 				driver->write_ptr_svc->buf = buf;
-				err = usb_diag_write(driver->legacy_ch,
+				err = diag_write_to_usb(driver->legacy_ch,
 						driver->write_ptr_svc);
 				/* Free the buffer if write failed */
 				if (err) {
@@ -941,7 +987,7 @@
 					   " USB: ", 16, 1, DUMP_PREFIX_ADDRESS,
 					    buf, write_ptr->length, 1);
 #endif /* DIAG DEBUG */
-			err = usb_diag_write(driver->legacy_ch, write_ptr);
+			err = diag_write_to_usb(driver->legacy_ch, write_ptr);
 		}
 #ifdef CONFIG_DIAG_SDIO_PIPE
 		else if (data_type == SDIO_DATA) {
@@ -1817,10 +1863,14 @@
 void diag_reset_smd_data(int queue)
 {
 	int i;
+	unsigned long flags;
 
 	for (i = 0; i < NUM_SMD_DATA_CHANNELS; i++) {
+		spin_lock_irqsave(&driver->smd_data[i].in_busy_lock, flags);
 		driver->smd_data[i].in_busy_1 = 0;
 		driver->smd_data[i].in_busy_2 = 0;
+		spin_unlock_irqrestore(&driver->smd_data[i].in_busy_lock,
+				       flags);
 		if (queue)
 			/* Poll SMD data channels to check for data */
 			queue_work(driver->smd_data[i].wq,
@@ -1829,8 +1879,12 @@
 
 	if (driver->supports_separate_cmdrsp) {
 		for (i = 0; i < NUM_SMD_CMD_CHANNELS; i++) {
+			spin_lock_irqsave(&driver->smd_cmd[i].in_busy_lock,
+					  flags);
 			driver->smd_cmd[i].in_busy_1 = 0;
 			driver->smd_cmd[i].in_busy_2 = 0;
+			spin_unlock_irqrestore(&driver->smd_cmd[i].in_busy_lock,
+					       flags);
 			if (queue)
 				/* Poll SMD data channels to check for data */
 				queue_work(driver->diag_wq,
@@ -1868,11 +1922,10 @@
 			N_LEGACY_WRITE_CMD : N_LEGACY_WRITE),
 			N_LEGACY_READ);
 	if (err)
-		printk(KERN_ERR "diag: unable to alloc USB req on legacy ch");
-
+		goto exit;
 	driver->usb_connected = 1;
 	diag_reset_smd_data(RESET_AND_QUEUE);
-	for (i = 0; i < NUM_SMD_DATA_CHANNELS; i++) {
+	for (i = 0; i < NUM_SMD_CONTROL_CHANNELS; i++) {
 		/* Poll SMD CNTL channels to check for data */
 		diag_smd_notify(&(driver->smd_cntl[i]), SMD_EVENT_DATA);
 	}
@@ -1889,26 +1942,40 @@
 			printk(KERN_INFO "diag: No USB MDM ch");
 	}
 #endif
+
 	return 0;
+exit:
+	pr_err("diag: unable to alloc USB req on legacy ch, err: %d", err);
+	return err;
 }
 
 int diagfwd_disconnect(void)
 {
 	int i;
+	unsigned long flags;
+	struct diag_smd_info *smd_info = NULL;
 
 	printk(KERN_DEBUG "diag: USB disconnected\n");
 	driver->usb_connected = 0;
 	driver->debug_flag = 1;
 	if (driver->logging_mode == USB_MODE) {
 		for (i = 0; i < NUM_SMD_DATA_CHANNELS; i++) {
-			driver->smd_data[i].in_busy_1 = 1;
-			driver->smd_data[i].in_busy_2 = 1;
+			smd_info = &driver->smd_data[i];
+			spin_lock_irqsave(&smd_info->in_busy_lock, flags);
+			smd_info->in_busy_1 = 1;
+			smd_info->in_busy_2 = 1;
+			spin_unlock_irqrestore(&smd_info->in_busy_lock, flags);
 		}
 
 		if (driver->supports_separate_cmdrsp) {
 			for (i = 0; i < NUM_SMD_CMD_CHANNELS; i++) {
-				driver->smd_cmd[i].in_busy_1 = 1;
-				driver->smd_cmd[i].in_busy_2 = 1;
+				smd_info = &driver->smd_cmd[i];
+				spin_lock_irqsave(&smd_info->in_busy_lock,
+						  flags);
+				smd_info->in_busy_1 = 1;
+				smd_info->in_busy_2 = 1;
+				spin_unlock_irqrestore(&smd_info->in_busy_lock,
+						       flags);
 			}
 		}
 	}
@@ -1928,7 +1995,9 @@
 {
 	int i;
 	int found_it = 0;
+	unsigned long flags;
 
+	spin_lock_irqsave(&data->in_busy_lock, flags);
 	for (i = 0; i < num_channels; i++) {
 		if (buf == (void *)data[i].buf_in_1) {
 			data[i].in_busy_1 = 0;
@@ -1940,6 +2009,7 @@
 			break;
 		}
 	}
+	spin_unlock_irqrestore(&data->in_busy_lock, flags);
 
 	if (found_it) {
 		if (data[i].type == SMD_DATA_TYPE)
@@ -2053,11 +2123,11 @@
 {
 	switch (event) {
 	case USB_DIAG_CONNECT:
-		queue_work(driver->diag_wq,
+		queue_work(driver->diag_usb_wq,
 			 &driver->diag_usb_connect_work);
 		break;
 	case USB_DIAG_DISCONNECT:
-		queue_work(driver->diag_wq,
+		queue_work(driver->diag_usb_wq,
 			 &driver->diag_usb_disconnect_work);
 		break;
 	case USB_DIAG_READ_DONE:
@@ -2071,7 +2141,6 @@
 		break;
 	}
 }
-
 #endif /* DIAG OVER USB */
 
 void diag_smd_notify(void *ctxt, unsigned event)
@@ -2283,6 +2352,7 @@
 	smd_info->type = type;
 	smd_info->encode_hdlc = 0;
 	mutex_init(&smd_info->smd_ch_mutex);
+	spin_lock_init(&smd_info->in_busy_lock);
 
 	switch (peripheral) {
 	case MODEM_DATA:
@@ -2596,6 +2666,7 @@
 		kmemleak_not_leak(driver->apps_rsp_buf);
 	}
 	driver->diag_wq = create_singlethread_workqueue("diag_wq");
+	driver->diag_usb_wq = create_singlethread_workqueue("diag_usb_wq");
 #ifdef CONFIG_DIAG_OVER_USB
 	INIT_WORK(&(driver->diag_usb_connect_work),
 						 diag_usb_connect_work_fn);
@@ -2643,6 +2714,8 @@
 	kfree(driver->user_space_data_buf);
 	if (driver->diag_wq)
 		destroy_workqueue(driver->diag_wq);
+	if (driver->diag_usb_wq)
+		destroy_workqueue(driver->diag_usb_wq);
 }
 
 void diagfwd_exit(void)
@@ -2680,4 +2753,5 @@
 	kfree(driver->apps_rsp_buf);
 	kfree(driver->user_space_data_buf);
 	destroy_workqueue(driver->diag_wq);
+	destroy_workqueue(driver->diag_usb_wq);
 }
diff --git a/drivers/coresight/coresight-event.c b/drivers/coresight/coresight-event.c
index aa8bfc5..95cadc2 100644
--- a/drivers/coresight/coresight-event.c
+++ b/drivers/coresight/coresight-event.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2012, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2012-2013, The Linux Foundation. All rights reserved.
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 and
@@ -10,9 +10,6 @@
  * GNU General Public License for more details.
  */
 
-/*
- * DLKM to register a callback with a ftrace event
- */
 #include <linux/module.h>
 #include <linux/kernel.h>
 #include <linux/slab.h>
@@ -23,49 +20,101 @@
 
 #include <trace/events/exception.h>
 
-static void abort_coresight_tracing(void *ignore, struct task_struct *task,\
-					unsigned long addr, unsigned int fsr)
+static int event_abort_enable;
+static int event_abort_set(const char *val, struct kernel_param *kp);
+module_param_call(event_abort_enable, event_abort_set, param_get_int,
+		  &event_abort_enable, 0644);
+
+static void event_abort_user_fault(void *ignore,
+				   struct task_struct *task,
+				   unsigned long addr,
+				   unsigned int fsr)
 {
 	coresight_abort();
-	pr_debug("control_trace: task_name: %s, addr: %lu, fsr:%u",\
+	pr_debug("coresight_event: task_name: %s, addr: %lu, fsr:%u",
 		(char *)task->comm, addr, fsr);
 }
 
-static void abort_tracing_undef_instr(void *ignore, struct pt_regs *regs,\
-					void *pc)
+static void event_abort_undef_instr(void *ignore,
+				    struct pt_regs *regs,
+				    void *pc)
 {
 	if (user_mode(regs)) {
 		coresight_abort();
-		pr_debug("control_trace: pc: %p", pc);
+		pr_debug("coresight_event: pc: %p", pc);
 	}
 }
 
-static int __init control_trace_init(void)
+static void event_abort_unhandled_abort(void *ignore,
+					struct pt_regs *regs,
+					unsigned long addr,
+					unsigned int fsr)
 {
-	int ret_user_fault, ret_undef_instr;
-	ret_user_fault = register_trace_user_fault(abort_coresight_tracing,\
-							NULL);
-	ret_undef_instr = register_trace_undef_instr(abort_tracing_undef_instr,\
-							NULL);
-	if (ret_user_fault != 0 || ret_undef_instr != 0) {
-		pr_info("control_trace: Module Not Registered\n");
-		return (ret_user_fault < 0 ?\
-			ret_user_fault : ret_undef_instr);
+	if (user_mode(regs)) {
+		coresight_abort();
+		pr_debug("coresight_event: addr: %lu, fsr:%u", addr, fsr);
 	}
-	pr_info("control_trace: Module Registered\n");
+}
+
+static int event_abort_register(void)
+{
+	int ret;
+
+	ret = register_trace_user_fault(event_abort_user_fault, NULL);
+	if (ret)
+		goto err_usr_fault;
+	ret = register_trace_undef_instr(event_abort_undef_instr, NULL);
+	if (ret)
+		goto err_undef_instr;
+	ret = register_trace_unhandled_abort(event_abort_unhandled_abort, NULL);
+	if (ret)
+		goto err_unhandled_abort;
+
+	return 0;
+
+err_unhandled_abort:
+	unregister_trace_undef_instr(event_abort_undef_instr, NULL);
+err_undef_instr:
+	unregister_trace_user_fault(event_abort_user_fault, NULL);
+err_usr_fault:
+	return ret;
+}
+
+static void event_abort_unregister(void)
+{
+	unregister_trace_user_fault(event_abort_user_fault, NULL);
+	unregister_trace_undef_instr(event_abort_undef_instr, NULL);
+	unregister_trace_unhandled_abort(event_abort_unhandled_abort, NULL);
+}
+
+static int event_abort_set(const char *val, struct kernel_param *kp)
+{
+	int ret;
+
+	ret = param_set_int(val, kp);
+	if (ret) {
+		pr_err("coresight_event: error setting value %d\n", ret);
+		return ret;
+	}
+
+	if (event_abort_enable)
+		ret = event_abort_register();
+	else
+		event_abort_unregister();
+
+	return ret;
+}
+
+static int __init event_init(void)
+{
 	return 0;
 }
+module_init(event_init);
 
-module_init(control_trace_init);
-
-static void __exit control_trace_exit(void)
+static void __exit event_exit(void)
 {
-	unregister_trace_user_fault(abort_coresight_tracing, NULL);
-	unregister_trace_undef_instr(abort_tracing_undef_instr, NULL);
-	pr_info("control_trace: Module Removed\n");
 }
-
-module_exit(control_trace_exit);
+module_exit(event_exit);
 
 MODULE_LICENSE("GPL v2");
-MODULE_DESCRIPTION("Kernel Module to abort tracing");
+MODULE_DESCRIPTION("Coresight Event driver to abort tracing");
diff --git a/drivers/crypto/msm/qcrypto.c b/drivers/crypto/msm/qcrypto.c
index 5530589..d7f0bcb 100644
--- a/drivers/crypto/msm/qcrypto.c
+++ b/drivers/crypto/msm/qcrypto.c
@@ -59,58 +59,60 @@
 #define QCRYPTO_HIGH_BANDWIDTH_TIMEOUT 1000
 
 struct crypto_stat {
-	u32 aead_sha1_aes_enc;
-	u32 aead_sha1_aes_dec;
-	u32 aead_sha1_des_enc;
-	u32 aead_sha1_des_dec;
-	u32 aead_sha1_3des_enc;
-	u32 aead_sha1_3des_dec;
-	u32 aead_ccm_aes_enc;
-	u32 aead_ccm_aes_dec;
-	u32 aead_rfc4309_ccm_aes_enc;
-	u32 aead_rfc4309_ccm_aes_dec;
-	u32 aead_op_success;
-	u32 aead_op_fail;
-	u32 aead_bad_msg;
-	u32 ablk_cipher_aes_enc;
-	u32 ablk_cipher_aes_dec;
-	u32 ablk_cipher_des_enc;
-	u32 ablk_cipher_des_dec;
-	u32 ablk_cipher_3des_enc;
-	u32 ablk_cipher_3des_dec;
-	u32 ablk_cipher_op_success;
-	u32 ablk_cipher_op_fail;
-	u32 sha1_digest;
-	u32 sha256_digest;
-	u32 sha_op_success;
-	u32 sha_op_fail;
-	u32 sha1_hmac_digest;
-	u32 sha256_hmac_digest;
-	u32 sha_hmac_op_success;
-	u32 sha_hmac_op_fail;
+	u64 aead_sha1_aes_enc;
+	u64 aead_sha1_aes_dec;
+	u64 aead_sha1_des_enc;
+	u64 aead_sha1_des_dec;
+	u64 aead_sha1_3des_enc;
+	u64 aead_sha1_3des_dec;
+	u64 aead_ccm_aes_enc;
+	u64 aead_ccm_aes_dec;
+	u64 aead_rfc4309_ccm_aes_enc;
+	u64 aead_rfc4309_ccm_aes_dec;
+	u64 aead_op_success;
+	u64 aead_op_fail;
+	u64 aead_bad_msg;
+	u64 ablk_cipher_aes_enc;
+	u64 ablk_cipher_aes_dec;
+	u64 ablk_cipher_des_enc;
+	u64 ablk_cipher_des_dec;
+	u64 ablk_cipher_3des_enc;
+	u64 ablk_cipher_3des_dec;
+	u64 ablk_cipher_op_success;
+	u64 ablk_cipher_op_fail;
+	u64 sha1_digest;
+	u64 sha256_digest;
+	u64 sha_op_success;
+	u64 sha_op_fail;
+	u64 sha1_hmac_digest;
+	u64 sha256_hmac_digest;
+	u64 sha_hmac_op_success;
+	u64 sha_hmac_op_fail;
 };
 static struct crypto_stat _qcrypto_stat;
 static struct dentry *_debug_dent;
 static char _debug_read_buf[DEBUG_MAX_RW_BUF];
+static bool _qcrypto_init_assign;
 struct crypto_priv;
 struct crypto_engine {
 	struct list_head elist;
 	void *qce; /* qce handle */
 	struct platform_device *pdev; /* platform device */
 	struct crypto_async_request *req; /* current active request */
+	struct qcrypto_resp_ctx *arsp;    /* rsp associcated with req */
+	int res;                          /* execution result */
 	struct crypto_priv *pcp;
 	struct tasklet_struct done_tasklet;
 	uint32_t  bus_scale_handle;
 	struct crypto_queue req_queue;	/*
 					 * request queue for those requests
-					 * that have this engine assgined
+					 * that have this engine assigned
 					 * waiting to be executed
 					 */
-	u32 total_req;
-	u32 err_req;
+	u64 total_req;
+	u64 err_req;
 	u32 unit;
 	u32 ce_device;
-	int res; /* execution result */
 	unsigned int signature;
 	uint32_t high_bw_req_count;
 	bool     high_bw_req;
@@ -140,6 +142,12 @@
 	int32_t total_units;   /* total units of engines */
 	struct mutex engine_lock;
 	struct crypto_engine *next_engine; /* next assign engine */
+	struct crypto_queue req_queue;	/*
+					 * request queue for those requests
+					 * that waiting for an available
+					 * engine.
+					 */
+
 };
 static struct crypto_priv qcrypto_dev;
 static struct crypto_engine *_qcrypto_static_assign_engine(
@@ -261,6 +269,11 @@
 #define	QCRYPTO_CCM4309_NONCE_LEN	3
 
 struct qcrypto_cipher_ctx {
+	struct list_head rsp_queue;     /* response queue */
+	struct crypto_engine *pengine;  /* fixed engine assigned to this tfm */
+	struct crypto_priv *cp;
+	unsigned int flags;
+
 	u8 auth_key[QCRYPTO_MAX_KEY_SIZE];
 	u8 iv[QCRYPTO_MAX_IV_LENGTH];
 
@@ -270,13 +283,18 @@
 	unsigned int authsize;
 	unsigned int auth_key_len;
 
-	struct crypto_priv *cp;
-	unsigned int flags;
-	struct crypto_engine *pengine;  /* fixed engine assigned */
 	u8 ccm4309_nonce[QCRYPTO_CCM4309_NONCE_LEN];
 };
 
+struct qcrypto_resp_ctx {
+	struct list_head list;
+	struct crypto_async_request *async_req; /* async req */
+	int res;                                /* execution result */
+};
+
 struct qcrypto_cipher_req_ctx {
+	struct qcrypto_resp_ctx rsp_entry;/* rsp entry. */
+	struct crypto_engine *pengine;  /* engine assigned to this request */
 	u8 *iv;
 	u8 rfc4309_iv[QCRYPTO_MAX_IV_LENGTH];
 	unsigned int ivsize;
@@ -301,6 +319,8 @@
 #define SHA_MAX_STATE_SIZE	(SHA256_DIGEST_SIZE / sizeof(u32))
 #define SHA_MAX_DIGEST_SIZE	 SHA256_DIGEST_SIZE
 
+#define	MSM_QCRYPTO_REQ_QUEUE_LENGTH 50
+
 static uint8_t  _std_init_vector_sha1_uint8[] =   {
 	0x67, 0x45, 0x23, 0x01, 0xEF, 0xCD, 0xAB, 0x89,
 	0x98, 0xBA, 0xDC, 0xFE, 0x10, 0x32, 0x54, 0x76,
@@ -316,18 +336,21 @@
 };
 
 struct qcrypto_sha_ctx {
+	struct list_head rsp_queue;     /* response queue */
+	struct crypto_engine *pengine;  /* fixed engine assigned to this tfm */
+	struct crypto_priv *cp;
+	unsigned int flags;
 	enum qce_hash_alg_enum  alg;
 	uint32_t		diglen;
 	uint32_t		authkey_in_len;
 	uint8_t			authkey[SHA_MAX_BLOCK_SIZE];
 	struct ahash_request *ahash_req;
 	struct completion ahash_req_complete;
-	struct crypto_priv *cp;
-	unsigned int flags;
-	struct crypto_engine *pengine;  /* fixed engine assigned */
 };
 
 struct qcrypto_sha_req_ctx {
+	struct qcrypto_resp_ctx rsp_entry;/* rsp entry. */
+	struct crypto_engine *pengine;  /* engine assigned to this request */
 
 	struct scatterlist *src;
 	uint32_t nbytes;
@@ -411,11 +434,10 @@
 	int ret = 0;
 
 	if (high_bw_req && pengine->high_bw_req == false) {
-		pm_stay_awake(&pengine->pdev->dev);
 		ret = qce_enable_clk(pengine->qce);
 		if (ret) {
 			pr_err("%s Unable enable clk\n", __func__);
-			goto clk_err;
+			return;
 		}
 		ret = msm_bus_scale_client_update_request(
 				pengine->bus_scale_handle, 1);
@@ -423,7 +445,7 @@
 			pr_err("%s Unable to set to high bandwidth\n",
 						__func__);
 			qce_disable_clk(pengine->qce);
-			goto clk_err;
+			return;
 		}
 		pengine->high_bw_req = true;
 	} else if (high_bw_req == false && pengine->high_bw_req == true) {
@@ -432,7 +454,7 @@
 		if (ret) {
 			pr_err("%s Unable to set to low bandwidth\n",
 						__func__);
-			goto clk_err;
+			return;
 		}
 		ret = qce_disable_clk(pengine->qce);
 		if (ret) {
@@ -442,16 +464,10 @@
 			if (ret)
 				pr_err("%s Unable to set to high bandwidth\n",
 						__func__);
-			goto clk_err;
+			return;
 		}
 		pengine->high_bw_req = false;
-		pm_relax(&pengine->pdev->dev);
 	}
-	return;
-clk_err:
-	pm_relax(&pengine->pdev->dev);
-	return;
-
 }
 
 static void qcrypto_bw_scale_down_timer_callback(unsigned long data)
@@ -473,20 +489,26 @@
 	add_timer(&(pengine->bw_scale_down_timer));
 }
 
-static void qcrypto_ce_bw_scaling_req(struct crypto_engine *pengine,
+static void qcrypto_ce_bw_scaling_req(struct crypto_priv *cp,
 				 bool high_bw_req)
 {
-	mutex_lock(&pengine->pcp->engine_lock);
-	if (high_bw_req) {
-		if (pengine->high_bw_req_count == 0)
-			qcrypto_ce_set_bus(pengine, true);
-		pengine->high_bw_req_count++;
-	} else {
-		pengine->high_bw_req_count--;
-		if (pengine->high_bw_req_count == 0)
-			qcrypto_bw_set_timeout(pengine);
+	struct crypto_engine *pengine;
+
+	if (cp->platform_support.bus_scale_table == NULL)
+		return;
+	mutex_lock(&cp->engine_lock);
+	list_for_each_entry(pengine, &cp->engine_list, elist) {
+		if (high_bw_req) {
+			if (pengine->high_bw_req_count == 0)
+				qcrypto_ce_set_bus(pengine, true);
+			pengine->high_bw_req_count++;
+		} else {
+			pengine->high_bw_req_count--;
+			if (pengine->high_bw_req_count == 0)
+				qcrypto_bw_set_timeout(pengine);
+		}
 	}
-	mutex_unlock(&pengine->pcp->engine_lock);
+	mutex_unlock(&cp->engine_lock);
 }
 
 static void qcrypto_low_bw_req_work(struct work_struct *work)
@@ -597,11 +619,14 @@
 
 	/* random first IV */
 	get_random_bytes(ctx->iv, QCRYPTO_MAX_IV_LENGTH);
-	ctx->pengine = _qcrypto_static_assign_engine(ctx->cp);
-	if (ctx->pengine == NULL)
-		return -ENODEV;
-	if (ctx->cp->platform_support.bus_scale_table != NULL)
-		qcrypto_ce_bw_scaling_req(ctx->pengine, true);
+	if (_qcrypto_init_assign) {
+		ctx->pengine = _qcrypto_static_assign_engine(ctx->cp);
+		if (ctx->pengine == NULL)
+			return -ENODEV;
+	} else
+		ctx->pengine = NULL;
+	qcrypto_ce_bw_scaling_req(ctx->cp, true);
+	INIT_LIST_HEAD(&ctx->rsp_queue);
 	return 0;
 };
 
@@ -619,11 +644,14 @@
 	sha_ctx->cp = q_alg->cp;
 	sha_ctx->flags = 0;
 	sha_ctx->ahash_req = NULL;
-	sha_ctx->pengine = _qcrypto_static_assign_engine(sha_ctx->cp);
-	if (sha_ctx->pengine == NULL)
-		return -ENODEV;
-	if (sha_ctx->cp->platform_support.bus_scale_table != NULL)
-		qcrypto_ce_bw_scaling_req(sha_ctx->pengine, true);
+	if (_qcrypto_init_assign) {
+		sha_ctx->pengine = _qcrypto_static_assign_engine(sha_ctx->cp);
+		if (sha_ctx->pengine == NULL)
+			return -ENODEV;
+	} else
+		sha_ctx->pengine = NULL;
+	qcrypto_ce_bw_scaling_req(sha_ctx->cp, true);
+	INIT_LIST_HEAD(&sha_ctx->rsp_queue);
 	return 0;
 };
 
@@ -631,13 +659,13 @@
 {
 	struct qcrypto_sha_ctx *sha_ctx = crypto_tfm_ctx(tfm);
 
+	if (!list_empty(&sha_ctx->rsp_queue))
+		pr_err("_qcrypto_ahash_cra_exit: requests still outstanding");
 	if (sha_ctx->ahash_req != NULL) {
 		ahash_request_free(sha_ctx->ahash_req);
 		sha_ctx->ahash_req = NULL;
 	}
-	if (sha_ctx->pengine &&
-			sha_ctx->cp->platform_support.bus_scale_table != NULL)
-		qcrypto_ce_bw_scaling_req(sha_ctx->pengine, false);
+	qcrypto_ce_bw_scaling_req(sha_ctx->cp, false);
 };
 
 
@@ -686,16 +714,18 @@
 {
 	struct qcrypto_cipher_ctx *ctx = crypto_tfm_ctx(tfm);
 
-	if (ctx->pengine && ctx->cp->platform_support.bus_scale_table != NULL)
-		qcrypto_ce_bw_scaling_req(ctx->pengine, false);
+	if (!list_empty(&ctx->rsp_queue))
+		pr_err("_qcrypto__cra_ablkcipher_exit: requests still outstanding");
+	qcrypto_ce_bw_scaling_req(ctx->cp, false);
 };
 
 static void _qcrypto_cra_aead_exit(struct crypto_tfm *tfm)
 {
 	struct qcrypto_cipher_ctx *ctx = crypto_tfm_ctx(tfm);
 
-	if (ctx->pengine && ctx->cp->platform_support.bus_scale_table != NULL)
-		qcrypto_ce_bw_scaling_req(ctx->pengine, false);
+	if (!list_empty(&ctx->rsp_queue))
+		pr_err("_qcrypto__cra_aead_exit: requests still outstanding");
+	qcrypto_ce_bw_scaling_req(ctx->cp, false);
 };
 
 static int _disp_stats(int id)
@@ -708,117 +738,117 @@
 
 	pstat = &_qcrypto_stat;
 	len = scnprintf(_debug_read_buf, DEBUG_MAX_RW_BUF - 1,
-			"\nQualcomm crypto accelerator %d Statistics:\n",
+			"\nQualcomm crypto accelerator %d Statistics\n",
 				id + 1);
 
 	len += scnprintf(_debug_read_buf + len, DEBUG_MAX_RW_BUF - len - 1,
-			"   ABLK AES CIPHER encryption   : %d\n",
+			"   ABLK AES CIPHER encryption          : %llu\n",
 					pstat->ablk_cipher_aes_enc);
 	len += scnprintf(_debug_read_buf + len, DEBUG_MAX_RW_BUF - len - 1,
-			"   ABLK AES CIPHER decryption   : %d\n",
+			"   ABLK AES CIPHER decryption          : %llu\n",
 					pstat->ablk_cipher_aes_dec);
 
 	len += scnprintf(_debug_read_buf + len, DEBUG_MAX_RW_BUF - len - 1,
-			"   ABLK DES CIPHER encryption   : %d\n",
+			"   ABLK DES CIPHER encryption          : %llu\n",
 					pstat->ablk_cipher_des_enc);
 	len += scnprintf(_debug_read_buf + len, DEBUG_MAX_RW_BUF - len - 1,
-			"   ABLK DES CIPHER decryption   : %d\n",
+			"   ABLK DES CIPHER decryption          : %llu\n",
 					pstat->ablk_cipher_des_dec);
 
 	len += scnprintf(_debug_read_buf + len, DEBUG_MAX_RW_BUF - len - 1,
-			"   ABLK 3DES CIPHER encryption  : %d\n",
+			"   ABLK 3DES CIPHER encryption         : %llu\n",
 					pstat->ablk_cipher_3des_enc);
 
 	len += scnprintf(_debug_read_buf + len, DEBUG_MAX_RW_BUF - len - 1,
-			"   ABLK 3DES CIPHER decryption  : %d\n",
+			"   ABLK 3DES CIPHER decryption         : %llu\n",
 					pstat->ablk_cipher_3des_dec);
 
 	len += scnprintf(_debug_read_buf + len, DEBUG_MAX_RW_BUF - len - 1,
-			"   ABLK CIPHER operation success: %d\n",
+			"   ABLK CIPHER operation success       : %llu\n",
 					pstat->ablk_cipher_op_success);
 	len += scnprintf(_debug_read_buf + len, DEBUG_MAX_RW_BUF - len - 1,
-			"   ABLK CIPHER operation fail   : %d\n",
+			"   ABLK CIPHER operation fail          : %llu\n",
 					pstat->ablk_cipher_op_fail);
 
 	len += scnprintf(_debug_read_buf + len, DEBUG_MAX_RW_BUF - len - 1,
-			"   AEAD SHA1-AES encryption      : %d\n",
+			"   AEAD SHA1-AES encryption            : %llu\n",
 					pstat->aead_sha1_aes_enc);
 	len += scnprintf(_debug_read_buf + len, DEBUG_MAX_RW_BUF - len - 1,
-			"   AEAD SHA1-AES decryption      : %d\n",
+			"   AEAD SHA1-AES decryption            : %llu\n",
 					pstat->aead_sha1_aes_dec);
 
 	len += scnprintf(_debug_read_buf + len, DEBUG_MAX_RW_BUF - len - 1,
-			"   AEAD SHA1-DES encryption      : %d\n",
+			"   AEAD SHA1-DES encryption            : %llu\n",
 					pstat->aead_sha1_des_enc);
 	len += scnprintf(_debug_read_buf + len, DEBUG_MAX_RW_BUF - len - 1,
-			"   AEAD SHA1-DES decryption      : %d\n",
+			"   AEAD SHA1-DES decryption            : %llu\n",
 					pstat->aead_sha1_des_dec);
 
 	len += scnprintf(_debug_read_buf + len, DEBUG_MAX_RW_BUF - len - 1,
-			"   AEAD SHA1-3DES encryption     : %d\n",
+			"   AEAD SHA1-3DES encryption           : %llu\n",
 					pstat->aead_sha1_3des_enc);
 	len += scnprintf(_debug_read_buf + len, DEBUG_MAX_RW_BUF - len - 1,
-			"   AEAD SHA1-3DES decryption     : %d\n",
+			"   AEAD SHA1-3DES decryption           : %llu\n",
 					pstat->aead_sha1_3des_dec);
 
 	len += scnprintf(_debug_read_buf + len, DEBUG_MAX_RW_BUF - len - 1,
-			"   AEAD CCM-AES encryption     : %d\n",
+			"   AEAD CCM-AES encryption             : %llu\n",
 					pstat->aead_ccm_aes_enc);
 	len += scnprintf(_debug_read_buf + len, DEBUG_MAX_RW_BUF - len - 1,
-			"   AEAD CCM-AES decryption     : %d\n",
+			"   AEAD CCM-AES decryption             : %llu\n",
 					pstat->aead_ccm_aes_dec);
 	len += scnprintf(_debug_read_buf + len, DEBUG_MAX_RW_BUF - len - 1,
-			"   AEAD RFC4309-CCM-AES encryption     : %d\n",
+			"   AEAD RFC4309-CCM-AES encryption     : %llu\n",
 					pstat->aead_rfc4309_ccm_aes_enc);
 	len += scnprintf(_debug_read_buf + len, DEBUG_MAX_RW_BUF - len - 1,
-			"   AEAD RFC4309-CCM-AES decryption     : %d\n",
+			"   AEAD RFC4309-CCM-AES decryption     : %llu\n",
 					pstat->aead_rfc4309_ccm_aes_dec);
 	len += scnprintf(_debug_read_buf + len, DEBUG_MAX_RW_BUF - len - 1,
-			"   AEAD operation success       : %d\n",
+			"   AEAD operation success              : %llu\n",
 					pstat->aead_op_success);
 	len += scnprintf(_debug_read_buf + len, DEBUG_MAX_RW_BUF - len - 1,
-			"   AEAD operation fail          : %d\n",
+			"   AEAD operation fail                 : %llu\n",
 					pstat->aead_op_fail);
 	len += scnprintf(_debug_read_buf + len, DEBUG_MAX_RW_BUF - len - 1,
-			"   AEAD bad message             : %d\n",
+			"   AEAD bad message                    : %llu\n",
 					pstat->aead_bad_msg);
 	len += scnprintf(_debug_read_buf + len, DEBUG_MAX_RW_BUF - len - 1,
-			"   SHA1 digest			 : %d\n",
+			"   SHA1 digest                         : %llu\n",
 					pstat->sha1_digest);
 	len += scnprintf(_debug_read_buf + len, DEBUG_MAX_RW_BUF - len - 1,
-			"   SHA256 digest		 : %d\n",
+			"   SHA256 digest                       : %llu\n",
 					pstat->sha256_digest);
 	len += scnprintf(_debug_read_buf + len, DEBUG_MAX_RW_BUF - len - 1,
-			"   SHA  operation fail          : %d\n",
+			"   SHA  operation fail                 : %llu\n",
 					pstat->sha_op_fail);
 	len += scnprintf(_debug_read_buf + len, DEBUG_MAX_RW_BUF - len - 1,
-			"   SHA  operation success          : %d\n",
+			"   SHA  operation success              : %llu\n",
 					pstat->sha_op_success);
 	len += scnprintf(_debug_read_buf + len, DEBUG_MAX_RW_BUF - len - 1,
-			"   SHA1 HMAC digest			 : %d\n",
+			"   SHA1 HMAC digest                    : %llu\n",
 					pstat->sha1_hmac_digest);
 	len += scnprintf(_debug_read_buf + len, DEBUG_MAX_RW_BUF - len - 1,
-			"   SHA256 HMAC digest		 : %d\n",
+			"   SHA256 HMAC digest                  : %llu\n",
 					pstat->sha256_hmac_digest);
 	len += scnprintf(_debug_read_buf + len, DEBUG_MAX_RW_BUF - len - 1,
-			"   SHA HMAC operation fail          : %d\n",
+			"   SHA HMAC operation fail             : %llu\n",
 					pstat->sha_hmac_op_fail);
 	len += scnprintf(_debug_read_buf + len, DEBUG_MAX_RW_BUF - len - 1,
-			"   SHA HMAC operation success          : %d\n",
+			"   SHA HMAC operation success          : %llu\n",
 					pstat->sha_hmac_op_success);
 	spin_lock_irqsave(&cp->lock, flags);
 	list_for_each_entry(pe, &cp->engine_list, elist) {
 		len += snprintf(
 			_debug_read_buf + len,
 			DEBUG_MAX_RW_BUF - len - 1,
-			"   Engine %d Req                : %d\n",
+			"   Engine %4d Req                     : %llu\n",
 			pe->unit,
 			pe->total_req
 		);
 		len += snprintf(
 			_debug_read_buf + len,
 			DEBUG_MAX_RW_BUF - len - 1,
-			"   Engine %d Req Error          : %d\n",
+			"   Engine %4d Req Error               : %llu\n",
 			pe->unit,
 			pe->err_req
 		);
@@ -847,7 +877,6 @@
 	tasklet_kill(&pengine->done_tasklet);
 	cancel_work_sync(&pengine->low_bw_req_ws);
 	del_timer_sync(&pengine->bw_scale_down_timer);
-	device_init_wakeup(&pengine->pdev->dev, false);
 
 	if (pengine->bus_scale_handle != 0)
 		msm_bus_scale_unregister_client(pengine->bus_scale_handle);
@@ -1020,27 +1049,73 @@
 	return 0;
 };
 
+static void _qcrypto_tfm_complete(struct crypto_priv *cp, u32 type,
+					 void *tfm_ctx)
+{
+	unsigned long flags;
+	struct qcrypto_resp_ctx *arsp;
+	struct list_head *plist;
+	struct crypto_async_request *areq;
+
+	switch (type) {
+	case CRYPTO_ALG_TYPE_AHASH:
+		plist = &((struct qcrypto_sha_ctx *) tfm_ctx)->rsp_queue;
+		break;
+	case CRYPTO_ALG_TYPE_ABLKCIPHER:
+	case CRYPTO_ALG_TYPE_AEAD:
+	default:
+		plist = &((struct qcrypto_cipher_ctx *) tfm_ctx)->rsp_queue;
+		break;
+	}
+again:
+	spin_lock_irqsave(&cp->lock, flags);
+	if (list_empty(plist)) {
+		arsp = NULL; /* nothing to do */
+	} else {
+		arsp = list_first_entry(plist,
+				struct  qcrypto_resp_ctx, list);
+		if (arsp->res == -EINPROGRESS)
+			arsp = NULL;  /* still in progress */
+		else
+			list_del(&arsp->list); /* request is complete */
+	}
+	spin_unlock_irqrestore(&cp->lock, flags);
+	if (arsp) {
+		areq = arsp->async_req;
+		areq->complete(areq, arsp->res);
+		goto again;
+	}
+}
+
 static void req_done(unsigned long data)
 {
 	struct crypto_async_request *areq;
 	struct crypto_engine *pengine = (struct crypto_engine *)data;
 	struct crypto_priv *cp;
 	unsigned long flags;
+	struct qcrypto_resp_ctx *arsp;
 	int res;
+	u32 type = 0;
+	void *tfm_ctx = NULL;
 
 	cp = pengine->pcp;
 	spin_lock_irqsave(&cp->lock, flags);
 	areq = pengine->req;
-	pengine->req = NULL;
-	res = pengine->res;
-	spin_unlock_irqrestore(&cp->lock, flags);
-	if (areq)
-		areq->complete(areq, res);
-	if (res)
-		pengine->err_req++;
-	_start_qcrypto_process(cp, pengine);
-};
 
+	arsp = pengine->arsp;
+	res = pengine->res;
+	pengine->req = NULL;
+	pengine->arsp = NULL;
+	if (areq) {
+		type = crypto_tfm_alg_type(areq->tfm);
+		tfm_ctx = crypto_tfm_ctx(areq->tfm);
+		arsp->res = res;
+	}
+	spin_unlock_irqrestore(&cp->lock, flags);
+	_start_qcrypto_process(cp, pengine);
+	if (areq)
+		_qcrypto_tfm_complete(cp, type, tfm_ctx);
+}
 
 static void _qce_ahash_complete(void *cookie, unsigned char *digest,
 		unsigned char *authdata, int ret)
@@ -1057,7 +1132,7 @@
 
 	pstat = &_qcrypto_stat;
 
-	pengine = sha_ctx->pengine;
+	pengine = rctx->pengine;
 #ifdef QCRYPTO_DEBUG
 	dev_info(&pengine->pdev->dev, "_qce_ahash_complete: %p ret %d\n",
 				areq, ret);
@@ -1103,10 +1178,12 @@
 	struct qcrypto_cipher_ctx *ctx = crypto_tfm_ctx(areq->base.tfm);
 	struct crypto_priv *cp = ctx->cp;
 	struct crypto_stat *pstat;
+	struct qcrypto_cipher_req_ctx *rctx;
 	struct crypto_engine *pengine;
 
 	pstat = &_qcrypto_stat;
-	pengine = ctx->pengine;
+	rctx = ablkcipher_request_ctx(areq);
+	pengine = rctx->pengine;
 #ifdef QCRYPTO_DEBUG
 	dev_info(&pengine->pdev->dev, "_qce_ablk_cipher_complete: %p ret %d\n",
 				areq, ret);
@@ -1158,8 +1235,8 @@
 	struct crypto_engine *pengine;
 
 	pstat = &_qcrypto_stat;
-	pengine = ctx->pengine;
 	rctx = aead_request_ctx(areq);
+	pengine = rctx->pengine;
 
 	if (rctx->mode == QCE_MODE_CCM) {
 		if (cp->ce_support.aligned_only)  {
@@ -1363,6 +1440,7 @@
 	req = container_of(async_req, struct ablkcipher_request, base);
 	cipher_ctx = crypto_tfm_ctx(async_req->tfm);
 	rctx = ablkcipher_request_ctx(req);
+	rctx->pengine = pengine;
 	tfm = crypto_ablkcipher_reqtfm(req);
 	if (pengine->pcp->ce_support.aligned_only) {
 		uint32_t bytes = 0;
@@ -1426,6 +1504,7 @@
 				struct ahash_request, base);
 	rctx = ahash_request_ctx(req);
 	sha_ctx = crypto_tfm_ctx(async_req->tfm);
+	rctx->pengine = pengine;
 
 	sreq.qce_cb = _qce_ahash_complete;
 	sreq.digest =  &rctx->digest[0];
@@ -1481,6 +1560,7 @@
 	struct crypto_aead *aead = crypto_aead_reqtfm(req);
 
 	rctx = aead_request_ctx(req);
+	rctx->pengine = pengine;
 	cipher_ctx = crypto_tfm_ctx(async_req->tfm);
 
 	qreq.op = QCE_REQ_AEAD;
@@ -1695,28 +1775,93 @@
 				struct crypto_engine *pengine)
 {
 	struct crypto_async_request *async_req = NULL;
-	struct crypto_async_request *backlog = NULL;
+	struct crypto_async_request *backlog_eng = NULL;
+	struct crypto_async_request *backlog_cp = NULL;
 	unsigned long flags;
 	u32 type;
 	int ret = 0;
 	struct crypto_stat *pstat;
+	void *tfm_ctx;
+	struct qcrypto_cipher_req_ctx *cipher_rctx;
+	struct qcrypto_sha_req_ctx *ahash_rctx;
+	struct ablkcipher_request *ablkcipher_req;
+	struct ahash_request *ahash_req;
+	struct aead_request *aead_req;
+	struct qcrypto_resp_ctx *arsp;
 
 	pstat = &_qcrypto_stat;
 
 again:
 	spin_lock_irqsave(&cp->lock, flags);
-	if (pengine->req == NULL) {
-		backlog = crypto_get_backlog(&pengine->req_queue);
-		async_req = crypto_dequeue_request(&pengine->req_queue);
-		pengine->req = async_req;
+	if (pengine->req) {
+		spin_unlock_irqrestore(&cp->lock, flags);
+		return 0;
 	}
-	spin_unlock_irqrestore(&cp->lock, flags);
-	if (!async_req)
-		return ret;
-	if (backlog)
-		backlog->complete(backlog, -EINPROGRESS);
-	type = crypto_tfm_alg_type(async_req->tfm);
 
+	backlog_eng = crypto_get_backlog(&pengine->req_queue);
+
+	/* try to get request from request queue of the engine first */
+	async_req = crypto_dequeue_request(&pengine->req_queue);
+	if (!async_req) {
+		/*
+		 * if no request from the engine,
+		 * try to  get from request queue of driver
+		 */
+		backlog_cp = crypto_get_backlog(&cp->req_queue);
+		async_req = crypto_dequeue_request(&cp->req_queue);
+		if (!async_req) {
+			spin_unlock_irqrestore(&cp->lock, flags);
+			return 0;
+		}
+	}
+
+	/* add associated rsp entry to tfm response queue */
+	type = crypto_tfm_alg_type(async_req->tfm);
+	tfm_ctx = crypto_tfm_ctx(async_req->tfm);
+	switch (type) {
+	case CRYPTO_ALG_TYPE_AHASH:
+		ahash_req = container_of(async_req,
+			struct ahash_request, base);
+		ahash_rctx = ahash_request_ctx(ahash_req);
+		arsp = &ahash_rctx->rsp_entry;
+		list_add_tail(
+			&arsp->list,
+			&((struct qcrypto_sha_ctx *)tfm_ctx)
+				->rsp_queue);
+		break;
+	case CRYPTO_ALG_TYPE_ABLKCIPHER:
+		ablkcipher_req = container_of(async_req,
+			struct ablkcipher_request, base);
+		cipher_rctx = ablkcipher_request_ctx(ablkcipher_req);
+		arsp = &cipher_rctx->rsp_entry;
+		list_add_tail(
+			&arsp->list,
+			&((struct qcrypto_sha_ctx *)tfm_ctx)
+				->rsp_queue);
+		break;
+	case CRYPTO_ALG_TYPE_AEAD:
+	default:
+		aead_req = container_of(async_req,
+			struct aead_request, base);
+		cipher_rctx = aead_request_ctx(aead_req);
+		arsp = &cipher_rctx->rsp_entry;
+		list_add_tail(
+			&arsp->list,
+			&((struct qcrypto_sha_ctx *)tfm_ctx)
+				->rsp_queue);
+		break;
+	}
+
+	arsp->res = -EINPROGRESS;
+	arsp->async_req = async_req;
+	pengine->req = async_req;
+	pengine->arsp = arsp;
+
+	spin_unlock_irqrestore(&cp->lock, flags);
+	if (backlog_eng)
+		backlog_eng->complete(backlog_eng, -EINPROGRESS);
+	if (backlog_cp)
+		backlog_cp->complete(backlog_cp, -EINPROGRESS);
 	switch (type) {
 	case CRYPTO_ALG_TYPE_ABLKCIPHER:
 		ret = _qcrypto_process_ablkcipher(pengine, async_req);
@@ -1732,9 +1877,11 @@
 	};
 	pengine->total_req++;
 	if (ret) {
+		arsp->res = ret;
 		pengine->err_req++;
 		spin_lock_irqsave(&cp->lock, flags);
 		pengine->req = NULL;
+		pengine->arsp = NULL;
 		spin_unlock_irqrestore(&cp->lock, flags);
 
 		if (type == CRYPTO_ALG_TYPE_ABLKCIPHER)
@@ -1745,11 +1892,22 @@
 			else
 				pstat->aead_op_fail++;
 
-		async_req->complete(async_req, ret);
+		_qcrypto_tfm_complete(cp, type, tfm_ctx);
 		goto again;
 	};
 	return ret;
-};
+}
+
+static struct crypto_engine *_avail_eng(struct crypto_priv *cp)
+{
+	struct crypto_engine *pe = NULL;
+
+	list_for_each_entry(pe, &cp->engine_list, elist) {
+		if (pe->req == NULL)
+			return pe;
+	}
+	return NULL;
+}
 
 static int _qcrypto_queue_req(struct crypto_priv *cp,
 				struct crypto_engine *pengine,
@@ -1765,9 +1923,15 @@
 	}
 
 	spin_lock_irqsave(&cp->lock, flags);
-	ret = crypto_enqueue_request(&pengine->req_queue, req);
+	if (pengine) {
+		ret = crypto_enqueue_request(&pengine->req_queue, req);
+	} else {
+		ret = crypto_enqueue_request(&cp->req_queue, req);
+		pengine = _avail_eng(cp);
+	}
 	spin_unlock_irqrestore(&cp->lock, flags);
-	_start_qcrypto_process(cp, pengine);
+	if (pengine)
+		_start_qcrypto_process(cp, pengine);
 
 	return ret;
 }
@@ -3363,7 +3527,7 @@
 static int _qcrypto_prefix_alg_cra_name(char cra_name[], unsigned int size)
 {
 	char new_cra_name[CRYPTO_MAX_ALG_NAME] = "qcom-";
-	if (CRYPTO_MAX_ALG_NAME < size + 5)
+	if (size >= CRYPTO_MAX_ALG_NAME - strlen("qcom-"))
 		return -EINVAL;
 	strlcat(new_cra_name, cra_name, CRYPTO_MAX_ALG_NAME);
 	strlcpy(cra_name, new_cra_name, CRYPTO_MAX_ALG_NAME);
@@ -3997,6 +4161,7 @@
 	pengine->pcp = cp;
 	pengine->pdev = pdev;
 	pengine->req = NULL;
+	pengine->signature = 0xdeadbeef;
 
 	pengine->high_bw_req_count = 0;
 	pengine->high_bw_req = false;
@@ -4004,11 +4169,8 @@
 	INIT_WORK(&pengine->low_bw_req_ws, qcrypto_low_bw_req_work);
 	pengine->bw_scale_down_timer.function =
 			qcrypto_bw_scale_down_timer_callback;
-
-	device_init_wakeup(&pengine->pdev->dev, true);
-
 	tasklet_init(&pengine->done_tasklet, req_done, (unsigned long)pengine);
-	crypto_init_queue(&pengine->req_queue, 50);
+	crypto_init_queue(&pengine->req_queue, MSM_QCRYPTO_REQ_QUEUE_LENGTH);
 
 	mutex_lock(&cp->engine_lock);
 	cp->total_units++;
@@ -4083,6 +4245,7 @@
 				dev_err(&pdev->dev,
 					"The algorithm name %s is too long.\n",
 					q_alg->cipher_alg.cra_name);
+				kfree(q_alg);
 				goto err;
 			}
 		}
@@ -4116,6 +4279,7 @@
 				dev_err(&pdev->dev,
 					"The algorithm name %s is too long.\n",
 					q_alg->cipher_alg.cra_name);
+				kfree(q_alg);
 				goto err;
 			}
 		}
@@ -4152,6 +4316,7 @@
 				dev_err(&pdev->dev,
 					"The algorithm name %s is too long.\n",
 					q_alg->sha_alg.halg.base.cra_name);
+				kfree(q_alg);
 				goto err;
 			}
 		}
@@ -4188,6 +4353,7 @@
 					dev_err(&pdev->dev,
 						"The algorithm name %s is too long.\n",
 						q_alg->cipher_alg.cra_name);
+					kfree(q_alg);
 					goto err;
 				}
 			}
@@ -4226,6 +4392,7 @@
 					dev_err(&pdev->dev,
 					     "The algorithm name %s is too long.\n",
 					     q_alg->sha_alg.halg.base.cra_name);
+					kfree(q_alg);
 					goto err;
 				}
 			}
@@ -4262,6 +4429,7 @@
 				dev_err(&pdev->dev,
 						"The algorithm name %s is too long.\n",
 						q_alg->cipher_alg.cra_name);
+				kfree(q_alg);
 				goto err;
 			}
 		}
@@ -4523,6 +4691,7 @@
 	pcp->ce_lock_count = 0;
 	pcp->platform_support.bus_scale_table = NULL;
 	pcp->next_engine = NULL;
+	crypto_init_queue(&pcp->req_queue, MSM_QCRYPTO_REQ_QUEUE_LENGTH);
 	return platform_driver_register(&_qualcomm_crypto);
 }
 
diff --git a/drivers/devfreq/governor_cpubw_hwmon.c b/drivers/devfreq/governor_cpubw_hwmon.c
index e7d373b..aa7ff69 100644
--- a/drivers/devfreq/governor_cpubw_hwmon.c
+++ b/drivers/devfreq/governor_cpubw_hwmon.c
@@ -246,8 +246,9 @@
 		new_bw /= 100;
 	}
 
-	*ab = roundup(mbps, bw_step);
-	*freq = (mbps * 100) / io_percent;
+	prev_ab = new_bw;
+	*ab = roundup(new_bw, bw_step);
+	*freq = (new_bw * 100) / io_percent;
 }
 
 #define TOO_SOON_US	(1 * USEC_PER_MSEC)
@@ -340,7 +341,6 @@
 
 	mbps = measure_bw_and_set_irq();
 	compute_bw(mbps, freq, df->data);
-	prev_ab = *(unsigned long *) df->data;
 
 	return 0;
 }
diff --git a/drivers/gpu/msm/adreno.c b/drivers/gpu/msm/adreno.c
index 695095f..f230033 100644
--- a/drivers/gpu/msm/adreno.c
+++ b/drivers/gpu/msm/adreno.c
@@ -272,7 +272,7 @@
 			struct adreno_device, input_work);
 	struct kgsl_device *device = &adreno_dev->dev;
 
-	mutex_lock(&device->mutex);
+	kgsl_mutex_lock(&device->mutex, &device->mutex_owner);
 
 	device->flags |= KGSL_FLAG_WAKE_ON_TOUCH;
 
@@ -290,7 +290,7 @@
 	 */
 	mod_timer(&device->idle_timer,
 		jiffies + msecs_to_jiffies(_wake_timeout));
-	mutex_unlock(&device->mutex);
+	kgsl_mutex_unlock(&device->mutex, &device->mutex_owner);
 }
 
 /*
@@ -1137,9 +1137,7 @@
 					uint32_t flags)
 {
 	phys_addr_t pt_val;
-	unsigned int link[230];
-	unsigned int *cmds = &link[0];
-	int sizedwords = 0;
+	unsigned int *link = NULL, *cmds;
 	struct adreno_device *adreno_dev = ADRENO_DEVICE(device);
 	int num_iommu_units;
 	struct kgsl_context *context;
@@ -1160,6 +1158,14 @@
 	}
 	adreno_ctx = ADRENO_CONTEXT(context);
 
+	link = kmalloc(PAGE_SIZE, GFP_KERNEL);
+	if (link == NULL) {
+		result = -ENOMEM;
+		goto done;
+	}
+
+	cmds = link;
+
 	result = kgsl_mmu_enable_clk(&device->mmu, KGSL_IOMMU_CONTEXT_USER);
 
 	if (result)
@@ -1179,17 +1185,11 @@
 		cmds += _adreno_iommu_setstate_v1(device, cmds, pt_val,
 						num_iommu_units, flags);
 
-	sizedwords += (cmds - &link[0]);
-	if (sizedwords == 0) {
-		KGSL_DRV_ERR(device, "no commands generated\n");
-		BUG();
-	}
 	/* invalidate all base pointers */
 	*cmds++ = cp_type3_packet(CP_INVALIDATE_STATE, 1);
 	*cmds++ = 0x7fff;
-	sizedwords += 2;
 
-	if (sizedwords > (ARRAY_SIZE(link))) {
+	if ((unsigned int) (cmds - link) > (PAGE_SIZE / sizeof(unsigned int))) {
 		KGSL_DRV_ERR(device, "Temp command buffer overflow\n");
 		BUG();
 	}
@@ -1198,7 +1198,8 @@
 	 * use the global timestamp for iommu clock disablement
 	 */
 	result = adreno_ringbuffer_issuecmds(device, adreno_ctx,
-			KGSL_CMD_FLAGS_PMODE, &link[0], sizedwords);
+			KGSL_CMD_FLAGS_PMODE, link,
+			(unsigned int)(cmds - link));
 
 	/*
 	 * On error disable the IOMMU clock right away otherwise turn it off
@@ -1212,6 +1213,7 @@
 						KGSL_IOMMU_CONTEXT_USER);
 
 done:
+	kfree(link);
 	kgsl_context_put(context);
 	return result;
 }
@@ -2103,7 +2105,7 @@
 	/* Nice ourselves to be higher priority but not too high priority */
 	set_user_nice(current, _wake_nice);
 
-	mutex_lock(&device->mutex);
+	kgsl_mutex_lock(&device->mutex, &device->mutex_owner);
 	/*
 	 *  If adreno start is already called, no need to call it again
 	 *  it can lead to unpredictable behavior if we try to start
@@ -2123,7 +2125,7 @@
 		_status = _adreno_start(adreno_dev);
 	else
 		_status = 0;
-	mutex_unlock(&device->mutex);
+	kgsl_mutex_unlock(&device->mutex, &device->mutex_owner);
 }
 
 /**
@@ -2148,9 +2150,9 @@
 	 * higher priority work queue and wait for it to finish
 	 */
 	queue_work(adreno_wq, &adreno_dev->start_work);
-	mutex_unlock(&device->mutex);
+	kgsl_mutex_unlock(&device->mutex, &device->mutex_owner);
 	flush_work(&adreno_dev->start_work);
-	mutex_lock(&device->mutex);
+	kgsl_mutex_lock(&device->mutex, &device->mutex_owner);
 
 	return _status;
 }
diff --git a/drivers/gpu/msm/adreno.h b/drivers/gpu/msm/adreno.h
index 976a355..3d9206b 100644
--- a/drivers/gpu/msm/adreno.h
+++ b/drivers/gpu/msm/adreno.h
@@ -416,7 +416,8 @@
 #define  KGSL_FT_DISABLE                  4
 #define  KGSL_FT_TEMP_DISABLE             5
 #define  KGSL_FT_THROTTLE                 6
-#define  KGSL_FT_DEFAULT_POLICY (BIT(KGSL_FT_REPLAY) + BIT(KGSL_FT_SKIPIB) \
+#define  KGSL_FT_SKIPCMD                  7
+#define  KGSL_FT_DEFAULT_POLICY (BIT(KGSL_FT_REPLAY) + BIT(KGSL_FT_SKIPCMD) \
 				+ BIT(KGSL_FT_THROTTLE))
 
 /* This internal bit is used to skip the PM dump on replayed command batches */
@@ -436,7 +437,8 @@
 	{ BIT(KGSL_FT_SKIPFRAME), "skipframe" }, \
 	{ BIT(KGSL_FT_DISABLE), "disable" }, \
 	{ BIT(KGSL_FT_TEMP_DISABLE), "temp" }, \
-	{ BIT(KGSL_FT_THROTTLE), "throttle"}
+	{ BIT(KGSL_FT_THROTTLE), "throttle"}, \
+	{ BIT(KGSL_FT_SKIPCMD), "skipcmd" }
 
 extern struct adreno_gpudev adreno_a2xx_gpudev;
 extern struct adreno_gpudev adreno_a3xx_gpudev;
@@ -516,6 +518,10 @@
 int adreno_ft_init_sysfs(struct kgsl_device *device);
 void adreno_ft_uninit_sysfs(struct kgsl_device *device);
 
+void adreno_fault_skipcmd_detached(struct kgsl_device *device,
+					 struct adreno_context *drawctxt,
+					 struct kgsl_cmdbatch *cmdbatch);
+
 int adreno_perfcounter_get_groupid(struct adreno_device *adreno_dev,
 					const char *name);
 
@@ -718,6 +724,11 @@
 	*cmds++ = val;
 	*cmds++ = 0xFFFFFFFF;
 	*cmds++ = 0xFFFFFFFF;
+
+	/* WAIT_REG_MEM turns back on protected mode - push it off */
+	*cmds++ = cp_type3_packet(CP_SET_PROTECTED_MODE, 1);
+	*cmds++ = 0;
+
 	cmds += __adreno_add_idle_indirect_cmds(cmds, nop_gpuaddr);
 	return cmds - start;
 }
diff --git a/drivers/gpu/msm/adreno_a3xx.c b/drivers/gpu/msm/adreno_a3xx.c
index 2faa278..2025d73 100644
--- a/drivers/gpu/msm/adreno_a3xx.c
+++ b/drivers/gpu/msm/adreno_a3xx.c
@@ -4150,6 +4150,7 @@
 
 	/* CP registers */
 	adreno_set_protected_registers(device, &index, 0x1C0, 5);
+	adreno_set_protected_registers(device, &index, 0x1EC, 1);
 	adreno_set_protected_registers(device, &index, 0x1F6, 1);
 	adreno_set_protected_registers(device, &index, 0x1F8, 2);
 	adreno_set_protected_registers(device, &index, 0x45E, 2);
@@ -4250,7 +4251,7 @@
  */
 int a3xx_coresight_enable(struct kgsl_device *device)
 {
-	mutex_lock(&device->mutex);
+	kgsl_mutex_lock(&device->mutex, &device->mutex_owner);
 	if (!kgsl_active_count_get(device)) {
 		kgsl_regwrite(device, A3XX_RBBM_DEBUG_BUS_CTL, 0x0001093F);
 		kgsl_regwrite(device, A3XX_RBBM_DEBUG_BUS_STB_CTL0,
@@ -4271,7 +4272,7 @@
 				0x00000001);
 		kgsl_active_count_put(device);
 	}
-	mutex_unlock(&device->mutex);
+	kgsl_mutex_unlock(&device->mutex, &device->mutex_owner);
 	return 0;
 }
 
@@ -4282,7 +4283,7 @@
  */
 void a3xx_coresight_disable(struct kgsl_device *device)
 {
-	mutex_lock(&device->mutex);
+	kgsl_mutex_lock(&device->mutex, &device->mutex_owner);
 	if (!kgsl_active_count_get(device)) {
 		kgsl_regwrite(device, A3XX_RBBM_DEBUG_BUS_CTL, 0x0);
 		kgsl_regwrite(device, A3XX_RBBM_DEBUG_BUS_STB_CTL0, 0x0);
@@ -4295,18 +4296,18 @@
 		kgsl_regwrite(device, A3XX_RBBM_EXT_TRACE_CMD, 0x0);
 		kgsl_active_count_put(device);
 	}
-	mutex_unlock(&device->mutex);
+	kgsl_mutex_unlock(&device->mutex, &device->mutex_owner);
 }
 
 static void a3xx_coresight_write_reg(struct kgsl_device *device,
 		unsigned int wordoffset, unsigned int val)
 {
-	mutex_lock(&device->mutex);
+	kgsl_mutex_lock(&device->mutex, &device->mutex_owner);
 	if (!kgsl_active_count_get(device)) {
 		kgsl_regwrite(device, wordoffset, val);
 		kgsl_active_count_put(device);
 	}
-	mutex_unlock(&device->mutex);
+	kgsl_mutex_unlock(&device->mutex, &device->mutex_owner);
 }
 
 void a3xx_coresight_config_debug_reg(struct kgsl_device *device,
diff --git a/drivers/gpu/msm/adreno_coresight.c b/drivers/gpu/msm/adreno_coresight.c
index d0ba145..d374e23 100644
--- a/drivers/gpu/msm/adreno_coresight.c
+++ b/drivers/gpu/msm/adreno_coresight.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2013, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2013-2014, 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
@@ -117,12 +117,12 @@
 {
 	unsigned int regval = 0;
 
-	mutex_lock(&device->mutex);
+	kgsl_mutex_lock(&device->mutex, &device->mutex_owner);
 	if (!kgsl_active_count_get(device)) {
 		kgsl_regread(device, offset, &regval);
 		kgsl_active_count_put(device);
 	}
-	mutex_unlock(&device->mutex);
+	kgsl_mutex_unlock(&device->mutex, &device->mutex_owner);
 	return snprintf(buf, PAGE_SIZE, "0x%X", regval);
 }
 
diff --git a/drivers/gpu/msm/adreno_dispatch.c b/drivers/gpu/msm/adreno_dispatch.c
index 7aae397..588c243 100644
--- a/drivers/gpu/msm/adreno_dispatch.c
+++ b/drivers/gpu/msm/adreno_dispatch.c
@@ -21,6 +21,7 @@
 #include "adreno.h"
 #include "adreno_ringbuffer.h"
 #include "adreno_trace.h"
+#include "kgsl_sharedmem.h"
 
 #define CMDQUEUE_NEXT(_i, _s) (((_i) + 1) % (_s))
 
@@ -49,7 +50,7 @@
 static unsigned int _cmdbatch_timeout = 2000;
 
 /* Interval for reading and comparing fault detection registers */
-static unsigned int _fault_timer_interval = 50;
+static unsigned int _fault_timer_interval = 200;
 
 /* Local array for the current set of fault detect registers */
 static unsigned int fault_detect_regs[FT_DETECT_REGS_COUNT];
@@ -269,7 +270,7 @@
 
 	dispatcher->inflight++;
 
-	mutex_lock(&device->mutex);
+	kgsl_mutex_lock(&device->mutex, &device->mutex_owner);
 
 	if (dispatcher->inflight == 1 &&
 			!test_bit(ADRENO_DISPATCHER_POWER, &dispatcher->priv)) {
@@ -277,7 +278,7 @@
 		ret = kgsl_active_count_get(device);
 		if (ret) {
 			dispatcher->inflight--;
-			mutex_unlock(&device->mutex);
+			kgsl_mutex_unlock(&device->mutex, &device->mutex_owner);
 			return ret;
 		}
 
@@ -300,7 +301,7 @@
 		}
 	}
 
-	mutex_unlock(&device->mutex);
+	kgsl_mutex_unlock(&device->mutex, &device->mutex_owner);
 
 	if (ret) {
 		dispatcher->inflight--;
@@ -770,7 +771,8 @@
  * passed in then zero the size which effectively skips it when it is submitted
  * in the ringbuffer.
  */
-static void cmdbatch_skip_ib(struct kgsl_cmdbatch *cmdbatch, unsigned int base)
+static void cmdbatch_skip_ib(struct kgsl_cmdbatch *cmdbatch,
+				unsigned int base)
 {
 	int i;
 
@@ -783,6 +785,48 @@
 	}
 }
 
+static void cmdbatch_skip_cmd(struct kgsl_cmdbatch *cmdbatch,
+	struct kgsl_cmdbatch **replay, int count)
+{
+	struct adreno_context *drawctxt = ADRENO_CONTEXT(cmdbatch->context);
+	int i;
+
+	/*
+	 * SKIPCMD policy: next IB issued for this context is tentative
+	 * if it fails we assume that GFT failed and if it succeeds
+	 * we mark GFT as a success.
+	 *
+	 * Find next commandbatch for the faulting context
+	 * If commandbatch is found
+	 * a) store the current commandbatch fault_policy in context's next
+	 *    commandbatch fault_policy
+	 * b) force preamble for next commandbatch
+	 */
+	for (i = 1; i < count; i++) {
+		if (replay[i]->context->id == cmdbatch->context->id) {
+			replay[i]->fault_policy = replay[0]->fault_policy;
+			set_bit(CMDBATCH_FLAG_FORCE_PREAMBLE, &replay[i]->priv);
+			set_bit(KGSL_FT_SKIPCMD, &replay[i]->fault_recovery);
+			break;
+		}
+	}
+
+	/*
+	 * If we did not find the next cmd then
+	 * a) set a flag for next command issued in this context
+	 * b) store the fault_policy, this fault_policy becomes the policy of
+	 *    next command issued in this context
+	 */
+	if ((i == count) && drawctxt) {
+		set_bit(ADRENO_CONTEXT_SKIP_CMD, &drawctxt->priv);
+		drawctxt->fault_policy = replay[0]->fault_policy;
+	}
+
+	/* set the flags to skip this cmdbatch */
+	set_bit(CMDBATCH_FLAG_SKIP, &cmdbatch->priv);
+	cmdbatch->fault_recovery = 0;
+}
+
 static void cmdbatch_skip_frame(struct kgsl_cmdbatch *cmdbatch,
 	struct kgsl_cmdbatch **replay, int count)
 {
@@ -852,10 +896,10 @@
 			drawctxt->state == ADRENO_CONTEXT_STATE_INVALID) {
 			replay[i] = NULL;
 
-			mutex_lock(&device->mutex);
+			kgsl_mutex_lock(&device->mutex, &device->mutex_owner);
 			kgsl_cancel_events_timestamp(device, cmd->context,
 				cmd->timestamp);
-			mutex_unlock(&device->mutex);
+			kgsl_mutex_unlock(&device->mutex, &device->mutex_owner);
 
 			kgsl_cmdbatch_destroy(cmd);
 		}
@@ -925,6 +969,18 @@
 		rptr, wptr, ib1base, ib1sz, ib2base, ib2sz);
 }
 
+void adreno_fault_skipcmd_detached(struct kgsl_device *device,
+				 struct adreno_context *drawctxt,
+				 struct kgsl_cmdbatch *cmdbatch)
+{
+	if (test_bit(ADRENO_CONTEXT_SKIP_CMD, &drawctxt->priv) &&
+			kgsl_context_detached(&drawctxt->base)) {
+		pr_fault(device, cmdbatch, "gpu %s ctx %d\n",
+			 "detached", cmdbatch->context->id);
+		clear_bit(ADRENO_CONTEXT_SKIP_CMD, &drawctxt->priv);
+	}
+}
+
 static int dispatcher_do_fault(struct kgsl_device *device)
 {
 	struct adreno_device *adreno_dev = ADRENO_DEVICE(device);
@@ -960,7 +1016,7 @@
 	del_timer_sync(&dispatcher->timer);
 	del_timer_sync(&dispatcher->fault_timer);
 
-	mutex_lock(&device->mutex);
+	kgsl_mutex_lock(&device->mutex, &device->mutex_owner);
 
 	cmdbatch = dispatcher->cmdqueue[dispatcher->head];
 
@@ -993,7 +1049,7 @@
 		kgsl_device_snapshot(device, 1);
 	}
 
-	mutex_unlock(&device->mutex);
+	kgsl_mutex_unlock(&device->mutex, &device->mutex_owner);
 
 	/* Allocate memory to store the inflight commands */
 	replay = kzalloc(sizeof(*replay) * dispatcher->inflight, GFP_KERNEL);
@@ -1154,6 +1210,16 @@
 		goto replay;
 	}
 
+	/* Skip the faulted command batch submission */
+	if (test_and_clear_bit(KGSL_FT_SKIPCMD, &cmdbatch->fault_policy)) {
+		trace_adreno_cmdbatch_recovery(cmdbatch, BIT(KGSL_FT_SKIPCMD));
+
+		/* Skip faulting command batch */
+		cmdbatch_skip_cmd(cmdbatch, replay, count);
+
+		goto replay;
+	}
+
 	if (test_and_clear_bit(KGSL_FT_SKIPFRAME, &cmdbatch->fault_policy)) {
 		trace_adreno_cmdbatch_recovery(cmdbatch,
 			BIT(KGSL_FT_SKIPFRAME));
@@ -1185,10 +1251,10 @@
 	dispatcher->head = dispatcher->tail = 0;
 
 	/* Reset the GPU */
-	mutex_lock(&device->mutex);
+	kgsl_mutex_lock(&device->mutex, &device->mutex_owner);
 
 	ret = adreno_reset(device);
-	mutex_unlock(&device->mutex);
+	kgsl_mutex_unlock(&device->mutex, &device->mutex_owner);
 	/* if any other fault got in until reset then ignore */
 	fault = atomic_xchg(&dispatcher->fault, 0);
 
@@ -1424,9 +1490,9 @@
 	 * stragglers
 	 */
 	if (dispatcher->inflight == 0 && count) {
-		mutex_lock(&device->mutex);
+		kgsl_mutex_lock(&device->mutex, &device->mutex_owner);
 		queue_work(device->work_queue, &device->ts_expired_ws);
-		mutex_unlock(&device->mutex);
+		kgsl_mutex_unlock(&device->mutex, &device->mutex_owner);
 	}
 
 	/* Dispatch new commands if we have the room */
@@ -1443,12 +1509,12 @@
 		mod_timer(&dispatcher->timer, cmdbatch->expires);
 
 		/* There are still things in flight - update the idle counts */
-		mutex_lock(&device->mutex);
+		kgsl_mutex_lock(&device->mutex, &device->mutex_owner);
 		kgsl_pwrscale_idle(device);
-		mutex_unlock(&device->mutex);
+		kgsl_mutex_unlock(&device->mutex, &device->mutex_owner);
 	} else {
 		/* There is nothing left in the pipeline.  Shut 'er down boys */
-		mutex_lock(&device->mutex);
+		kgsl_mutex_lock(&device->mutex, &device->mutex_owner);
 		/*
 		 * Stop the fault timer before decrementing the active count to
 		 * avoid reading the hardware registers while we are trying to
@@ -1461,13 +1527,13 @@
 			clear_bit(ADRENO_DISPATCHER_POWER, &dispatcher->priv);
 		}
 
-		mutex_unlock(&device->mutex);
+		kgsl_mutex_unlock(&device->mutex, &device->mutex_owner);
 	}
 
 	/* Before leaving update the pwrscale information */
-	mutex_lock(&device->mutex);
+	kgsl_mutex_lock(&device->mutex, &device->mutex_owner);
 	kgsl_pwrscale_idle(device);
-	mutex_unlock(&device->mutex);
+	kgsl_mutex_unlock(&device->mutex, &device->mutex_owner);
 
 	mutex_unlock(&dispatcher->mutex);
 }
@@ -1565,14 +1631,8 @@
  */
 void adreno_dispatcher_start(struct kgsl_device *device)
 {
-	struct adreno_device *adreno_dev = ADRENO_DEVICE(device);
-
 	complete_all(&device->cmdbatch_gate);
 
-	/* a305b & a305c GPUs are slower than a330 and needs a larger timer */
-	if (adreno_is_a305b(adreno_dev) || adreno_is_a305c(adreno_dev))
-		_fault_timer_interval = 200;
-
 	/* Schedule the work loop to get things going */
 	adreno_dispatcher_schedule(device);
 }
diff --git a/drivers/gpu/msm/adreno_drawctxt.c b/drivers/gpu/msm/adreno_drawctxt.c
index 136456a..0778cac 100644
--- a/drivers/gpu/msm/adreno_drawctxt.c
+++ b/drivers/gpu/msm/adreno_drawctxt.c
@@ -171,9 +171,9 @@
 		drawctxt->state != ADRENO_CONTEXT_STATE_ACTIVE)
 		return 1;
 
-	mutex_lock(&device->mutex);
+	kgsl_mutex_lock(&device->mutex, &device->mutex_owner);
 	ret = kgsl_check_timestamp(device, &drawctxt->base, timestamp);
-	mutex_unlock(&device->mutex);
+	kgsl_mutex_unlock(&device->mutex, &device->mutex_owner);
 
 	return ret;
 }
@@ -227,7 +227,7 @@
 	io = (io_cnt < pwr->pwrlevels[pwr->active_pwrlevel].io_fraction)
 		? 0 : 1;
 
-	mutex_unlock(&device->mutex);
+	kgsl_mutex_unlock(&device->mutex, &device->mutex_owner);
 
 	if (timeout) {
 		ret = (int) adreno_wait_event_interruptible_timeout(
@@ -245,7 +245,7 @@
 				io);
 	}
 
-	mutex_lock(&device->mutex);
+	kgsl_mutex_lock(&device->mutex, &device->mutex_owner);
 
 	/* -EDEADLK if the context was invalidated while we were waiting */
 	if (drawctxt->state == ADRENO_CONTEXT_STATE_INVALID)
@@ -314,7 +314,7 @@
 		goto done;
 	}
 
-	mutex_unlock(&device->mutex);
+	kgsl_mutex_unlock(&device->mutex, &device->mutex_owner);
 
 	if (timeout) {
 		ret = (int) wait_event_timeout(drawctxt->waiting,
@@ -330,7 +330,7 @@
 			_check_global_timestamp(device, drawctxt, timestamp));
 	}
 
-	mutex_lock(&device->mutex);
+	kgsl_mutex_lock(&device->mutex, &device->mutex_owner);
 
 	if (ret)
 		kgsl_cancel_events_timestamp(device, NULL, timestamp);
@@ -381,10 +381,10 @@
 
 		mutex_unlock(&drawctxt->mutex);
 
-		mutex_lock(&device->mutex);
+		kgsl_mutex_lock(&device->mutex, &device->mutex_owner);
 		kgsl_cancel_events_timestamp(device, context,
 			cmdbatch->timestamp);
-		mutex_unlock(&device->mutex);
+		kgsl_mutex_unlock(&device->mutex, &device->mutex_owner);
 
 		kgsl_cmdbatch_destroy(cmdbatch);
 		mutex_lock(&drawctxt->mutex);
@@ -530,6 +530,13 @@
 		mutex_unlock(&drawctxt->mutex);
 
 		/*
+		 * If the context is deteached while we are waiting for
+		 * the next command in GFT SKIP CMD, print the context
+		 * detached status here.
+		 */
+		adreno_fault_skipcmd_detached(device, drawctxt, cmdbatch);
+
+		/*
 		 * Don't hold the drawctxt mutex while the cmdbatch is being
 		 * destroyed because the cmdbatch destroy takes the device
 		 * mutex and the world falls in on itself
diff --git a/drivers/gpu/msm/adreno_drawctxt.h b/drivers/gpu/msm/adreno_drawctxt.h
index 258cf94..8543f39 100644
--- a/drivers/gpu/msm/adreno_drawctxt.h
+++ b/drivers/gpu/msm/adreno_drawctxt.h
@@ -130,6 +130,7 @@
  * @waiting: Workqueue structure for contexts waiting for a timestamp or event
  * @queued: Number of commands queued in the cmdqueue
  * @ops: Context switch functions for this context.
+ * @fault_policy: GFT fault policy set in cmdbatch_skip_cmd();
  */
 struct adreno_context {
 	struct kgsl_context base;
@@ -177,6 +178,7 @@
 	int queued;
 
 	const struct adreno_context_ops *ops;
+	unsigned int fault_policy;
 };
 
 /**
@@ -192,6 +194,8 @@
  * @ADRENO_CONTEXT_SKIP_EOF - Context skip IBs until the next end of frame
  *      marker.
  * @ADRENO_CONTEXT_FORCE_PREAMBLE - Force the preamble for the next submission.
+ * @ADRENO_CONTEXT_SKIP_CMD - Context's command batch is skipped during
+	fault tolerance.
  */
 enum adreno_context_priv {
 	ADRENO_CONTEXT_FAULT = 0,
@@ -203,6 +207,7 @@
 	ADRENO_CONTEXT_GPU_HANG_FT,
 	ADRENO_CONTEXT_SKIP_EOF,
 	ADRENO_CONTEXT_FORCE_PREAMBLE,
+	ADRENO_CONTEXT_SKIP_CMD,
 };
 
 struct kgsl_context *adreno_drawctxt_create(struct kgsl_device_private *,
diff --git a/drivers/gpu/msm/adreno_profile.c b/drivers/gpu/msm/adreno_profile.c
index 26c8b69..38e0af8 100644
--- a/drivers/gpu/msm/adreno_profile.c
+++ b/drivers/gpu/msm/adreno_profile.c
@@ -479,9 +479,9 @@
 	struct kgsl_device *device = data;
 	struct adreno_device *adreno_dev = ADRENO_DEVICE(device);
 
-	mutex_lock(&device->mutex);
+	kgsl_mutex_lock(&device->mutex, &device->mutex_owner);
 	*val = adreno_profile_enabled(&adreno_dev->profile);
-	mutex_unlock(&device->mutex);
+	kgsl_mutex_unlock(&device->mutex, &device->mutex_owner);
 
 	return 0;
 }
@@ -492,10 +492,10 @@
 	struct adreno_device *adreno_dev = ADRENO_DEVICE(device);
 	struct adreno_profile *profile = &adreno_dev->profile;
 
-	mutex_lock(&device->mutex);
+	kgsl_mutex_lock(&device->mutex, &device->mutex_owner);
 
 	if (adreno_is_a2xx(adreno_dev)) {
-		mutex_unlock(&device->mutex);
+		kgsl_mutex_unlock(&device->mutex, &device->mutex_owner);
 		return 0;
 	}
 
@@ -503,7 +503,7 @@
 
 	check_close_profile(profile);
 
-	mutex_unlock(&device->mutex);
+	kgsl_mutex_unlock(&device->mutex, &device->mutex_owner);
 
 	return 0;
 }
@@ -522,11 +522,11 @@
 	if (adreno_is_a2xx(adreno_dev))
 		return -EINVAL;
 
-	mutex_lock(&device->mutex);
+	kgsl_mutex_lock(&device->mutex, &device->mutex_owner);
 
 	buf = kmalloc(max_size, GFP_KERNEL);
 	if (!buf) {
-		mutex_unlock(&device->mutex);
+		kgsl_mutex_unlock(&device->mutex, &device->mutex_owner);
 		return -ENOMEM;
 	}
 
@@ -546,7 +546,7 @@
 
 	kfree(buf);
 
-	mutex_unlock(&device->mutex);
+	kgsl_mutex_unlock(&device->mutex, &device->mutex_owner);
 	return size;
 }
 
@@ -679,7 +679,7 @@
 	if (adreno_is_a2xx(adreno_dev))
 		return -ENOSPC;
 
-	mutex_lock(&device->mutex);
+	kgsl_mutex_lock(&device->mutex, &device->mutex_owner);
 
 	if (adreno_profile_enabled(profile)) {
 		size = -EINVAL;
@@ -745,7 +745,7 @@
 error_put:
 	kgsl_active_count_put(device);
 error_unlock:
-	mutex_unlock(&device->mutex);
+	kgsl_mutex_unlock(&device->mutex, &device->mutex_owner);
 	return size;
 }
 
@@ -883,7 +883,7 @@
 	 * for each perf counter <cntr_reg_off> <start hi & lo> <end hi & low>
 	 */
 
-	mutex_lock(&device->mutex);
+	kgsl_mutex_lock(&device->mutex, &device->mutex_owner);
 
 	while (1) {
 		/* process any results that are available into the log_buffer */
@@ -905,10 +905,10 @@
 			}
 		}
 
-		mutex_unlock(&device->mutex);
+		kgsl_mutex_unlock(&device->mutex, &device->mutex_owner);
 		set_current_state(TASK_INTERRUPTIBLE);
 		schedule_timeout(HZ / 10);
-		mutex_lock(&device->mutex);
+		kgsl_mutex_lock(&device->mutex, &device->mutex_owner);
 
 		if (signal_pending(current)) {
 			status = 0;
@@ -917,7 +917,7 @@
 	}
 
 	check_close_profile(profile);
-	mutex_unlock(&device->mutex);
+	kgsl_mutex_unlock(&device->mutex, &device->mutex_owner);
 
 	return status;
 }
@@ -934,7 +934,7 @@
 	if (adreno_is_a2xx(adreno_dev))
 		return -EINVAL;
 
-	mutex_lock(&device->mutex);
+	kgsl_mutex_lock(&device->mutex, &device->mutex_owner);
 
 	for (i = 0; i < counters->group_count; ++i) {
 		group = &(counters->groups[i]);
@@ -950,7 +950,7 @@
 			group->reg_count, used);
 	}
 
-	mutex_unlock(&device->mutex);
+	kgsl_mutex_unlock(&device->mutex, &device->mutex_owner);
 
 	return 0;
 }
diff --git a/drivers/gpu/msm/adreno_ringbuffer.c b/drivers/gpu/msm/adreno_ringbuffer.c
index 7bbbc35..57d21f5 100644
--- a/drivers/gpu/msm/adreno_ringbuffer.c
+++ b/drivers/gpu/msm/adreno_ringbuffer.c
@@ -1228,6 +1228,29 @@
 	/* process any profiling results that are available into the log_buf */
 	adreno_profile_process_results(device);
 
+	/*
+	 * If SKIP CMD flag is set for current context
+	 * a) set SKIPCMD as fault_recovery for current commandbatch
+	 * b) store context's commandbatch fault_policy in current
+	 *    commandbatch fault_policy and clear context's commandbatch
+	 *    fault_policy
+	 * c) force preamble for commandbatch
+	 */
+	if (test_bit(ADRENO_CONTEXT_SKIP_CMD, &drawctxt->priv) &&
+		(!test_bit(CMDBATCH_FLAG_SKIP, &cmdbatch->priv))) {
+
+		set_bit(KGSL_FT_SKIPCMD, &cmdbatch->fault_recovery);
+		cmdbatch->fault_policy = drawctxt->fault_policy;
+		set_bit(CMDBATCH_FLAG_FORCE_PREAMBLE, &cmdbatch->priv);
+
+		/* if context is detached print fault recovery */
+		adreno_fault_skipcmd_detached(device, drawctxt, cmdbatch);
+
+		/* clear the drawctxt flags */
+		clear_bit(ADRENO_CONTEXT_SKIP_CMD, &drawctxt->priv);
+		drawctxt->fault_policy = 0;
+	}
+
 	/*When preamble is enabled, the preamble buffer with state restoration
 	commands are stored in the first node of the IB chain. We can skip that
 	if a context switch hasn't occured */
diff --git a/drivers/gpu/msm/kgsl.c b/drivers/gpu/msm/kgsl.c
index 11b7429..a96ab2b 100644
--- a/drivers/gpu/msm/kgsl.c
+++ b/drivers/gpu/msm/kgsl.c
@@ -628,7 +628,7 @@
 
 	KGSL_PWR_WARN(device, "suspend start\n");
 
-	mutex_lock(&device->mutex);
+	kgsl_mutex_lock(&device->mutex, &device->mutex_owner);
 	kgsl_pwrctrl_request_state(device, KGSL_STATE_SUSPEND);
 
 	/* Tell the device to drain the submission queue */
@@ -683,7 +683,7 @@
 			device->ftbl->resume(device);
 	}
 
-	mutex_unlock(&device->mutex);
+	kgsl_mutex_unlock(&device->mutex, &device->mutex_owner);
 	KGSL_PWR_WARN(device, "suspend end\n");
 	return status;
 }
@@ -694,7 +694,7 @@
 		return -EINVAL;
 
 	KGSL_PWR_WARN(device, "resume start\n");
-	mutex_lock(&device->mutex);
+	kgsl_mutex_lock(&device->mutex, &device->mutex_owner);
 	if (device->state == KGSL_STATE_SUSPEND) {
 		kgsl_pwrctrl_set_state(device, KGSL_STATE_SLUMBER);
 		complete_all(&device->hwaccess_gate);
@@ -718,7 +718,7 @@
 	if (device->ftbl->resume)
 		device->ftbl->resume(device);
 
-	mutex_unlock(&device->mutex);
+	kgsl_mutex_unlock(&device->mutex, &device->mutex_owner);
 	KGSL_PWR_WARN(device, "resume end\n");
 	return 0;
 }
@@ -953,7 +953,7 @@
 
 	filep->private_data = NULL;
 
-	mutex_lock(&device->mutex);
+	kgsl_mutex_lock(&device->mutex, &device->mutex_owner);
 
 	while (1) {
 		read_lock(&device->context_lock);
@@ -1005,7 +1005,7 @@
 	kgsl_cancel_events(device, dev_priv);
 
 	result = kgsl_close_device(device);
-	mutex_unlock(&device->mutex);
+	kgsl_mutex_unlock(&device->mutex, &device->mutex_owner);
 
 	kfree(dev_priv);
 
@@ -1087,12 +1087,12 @@
 	dev_priv->device = device;
 	filep->private_data = dev_priv;
 
-	mutex_lock(&device->mutex);
+	kgsl_mutex_lock(&device->mutex, &device->mutex_owner);
 
 	result = kgsl_open_device(device);
 	if (result)
 		goto err_freedevpriv;
-	mutex_unlock(&device->mutex);
+	kgsl_mutex_unlock(&device->mutex, &device->mutex_owner);
 
 	/*
 	 * Get file (per process) private struct. This must be done
@@ -1112,7 +1112,7 @@
 	return result;
 
 err_stop:
-	mutex_lock(&device->mutex);
+	kgsl_mutex_lock(&device->mutex, &device->mutex_owner);
 	device->open_count--;
 	if (device->open_count == 0) {
 		/* make sure power is on to stop the device */
@@ -1122,7 +1122,7 @@
 		atomic_dec(&device->active_cnt);
 	}
 err_freedevpriv:
-	mutex_unlock(&device->mutex);
+	kgsl_mutex_unlock(&device->mutex, &device->mutex_owner);
 	filep->private_data = NULL;
 	kfree(dev_priv);
 err_pmruntime:
@@ -1789,10 +1789,10 @@
 	list_add(&event->node, &cmdbatch->synclist);
 	spin_unlock(&cmdbatch->lock);
 
-	mutex_lock(&device->mutex);
+	kgsl_mutex_lock(&device->mutex, &device->mutex_owner);
 	ret = kgsl_add_event(device, context->id, sync->timestamp,
 		kgsl_cmdbatch_sync_func, event, NULL);
-	mutex_unlock(&device->mutex);
+	kgsl_mutex_unlock(&device->mutex, &device->mutex_owner);
 
 	if (ret) {
 		spin_lock(&cmdbatch->lock);
@@ -3525,12 +3525,14 @@
 	}
 
 	if (lock)
-		mutex_lock(&dev_priv->device->mutex);
+		kgsl_mutex_lock(&dev_priv->device->mutex,
+			&dev_priv->device->mutex_owner);
 
 	ret = func(dev_priv, cmd, uptr);
 
 	if (lock)
-		mutex_unlock(&dev_priv->device->mutex);
+		kgsl_mutex_unlock(&dev_priv->device->mutex,
+			&dev_priv->device->mutex_owner);
 
 	/*
 	 * Still copy back on failure, but assume function took
diff --git a/drivers/gpu/msm/kgsl_cffdump.c b/drivers/gpu/msm/kgsl_cffdump.c
index 43bcc30..171435a 100644
--- a/drivers/gpu/msm/kgsl_cffdump.c
+++ b/drivers/gpu/msm/kgsl_cffdump.c
@@ -631,20 +631,20 @@
 			}
 		}
 		if (!device->cff_dump_enable) {
-			mutex_lock(&device->mutex);
+			kgsl_mutex_lock(&device->mutex, &device->mutex_owner);
 			device->cff_dump_enable = 1;
 			ret = kgsl_open_device(device);
 			if (!ret)
 				ret = kgsl_active_count_get(device);
 			if (ret)
 				device->cff_dump_enable = 0;
-			mutex_unlock(&device->mutex);
+			kgsl_mutex_unlock(&device->mutex, &device->mutex_owner);
 		}
 	} else if (device->cff_dump_enable && !val) {
-		mutex_lock(&device->mutex);
+		kgsl_mutex_lock(&device->mutex, &device->mutex_owner);
 		ret = kgsl_close_device(device);
 		device->cff_dump_enable = 0;
-		mutex_unlock(&device->mutex);
+		kgsl_mutex_unlock(&device->mutex, &device->mutex_owner);
 	}
 done:
 	mutex_unlock(&kgsl_driver.devlock);
diff --git a/drivers/gpu/msm/kgsl_debugfs.c b/drivers/gpu/msm/kgsl_debugfs.c
index 2d833e4..c1b3139 100644
--- a/drivers/gpu/msm/kgsl_debugfs.c
+++ b/drivers/gpu/msm/kgsl_debugfs.c
@@ -30,9 +30,9 @@
 	struct kgsl_device *device = data;
 
 	if (val) {
-		mutex_lock(&device->mutex);
+		kgsl_mutex_lock(&device->mutex, &device->mutex_owner);
 		kgsl_postmortem_dump(device, 1);
-		mutex_unlock(&device->mutex);
+		kgsl_mutex_unlock(&device->mutex, &device->mutex_owner);
 	}
 
 	return 0;
diff --git a/drivers/gpu/msm/kgsl_device.h b/drivers/gpu/msm/kgsl_device.h
index fc4b77e..47801a4 100644
--- a/drivers/gpu/msm/kgsl_device.h
+++ b/drivers/gpu/msm/kgsl_device.h
@@ -251,6 +251,7 @@
 	int open_count;
 
 	struct mutex mutex;
+	atomic64_t mutex_owner;
 	uint32_t state;
 	uint32_t requested_state;
 
@@ -745,4 +746,35 @@
 
 	return 0;
 }
+
+/**
+ * kgsl_mutex_lock() -- try to acquire the mutex if current thread does not
+ *                      already own it
+ * @mutex: mutex to lock
+ * @owner: current mutex owner
+ */
+
+static inline int kgsl_mutex_lock(struct mutex *mutex, atomic64_t *owner)
+{
+
+	if (atomic64_read(owner) != (long)current) {
+		mutex_lock(mutex);
+		atomic64_set(owner, (long)current);
+		/* Barrier to make sure owner is updated */
+		smp_wmb();
+		return 0;
+	}
+	return 1;
+}
+
+/**
+ * kgsl_mutex_unlock() -- Clear the owner and unlock the mutex
+ * @mutex: mutex to unlock
+ * @owner: current mutex owner
+ */
+static inline void kgsl_mutex_unlock(struct mutex *mutex, atomic64_t *owner)
+{
+	atomic64_set(owner, 0);
+	mutex_unlock(mutex);
+}
 #endif  /* __KGSL_DEVICE_H */
diff --git a/drivers/gpu/msm/kgsl_events.c b/drivers/gpu/msm/kgsl_events.c
index ccd13d5..6cea80f 100644
--- a/drivers/gpu/msm/kgsl_events.c
+++ b/drivers/gpu/msm/kgsl_events.c
@@ -409,7 +409,7 @@
 	struct kgsl_context *context, *tmp;
 	uint32_t timestamp;
 
-	mutex_lock(&device->mutex);
+	kgsl_mutex_lock(&device->mutex, &device->mutex_owner);
 
 	timestamp = kgsl_readtimestamp(device, NULL, KGSL_TIMESTAMP_RETIRED);
 	_retire_events(device, &device->events, timestamp);
@@ -436,6 +436,6 @@
 		}
 	}
 
-	mutex_unlock(&device->mutex);
+	kgsl_mutex_unlock(&device->mutex, &device->mutex_owner);
 }
 EXPORT_SYMBOL(kgsl_process_events);
diff --git a/drivers/gpu/msm/kgsl_iommu.c b/drivers/gpu/msm/kgsl_iommu.c
old mode 100755
new mode 100644
index 69b953f..488e5a8
--- a/drivers/gpu/msm/kgsl_iommu.c
+++ b/drivers/gpu/msm/kgsl_iommu.c
@@ -1048,6 +1048,10 @@
 	*cmds++ = 0x1;
 	*cmds++ = 0x1;
 
+	/* WAIT_REG_MEM turns back on protected mode - push it off */
+	*cmds++ = cp_type3_packet(CP_SET_PROTECTED_MODE, 1);
+	*cmds++ = 0;
+
 	*cmds++ = cp_type3_packet(CP_MEM_WRITE, 2);
 	*cmds++ = lock_vars->turn;
 	*cmds++ = 0;
@@ -1062,11 +1066,19 @@
 	*cmds++ = 0x1;
 	*cmds++ = 0x1;
 
+	/* WAIT_REG_MEM turns back on protected mode - push it off */
+	*cmds++ = cp_type3_packet(CP_SET_PROTECTED_MODE, 1);
+	*cmds++ = 0;
+
 	*cmds++ = cp_type3_packet(CP_TEST_TWO_MEMS, 3);
 	*cmds++ = lock_vars->flag[PROC_APPS];
 	*cmds++ = lock_vars->turn;
 	*cmds++ = 0;
 
+	/* TEST_TWO_MEMS turns back on protected mode - push it off */
+	*cmds++ = cp_type3_packet(CP_SET_PROTECTED_MODE, 1);
+	*cmds++ = 0;
+
 	cmds += adreno_add_idle_cmds(adreno_dev, cmds);
 
 	return cmds - start;
@@ -1104,6 +1116,10 @@
 	*cmds++ = 0x1;
 	*cmds++ = 0x1;
 
+	/* WAIT_REG_MEM turns back on protected mode - push it off */
+	*cmds++ = cp_type3_packet(CP_SET_PROTECTED_MODE, 1);
+	*cmds++ = 0;
+
 	cmds += adreno_add_idle_cmds(adreno_dev, cmds);
 
 	return cmds - start;
@@ -1744,16 +1760,42 @@
 	return status;
 }
 
+static void kgsl_iommu_flush_tlb_pt_current(struct kgsl_pagetable *pt)
+{
+	int lock_taken = 0;
+	struct kgsl_device *device = pt->mmu->device;
+	struct kgsl_iommu *iommu = pt->mmu->priv;
+
+	/*
+	 * Check to see if the current thread already holds the device mutex.
+	 * If it does not, then take the device mutex which is required for
+	 * flushing the tlb
+	 */
+	if (!kgsl_mutex_lock(&device->mutex, &device->mutex_owner))
+		lock_taken = 1;
+
+	/*
+	 * Flush the tlb only if the iommu device is attached and the pagetable
+	 * hasn't been switched yet
+	 */
+	if (kgsl_mmu_is_perprocess(pt->mmu) &&
+		iommu->iommu_units[0].dev[KGSL_IOMMU_CONTEXT_USER].attached &&
+		kgsl_iommu_pt_equal(pt->mmu, pt,
+		kgsl_iommu_get_current_ptbase(pt->mmu)))
+		kgsl_iommu_default_setstate(pt->mmu, KGSL_MMUFLAGS_TLBFLUSH);
+
+	if (lock_taken)
+		kgsl_mutex_unlock(&device->mutex, &device->mutex_owner);
+}
+
 static int
 kgsl_iommu_unmap(struct kgsl_pagetable *pt,
 		struct kgsl_memdesc *memdesc,
 		unsigned int *tlb_flags)
 {
-	int ret = 0, lock_taken = 0;
+	int ret = 0;
 	unsigned int range = memdesc->size;
 	struct kgsl_iommu_pt *iommu_pt = pt->priv;
-	struct kgsl_device *device = pt->mmu->device;
-	struct kgsl_iommu *iommu = pt->mmu->priv;
 
 	/* All GPU addresses as assigned are page aligned, but some
 	   functions purturb the gpuaddr with an offset, so apply the
@@ -1775,29 +1817,7 @@
 		return ret;
 	}
 
-	/*
-	 * Check to see if the current thread already holds the device mutex.
-	 * If it does not, then take the device mutex which is required for
-	 * flushing the tlb
-	 */
-	if (!mutex_is_locked(&device->mutex) ||
-		device->mutex.owner != current) {
-		mutex_lock(&device->mutex);
-		lock_taken = 1;
-	}
-
-	/*
-	 * Flush the tlb only if the iommu device is attached and the pagetable
-	 * hasn't been switched yet
-	 */
-	if (kgsl_mmu_is_perprocess(pt->mmu) &&
-		iommu->iommu_units[0].dev[KGSL_IOMMU_CONTEXT_USER].attached &&
-		kgsl_iommu_pt_equal(pt->mmu, pt,
-		kgsl_iommu_get_current_ptbase(pt->mmu)))
-		kgsl_iommu_default_setstate(pt->mmu, KGSL_MMUFLAGS_TLBFLUSH);
-
-	if (lock_taken)
-		mutex_unlock(&device->mutex);
+	kgsl_iommu_flush_tlb_pt_current(pt);
 
 	return ret;
 }
@@ -1839,6 +1859,23 @@
 					  size);
 		}
 	}
+
+	/*
+	 *  IOMMU V1 BFBs pre-fetch data beyond what is being used by the core.
+	 *  This can include both allocated pages and un-allocated pages.
+	 *  If an un-allocated page is cached, and later used (if it has been
+	 *  newly dynamically allocated by SW) the SMMU HW should automatically
+	 *  re-fetch the pages from memory (rather than using the cached
+	 *  un-allocated page). This logic is known as the re-fetch logic.
+	 *  In current chips we suspect this re-fetch logic is broken,
+	 *  it can result in bad translations which can either cause downstream
+	 *  bus errors, or upstream cores being hung (because of garbage data
+	 *  being read) -> causing TLB sync stuck issues. As a result SW must
+	 *  implement the invalidate+map.
+	 */
+	if (!msm_soc_version_supports_iommu_v0())
+		kgsl_iommu_flush_tlb_pt_current(pt);
+
 	return ret;
 }
 
diff --git a/drivers/gpu/msm/kgsl_mmu.c b/drivers/gpu/msm/kgsl_mmu.c
index d64d0d3..65e607b 100644
--- a/drivers/gpu/msm/kgsl_mmu.c
+++ b/drivers/gpu/msm/kgsl_mmu.c
@@ -401,6 +401,10 @@
 	status = kgsl_allocate_contiguous(&mmu->setstate_memory, PAGE_SIZE);
 	if (status)
 		return status;
+
+	/* Mark the setstate memory as read only */
+	mmu->setstate_memory.flags |= KGSL_MEMFLAGS_GPUREADONLY;
+
 	kgsl_sharedmem_set(device, &mmu->setstate_memory, 0, 0,
 				mmu->setstate_memory.size);
 
diff --git a/drivers/gpu/msm/kgsl_pwrctrl.c b/drivers/gpu/msm/kgsl_pwrctrl.c
index fb9bdb1..563f7ef 100644
--- a/drivers/gpu/msm/kgsl_pwrctrl.c
+++ b/drivers/gpu/msm/kgsl_pwrctrl.c
@@ -233,7 +233,7 @@
 	if (ret)
 		return ret;
 
-	mutex_lock(&device->mutex);
+	kgsl_mutex_lock(&device->mutex, &device->mutex_owner);
 
 	if (level > pwr->num_pwrlevels - 2)
 		level = pwr->num_pwrlevels - 2;
@@ -249,7 +249,7 @@
 	 */
 	if (pwr->thermal_pwrlevel > pwr->active_pwrlevel)
 		kgsl_pwrctrl_pwrlevel_change(device, pwr->thermal_pwrlevel);
-	mutex_unlock(&device->mutex);
+	kgsl_mutex_unlock(&device->mutex, &device->mutex_owner);
 
 	return count;
 }
@@ -285,7 +285,7 @@
 	if (ret)
 		return ret;
 
-	mutex_lock(&device->mutex);
+	kgsl_mutex_lock(&device->mutex, &device->mutex_owner);
 
 	/* You can't set a maximum power level lower than the minimum */
 	if (level > pwr->min_pwrlevel)
@@ -302,7 +302,7 @@
 	 */
 	if (max_level > pwr->active_pwrlevel)
 		kgsl_pwrctrl_pwrlevel_change(device, max_level);
-	mutex_unlock(&device->mutex);
+	kgsl_mutex_unlock(&device->mutex, &device->mutex_owner);
 
 	return count;
 }
@@ -337,7 +337,7 @@
 	if (ret)
 		return ret;
 
-	mutex_lock(&device->mutex);
+	kgsl_mutex_lock(&device->mutex, &device->mutex_owner);
 	if (level > pwr->num_pwrlevels - 2)
 		level = pwr->num_pwrlevels - 2;
 
@@ -356,7 +356,7 @@
 	if (min_level < pwr->active_pwrlevel)
 		kgsl_pwrctrl_pwrlevel_change(device, min_level);
 
-	mutex_unlock(&device->mutex);
+	kgsl_mutex_unlock(&device->mutex, &device->mutex_owner);
 
 	return count;
 }
@@ -418,7 +418,7 @@
 	if (ret)
 		return ret;
 
-	mutex_lock(&device->mutex);
+	kgsl_mutex_lock(&device->mutex, &device->mutex_owner);
 	level = _get_nearest_pwrlevel(pwr, val);
 	if (level < 0)
 		goto done;
@@ -434,7 +434,7 @@
 		kgsl_pwrctrl_pwrlevel_change(device, pwr->thermal_pwrlevel);
 
 done:
-	mutex_unlock(&device->mutex);
+	kgsl_mutex_unlock(&device->mutex, &device->mutex_owner);
 	return count;
 }
 
@@ -470,12 +470,12 @@
 	if (ret)
 		return ret;
 
-	mutex_lock(&device->mutex);
+	kgsl_mutex_lock(&device->mutex, &device->mutex_owner);
 	level = _get_nearest_pwrlevel(pwr, val);
 	if (level >= 0)
 		kgsl_pwrctrl_pwrlevel_change(device, level);
 
-	mutex_unlock(&device->mutex);
+	kgsl_mutex_unlock(&device->mutex, &device->mutex_owner);
 	return count;
 }
 
@@ -509,13 +509,13 @@
 	if (ret)
 		return ret;
 
-	mutex_lock(&device->mutex);
+	kgsl_mutex_lock(&device->mutex, &device->mutex_owner);
 
 	/* Let the timeout be requested in ms, but convert to jiffies. */
 	val /= div;
 	pwr->interval_timeout = val;
 
-	mutex_unlock(&device->mutex);
+	kgsl_mutex_unlock(&device->mutex, &device->mutex_owner);
 
 	return count;
 }
@@ -548,9 +548,9 @@
 	if (ret)
 		return ret;
 
-	mutex_lock(&device->mutex);
+	kgsl_mutex_lock(&device->mutex, &device->mutex_owner);
 	device->pwrctrl.pm_qos_latency = val;
-	mutex_unlock(&device->mutex);
+	kgsl_mutex_unlock(&device->mutex, &device->mutex_owner);
 
 	return count;
 }
@@ -692,9 +692,9 @@
 	if (ret)
 		return ret;
 
-	mutex_lock(&device->mutex);
+	kgsl_mutex_lock(&device->mutex, &device->mutex_owner);
 	__force_on(device, flag, val);
-	mutex_unlock(&device->mutex);
+	kgsl_mutex_unlock(&device->mutex, &device->mutex_owner);
 
 	return count;
 }
@@ -767,9 +767,9 @@
 	if (ret)
 		return ret;
 
-	mutex_lock(&device->mutex);
+	kgsl_mutex_lock(&device->mutex, &device->mutex_owner);
 	device->pwrctrl.bus_control = val ? true : false;
-	mutex_unlock(&device->mutex);
+	kgsl_mutex_unlock(&device->mutex, &device->mutex_owner);
 
 	return count;
 }
@@ -1242,7 +1242,7 @@
 	if (device == NULL)
 		return;
 
-	mutex_lock(&device->mutex);
+	kgsl_mutex_lock(&device->mutex, &device->mutex_owner);
 
 	kgsl_pwrscale_update(device);
 
@@ -1266,10 +1266,10 @@
 			if (!device->pwrctrl.irq_last)
 				break;
 			kgsl_pwrctrl_request_state(device, requested_state);
-			mutex_unlock(&device->mutex);
+			kgsl_mutex_unlock(&device->mutex, &device->mutex_owner);
 			udelay(delay);
 			delay *= 2;
-			mutex_lock(&device->mutex);
+			kgsl_mutex_lock(&device->mutex, &device->mutex_owner);
 		}
 
 
@@ -1293,7 +1293,7 @@
 		}
 	}
 
-	mutex_unlock(&device->mutex);
+	kgsl_mutex_unlock(&device->mutex, &device->mutex_owner);
 }
 EXPORT_SYMBOL(kgsl_idle_check);
 
@@ -1627,9 +1627,9 @@
 
 	if ((atomic_read(&device->active_cnt) == 0) &&
 		(device->state != KGSL_STATE_ACTIVE)) {
-		mutex_unlock(&device->mutex);
+		kgsl_mutex_unlock(&device->mutex, &device->mutex_owner);
 		wait_for_completion(&device->hwaccess_gate);
-		mutex_lock(&device->mutex);
+		kgsl_mutex_lock(&device->mutex, &device->mutex_owner);
 
 		ret = kgsl_pwrctrl_wake(device, 1);
 	}
@@ -1719,10 +1719,10 @@
 
 	if (atomic_read(&device->active_cnt) > count) {
 		int ret;
-		mutex_unlock(&device->mutex);
+		kgsl_mutex_unlock(&device->mutex, &device->mutex_owner);
 		ret = wait_event_timeout(device->active_cnt_wq,
 			_check_active_count(device, count), HZ);
-		mutex_lock(&device->mutex);
+		kgsl_mutex_lock(&device->mutex, &device->mutex_owner);
 		result = ret == 0 ? -ETIMEDOUT : 0;
 	}
 
diff --git a/drivers/gpu/msm/kgsl_pwrscale.c b/drivers/gpu/msm/kgsl_pwrscale.c
index 0bb13a4..b0b1474 100644
--- a/drivers/gpu/msm/kgsl_pwrscale.c
+++ b/drivers/gpu/msm/kgsl_pwrscale.c
@@ -197,7 +197,7 @@
 
 	pwr = &device->pwrctrl;
 
-	mutex_lock(&device->mutex);
+	kgsl_mutex_lock(&device->mutex, &device->mutex_owner);
 	cur_freq = kgsl_pwrctrl_active_freq(pwr);
 	level = pwr->active_pwrlevel;
 
@@ -247,7 +247,7 @@
 		*freq = kgsl_pwrctrl_active_freq(pwr);
 	}
 
-	mutex_unlock(&device->mutex);
+	kgsl_mutex_unlock(&device->mutex, &device->mutex_owner);
 	return 0;
 }
 EXPORT_SYMBOL(kgsl_devfreq_target);
@@ -274,7 +274,7 @@
 
 	pwrscale = &device->pwrscale;
 
-	mutex_lock(&device->mutex);
+	kgsl_mutex_lock(&device->mutex, &device->mutex_owner);
 	/* make sure we don't turn on clocks just to read stats */
 	if (device->state == KGSL_STATE_ACTIVE) {
 		struct kgsl_power_stats extra;
@@ -302,7 +302,7 @@
 	trace_kgsl_pwrstats(device, stat->total_time, &pwrscale->accum_stats);
 	memset(&pwrscale->accum_stats, 0, sizeof(pwrscale->accum_stats));
 
-	mutex_unlock(&device->mutex);
+	kgsl_mutex_unlock(&device->mutex, &device->mutex_owner);
 
 	return 0;
 }
@@ -325,9 +325,9 @@
 	if (freq == NULL)
 		return -EINVAL;
 
-	mutex_lock(&device->mutex);
+	kgsl_mutex_lock(&device->mutex, &device->mutex_owner);
 	*freq = kgsl_pwrctrl_active_freq(&device->pwrctrl);
-	mutex_unlock(&device->mutex);
+	kgsl_mutex_unlock(&device->mutex, &device->mutex_owner);
 
 	return 0;
 }
diff --git a/drivers/gpu/msm/kgsl_snapshot.c b/drivers/gpu/msm/kgsl_snapshot.c
index 333089a..76f0507 100644
--- a/drivers/gpu/msm/kgsl_snapshot.c
+++ b/drivers/gpu/msm/kgsl_snapshot.c
@@ -660,7 +660,7 @@
 		return 0;
 
 	/* Get the mutex to keep things from changing while we are dumping */
-	mutex_lock(&device->mutex);
+	kgsl_mutex_lock(&device->mutex, &device->mutex_owner);
 
 	obj_itr_init(&itr, buf, off, count);
 
@@ -699,7 +699,7 @@
 	}
 
 done:
-	mutex_unlock(&device->mutex);
+	kgsl_mutex_unlock(&device->mutex, &device->mutex_owner);
 
 	return itr.write;
 }
@@ -731,12 +731,12 @@
 	size_t count)
 {
 	if (device && count > 0) {
-		mutex_lock(&device->mutex);
+		kgsl_mutex_lock(&device->mutex, &device->mutex_owner);
 		if (!kgsl_active_count_get(device)) {
 				kgsl_device_snapshot(device, 0);
 				kgsl_active_count_put(device);
 		}
-		mutex_unlock(&device->mutex);
+		kgsl_mutex_unlock(&device->mutex, &device->mutex_owner);
 	}
 
 	return count;
diff --git a/drivers/gpu/msm/z180.c b/drivers/gpu/msm/z180.c
index 270a7a6..622bd92 100644
--- a/drivers/gpu/msm/z180.c
+++ b/drivers/gpu/msm/z180.c
@@ -404,7 +404,7 @@
 	unsigned int numibs;
 	struct kgsl_ibdesc *ibdesc;
 
-	mutex_lock(&device->mutex);
+	kgsl_mutex_lock(&device->mutex, &device->mutex_owner);
 
 	result = kgsl_active_count_get(device);
 	if (result)
@@ -518,7 +518,7 @@
 
 	kgsl_active_count_put(device);
 error_active_count:
-	mutex_unlock(&device->mutex);
+	kgsl_mutex_unlock(&device->mutex, &device->mutex_owner);
 
 	return (int)result;
 }
@@ -866,9 +866,9 @@
 
 	status = kgsl_active_count_get(device);
 	if (!status) {
-		mutex_unlock(&device->mutex);
+		kgsl_mutex_unlock(&device->mutex, &device->mutex_owner);
 		status = z180_wait(device, context, timestamp, msecs);
-		mutex_lock(&device->mutex);
+		kgsl_mutex_lock(&device->mutex, &device->mutex_owner);
 		kgsl_active_count_put(device);
 	}
 
diff --git a/drivers/hwmon/qpnp-adc-current.c b/drivers/hwmon/qpnp-adc-current.c
index ec6d8ec..dddbbd0 100644
--- a/drivers/hwmon/qpnp-adc-current.c
+++ b/drivers/hwmon/qpnp-adc-current.c
@@ -130,7 +130,8 @@
 #define QPNP_RSENSE_MSB_SIGN_CHECK			0x80
 #define QPNP_ADC_COMPLETION_TIMEOUT			HZ
 #define SMBB_BAT_IF_TRIM_CNST_RDS_MASK			0x7
-#define SMBB_BAT_IF_TRIM_CNST_RDS_MASK_CONST		2
+#define SMBB_BAT_IF_TRIM_CNST_RDS_MASK_CONST_0		0
+#define SMBB_BAT_IF_TRIM_CNST_RDS_MASK_CONST_2		2
 #define QPNP_IADC1_USR_TRIM2_ADC_FULLSCALE1_CONST	127
 #define QPNP_IADC_RSENSE_DEFAULT_VALUE			7800000
 #define QPNP_IADC_RSENSE_DEFAULT_TYPEB_GF		9000000
@@ -172,6 +173,7 @@
 enum qpnp_iadc_rsense_rds_workaround {
 	QPNP_IADC_RDS_DEFAULT_TYPEA,
 	QPNP_IADC_RDS_DEFAULT_TYPEB,
+	QPNP_IADC_RDS_DEFAULT_TYPEC,
 };
 
 static int32_t qpnp_iadc_read_reg(struct qpnp_iadc_chip *iadc,
@@ -644,6 +646,7 @@
 {
 	int rc = 0;
 	u8 trim2_val = 0, smbb_batt_trm_data = 0;
+	u8 smbb_batt_trm_cnst_rds = 0;
 
 	if (!iadc->rds_trim_default_check) {
 		pr_debug("No internal rds trim check needed\n");
@@ -663,11 +666,15 @@
 		return rc;
 	}
 
+	smbb_batt_trm_cnst_rds = smbb_batt_trm_data &
+				SMBB_BAT_IF_TRIM_CNST_RDS_MASK;
+
 	pr_debug("n_trim:0x%x smb_trm:0x%x\n", trim2_val, smbb_batt_trm_data);
 
 	if (iadc->rds_trim_default_type == QPNP_IADC_RDS_DEFAULT_TYPEA) {
-		if (((smbb_batt_trm_data & SMBB_BAT_IF_TRIM_CNST_RDS_MASK) ==
-				SMBB_BAT_IF_TRIM_CNST_RDS_MASK_CONST) &&
+
+		if ((smbb_batt_trm_cnst_rds ==
+				SMBB_BAT_IF_TRIM_CNST_RDS_MASK_CONST_2) &&
 		(trim2_val == QPNP_IADC1_USR_TRIM2_ADC_FULLSCALE1_CONST)) {
 			iadc->rsense_workaround_value =
 					QPNP_IADC_RSENSE_DEFAULT_VALUE;
@@ -675,15 +682,14 @@
 		}
 	} else if (iadc->rds_trim_default_type ==
 						QPNP_IADC_RDS_DEFAULT_TYPEB) {
-		if (((smbb_batt_trm_data & SMBB_BAT_IF_TRIM_CNST_RDS_MASK) >=
-				SMBB_BAT_IF_TRIM_CNST_RDS_MASK_CONST) &&
+		if ((smbb_batt_trm_cnst_rds >=
+				SMBB_BAT_IF_TRIM_CNST_RDS_MASK_CONST_2) &&
 		(trim2_val == QPNP_IADC1_USR_TRIM2_ADC_FULLSCALE1_CONST)) {
 			iadc->rsense_workaround_value =
 					QPNP_IADC_RSENSE_DEFAULT_VALUE;
 				iadc->default_internal_rsense = true;
-		} else if (((smbb_batt_trm_data &
-			SMBB_BAT_IF_TRIM_CNST_RDS_MASK)
-			< SMBB_BAT_IF_TRIM_CNST_RDS_MASK_CONST) &&
+		} else if ((smbb_batt_trm_cnst_rds <
+				SMBB_BAT_IF_TRIM_CNST_RDS_MASK_CONST_2) &&
 			(trim2_val ==
 				QPNP_IADC1_USR_TRIM2_ADC_FULLSCALE1_CONST)) {
 			if (iadc->iadc_comp.id == COMP_ID_GF) {
@@ -696,6 +702,17 @@
 				iadc->default_internal_rsense = true;
 			}
 		}
+	} else if (iadc->rds_trim_default_type == QPNP_IADC_RDS_DEFAULT_TYPEC) {
+
+		if ((smbb_batt_trm_cnst_rds >
+				SMBB_BAT_IF_TRIM_CNST_RDS_MASK_CONST_0) &&
+		(smbb_batt_trm_cnst_rds <=
+				SMBB_BAT_IF_TRIM_CNST_RDS_MASK_CONST_2) &&
+		(trim2_val == QPNP_IADC1_USR_TRIM2_ADC_FULLSCALE1_CONST)) {
+			iadc->rsense_workaround_value =
+					QPNP_IADC_RSENSE_DEFAULT_VALUE;
+			iadc->default_internal_rsense = true;
+		}
 	}
 
 	return 0;
diff --git a/drivers/input/misc/mma8x5x.c b/drivers/input/misc/mma8x5x.c
index d576752..85b4317 100644
--- a/drivers/input/misc/mma8x5x.c
+++ b/drivers/input/misc/mma8x5x.c
@@ -394,9 +394,14 @@
 
 static int mma8x5x_device_set_odr(struct i2c_client *client, u32 delay_ms)
 {
+	struct mma8x5x_data *pdata = i2c_get_clientdata(client);
 	int result;
 	u8 val;
 
+	/* set ODR is only required for interrupt mode */
+	if (!pdata->use_int)
+		return 0;
+
 	result = mma8x5x_delay2odr(delay_ms);
 	if (result < 0)
 		goto out;
diff --git a/drivers/input/touchscreen/Makefile b/drivers/input/touchscreen/Makefile
index 2b98145..dc3bbe0 100644
--- a/drivers/input/touchscreen/Makefile
+++ b/drivers/input/touchscreen/Makefile
@@ -80,7 +80,7 @@
 obj-$(CONFIG_TOUCHSCREEN_CY8C_TS)	+= cy8c_ts.o
 obj-$(CONFIG_TOUCHSCREEN_CYTTSP_I2C_QC)       += cyttsp-i2c-qc.o
 obj-$(CONFIG_TOUCHSCREEN_FT5X06)	+= ft5x06_ts.o
-obj-$(CONFIG_TOUCHSCREEN_SYNAPTICS_I2C_RMI4)		+= synaptics_i2c_rmi4.o
 obj-$(CONFIG_TOUCHSCREEN_SYNAPTICS_DSX_RMI4_DEV)	+= synaptics_rmi_dev.o
 obj-$(CONFIG_TOUCHSCREEN_SYNAPTICS_DSX_FW_UPDATE) 	+= synaptics_fw_update.o
+obj-$(CONFIG_TOUCHSCREEN_SYNAPTICS_I2C_RMI4)		+= synaptics_i2c_rmi4.o
 obj-$(CONFIG_TOUCHSCREEN_GT9XX)		+= gt9xx/
diff --git a/drivers/leds/leds-qpnp.c b/drivers/leds/leds-qpnp.c
index eba5ca8..0659b77 100644
--- a/drivers/leds/leds-qpnp.c
+++ b/drivers/leds/leds-qpnp.c
@@ -484,6 +484,7 @@
 };
 
 static int num_kpbl_leds_on;
+static DEFINE_MUTEX(flash_lock);
 
 static int
 qpnp_led_masked_write(struct qpnp_led_data *led, u16 addr, u8 mask, u8 val)
@@ -1408,7 +1409,10 @@
 {
 	int rc;
 
-	mutex_lock(&led->lock);
+	if (led->id == QPNP_ID_FLASH1_LED0 || led->id == QPNP_ID_FLASH1_LED1)
+		mutex_lock(&flash_lock);
+	else
+		mutex_lock(&led->lock);
 
 	switch (led->id) {
 	case QPNP_ID_WLED:
@@ -1448,7 +1452,10 @@
 		dev_err(&led->spmi_dev->dev, "Invalid LED(%d)\n", led->id);
 		break;
 	}
-	mutex_unlock(&led->lock);
+	if (led->id == QPNP_ID_FLASH1_LED0 || led->id == QPNP_ID_FLASH1_LED1)
+		mutex_unlock(&flash_lock);
+	else
+		mutex_unlock(&led->lock);
 
 }
 
@@ -3314,7 +3321,9 @@
 			goto fail_id_check;
 		}
 
-		mutex_init(&led->lock);
+		if (led->id != QPNP_ID_FLASH1_LED0 &&
+					led->id != QPNP_ID_FLASH1_LED1)
+			mutex_init(&led->lock);
 		INIT_WORK(&led->work, qpnp_led_work);
 
 		rc =  qpnp_led_initialize(led);
@@ -3409,7 +3418,9 @@
 
 fail_id_check:
 	for (i = 0; i < parsed_leds; i++) {
-		mutex_destroy(&led_array[i].lock);
+		if (led_array[i].id != QPNP_ID_FLASH1_LED0 &&
+				led_array[i].id != QPNP_ID_FLASH1_LED1)
+			mutex_destroy(&led_array[i].lock);
 		led_classdev_unregister(&led_array[i].cdev);
 	}
 
@@ -3423,7 +3434,10 @@
 
 	for (i = 0; i < parsed_leds; i++) {
 		cancel_work_sync(&led_array[i].work);
-		mutex_destroy(&led_array[i].lock);
+		if (led_array[i].id != QPNP_ID_FLASH1_LED0 &&
+				led_array[i].id != QPNP_ID_FLASH1_LED1)
+			mutex_destroy(&led_array[i].lock);
+
 		led_classdev_unregister(&led_array[i].cdev);
 		switch (led_array[i].id) {
 		case QPNP_ID_WLED:
diff --git a/drivers/md/dm-req-crypt.c b/drivers/md/dm-req-crypt.c
index ab21404..87a4ab9 100644
--- a/drivers/md/dm-req-crypt.c
+++ b/drivers/md/dm-req-crypt.c
@@ -45,6 +45,7 @@
 #define AES_XTS_IV_LEN 16
 
 #define DM_REQ_CRYPT_ERROR -1
+#define DM_REQ_CRYPT_ERROR_AFTER_PAGE_MALLOC -2
 
 struct req_crypt_result {
 	struct completion completion;
@@ -105,9 +106,10 @@
 
 	atomic_dec(&io->pending);
 
-	if (error < 0)
+	if (error < 0) {
 		dm_kill_unmapped_request(clone, error);
-	else
+		mempool_free(io, req_io_pool);
+	} else
 		dm_dispatch_request(clone);
 }
 
@@ -158,8 +160,6 @@
 	struct req_crypt_result result;
 	struct scatterlist *req_sg_read = NULL;
 	int err = 0;
-	struct req_iterator iter2;
-	struct bio_vec *bvec = NULL;
 	u8 IV[AES_XTS_IV_LEN];
 
 	if (io) {
@@ -217,11 +217,12 @@
 		goto ablkcipher_req_alloc_failure;
 	}
 
-
-	/* total bytes to copy */
-	bvec = NULL;
-	rq_for_each_segment(bvec, clone, iter2) {
-		total_bytes_in_req = total_bytes_in_req + bvec->bv_len;
+	total_bytes_in_req = clone->__data_len;
+	if (total_bytes_in_req > REQ_DM_512_KB) {
+		DMERR("%s total_bytes_in_req > 512 MB %d",
+				__func__, total_bytes_in_req);
+		err = DM_REQ_CRYPT_ERROR;
+		goto ablkcipher_req_alloc_failure;
 	}
 
 	memset(IV, 0, AES_XTS_IV_LEN);
@@ -263,7 +264,8 @@
 	kfree(req_sg_read);
 
 submit_request:
-	io->error = err;
+	if (io)
+		io->error = err;
 	req_crypt_dec_pending_decrypt(io);
 }
 
@@ -277,7 +279,8 @@
 	struct bio *bio_src = NULL;
 	unsigned int total_sg_len_req_in = 0, total_sg_len_req_out = 0,
 		total_bytes_in_req = 0, error = DM_MAPIO_REMAPPED, rc = 0;
-	struct req_iterator iter;
+	struct req_iterator iter = {0, NULL};
+	struct req_iterator iter1 = {0, NULL};
 	struct ablkcipher_request *req = NULL;
 	struct req_crypt_result result;
 	struct bio_vec *bvec = NULL;
@@ -350,20 +353,28 @@
 		goto ablkcipher_req_alloc_failure;
 	}
 
+	total_bytes_in_req = clone->__data_len;
+	if (total_bytes_in_req > REQ_DM_512_KB) {
+		DMERR("%s total_bytes_in_req > 512 MB %d",
+				__func__, total_bytes_in_req);
+		error = DM_REQ_CRYPT_ERROR;
+		goto ablkcipher_req_alloc_failure;
+	}
 
 	rq_for_each_segment(bvec, clone, iter) {
-try_again:
 		if (bvec->bv_len > remaining_size) {
 			page = NULL;
-		page = mempool_alloc(req_page_pool, gfp_mask);
-		if (!page) {
-			DMERR("%s Crypt page alloc failed", __func__);
-			congestion_wait(BLK_RW_ASYNC, HZ/100);
-			goto try_again;
+			while (page == NULL) {
+				page = mempool_alloc(req_page_pool, gfp_mask);
+				if (!page) {
+					DMERR("%s Crypt page alloc failed",
+							__func__);
+					congestion_wait(BLK_RW_ASYNC, HZ/100);
+				}
 			}
+
 			bvec->bv_page = page;
 			bvec->bv_offset = 0;
-			total_bytes_in_req = total_bytes_in_req + bvec->bv_len;
 			remaining_size = PAGE_SIZE -  bvec->bv_len;
 			if (remaining_size < 0)
 				BUG();
@@ -371,7 +382,6 @@
 			bvec->bv_page = page;
 			bvec->bv_offset = PAGE_SIZE - remaining_size;
 			remaining_size = remaining_size -  bvec->bv_len;
-			total_bytes_in_req = total_bytes_in_req + bvec->bv_len;
 		}
 	}
 
@@ -379,7 +389,7 @@
 	if ((total_sg_len_req_out <= 0) ||
 			(total_sg_len_req_out > MAX_SG_LIST)) {
 		DMERR("%s Request Error %d", __func__, total_sg_len_req_out);
-		error = DM_REQ_CRYPT_ERROR;
+		error = DM_REQ_CRYPT_ERROR_AFTER_PAGE_MALLOC;
 		goto ablkcipher_req_alloc_failure;
 	}
 
@@ -405,13 +415,13 @@
 		if (result.err) {
 			DMERR("%s error = %d encrypting the request\n",
 				 __func__, result.err);
-			error = DM_REQ_CRYPT_ERROR;
+			error = DM_REQ_CRYPT_ERROR_AFTER_PAGE_MALLOC;
 			goto ablkcipher_req_alloc_failure;
 		}
 		break;
 
 	default:
-		error = DM_REQ_CRYPT_ERROR;
+		error = DM_REQ_CRYPT_ERROR_AFTER_PAGE_MALLOC;
 		goto ablkcipher_req_alloc_failure;
 	}
 
@@ -428,13 +438,25 @@
 	if (req)
 		ablkcipher_request_free(req);
 
+	if (error == DM_REQ_CRYPT_ERROR_AFTER_PAGE_MALLOC) {
+		bvec = NULL;
+		rq_for_each_segment(bvec, clone, iter1) {
+			if (bvec->bv_offset == 0) {
+				mempool_free(bvec->bv_page, req_page_pool);
+				bvec->bv_page = NULL;
+			} else
+				bvec->bv_page = NULL;
+		}
+	}
+
 
 	kfree(req_sg_in);
 
 	kfree(req_sg_out);
 
 submit_request:
-	io->error = error;
+	if (io)
+		io->error = error;
 	req_crypt_dec_pending_encrypt(io);
 }
 
@@ -449,7 +471,7 @@
 	else if (rq_data_dir(io->cloned_request) == READ)
 		req_cryptd_crypt_read_convert(io);
 	else
-		DMERR("%s received non-write request for Clone %u\n",
+		DMERR("%s received non-read/write request for Clone %u\n",
 				__func__, (unsigned int)io->cloned_request);
 }
 
@@ -484,6 +506,11 @@
 
 	if (bio_sectors(bio) && bdev != bdev->bd_contains) {
 		struct hd_struct *p = bdev->bd_part;
+		/*
+		* Check for integer overflow, should never happen.
+		*/
+		if (p->start_sect > (UINT_MAX - bio->bi_sector))
+			BUG();
 
 		bio->bi_sector += p->start_sect;
 		bio->bi_bdev = bdev->bd_contains;
@@ -543,9 +570,16 @@
 			 union map_info *map_context)
 {
 	struct req_dm_crypt_io *req_io = NULL;
-	int error = DM_MAPIO_REMAPPED, copy_bio_sector_to_req = 0;
+	int error = DM_REQ_CRYPT_ERROR, copy_bio_sector_to_req = 0;
 	struct bio *bio_src = NULL;
 
+	if ((rq_data_dir(clone) != READ) &&
+			 (rq_data_dir(clone) != WRITE)) {
+		error = DM_REQ_CRYPT_ERROR;
+		DMERR("%s Unknown request\n", __func__);
+		goto submit_request;
+	}
+
 	req_io = mempool_alloc(req_io_pool, GFP_NOWAIT);
 	if (!req_io) {
 		DMERR("%s req_io allocation failed\n", __func__);
@@ -598,9 +632,6 @@
 		req_cryptd_queue_crypt(req_io);
 		error = DM_MAPIO_SUBMITTED;
 		goto submit_request;
-	} else {
-		error = DM_REQ_CRYPT_ERROR;
-		DMERR("%s Unknown request\n", __func__);
 	}
 
 submit_request:
@@ -608,22 +639,24 @@
 
 }
 
-static int req_crypt_status(struct dm_target *ti, status_type_t type,
-			char *result, unsigned maxlen)
-{
-	return 0;
-}
-
 static void req_crypt_dtr(struct dm_target *ti)
 {
-	if (req_crypt_queue)
+	if (req_crypt_queue) {
 		destroy_workqueue(req_crypt_queue);
-	if (req_io_pool)
+		req_crypt_queue = NULL;
+	}
+	if (req_io_pool) {
 		mempool_destroy(req_io_pool);
-	if (req_page_pool)
+		req_io_pool = NULL;
+	}
+	if (req_page_pool) {
 		mempool_destroy(req_page_pool);
-	if (tfm)
+		req_page_pool = NULL;
+	}
+	if (tfm) {
 		crypto_free_ablkcipher(tfm);
+		tfm = NULL;
+	}
 }
 
 
@@ -635,71 +668,96 @@
 {
 	unsigned long long tmpll;
 	char dummy;
+	int err = DM_REQ_CRYPT_ERROR;
 
-	if (dm_get_device(ti, argv[3], dm_table_get_mode(ti->table), &dev)) {
-		DMERR(" %s Device Lookup failed\n", __func__);
-		return DM_REQ_CRYPT_ERROR;
+	if (argc < 5) {
+		DMERR(" %s Not enough args\n", __func__);
+		err = DM_REQ_CRYPT_ERROR;
+		goto ctr_exit;
 	}
 
-	if (sscanf(argv[4], "%llu%c", &tmpll, &dummy) != 1) {
-		DMERR("%s Invalid device sector\n", __func__);
-		return DM_REQ_CRYPT_ERROR;
+	if (argv[3]) {
+		if (dm_get_device(ti, argv[3],
+				dm_table_get_mode(ti->table), &dev)) {
+			DMERR(" %s Device Lookup failed\n", __func__);
+			err =  DM_REQ_CRYPT_ERROR;
+			goto ctr_exit;
+		}
+	} else {
+		DMERR(" %s Arg[3] invalid\n", __func__);
+		err =  DM_REQ_CRYPT_ERROR;
+		goto ctr_exit;
 	}
+
+	if (argv[4]) {
+		if (sscanf(argv[4], "%llu%c", &tmpll, &dummy) != 1) {
+			DMERR("%s Invalid device sector\n", __func__);
+			err =  DM_REQ_CRYPT_ERROR;
+			goto ctr_exit;
+		}
+	} else {
+		DMERR(" %s Arg[4]invalid\n", __func__);
+		err =  DM_REQ_CRYPT_ERROR;
+		goto ctr_exit;
+	}
+
 	start_sector_orig = tmpll;
 
 	req_crypt_queue = alloc_workqueue("req_cryptd",
-					  WQ_HIGHPRI |
-					  WQ_CPU_INTENSIVE|
-					  WQ_MEM_RECLAIM,
-					  1);
+					WQ_NON_REENTRANT |
+					WQ_HIGHPRI |
+					WQ_CPU_INTENSIVE|
+					WQ_MEM_RECLAIM,
+					1);
 	if (!req_crypt_queue) {
 		DMERR("%s req_crypt_queue not allocated\n", __func__);
-		return DM_REQ_CRYPT_ERROR;
+		err =  DM_REQ_CRYPT_ERROR;
+		goto ctr_exit;
 	}
 
 	/* Allocate the crypto alloc blk cipher and keep the handle */
 	tfm = crypto_alloc_ablkcipher("qcom-xts(aes)", 0, 0);
 	if (IS_ERR(tfm)) {
-		DMERR("%s ablkcipher tfm allocation failed : error = %lu\n",
-					 __func__, PTR_ERR(tfm));
-		return DM_REQ_CRYPT_ERROR;
+		DMERR("%s ablkcipher tfm allocation failed : error\n",
+					 __func__);
+		err =  DM_REQ_CRYPT_ERROR;
+		goto ctr_exit;
 	}
 
 	req_io_pool = mempool_create_slab_pool(MIN_IOS, _req_crypt_io_pool);
 	if (!req_io_pool) {
 		DMERR("%s req_io_pool not allocated\n", __func__);
-		return DM_REQ_CRYPT_ERROR;
+		err =  DM_REQ_CRYPT_ERROR;
+		goto ctr_exit;
 	}
 
 	req_page_pool = mempool_create_page_pool(MIN_POOL_PAGES, 0);
 	if (!req_page_pool) {
 		DMERR("%s req_page_pool not allocated\n", __func__);
-		return DM_REQ_CRYPT_ERROR;
+		err =  DM_REQ_CRYPT_ERROR;
+		goto ctr_exit;
 	}
-
-	return 0;
-}
-
-static void req_crypt_postsuspend(struct dm_target *ti)
-{
-}
-
-static int req_crypt_preresume(struct dm_target *ti)
-{
-	return 0;
-}
-
-static void req_crypt_resume(struct dm_target *ti)
-{
-}
-
-/* Message interface
- *	key set <key>
- *	key wipe
- */
-static int req_crypt_message(struct dm_target *ti, unsigned argc, char **argv)
-{
-	return 0;
+	err = 0;
+ctr_exit:
+	if (err != 0) {
+		if (req_crypt_queue) {
+			destroy_workqueue(req_crypt_queue);
+			req_crypt_queue = NULL;
+		}
+		if (req_io_pool) {
+			mempool_destroy(req_io_pool);
+			req_io_pool = NULL;
+		}
+		if (req_page_pool) {
+			mempool_destroy(req_page_pool);
+			req_page_pool = NULL;
+		}
+		if (tfm) {
+			crypto_free_ablkcipher(tfm);
+			tfm = NULL;
+		}
+	}
+	return err;
 }
 
 static int req_crypt_iterate_devices(struct dm_target *ti,
@@ -716,11 +774,6 @@
 	.dtr    = req_crypt_dtr,
 	.map_rq = req_crypt_map,
 	.rq_end_io = req_crypt_endio,
-	.status = req_crypt_status,
-	.postsuspend = req_crypt_postsuspend,
-	.preresume = req_crypt_preresume,
-	.resume = req_crypt_resume,
-	.message = req_crypt_message,
 	.iterate_devices = req_crypt_iterate_devices,
 };
 
@@ -733,8 +786,10 @@
 		return -ENOMEM;
 
 	r = dm_register_target(&req_crypt_target);
-	if (r < 0)
+	if (r < 0) {
 		DMERR("register failed %d", r);
+		kmem_cache_destroy(_req_crypt_io_pool);
+	}
 
 	return r;
 }
diff --git a/drivers/media/platform/msm/camera_v2/Kconfig b/drivers/media/platform/msm/camera_v2/Kconfig
index 262fb38..9fff025 100644
--- a/drivers/media/platform/msm/camera_v2/Kconfig
+++ b/drivers/media/platform/msm/camera_v2/Kconfig
@@ -101,24 +101,6 @@
           of any CID of MSM_CSI22_HEADER can be routed to of pixel
           or raw data interface in VFE.
 
-config S5K3L1YX
-	bool "Sensor S5K3L1YX (BAYER 12M)"
-	depends on MSMB_CAMERA
-	---help---
-		Samsung 12 MP Bayer Sensor with auto focus, uses
-		4 mipi lanes, preview config = 1984 * 1508 at 30 fps,
-		snapshot config = 4000 * 3000 at 20 fps,
-		hfr video at 60, 90 and 120 fps.
-
-config IMX135
-	bool "Sensor IMX135 (BAYER 12M)"
-	depends on MSMB_CAMERA
-	---help---
-		Sony 12 MP Bayer Sensor with auto focus, uses
-		4 mipi lanes, preview config = 2104 x 1560 at 49 fps,
-		snapshot config = 4208 x 3120 at 24 fps,
-		Video HDR support.
-
 config IMX134
 	bool "Sensor IMX134 (BAYER 8M)"
 	depends on MSMB_CAMERA
@@ -128,15 +110,6 @@
 		HFR @60fps and @120fps
 		Video HDR support.
 
-config OV2720
-	bool "Sensor OV2720 (BAYER 2M)"
-	depends on MSMB_CAMERA
-	---help---
-		OmniVision 2 MP Bayer Sensor, supports 2 mipi lanes,
-		preview and snapshot config at 1932 * 1092 at 30 fps,
-		hfr video at 60, 90 and 120 fps. This sensor driver does
-		not support auto focus.
-
 config OV9724
 	bool "Sensor OV9724 (BAYER 2M)"
 	depends on MSMB_CAMERA
diff --git a/drivers/media/platform/msm/camera_v2/camera/camera.c b/drivers/media/platform/msm/camera_v2/camera/camera.c
index 43cdcbb..170efa8 100644
--- a/drivers/media/platform/msm/camera_v2/camera/camera.c
+++ b/drivers/media/platform/msm/camera_v2/camera/camera.c
@@ -345,20 +345,17 @@
 
 		rc = msm_post_event(&event, MSM_POST_EVT_TIMEOUT);
 		if (rc < 0)
-			goto set_fmt_fail;
+			return rc;
 
 		rc = camera_check_event_status(&event);
 		if (rc < 0)
-			goto set_fmt_fail;
+			return rc;
+
 		sp->is_vb2_valid = 1;
 	}
 
 	return rc;
 
-set_fmt_fail:
-	kzfree(sp->vb2_q.drv_priv);
-	sp->vb2_q.drv_priv = NULL;
-	return rc;
 }
 
 static int camera_v4l2_try_fmt_vid_cap_mplane(struct file *filep, void *fh,
diff --git a/drivers/media/platform/msm/camera_v2/isp/msm_isp32.c b/drivers/media/platform/msm/camera_v2/isp/msm_isp32.c
index eb05015..4beb3c3 100644
--- a/drivers/media/platform/msm/camera_v2/isp/msm_isp32.c
+++ b/drivers/media/platform/msm/camera_v2/isp/msm_isp32.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2013, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2013-2014, 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
@@ -41,6 +41,8 @@
 	(~(ping_pong >> (idx + VFE32_STATS_PING_PONG_OFFSET)) & 0x1))
 
 #define VFE32_CLK_IDX 0
+#define MSM_ISP32_TOTAL_WM_UB 792
+
 static struct msm_cam_clk_info msm_vfe32_1_clk_info[] = {
 	/*vfe32 clock info for B-family: 8610 */
 	{"vfe_clk_src", 266670000},
@@ -375,7 +377,7 @@
 	rst_val = msm_vfe32_reset_values[reset_type];
 	init_completion(&vfe_dev->reset_complete);
 	msm_camera_io_w_mb(rst_val, vfe_dev->vfe_base + 0x4);
-	return wait_for_completion_interruptible_timeout(
+	return wait_for_completion_timeout(
 	   &vfe_dev->reset_complete, msecs_to_jiffies(50));
 }
 
@@ -787,7 +789,43 @@
 	msm_camera_io_w(xbar_reg_cfg, vfe_dev->vfe_base + VFE32_XBAR_BASE(wm));
 }
 
-static void msm_vfe32_cfg_axi_ub(struct vfe_device *vfe_dev)
+static void msm_vfe32_cfg_axi_ub_equal_default(struct vfe_device *vfe_dev)
+{
+	int i;
+	uint32_t ub_offset = 0;
+	struct msm_vfe_axi_shared_data *axi_data = &vfe_dev->axi_data;
+	uint32_t total_image_size = 0;
+	uint32_t num_used_wms = 0;
+	uint32_t prop_size = 0;
+	uint32_t wm_ub_size;
+	uint64_t delta;
+	for (i = 0; i < axi_data->hw_info->num_wm; i++) {
+		if (axi_data->free_wm[i] > 0) {
+			num_used_wms++;
+			total_image_size += axi_data->wm_image_size[i];
+		}
+	}
+	prop_size = MSM_ISP32_TOTAL_WM_UB -
+		axi_data->hw_info->min_wm_ub * num_used_wms;
+	for (i = 0; i < axi_data->hw_info->num_wm; i++) {
+		if (axi_data->free_wm[i]) {
+			delta =
+				(uint64_t)(axi_data->wm_image_size[i] *
+					prop_size);
+			do_div(delta, total_image_size);
+			wm_ub_size = axi_data->hw_info->min_wm_ub +
+				(uint32_t)delta;
+			msm_camera_io_w(ub_offset << 16 |
+				(wm_ub_size - 1), vfe_dev->vfe_base +
+					VFE32_WM_BASE(i) + 0xC);
+			ub_offset += wm_ub_size;
+		} else
+			msm_camera_io_w(0,
+				vfe_dev->vfe_base + VFE32_WM_BASE(i) + 0xC);
+	}
+}
+
+static void msm_vfe32_cfg_axi_ub_equal_slicing(struct vfe_device *vfe_dev)
 {
 	int i;
 	uint32_t ub_offset = 0;
@@ -809,6 +847,16 @@
 	}
 }
 
+static void msm_vfe32_cfg_axi_ub(struct vfe_device *vfe_dev)
+{
+	struct msm_vfe_axi_shared_data *axi_data = &vfe_dev->axi_data;
+	axi_data->wm_ub_cfg_policy = MSM_WM_UB_CFG_DEFAULT;
+	if (axi_data->wm_ub_cfg_policy == MSM_WM_UB_EQUAL_SLICING)
+		msm_vfe32_cfg_axi_ub_equal_slicing(vfe_dev);
+	else
+		msm_vfe32_cfg_axi_ub_equal_default(vfe_dev);
+}
+
 static void msm_vfe32_update_ping_pong_addr(struct vfe_device *vfe_dev,
 		uint8_t wm_idx, uint32_t pingpong_status, unsigned long paddr)
 {
@@ -1069,6 +1117,7 @@
 	.num_comp_mask = 3,
 	.num_rdi = 3,
 	.num_rdi_master = 3,
+	.min_wm_ub = 64,
 };
 
 static struct msm_vfe_stats_hardware_info msm_vfe32_stats_hw_info = {
diff --git a/drivers/media/platform/msm/camera_v2/isp/msm_isp40.c b/drivers/media/platform/msm/camera_v2/isp/msm_isp40.c
index c3fb176..827dbb0 100644
--- a/drivers/media/platform/msm/camera_v2/isp/msm_isp40.c
+++ b/drivers/media/platform/msm/camera_v2/isp/msm_isp40.c
@@ -600,7 +600,7 @@
 	rst_val = msm_vfe40_reset_values[reset_type];
 	init_completion(&vfe_dev->reset_complete);
 	msm_camera_io_w_mb(rst_val, vfe_dev->vfe_base + 0xC);
-	return wait_for_completion_interruptible_timeout(
+	return wait_for_completion_timeout(
 		&vfe_dev->reset_complete, msecs_to_jiffies(50));
 }
 
diff --git a/drivers/media/platform/msm/camera_v2/isp/msm_isp_axi_util.c b/drivers/media/platform/msm/camera_v2/isp/msm_isp_axi_util.c
index a60fa09..508bcec 100644
--- a/drivers/media/platform/msm/camera_v2/isp/msm_isp_axi_util.c
+++ b/drivers/media/platform/msm/camera_v2/isp/msm_isp_axi_util.c
@@ -1086,8 +1086,8 @@
 	if (num_pix_streams > 0)
 		total_pix_bandwidth = total_pix_bandwidth /
 			num_pix_streams * (num_pix_streams - 1) +
-			axi_data->src_info[VFE_PIX_0].pixel_clock *
-			ISP_DEFAULT_FORMAT_FACTOR / ISP_Q2;
+			((unsigned long)axi_data->src_info[VFE_PIX_0].
+			pixel_clock) * ISP_DEFAULT_FORMAT_FACTOR / ISP_Q2;
 	total_bandwidth = total_pix_bandwidth + total_rdi_bandwidth;
 
 	rc = msm_isp_update_bandwidth(ISP_VFE0 + vfe_dev->pdev->id,
@@ -1109,7 +1109,7 @@
 	vfe_dev->axi_data.pipeline_update = camif_update;
 	vfe_dev->axi_data.stream_update = 2;
 	spin_unlock_irqrestore(&vfe_dev->shared_data_lock, flags);
-	rc = wait_for_completion_interruptible_timeout(
+	rc = wait_for_completion_timeout(
 		&vfe_dev->stream_config_complete,
 		msecs_to_jiffies(VFE_MAX_CFG_TIMEOUT));
 	if (rc == 0) {
@@ -1320,7 +1320,7 @@
 		if (camif_update == DISABLE_CAMIF_IMMEDIATELY) {
 			vfe_dev->hw_info->vfe_ops.axi_ops.halt(vfe_dev);
 		}
-		vfe_dev->hw_info->vfe_ops.core_ops.reset_hw(vfe_dev, ISP_RST_SOFT);
+		vfe_dev->hw_info->vfe_ops.core_ops.reset_hw(vfe_dev, ISP_RST_HARD);
 		vfe_dev->hw_info->vfe_ops.core_ops.init_hw_reg(vfe_dev);
 		vfe_dev->ignore_error = 0;
 	}
diff --git a/drivers/media/platform/msm/camera_v2/isp/msm_isp_stats_util.c b/drivers/media/platform/msm/camera_v2/isp/msm_isp_stats_util.c
index 8b83144..6bd7585 100644
--- a/drivers/media/platform/msm/camera_v2/isp/msm_isp_stats_util.c
+++ b/drivers/media/platform/msm/camera_v2/isp/msm_isp_stats_util.c
@@ -367,7 +367,7 @@
 	int rc;
 	init_completion(&vfe_dev->stats_config_complete);
 	atomic_set(&vfe_dev->stats_data.stats_update, 2);
-	rc = wait_for_completion_interruptible_timeout(
+	rc = wait_for_completion_timeout(
 		&vfe_dev->stats_config_complete,
 		msecs_to_jiffies(VFE_MAX_CFG_TIMEOUT));
 	if (rc == 0) {
diff --git a/drivers/media/platform/msm/camera_v2/ispif/msm_ispif.c b/drivers/media/platform/msm/camera_v2/ispif/msm_ispif.c
index 70042f2..a08fad7 100755
--- a/drivers/media/platform/msm/camera_v2/ispif/msm_ispif.c
+++ b/drivers/media/platform/msm/camera_v2/ispif/msm_ispif.c
@@ -118,7 +118,7 @@
 		msm_camera_io_w(ISPIF_RST_CMD_1_MASK,
 					ispif->base + ISPIF_RST_CMD_1_ADDR);
 
-	timeout = wait_for_completion_interruptible_timeout(
+	timeout = wait_for_completion_timeout(
 			&ispif->reset_complete[VFE0], msecs_to_jiffies(500));
 	CDBG("%s: VFE0 done\n", __func__);
 	if (timeout <= 0) {
diff --git a/drivers/media/platform/msm/camera_v2/msm.c b/drivers/media/platform/msm/camera_v2/msm.c
index f8f5110..e708d37 100644
--- a/drivers/media/platform/msm/camera_v2/msm.c
+++ b/drivers/media/platform/msm/camera_v2/msm.c
@@ -20,7 +20,6 @@
 #include <linux/spinlock.h>
 #include <linux/proc_fs.h>
 #include <linux/atomic.h>
-#include <linux/wait.h>
 #include <linux/videodev2.h>
 #include <linux/msm_ion.h>
 #include <linux/iommu.h>
@@ -402,7 +401,7 @@
 
 	msm_init_queue(&cmd_ack->command_q);
 	INIT_LIST_HEAD(&cmd_ack->list);
-	init_waitqueue_head(&cmd_ack->wait);
+	init_completion(&cmd_ack->wait_complete);
 	cmd_ack->stream_id = stream_id;
 
 	msm_enqueue(&session->command_ack_q, &cmd_ack->list);
@@ -602,7 +601,7 @@
 		   spin_flags);
 		ret_cmd->event = *(struct v4l2_event *)arg;
 		msm_enqueue(&cmd_ack->command_q, &ret_cmd->list);
-		wake_up(&cmd_ack->wait);
+		complete(&cmd_ack->wait_complete);
 		spin_unlock_irqrestore(&(session->command_ack_q.lock),
 		   spin_flags);
 	}
@@ -705,6 +704,9 @@
 		return -EIO;
 	}
 
+	/*re-init wait_complete */
+	INIT_COMPLETION(cmd_ack->wait_complete);
+
 	v4l2_event_queue(vdev, event);
 
 	if (timeout < 0) {
@@ -715,23 +717,18 @@
 	}
 
 	/* should wait on session based condition */
-	do {
-		rc = wait_event_interruptible_timeout(cmd_ack->wait,
-			!list_empty_careful(&cmd_ack->command_q.list),
+	rc = wait_for_completion_timeout(&cmd_ack->wait_complete,
 			msecs_to_jiffies(timeout));
-		if (rc != -ERESTARTSYS)
-			break;
-	} while (1);
 
 	if (list_empty_careful(&cmd_ack->command_q.list)) {
 		if (!rc) {
 			pr_err("%s: Timed out\n", __func__);
 			rc = -ETIMEDOUT;
-		}
-		if (rc < 0) {
-			pr_err("%s: rc = %d\n", __func__, rc);
+		} else {
+			pr_err("%s: Error: No timeout but list empty!",
+					__func__);
 			mutex_unlock(&session->lock);
-			return rc;
+			return -EINVAL;
 		}
 	}
 
diff --git a/drivers/media/platform/msm/camera_v2/msm.h b/drivers/media/platform/msm/camera_v2/msm.h
index 32b7222..c97def3 100644
--- a/drivers/media/platform/msm/camera_v2/msm.h
+++ b/drivers/media/platform/msm/camera_v2/msm.h
@@ -14,6 +14,7 @@
 #define _MSM_H
 
 #include <linux/version.h>
+#include <linux/completion.h>
 #include <linux/i2c.h>
 #include <linux/videodev2.h>
 #include <linux/pm_qos.h>
@@ -70,7 +71,7 @@
 struct msm_command_ack {
 	struct list_head list;
 	struct msm_queue_head command_q;
-	wait_queue_head_t wait;
+	struct completion wait_complete;
 	int stream_id;
 };
 
diff --git a/drivers/media/platform/msm/camera_v2/msm_vb2/msm_vb2.c b/drivers/media/platform/msm/camera_v2/msm_vb2/msm_vb2.c
index 0fbaeca..6e9336a 100644
--- a/drivers/media/platform/msm/camera_v2/msm_vb2/msm_vb2.c
+++ b/drivers/media/platform/msm/camera_v2/msm_vb2/msm_vb2.c
@@ -20,6 +20,10 @@
 	int i;
 	struct msm_v4l2_format_data *data = q->drv_priv;
 
+	if (!data) {
+		pr_err("%s: drv_priv NULL\n", __func__);
+		return -EINVAL;
+	}
 	if (data->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) {
 		if (WARN_ON(data->num_planes > VIDEO_MAX_PLANES))
 			return -EINVAL;
diff --git a/drivers/media/platform/msm/camera_v2/pproc/cpp/msm_cpp.c b/drivers/media/platform/msm/camera_v2/pproc/cpp/msm_cpp.c
old mode 100755
new mode 100644
index bba774d..a53ac38
--- a/drivers/media/platform/msm/camera_v2/pproc/cpp/msm_cpp.c
+++ b/drivers/media/platform/msm/camera_v2/pproc/cpp/msm_cpp.c
@@ -51,6 +51,9 @@
 #define CPP_CMD_TIMEOUT_MS 300
 #define MSM_MICRO_IFACE_CLK_IDX 7
 
+#define MSM_CPP_NOMINAL_CLOCK 266670000
+#define MSM_CPP_TURBO_CLOCK 320000000
+
 struct msm_cpp_timer_data_t {
 	struct cpp_device *cpp_dev;
 	struct msm_cpp_frame_info_t *processed_frame;
@@ -1120,9 +1123,6 @@
 	}
 
 	this_frame = cpp_timer.data.processed_frame;
-	pr_err("ReInstalling cpp_timer\n");
-	setup_timer(&cpp_timer.cpp_timer, cpp_timer_callback,
-		(unsigned long)&cpp_timer);
 	pr_err("Starting timer to fire in %d ms. (jiffies=%lu)\n",
 		CPP_CMD_TIMEOUT_MS, jiffies);
 	ret = mod_timer(&cpp_timer.cpp_timer,
@@ -1609,6 +1609,52 @@
 		}
 		break;
 	}
+	case VIDIOC_MSM_CPP_SET_CLOCK: {
+		long clock_rate = 0;
+		if (ioctl_ptr->len == 0) {
+			pr_err("ioctl_ptr->len is 0\n");
+			mutex_unlock(&cpp_dev->mutex);
+			return -EINVAL;
+		}
+
+		if (ioctl_ptr->ioctl_ptr == NULL) {
+			pr_err("ioctl_ptr->ioctl_ptr is NULL\n");
+			mutex_unlock(&cpp_dev->mutex);
+			return -EINVAL;
+		}
+
+		if (ioctl_ptr->len > sizeof(clock_rate)) {
+			pr_err("Not valid ioctl_ptr->len\n");
+			mutex_unlock(&cpp_dev->mutex);
+			return -EINVAL;
+		}
+
+		rc = (copy_from_user(&clock_rate,
+			(void __user *)ioctl_ptr->ioctl_ptr,
+			ioctl_ptr->len) ? -EFAULT : 0);
+		if (rc) {
+			ERR_COPY_FROM_USER();
+			mutex_unlock(&cpp_dev->mutex);
+			return -EINVAL;
+		}
+
+		if (clock_rate > 0) {
+			clock_rate =
+				clk_round_rate(cpp_dev->cpp_clk[4], clock_rate);
+			CPP_DBG("clk:%ld\n", clock_rate);
+			clk_set_rate(cpp_dev->cpp_clk[4], clock_rate);
+			rc = msm_isp_update_bandwidth(ISP_CPP, clock_rate * 4,
+				clock_rate * 6);
+			if (rc < 0) {
+				pr_err("Bandwidth Set Failed!\n");
+				msm_isp_update_bandwidth(ISP_CPP, 0, 0);
+				mutex_unlock(&cpp_dev->mutex);
+				return -EINVAL;
+			}
+		}
+
+		break;
+	}
 	case MSM_SD_SHUTDOWN: {
 		mutex_unlock(&cpp_dev->mutex);
 		while (cpp_dev->cpp_open_cnt != 0)
diff --git a/drivers/media/platform/msm/camera_v2/sensor/Makefile b/drivers/media/platform/msm/camera_v2/sensor/Makefile
index d1ec5d8e..a33cf62 100644
--- a/drivers/media/platform/msm/camera_v2/sensor/Makefile
+++ b/drivers/media/platform/msm/camera_v2/sensor/Makefile
@@ -5,14 +5,11 @@
 ccflags-y += -Idrivers/media/platform/msm/camera_v2/sensor/cci
 obj-$(CONFIG_MSMB_CAMERA) += cci/ io/ csiphy/ csid/ actuator/ flash/ eeprom/
 obj-$(CONFIG_MSM_CAMERA_SENSOR) += msm_sensor_init.o msm_sensor_driver.o msm_sensor.o
-obj-$(CONFIG_S5K3L1YX) += s5k3l1yx.o
-obj-$(CONFIG_IMX135) += imx135.o
 obj-$(CONFIG_IMX134) += imx134.o
 obj-$(CONFIG_OV8825) += ov8825.o
 obj-$(CONFIG_OV8865) += ov8865.o
 obj-$(CONFIG_s5k4e1) += s5k4e1.o
 obj-$(CONFIG_OV12830) += ov12830.o
-obj-$(CONFIG_OV2720) += ov2720.o
 obj-$(CONFIG_OV9724) += ov9724.o
 obj-$(CONFIG_HI256) += hi256.o
 obj-$(CONFIG_OV5648) += ov5648.o
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 e072e53..bf66442 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
@@ -98,7 +98,7 @@
 	int32_t rc = 0;
 
 	msm_camera_io_w(1 << master, cci_dev->base + CCI_HALT_REQ_ADDR);
-	rc = wait_for_completion_interruptible_timeout(
+	rc = wait_for_completion_timeout(
 		&cci_dev->cci_master_info[master].reset_complete, CCI_TIMEOUT);
 	if (rc < 0) {
 		pr_err("%s:%d wait failed\n", __func__, __LINE__);
@@ -117,7 +117,7 @@
 				cci_dev->base + CCI_RESET_CMD_ADDR);
 
 		/* wait for reset done irq */
-		rc = wait_for_completion_interruptible_timeout(
+		rc = wait_for_completion_timeout(
 			&cci_dev->cci_master_info[master].reset_complete,
 			CCI_TIMEOUT);
 		if (rc <= 0)
@@ -158,10 +158,10 @@
 		msm_camera_io_w(reg_val, cci_dev->base + CCI_QUEUE_START_ADDR);
 		CDBG("%s line %d wait_for_completion_interruptible\n",
 			__func__, __LINE__);
-		rc = wait_for_completion_interruptible_timeout(&cci_dev->
+		rc = wait_for_completion_timeout(&cci_dev->
 			cci_master_info[master].reset_complete, CCI_TIMEOUT);
 		if (rc <= 0) {
-			pr_err("%s: wait_for_completion_interruptible_timeout %d\n",
+			pr_err("%s: wait_for_completion_timeout %d\n",
 				 __func__, __LINE__);
 			if (rc == 0)
 				rc = -ETIMEDOUT;
@@ -181,7 +181,7 @@
 	uint16_t i = 0, j = 0, k = 0, h = 0, len = 0;
 	int32_t rc = 0;
 	uint32_t cmd = 0, delay = 0;
-	uint8_t data[10];
+	uint8_t data[11];
 	uint16_t reg_addr = 0;
 	struct msm_camera_i2c_reg_setting *i2c_msg =
 		&c_ctrl->cfg.cci_i2c_write_cfg;
@@ -401,12 +401,12 @@
 
 	val = 1 << ((master * 2) + queue);
 	msm_camera_io_w(val, cci_dev->base + CCI_QUEUE_START_ADDR);
-	CDBG("%s:%d E wait_for_completion_interruptible_timeout\n", __func__,
+	CDBG("%s:%d E wait_for_completion_timeout\n", __func__,
 		__LINE__);
-	rc = wait_for_completion_interruptible_timeout(&cci_dev->
+	rc = wait_for_completion_timeout(&cci_dev->
 		cci_master_info[master].reset_complete, CCI_TIMEOUT);
 	if (rc <= 0) {
-		pr_err("%s: wait_for_completion_interruptible_timeout %d\n",
+		pr_err("%s: wait_for_completion_timeout %d\n",
 			 __func__, __LINE__);
 		if (rc == 0)
 			rc = -ETIMEDOUT;
@@ -415,7 +415,7 @@
 	} else {
 		rc = 0;
 	}
-	CDBG("%s:%d E wait_for_completion_interruptible_timeout\n", __func__,
+	CDBG("%s:%d E wait_for_completion_timeout\n", __func__,
 		__LINE__);
 
 	read_words = msm_camera_io_r(cci_dev->base +
@@ -608,17 +608,17 @@
 
 	CDBG("%s:%d E wait_for_completion_interruptible\n",
 		__func__, __LINE__);
-	rc = wait_for_completion_interruptible_timeout(&cci_dev->
+	rc = wait_for_completion_timeout(&cci_dev->
 		cci_master_info[master].reset_complete, CCI_TIMEOUT);
 	if (rc <= 0) {
-		pr_err("%s: wait_for_completion_interruptible_timeout %d\n",
+		pr_err("%s: wait_for_completion_timeout %d\n",
 			 __func__, __LINE__);
 		if (rc == 0)
 			rc = -ETIMEDOUT;
 		msm_cci_flush_queue(cci_dev, master);
 		goto ERROR;
 	} else {
-		rc = 0;
+		rc = cci_dev->cci_master_info[master].status;
 	}
 	CDBG("%s:%d X wait_for_completion_interruptible\n", __func__,
 		__LINE__);
@@ -679,7 +679,7 @@
 				msm_camera_io_w(CCI_M1_RESET_RMSK,
 					cci_dev->base + CCI_RESET_CMD_ADDR);
 			/* wait for reset done irq */
-			rc = wait_for_completion_interruptible_timeout(
+			rc = wait_for_completion_timeout(
 				&cci_dev->cci_master_info[master].
 				reset_complete,
 				CCI_TIMEOUT);
@@ -713,11 +713,11 @@
 	cci_dev->cci_master_info[MASTER_0].reset_pending = TRUE;
 	msm_camera_io_w(CCI_RESET_CMD_RMSK, cci_dev->base + CCI_RESET_CMD_ADDR);
 	msm_camera_io_w(0x1, cci_dev->base + CCI_RESET_CMD_ADDR);
-	rc = wait_for_completion_interruptible_timeout(
+	rc = wait_for_completion_timeout(
 		&cci_dev->cci_master_info[MASTER_0].reset_complete,
 		CCI_TIMEOUT);
 	if (rc <= 0) {
-		pr_err("%s: wait_for_completion_interruptible_timeout %d\n",
+		pr_err("%s: wait_for_completion_timeout %d\n",
 			 __func__, __LINE__);
 		if (rc == 0)
 			rc = -ETIMEDOUT;
diff --git a/drivers/media/platform/msm/camera_v2/sensor/csid/msm_csid.c b/drivers/media/platform/msm/camera_v2/sensor/csid/msm_csid.c
index 8662657..3596a12 100644
--- a/drivers/media/platform/msm/camera_v2/sensor/csid/msm_csid.c
+++ b/drivers/media/platform/msm/camera_v2/sensor/csid/msm_csid.c
@@ -95,7 +95,7 @@
 static void msm_csid_reset(struct csid_device *csid_dev)
 {
 	msm_camera_io_w(CSID_RST_STB_ALL, csid_dev->base + CSID_RST_CMD_ADDR);
-	wait_for_completion_interruptible(&csid_dev->reset_complete);
+	wait_for_completion(&csid_dev->reset_complete);
 	return;
 }
 
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 d5b89b7..6f9aeec 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
@@ -69,7 +69,7 @@
 	rc = i2c_transfer(dev_client->client->adapter, msg, 1);
 	if (rc < 0)
 		S_I2C_DBG("msm_camera_qup_i2c_txdata faild 0x%x\n", saddr);
-	return 0;
+	return rc;
 }
 
 int32_t msm_camera_qup_i2c_read(struct msm_camera_i2c_client *client,
diff --git a/drivers/media/platform/msm/camera_v2/sensor/msm_sensor_driver.c b/drivers/media/platform/msm/camera_v2/sensor/msm_sensor_driver.c
index 772ed0e..d8b90dd 100644
--- a/drivers/media/platform/msm/camera_v2/sensor/msm_sensor_driver.c
+++ b/drivers/media/platform/msm/camera_v2/sensor/msm_sensor_driver.c
@@ -793,7 +793,6 @@
 	if (rc < 0) {
 		pr_err("%s:%d Invalid sensor position\n", __func__, __LINE__);
 		sensordata->sensor_info->position = INVALID_CAMERA_B;
-		rc = 0;
 	}
 
 	rc = of_property_read_u32(of_node, "qcom,sensor-mode",
diff --git a/drivers/media/platform/msm/vidc/hfi_packetization.c b/drivers/media/platform/msm/vidc/hfi_packetization.c
index 014b843..a563f68 100644
--- a/drivers/media/platform/msm/vidc/hfi_packetization.c
+++ b/drivers/media/platform/msm/vidc/hfi_packetization.c
@@ -1492,6 +1492,20 @@
 		pkt->size += sizeof(u32) * 2;
 		break;
 	}
+	case HAL_PARAM_VENC_ENABLE_INITIAL_QP:
+	{
+		struct hfi_initial_quantization *hfi;
+		struct hal_initial_quantization *quant = pdata;
+		pkt->rg_property_data[0] =
+			HFI_PROPERTY_PARAM_VENC_INITIAL_QP;
+		hfi = (struct hfi_initial_quantization *) &pkt->rg_property_data[1];
+		hfi->init_qp_enable = quant->initqp_enable;
+		hfi->qp_i = quant->qpi;
+		hfi->qp_p = quant->qpp;
+		hfi->qp_b = quant->qpb;
+		pkt->size += sizeof(u32) + sizeof(struct hfi_initial_quantization);
+		break;
+	}
 	/* FOLLOWING PROPERTIES ARE NOT IMPLEMENTED IN CORE YET */
 	case HAL_CONFIG_BUFFER_REQUIREMENTS:
 	case HAL_CONFIG_PRIORITY:
diff --git a/drivers/media/platform/msm/vidc/msm_vdec.c b/drivers/media/platform/msm/vidc/msm_vdec.c
index 1747cea..7d27cea 100644
--- a/drivers/media/platform/msm/vidc/msm_vdec.c
+++ b/drivers/media/platform/msm/vidc/msm_vdec.c
@@ -102,7 +102,6 @@
 		),
 		.qmenu = mpeg_video_stream_format,
 		.step = 0,
-		.cluster = 0,
 	},
 	{
 		.id = V4L2_CID_MPEG_VIDC_VIDEO_OUTPUT_ORDER,
@@ -117,7 +116,6 @@
 			),
 		.qmenu = mpeg_video_output_order,
 		.step = 0,
-		.cluster = 0,
 	},
 	{
 		.id = V4L2_CID_MPEG_VIDC_VIDEO_ENABLE_PICTURE_TYPE,
@@ -129,7 +127,6 @@
 		.step = 1,
 		.menu_skip_mask = 0,
 		.qmenu = NULL,
-		.cluster = 0,
 	},
 	{
 		.id = V4L2_CID_MPEG_VIDC_VIDEO_KEEP_ASPECT_RATIO,
@@ -141,7 +138,6 @@
 		.step = 1,
 		.menu_skip_mask = 0,
 		.qmenu = NULL,
-		.cluster = 0,
 	},
 	{
 		.id = V4L2_CID_MPEG_VIDC_VIDEO_POST_LOOP_DEBLOCKER_MODE,
@@ -153,7 +149,6 @@
 		.step = 1,
 		.menu_skip_mask = 0,
 		.qmenu = NULL,
-		.cluster = 0,
 	},
 	{
 		.id = V4L2_CID_MPEG_VIDC_VIDEO_DIVX_FORMAT,
@@ -169,7 +164,6 @@
 			),
 		.qmenu = mpeg_video_vidc_divx_format,
 		.step = 0,
-		.cluster = 0,
 	},
 	{
 		.id = V4L2_CID_MPEG_VIDC_VIDEO_MB_ERROR_MAP_REPORTING,
@@ -181,7 +175,6 @@
 		.step = 1,
 		.menu_skip_mask = 0,
 		.qmenu = NULL,
-		.cluster = 0,
 	},
 	{
 		.id = V4L2_CID_MPEG_VIDC_VIDEO_CONTINUE_DATA_TRANSFER,
@@ -193,7 +186,6 @@
 		.step = 1,
 		.menu_skip_mask = 0,
 		.qmenu = NULL,
-		.cluster = 0,
 	},
 	{
 		.id = V4L2_CID_MPEG_VIDC_VIDEO_SYNC_FRAME_DECODE,
@@ -213,7 +205,6 @@
 		.step = 0,
 		.menu_skip_mask = 0,
 		.qmenu = NULL,
-		.cluster = 0,
 	},
 	{
 		.id = V4L2_CID_MPEG_VIDC_VIDEO_EXTRADATA,
@@ -274,7 +265,6 @@
 			),
 		.qmenu = mpeg_vidc_video_alloc_mode_type,
 		.step = 0,
-		.cluster = 0,
 	},
 	{
 		.id = V4L2_CID_MPEG_VIDC_VIDEO_ALLOC_MODE_OUTPUT,
@@ -290,7 +280,6 @@
 			),
 		.qmenu = mpeg_vidc_video_alloc_mode_type,
 		.step = 0,
-		.cluster = 0,
 	},
 	{
 		.id = V4L2_CID_MPEG_VIDC_VIDEO_FRAME_ASSEMBLY,
@@ -302,7 +291,6 @@
 		.step = 1,
 		.menu_skip_mask = 0,
 		.qmenu = NULL,
-		.cluster = 0,
 	},
 	{
 		.id = V4L2_CID_MPEG_VIDC_VIDEO_STREAM_OUTPUT_MODE,
@@ -318,7 +306,6 @@
 		.menu_skip_mask = 0,
 		.step = 1,
 		.qmenu = NULL,
-		.cluster = 0,
 	},
 	{
 		.id = V4L2_CID_MPEG_VIDC_VIDEO_CONCEAL_COLOR,
@@ -328,7 +315,6 @@
 		.maximum = 0xffffff,
 		.default_value = DEFAULT_VIDEO_CONCEAL_COLOR_BLACK,
 		.step = 1,
-		.cluster = 0,
 	},
 };
 
@@ -815,6 +801,26 @@
 			f->fmt.pix_mp.plane_fmt[0].reserved[0] =
 				(__u16)inst->prop.height[CAPTURE_PORT];
 		}
+
+		if (msm_comm_get_stream_output_mode(inst) ==
+			HAL_VIDEO_DECODER_SECONDARY) {
+			if (f->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) {
+				f->fmt.pix_mp.height =
+					inst->prop.height[CAPTURE_PORT];
+				f->fmt.pix_mp.width =
+					inst->prop.width[CAPTURE_PORT];
+			} else if (f->type ==
+							V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) {
+				f->fmt.pix_mp.height =
+					inst->prop.height[OUTPUT_PORT];
+				f->fmt.pix_mp.width =
+					inst->prop.width[OUTPUT_PORT];
+				f->fmt.pix_mp.plane_fmt[0].bytesperline =
+					(__u16)inst->prop.width[OUTPUT_PORT];
+				f->fmt.pix_mp.plane_fmt[0].reserved[0] =
+					(__u16)inst->prop.height[OUTPUT_PORT];
+			}
+		}
 	} else {
 		dprintk(VIDC_ERR,
 			"Buf type not recognized, type = %d\n",
@@ -1184,64 +1190,6 @@
 	return rc;
 }
 
-static int msm_vdec_queue_output_buffers(struct msm_vidc_inst *inst)
-{
-	struct internal_buf *binfo;
-	struct hfi_device *hdev;
-	struct msm_smem *handle;
-	struct vidc_frame_data frame_data = {0};
-	struct hal_buffer_requirements *output_buf, *extradata_buf;
-	int rc = 0;
-	hdev = inst->core->device;
-
-	output_buf = get_buff_req_buffer(inst, HAL_BUFFER_OUTPUT);
-	if (!output_buf) {
-		dprintk(VIDC_DBG,
-			"This output buffer not required, buffer_type: %x\n",
-			HAL_BUFFER_OUTPUT);
-		return 0;
-	}
-	dprintk(VIDC_DBG,
-		"output: num = %d, size = %d\n",
-		output_buf->buffer_count_actual,
-		output_buf->buffer_size);
-
-	extradata_buf = get_buff_req_buffer(inst, HAL_BUFFER_EXTRADATA_OUTPUT);
-	if (!extradata_buf) {
-		dprintk(VIDC_DBG,
-			"This extradata buffer not required, buffer_type: %x\n",
-			HAL_BUFFER_EXTRADATA_OUTPUT);
-		return 0;
-	}
-
-	hdev = inst->core->device;
-
-	mutex_lock(&inst->lock);
-	if (!list_empty(&inst->outputbufs)) {
-		list_for_each_entry(binfo, &inst->outputbufs, list) {
-			if (!binfo) {
-				dprintk(VIDC_ERR, "Invalid parameter\n");
-				mutex_unlock(&inst->lock);
-				return -EINVAL;
-			}
-			handle = binfo->handle;
-			frame_data.alloc_len = output_buf->buffer_size;
-			frame_data.filled_len = 0;
-			frame_data.offset = 0;
-			frame_data.device_addr = handle->device_addr;
-			frame_data.flags = 0;
-			frame_data.extradata_addr = handle->device_addr +
-				output_buf->buffer_size;
-			frame_data.buffer_type = HAL_BUFFER_OUTPUT;
-			rc = call_hfi_op(hdev, session_ftb,
-					(void *) inst->session, &frame_data);
-			binfo->buffer_ownership = FIRMWARE;
-		}
-	}
-	mutex_unlock(&inst->lock);
-	return 0;
-}
-
 static inline int start_streaming(struct msm_vidc_inst *inst)
 {
 	int rc = 0;
@@ -1292,7 +1240,7 @@
 	}
 	if (msm_comm_get_stream_output_mode(inst) ==
 		HAL_VIDEO_DECODER_SECONDARY) {
-		rc = msm_vdec_queue_output_buffers(inst);
+		rc = msm_comm_queue_output_buffers(inst);
 		if (rc) {
 			dprintk(VIDC_ERR,
 				"Failed to queue output buffers: %d\n", rc);
@@ -1830,21 +1778,18 @@
 	return v4l2_g_ctrl(&inst->ctrl_handler, ctrl);
 }
 
-static struct v4l2_ctrl **get_cluster(int type, int *size)
+static struct v4l2_ctrl **get_super_cluster(struct msm_vidc_inst *inst,
+				int *size)
 {
 	int c = 0, sz = 0;
 	struct v4l2_ctrl **cluster = kmalloc(sizeof(struct v4l2_ctrl *) *
 			NUM_CTRLS, GFP_KERNEL);
 
-	if (type <= 0 || !size || !cluster)
+	if (!size || !cluster || !inst)
 		return NULL;
 
-	for (c = 0; c < NUM_CTRLS; c++) {
-		if (msm_vdec_ctrls[c].cluster & type) {
-			cluster[sz] = msm_vdec_ctrls[c].priv;
-			++sz;
-		}
-	}
+	for (c = 0; c < NUM_CTRLS; c++)
+		cluster[sz++] = inst->ctrls[c];
 
 	*size = sz;
 	return cluster;
@@ -1855,6 +1800,19 @@
 	int idx = 0;
 	struct v4l2_ctrl_config ctrl_cfg = {0};
 	int ret_val = 0;
+	int cluster_size = 0;
+
+	if (!inst) {
+		dprintk(VIDC_ERR, "%s - invalid input\n", __func__);
+		return -EINVAL;
+	}
+
+	inst->ctrls = kzalloc(sizeof(struct v4l2_ctrl *) * NUM_CTRLS,
+				GFP_KERNEL);
+	if (!inst->ctrls) {
+		dprintk(VIDC_ERR, "%s - failed to allocate ctrl\n", __func__);
+		return -ENOMEM;
+	}
 
 	ret_val = v4l2_ctrl_handler_init(&inst->ctrl_handler, NUM_CTRLS);
 
@@ -1908,7 +1866,7 @@
 		}
 
 
-		msm_vdec_ctrls[idx].priv = ctrl;
+		inst->ctrls[idx] = ctrl;
 	}
 	ret_val = inst->ctrl_handler.error;
 	if (ret_val)
@@ -1916,41 +1874,24 @@
 			"Error adding ctrls to ctrl handle, %d\n",
 			inst->ctrl_handler.error);
 
-	/* Construct clusters */
-	for (idx = 1; idx < MSM_VDEC_CTRL_CLUSTER_MAX; ++idx) {
-		struct msm_vidc_ctrl_cluster *temp = NULL;
-		struct v4l2_ctrl **cluster = NULL;
-		int cluster_size = 0;
-
-		cluster = get_cluster(idx, &cluster_size);
-		if (!cluster || !cluster_size) {
-			dprintk(VIDC_WARN, "Failed to setup cluster of type %d",
-					idx);
-			continue;
-		}
-
-		v4l2_ctrl_cluster(cluster_size, cluster);
-
-		temp = kzalloc(sizeof(*temp), GFP_KERNEL);
-		if (!temp) {
-			ret_val = -ENOMEM;
-			break;
-		}
-
-		temp->cluster = cluster;
-		INIT_LIST_HEAD(&temp->list);
-		list_add_tail(&temp->list, &inst->ctrl_clusters);
+	/* Construct a super cluster of all controls */
+	inst->cluster = get_super_cluster(inst, &cluster_size);
+	if (!inst->cluster || !cluster_size) {
+		dprintk(VIDC_WARN,
+				"Failed to setup super cluster\n");
+		return -EINVAL;
 	}
+
+	v4l2_ctrl_cluster(cluster_size, inst->cluster);
+
 	return ret_val;
 }
 
 int msm_vdec_ctrl_deinit(struct msm_vidc_inst *inst)
 {
-	struct msm_vidc_ctrl_cluster *curr, *next;
-	list_for_each_entry_safe(curr, next, &inst->ctrl_clusters, list) {
-		kfree(curr->cluster);
-		kfree(curr);
-	}
+	kfree(inst->ctrls);
+	kfree(inst->cluster);
 	v4l2_ctrl_handler_free(&inst->ctrl_handler);
+
 	return 0;
 }
diff --git a/drivers/media/platform/msm/vidc/msm_venc.c b/drivers/media/platform/msm/vidc/msm_venc.c
index ca4b544..9504817 100644
--- a/drivers/media/platform/msm/vidc/msm_venc.c
+++ b/drivers/media/platform/msm/vidc/msm_venc.c
@@ -162,7 +162,6 @@
 		.step = 1,
 		.menu_skip_mask = 0,
 		.qmenu = NULL,
-		.cluster = 0,
 	},
 	{
 		.id = V4L2_CID_MPEG_VIDEO_H264_I_PERIOD,
@@ -174,7 +173,6 @@
 		.step = 1,
 		.menu_skip_mask = 0,
 		.qmenu = NULL,
-		.cluster = MSM_VENC_CTRL_CLUSTER_INTRA_PERIOD,
 	},
 	{
 		.id = V4L2_CID_MPEG_VIDC_VIDEO_NUM_P_FRAMES,
@@ -186,7 +184,6 @@
 		.step = 1,
 		.menu_skip_mask = 0,
 		.qmenu = NULL,
-		.cluster = MSM_VENC_CTRL_CLUSTER_INTRA_PERIOD,
 	},
 	{
 		.id = V4L2_CID_MPEG_VIDC_VIDEO_NUM_B_FRAMES,
@@ -198,7 +195,6 @@
 		.step = 1,
 		.menu_skip_mask = 0,
 		.qmenu = NULL,
-		.cluster = MSM_VENC_CTRL_CLUSTER_INTRA_PERIOD,
 	},
 	{
 		.id = V4L2_CID_MPEG_VIDC_VIDEO_REQUEST_IFRAME,
@@ -210,7 +206,6 @@
 		.step = 0,
 		.menu_skip_mask = 0,
 		.qmenu = NULL,
-		.cluster = 0,
 	},
 	{
 		.id = V4L2_CID_MPEG_VIDC_VIDEO_RATE_CONTROL,
@@ -228,8 +223,6 @@
 		(1 << V4L2_CID_MPEG_VIDC_VIDEO_RATE_CONTROL_CBR_CFR)
 		),
 		.qmenu = mpeg_video_rate_control,
-		.cluster = MSM_VENC_CTRL_CLUSTER_BITRATE |
-			MSM_VENC_CTRL_CLUSTER_TIMING,
 	},
 	{
 		.id = V4L2_CID_MPEG_VIDEO_BITRATE_MODE,
@@ -244,7 +237,6 @@
 		(1 << V4L2_MPEG_VIDEO_BITRATE_MODE_CBR)
 		),
 		.qmenu = NULL,
-		.cluster = MSM_VENC_CTRL_CLUSTER_BITRATE,
 	},
 	{
 		.id = V4L2_CID_MPEG_VIDEO_BITRATE,
@@ -256,7 +248,6 @@
 		.step = BIT_RATE_STEP,
 		.menu_skip_mask = 0,
 		.qmenu = NULL,
-		.cluster = MSM_VENC_CTRL_CLUSTER_BITRATE,
 	},
 	{
 		.id = V4L2_CID_MPEG_VIDEO_BITRATE_PEAK,
@@ -268,7 +259,6 @@
 		.step = BIT_RATE_STEP,
 		.menu_skip_mask = 0,
 		.qmenu = NULL,
-		.cluster = MSM_VENC_CTRL_CLUSTER_BITRATE,
 	},
 	{
 		.id = V4L2_CID_MPEG_VIDEO_H264_ENTROPY_MODE,
@@ -282,7 +272,6 @@
 		(1 << V4L2_MPEG_VIDEO_H264_ENTROPY_MODE_CAVLC) |
 		(1 << V4L2_MPEG_VIDEO_H264_ENTROPY_MODE_CABAC)
 		),
-		.cluster = MSM_VENC_CTRL_CLUSTER_H264_ENTROPY,
 	},
 	{
 		.id = V4L2_CID_MPEG_VIDC_VIDEO_H264_CABAC_MODEL,
@@ -298,7 +287,6 @@
 		(1 << V4L2_CID_MPEG_VIDC_VIDEO_H264_CABAC_MODEL_2)
 		),
 		.qmenu = h264_video_entropy_cabac_model,
-		.cluster = MSM_VENC_CTRL_CLUSTER_H264_ENTROPY,
 	},
 	{
 		.id = V4L2_CID_MPEG_VIDEO_MPEG4_PROFILE,
@@ -309,7 +297,6 @@
 		.default_value = V4L2_MPEG_VIDEO_MPEG4_PROFILE_SIMPLE,
 		.step = 1,
 		.menu_skip_mask = 0,
-		.cluster = MSM_VENC_CTRL_CLUSTER_MPEG_PROFILE_LEVEL,
 	},
 	{
 		.id = V4L2_CID_MPEG_VIDEO_MPEG4_LEVEL,
@@ -320,7 +307,6 @@
 		.default_value = V4L2_MPEG_VIDEO_MPEG4_LEVEL_0,
 		.step = 1,
 		.menu_skip_mask = 0,
-		.cluster = MSM_VENC_CTRL_CLUSTER_MPEG_PROFILE_LEVEL,
 	},
 	{
 		.id = V4L2_CID_MPEG_VIDEO_H264_PROFILE,
@@ -331,7 +317,6 @@
 		.default_value = V4L2_MPEG_VIDEO_H264_PROFILE_BASELINE,
 		.step = 1,
 		.menu_skip_mask = 0,
-		.cluster = MSM_VENC_CTRL_CLUSTER_H264_PROFILE_LEVEL,
 	},
 	{
 		.id = V4L2_CID_MPEG_VIDEO_H264_LEVEL,
@@ -342,7 +327,6 @@
 		.default_value = V4L2_MPEG_VIDEO_H264_LEVEL_1_0,
 		.step = 0,
 		.menu_skip_mask = 0,
-		.cluster = MSM_VENC_CTRL_CLUSTER_H264_PROFILE_LEVEL,
 	},
 	{
 		.id = V4L2_CID_MPEG_VIDC_VIDEO_H263_PROFILE,
@@ -363,7 +347,6 @@
 		(1 << V4L2_MPEG_VIDC_VIDEO_H263_PROFILE_HIGHLATENCY)
 		),
 		.qmenu = h263_profile,
-		.cluster = MSM_VENC_CTRL_CLUSTER_H263_PROFILE_LEVEL,
 	},
 	{
 		.id = V4L2_CID_MPEG_VIDC_VIDEO_H263_LEVEL,
@@ -382,7 +365,6 @@
 		(1 << V4L2_MPEG_VIDC_VIDEO_H263_LEVEL_7_0)
 		),
 		.qmenu = h263_level,
-		.cluster = MSM_VENC_CTRL_CLUSTER_H263_PROFILE_LEVEL,
 	},
 	{
 		.id = V4L2_CID_MPEG_VIDC_VIDEO_VP8_PROFILE_LEVEL,
@@ -397,7 +379,6 @@
 		(1 << V4L2_MPEG_VIDC_VIDEO_VP8_VERSION_1)
 		),
 		.qmenu = vp8_profile_level,
-		.cluster = MSM_VENC_CTRL_CLUSTER_VP8_PROFILE_LEVEL,
 	},
 	{
 		.id = V4L2_CID_MPEG_VIDC_VIDEO_ROTATION,
@@ -414,7 +395,6 @@
 		(1 << V4L2_CID_MPEG_VIDC_VIDEO_ROTATION_270)
 		),
 		.qmenu = mpeg_video_rotation,
-		.cluster = MSM_VENC_CTRL_CLUSTER_DEINTERLACE,
 	},
 	{
 		.id = V4L2_CID_MPEG_VIDEO_H264_I_FRAME_QP,
@@ -426,7 +406,6 @@
 		.step = 1,
 		.menu_skip_mask = 0,
 		.qmenu = NULL,
-		.cluster = MSM_VENC_CTRL_CLUSTER_QP,
 	},
 	{
 		.id = V4L2_CID_MPEG_VIDEO_H264_P_FRAME_QP,
@@ -438,7 +417,6 @@
 		.step = 1,
 		.menu_skip_mask = 0,
 		.qmenu = NULL,
-		.cluster = MSM_VENC_CTRL_CLUSTER_QP,
 	},
 	{
 		.id = V4L2_CID_MPEG_VIDEO_H264_B_FRAME_QP,
@@ -450,7 +428,6 @@
 		.step = 1,
 		.menu_skip_mask = 0,
 		.qmenu = NULL,
-		.cluster = MSM_VENC_CTRL_CLUSTER_QP,
 	},
 	{
 		.id = V4L2_CID_MPEG_VIDEO_H264_MIN_QP,
@@ -462,7 +439,6 @@
 		.step = 1,
 		.menu_skip_mask = 0,
 		.qmenu = NULL,
-		.cluster = MSM_VENC_CTRL_CLUSTER_QP,
 	},
 	{
 		.id = V4L2_CID_MPEG_VIDEO_H264_MAX_QP,
@@ -474,7 +450,6 @@
 		.step = 1,
 		.menu_skip_mask = 0,
 		.qmenu = NULL,
-		.cluster = MSM_VENC_CTRL_CLUSTER_QP,
 	},
 	{
 		.id = V4L2_CID_MPEG_VIDC_VIDEO_VP8_MIN_QP,
@@ -484,7 +459,6 @@
 		.maximum = 128,
 		.default_value = 1,
 		.step = 1,
-		.cluster = MSM_VENC_CTRL_CLUSTER_QP,
 	},
 	{
 		.id = V4L2_CID_MPEG_VIDC_VIDEO_VP8_MAX_QP,
@@ -494,7 +468,6 @@
 		.maximum = 128,
 		.default_value = 128,
 		.step = 1,
-		.cluster = MSM_VENC_CTRL_CLUSTER_QP,
 	},
 	{
 		.id = V4L2_CID_MPEG_VIDEO_MULTI_SLICE_MODE,
@@ -510,7 +483,6 @@
 		(1 << V4L2_MPEG_VIDEO_MULTI_SICE_MODE_MAX_BYTES) |
 		(1 << V4L2_MPEG_VIDEO_MULTI_SLICE_GOB)
 		),
-		.cluster = MSM_VENC_CTRL_CLUSTER_SLICING,
 	},
 	{
 		.id = V4L2_CID_MPEG_VIDEO_MULTI_SLICE_MAX_BYTES,
@@ -522,7 +494,6 @@
 		.step = 1,
 		.menu_skip_mask = 0,
 		.qmenu = NULL,
-		.cluster = MSM_VENC_CTRL_CLUSTER_SLICING,
 	},
 	{
 		.id = V4L2_CID_MPEG_VIDEO_MULTI_SLICE_MAX_MB,
@@ -534,7 +505,6 @@
 		.step = 1,
 		.menu_skip_mask = 0,
 		.qmenu = NULL,
-		.cluster = MSM_VENC_CTRL_CLUSTER_SLICING,
 	},
 	{
 		.id = V4L2_CID_MPEG_VIDEO_MULTI_SLICE_GOB,
@@ -546,7 +516,6 @@
 		.step = 1,
 		.menu_skip_mask = 0,
 		.qmenu = NULL,
-		.cluster = MSM_VENC_CTRL_CLUSTER_SLICING,
 	},
 	{
 		.id = V4L2_CID_MPEG_VIDEO_MULTI_SLICE_DELIVERY_MODE,
@@ -558,7 +527,6 @@
 		.step = 1,
 		.menu_skip_mask = 0,
 		.qmenu = NULL,
-		.cluster = MSM_VENC_CTRL_CLUSTER_SLICING,
 	},
 	{
 		.id = V4L2_CID_MPEG_VIDC_VIDEO_INTRA_REFRESH_MODE,
@@ -576,7 +544,6 @@
 		(1 << V4L2_CID_MPEG_VIDC_VIDEO_INTRA_REFRESH_RANDOM)
 		),
 		.qmenu = intra_refresh_modes,
-		.cluster = MSM_VENC_CTRL_CLUSTER_INTRA_REFRESH,
 	},
 	{
 		.id = V4L2_CID_MPEG_VIDC_VIDEO_AIR_MBS,
@@ -588,7 +555,6 @@
 		.step = 1,
 		.menu_skip_mask = 0,
 		.qmenu = NULL,
-		.cluster = MSM_VENC_CTRL_CLUSTER_INTRA_REFRESH,
 	},
 	{
 		.id = V4L2_CID_MPEG_VIDC_VIDEO_AIR_REF,
@@ -600,7 +566,6 @@
 		.step = 1,
 		.menu_skip_mask = 0,
 		.qmenu = NULL,
-		.cluster = MSM_VENC_CTRL_CLUSTER_INTRA_REFRESH,
 	},
 	{
 		.id = V4L2_CID_MPEG_VIDC_VIDEO_CIR_MBS,
@@ -612,7 +577,6 @@
 		.step = 1,
 		.menu_skip_mask = 0,
 		.qmenu = NULL,
-		.cluster = MSM_VENC_CTRL_CLUSTER_INTRA_REFRESH,
 	},
 	{
 		.id = V4L2_CID_MPEG_VIDEO_H264_LOOP_FILTER_ALPHA,
@@ -624,7 +588,6 @@
 		.step = 1,
 		.menu_skip_mask = 0,
 		.qmenu = NULL,
-		.cluster = 0,
 	},
 	{
 		.id = V4L2_CID_MPEG_VIDEO_H264_LOOP_FILTER_BETA,
@@ -636,7 +599,6 @@
 		.step = 1,
 		.menu_skip_mask = 0,
 		.qmenu = NULL,
-		.cluster = 0,
 	},
 	{
 		.id = V4L2_CID_MPEG_VIDEO_H264_LOOP_FILTER_MODE,
@@ -651,7 +613,6 @@
 		(1 << V4L2_MPEG_VIDEO_H264_LOOP_FILTER_MODE_DISABLED) |
 		(1 << L_MODE)
 		),
-		.cluster = 0,
 	},
 	{
 		.id = V4L2_CID_MPEG_VIDEO_HEADER_MODE,
@@ -666,7 +627,6 @@
 		(1 << V4L2_MPEG_VIDEO_HEADER_MODE_SEPARATE) |
 		(1 << V4L2_MPEG_VIDEO_HEADER_MODE_JOINED_WITH_I_FRAME)
 		),
-		.cluster = 0,
 	},
 	{
 		.id = V4L2_CID_MPEG_VIDC_VIDEO_SECURE,
@@ -678,7 +638,6 @@
 		.step = 0,
 		.menu_skip_mask = 0,
 		.qmenu = NULL,
-		.cluster = 0,
 	},
 	{
 		.id = V4L2_CID_MPEG_VIDC_VIDEO_EXTRADATA,
@@ -718,7 +677,6 @@
 		.maximum = V4L2_MPEG_VIDC_VIDEO_H264_VUI_TIMING_INFO_ENABLED,
 		.default_value =
 			V4L2_MPEG_VIDC_VIDEO_H264_VUI_TIMING_INFO_DISABLED,
-		.cluster = MSM_VENC_CTRL_CLUSTER_TIMING,
 	},
 	{
 		.id = V4L2_CID_MPEG_VIDC_VIDEO_H264_AU_DELIMITER,
@@ -752,7 +710,6 @@
 		.step = 1,
 		.menu_skip_mask = 0,
 		.qmenu = NULL,
-		.cluster = MSM_VENC_CTRL_CLUSTER_INTRA_REFRESH,
 	},
 	{
 		.id = V4L2_CID_MPEG_VIDC_VIDEO_DEINTERLACE,
@@ -762,7 +719,6 @@
 		.maximum = V4L2_CID_MPEG_VIDC_VIDEO_DEINTERLACE_ENABLED,
 		.default_value = V4L2_CID_MPEG_VIDC_VIDEO_DEINTERLACE_DISABLED,
 		.step = 1,
-		.cluster = MSM_VENC_CTRL_CLUSTER_DEINTERLACE,
 	},
 	{
 		.id = V4L2_CID_MPEG_VIDC_VIDEO_USELTRFRAME,
@@ -773,7 +729,6 @@
 		.default_value = 0,
 		.step = 1,
 		.qmenu = NULL,
-		.cluster = 0,
 	},
 	{
 		.id = V4L2_CID_MPEG_VIDC_VIDEO_LTRCOUNT,
@@ -784,7 +739,6 @@
 		.default_value = 0,
 		.step = 1,
 		.qmenu = NULL,
-		.cluster = MSM_VENC_CTRL_CLUSTER_USE_LTRFRAME,
 	},
 	{
 		.id = V4L2_CID_MPEG_VIDC_VIDEO_LTRMODE,
@@ -795,7 +749,6 @@
 		.default_value = V4L2_MPEG_VIDC_VIDEO_LTR_MODE_DISABLE,
 		.step = 1,
 		.qmenu = NULL,
-		.cluster = MSM_VENC_CTRL_CLUSTER_USE_LTRFRAME,
 	},
 	{
 		.id = V4L2_CID_MPEG_VIDC_VIDEO_MARKLTRFRAME,
@@ -806,7 +759,6 @@
 		.default_value = 0,
 		.step = 1,
 		.qmenu = NULL,
-		.cluster = 0,
 	},
 	{
 		.id = V4L2_CID_MPEG_VIDC_VIDEO_HIER_P_NUM_LAYERS,
@@ -817,7 +769,45 @@
 		.default_value = 0,
 		.step = 1,
 		.qmenu = NULL,
-		.cluster = 0,
+	},
+	{
+		.id = V4L2_CID_MPEG_VIDC_VIDEO_ENABLE_INITIAL_QP,
+		.name = "Enable setting initial QP",
+		.type = V4L2_CTRL_TYPE_BUTTON,
+		.minimum = 0,
+		.maximum = 0,
+		.default_value = 0,
+		.step = 0,
+	},
+	{
+		.id = V4L2_CID_MPEG_VIDC_VIDEO_I_FRAME_QP,
+		.name = "Iframe initial QP",
+		.type = V4L2_CTRL_TYPE_INTEGER,
+		.minimum = 1,
+		.maximum = 51,
+		.default_value = 1,
+		.step = 1,
+		.qmenu = NULL,
+	},
+	{
+		.id = V4L2_CID_MPEG_VIDC_VIDEO_P_FRAME_QP,
+		.name = "Pframe initial QP",
+		.type = V4L2_CTRL_TYPE_INTEGER,
+		.minimum = 1,
+		.maximum = 51,
+		.default_value = 1,
+		.step = 1,
+		.qmenu = NULL,
+	},
+	{
+		.id = V4L2_CID_MPEG_VIDC_VIDEO_B_FRAME_QP,
+		.name = "Bframe initial QP",
+		.type = V4L2_CTRL_TYPE_INTEGER,
+		.minimum = 1,
+		.maximum = 51,
+		.default_value = 1,
+		.step = 1,
+		.qmenu = NULL,
 	}
 };
 
@@ -2172,15 +2162,6 @@
 	return rc;
 }
 
-static struct v4l2_ctrl *get_cluster_from_id(int id)
-{
-	int c;
-	for (c = 0; c < ARRAY_SIZE(msm_venc_ctrls); ++c)
-		if (msm_venc_ctrls[c].id == id)
-			return (struct v4l2_ctrl *)msm_venc_ctrls[c].priv;
-	return NULL;
-}
-
 static int try_set_ext_ctrl(struct msm_vidc_inst *inst,
 	struct v4l2_ext_controls *ctrl)
 {
@@ -2188,24 +2169,16 @@
 	struct v4l2_ext_control *control;
 	struct hfi_device *hdev;
 	struct hal_ltrmode ltrmode;
-	struct v4l2_ctrl *cluster;
 	u32 property_id = 0;
 	void *pdata = NULL;
 	struct msm_vidc_core_capability *cap = NULL;
+	struct hal_initial_quantization quant;
 
 	if (!inst || !inst->core || !inst->core->device || !ctrl) {
 		dprintk(VIDC_ERR, "%s invalid parameters\n", __func__);
 		return -EINVAL;
 	}
 
-	cluster = get_cluster_from_id(ctrl->controls[0].id);
-
-	if (!cluster) {
-		dprintk(VIDC_ERR, "Invalid Ctrl returned for id: %x\n",
-			ctrl->controls[0].id);
-		return -EINVAL;
-	}
-
 	hdev = inst->core->device;
 	cap = &inst->capability;
 
@@ -2236,6 +2209,26 @@
 			property_id = HAL_PARAM_VENC_LTRMODE;
 			pdata = &ltrmode;
 			break;
+		case V4L2_CID_MPEG_VIDC_VIDEO_ENABLE_INITIAL_QP:
+			property_id = HAL_PARAM_VENC_ENABLE_INITIAL_QP;
+			quant.initqp_enable = control[i].value;
+			pdata = &quant;
+			break;
+		case V4L2_CID_MPEG_VIDC_VIDEO_I_FRAME_QP:
+			quant.qpi = control[i].value;
+			property_id = HAL_PARAM_VENC_ENABLE_INITIAL_QP;
+			pdata = &quant;
+			break;
+		case V4L2_CID_MPEG_VIDC_VIDEO_P_FRAME_QP:
+			quant.qpp = control[i].value;
+			property_id = HAL_PARAM_VENC_ENABLE_INITIAL_QP;
+			pdata = &quant;
+			break;
+		case V4L2_CID_MPEG_VIDC_VIDEO_B_FRAME_QP:
+			quant.qpb = control[i].value;
+			property_id = HAL_PARAM_VENC_ENABLE_INITIAL_QP;
+			pdata = &quant;
+			break;
 		default:
 			dprintk(VIDC_ERR, "Invalid id set: %d\n",
 					control[i].id);
@@ -2938,21 +2931,18 @@
 	return rc;
 }
 
-static struct v4l2_ctrl **get_cluster(int type, int *size)
+static struct v4l2_ctrl **get_super_cluster(struct msm_vidc_inst *inst,
+				int *size)
 {
 	int c = 0, sz = 0;
 	struct v4l2_ctrl **cluster = kmalloc(sizeof(struct v4l2_ctrl *) *
 			NUM_CTRLS, GFP_KERNEL);
 
-	if (type <= 0 || !size || !cluster)
+	if (!size || !cluster || !inst)
 		return NULL;
 
-	for (c = 0; c < NUM_CTRLS; c++) {
-		if (msm_venc_ctrls[c].cluster & type) {
-			cluster[sz] = msm_venc_ctrls[c].priv;
-			++sz;
-		}
-	}
+	for (c = 0; c < NUM_CTRLS; c++)
+		cluster[sz++] =  inst->ctrls[c];
 
 	*size = sz;
 	return cluster;
@@ -2960,10 +2950,23 @@
 
 int msm_venc_ctrl_init(struct msm_vidc_inst *inst)
 {
-
 	int idx = 0;
 	struct v4l2_ctrl_config ctrl_cfg = {0};
 	int ret_val = 0;
+	int cluster_size = 0;
+
+	if (!inst) {
+		dprintk(VIDC_ERR, "%s - invalid input\n", __func__);
+		return -EINVAL;
+	}
+
+	inst->ctrls = kzalloc(sizeof(struct v4l2_ctrl *) * NUM_CTRLS,
+				GFP_KERNEL);
+	if (!inst->ctrls) {
+		dprintk(VIDC_ERR, "%s - failed to allocate ctrl\n", __func__);
+		return -ENOMEM;
+	}
+
 	ret_val = v4l2_ctrl_handler_init(&inst->ctrl_handler, NUM_CTRLS);
 	if (ret_val) {
 		dprintk(VIDC_ERR, "CTRL ERR: Control handler init failed, %d\n",
@@ -3013,7 +3016,8 @@
 			"Failed to get ctrl for: idx: %d, %d\n",
 			idx, msm_venc_ctrls[idx].id);
 		}
-		msm_venc_ctrls[idx].priv = ctrl;
+
+		inst->ctrls[idx] = ctrl;
 	}
 	ret_val = inst->ctrl_handler.error;
 	if (ret_val)
@@ -3021,41 +3025,24 @@
 			"CTRL ERR: Error adding ctrls to ctrl handle, %d\n",
 			inst->ctrl_handler.error);
 
-	/* Construct clusters */
-	for (idx = 1; idx < MSM_VENC_CTRL_CLUSTER_MAX; ++idx) {
-		struct msm_vidc_ctrl_cluster *temp = NULL;
-		struct v4l2_ctrl **cluster = NULL;
-		int cluster_size = 0;
-
-		cluster = get_cluster(idx, &cluster_size);
-		if (!cluster || !cluster_size) {
-			dprintk(VIDC_WARN, "Failed to setup cluster of type %d",
-					idx);
-			continue;
-		}
-		v4l2_ctrl_cluster(cluster_size, cluster);
-
-		temp = kzalloc(sizeof(*temp), GFP_KERNEL);
-		if (!temp) {
-			ret_val = -ENOMEM;
-			break;
-		}
-
-		temp->cluster = cluster;
-		INIT_LIST_HEAD(&temp->list);
-		list_add_tail(&temp->list, &inst->ctrl_clusters);
+	/* Construct a super cluster of all controls */
+	inst->cluster = get_super_cluster(inst, &cluster_size);
+	if (!inst->cluster || !cluster_size) {
+		dprintk(VIDC_WARN,
+				"Failed to setup super cluster\n");
+		return -EINVAL;
 	}
 
+	v4l2_ctrl_cluster(cluster_size, inst->cluster);
+
 	return ret_val;
 }
 
 int msm_venc_ctrl_deinit(struct msm_vidc_inst *inst)
 {
-	struct msm_vidc_ctrl_cluster *curr, *next;
-	list_for_each_entry_safe(curr, next, &inst->ctrl_clusters, list) {
-		kfree(curr->cluster);
-		kfree(curr);
-	}
+	kfree(inst->ctrls);
+	kfree(inst->cluster);
 	v4l2_ctrl_handler_free(&inst->ctrl_handler);
+
 	return 0;
 }
diff --git a/drivers/media/platform/msm/vidc/msm_vidc.c b/drivers/media/platform/msm/vidc/msm_vidc.c
index 7960298..bfa9025 100644
--- a/drivers/media/platform/msm/vidc/msm_vidc.c
+++ b/drivers/media/platform/msm/vidc/msm_vidc.c
@@ -63,8 +63,14 @@
 		struct poll_table_struct *wait)
 {
 	struct msm_vidc_inst *inst = instance;
-	struct vb2_queue *outq = &inst->bufq[OUTPUT_PORT].vb2_bufq;
-	struct vb2_queue *capq = &inst->bufq[CAPTURE_PORT].vb2_bufq;
+	struct vb2_queue *outq = NULL;
+	struct vb2_queue *capq = NULL;
+
+	if (!inst)
+		return -EINVAL;
+
+	outq = &inst->bufq[OUTPUT_PORT].vb2_bufq;
+	capq = &inst->bufq[CAPTURE_PORT].vb2_bufq;
 
 	poll_wait(filp, &inst->event_handler.wait, wait);
 	poll_wait(filp, &capq->done_wq, wait);
@@ -78,6 +84,9 @@
 	struct msm_vidc_inst *inst = instance;
 	int rc = 0;
 
+	if (!inst)
+		return -EINVAL;
+
 	wait_event(inst->kernel_event_queue, (rc = get_poll_flags(inst)));
 	return rc;
 }
@@ -1217,7 +1226,6 @@
 	INIT_LIST_HEAD(&inst->pendingq);
 	INIT_LIST_HEAD(&inst->internalbufs);
 	INIT_LIST_HEAD(&inst->persistbufs);
-	INIT_LIST_HEAD(&inst->ctrl_clusters);
 	INIT_LIST_HEAD(&inst->registered_bufs);
 	INIT_LIST_HEAD(&inst->outputbufs);
 	init_waitqueue_head(&inst->kernel_event_queue);
diff --git a/drivers/media/platform/msm/vidc/msm_vidc_common.c b/drivers/media/platform/msm/vidc/msm_vidc_common.c
index 0135048..7fa7f9e 100644
--- a/drivers/media/platform/msm/vidc/msm_vidc_common.c
+++ b/drivers/media/platform/msm/vidc/msm_vidc_common.c
@@ -14,6 +14,7 @@
 #include <linux/jiffies.h>
 #include <linux/sched.h>
 #include <linux/slab.h>
+#include <linux/workqueue.h>
 #include <asm/div64.h>
 #include <mach/subsystem_restart.h>
 
@@ -587,10 +588,16 @@
 		} else {
 			dprintk(VIDC_DBG,
 				"V4L2_EVENT_SEQ_CHANGED_SUFFICIENT\n");
-			inst->prop.height[CAPTURE_PORT] = event_notify->height;
-			inst->prop.width[CAPTURE_PORT] = event_notify->width;
-			if (!msm_comm_get_stream_output_mode(inst) ==
+			if (msm_comm_get_stream_output_mode(inst) !=
 				HAL_VIDEO_DECODER_SECONDARY) {
+				dprintk(VIDC_DBG,
+					"event_notify->height = %d event_notify->width = %d\n",
+					event_notify->height,
+					event_notify->width);
+				inst->prop.height[CAPTURE_PORT] =
+					event_notify->height;
+				inst->prop.width[CAPTURE_PORT] =
+					event_notify->width;
 				inst->prop.height[OUTPUT_PORT] =
 					event_notify->height;
 				inst->prop.width[OUTPUT_PORT] =
@@ -711,8 +718,8 @@
 			return;
 		}
 		if (binfo->buffer_ownership != DRIVER) {
-			dprintk(VIDC_ERR,
-					"Failed : This buffer is with FW 0x%lx\n",
+			dprintk(VIDC_DBG,
+					"This buffer is with FW 0x%lx\n",
 					binfo->handle->device_addr);
 			return;
 		}
@@ -726,16 +733,71 @@
 
 	return;
 }
+
+int msm_comm_queue_output_buffers(struct msm_vidc_inst *inst)
+{
+	struct internal_buf *binfo;
+	struct hfi_device *hdev;
+	struct msm_smem *handle;
+	struct vidc_frame_data frame_data = {0};
+	struct hal_buffer_requirements *output_buf;
+	int rc = 0;
+
+	if (!inst || !inst->core || !inst->core->device) {
+		dprintk(VIDC_ERR, "%s invalid parameters\n", __func__);
+		return -EINVAL;
+	}
+	hdev = inst->core->device;
+	output_buf = get_buff_req_buffer(inst, HAL_BUFFER_OUTPUT);
+	if (!output_buf) {
+		dprintk(VIDC_DBG,
+			"This output buffer not required, buffer_type: %x\n",
+			HAL_BUFFER_OUTPUT);
+		return 0;
+	}
+	dprintk(VIDC_DBG,
+		"output: num = %d, size = %d\n",
+		output_buf->buffer_count_actual,
+		output_buf->buffer_size);
+
+	list_for_each_entry(binfo, &inst->outputbufs, list) {
+		if (binfo->buffer_ownership != DRIVER)
+			continue;
+		handle = binfo->handle;
+		frame_data.alloc_len = output_buf->buffer_size;
+		frame_data.filled_len = 0;
+		frame_data.offset = 0;
+		frame_data.device_addr = handle->device_addr;
+		frame_data.flags = 0;
+		frame_data.extradata_addr = handle->device_addr +
+		output_buf->buffer_size;
+		frame_data.buffer_type = HAL_BUFFER_OUTPUT;
+		rc = call_hfi_op(hdev, session_ftb,
+			(void *) inst->session, &frame_data);
+		binfo->buffer_ownership = FIRMWARE;
+	}
+	return 0;
+}
+
 static void handle_session_flush(enum command_response cmd, void *data)
 {
 	struct msm_vidc_cb_cmd_done *response = data;
 	struct msm_vidc_inst *inst;
+	int rc;
 	if (response) {
 		inst = (struct msm_vidc_inst *)response->session_id;
 		if (msm_comm_get_stream_output_mode(inst) ==
 			HAL_VIDEO_DECODER_SECONDARY) {
 			mutex_lock(&inst->lock);
 			validate_output_buffers(inst);
+			if (!inst->in_reconfig) {
+				rc = msm_comm_queue_output_buffers(inst);
+				if (rc) {
+					dprintk(VIDC_ERR,
+						"Failed to queue output buffers: %d\n",
+						rc);
+				}
+			}
 			mutex_unlock(&inst->lock);
 		}
 		msm_vidc_queue_v4l2_event(inst, V4L2_EVENT_MSM_VIDC_FLUSH_DONE);
@@ -764,95 +826,131 @@
 			"Failed to get valid response for session error\n");
 	}
 }
+
+struct sys_err_handler_data {
+	struct msm_vidc_core *core;
+	struct delayed_work work;
+};
+
+
+void hw_sys_error_handler(struct work_struct *work)
+{
+	struct msm_vidc_core *core = NULL;
+	struct hfi_device *hdev = NULL;
+	struct sys_err_handler_data *handler = NULL;
+	int rc = 0;
+
+	handler = container_of(work, struct sys_err_handler_data, work.work);
+	if (!handler || !handler->core || !handler->core->device) {
+		dprintk(VIDC_ERR, "%s - invalid work or core handle\n",
+				__func__);
+		goto exit;
+	}
+
+	core = handler->core;
+	hdev = core->device;
+
+	mutex_lock(&core->sync_lock);
+	/*
+	* Restart the firmware to bring out of bad state.
+	*/
+	if ((core->state == VIDC_CORE_INVALID) &&
+		hdev->resurrect_fw) {
+		mutex_lock(&core->lock);
+		rc = call_hfi_op(hdev, resurrect_fw,
+				hdev->hfi_device_data);
+		if (rc) {
+			dprintk(VIDC_ERR,
+				"%s - resurrect_fw failed: %d\n",
+				__func__, rc);
+		}
+		core->state = VIDC_CORE_LOADED;
+		mutex_unlock(&core->lock);
+	} else {
+		dprintk(VIDC_DBG,
+			"fw unloaded after sys error, no need to resurrect\n");
+	}
+	mutex_unlock(&core->sync_lock);
+
+exit:
+	/* free sys error handler, allocated in handle_sys_err */
+	kfree(handler);
+}
+
 static void handle_sys_error(enum command_response cmd, void *data)
 {
 	struct msm_vidc_cb_cmd_done *response = data;
-	struct msm_vidc_inst *inst = NULL ;
 	struct msm_vidc_core *core = NULL;
+	struct sys_err_handler_data *handler = NULL;
 	struct hfi_device *hdev = NULL;
+	struct msm_vidc_inst *inst = NULL;
 	int rc = 0;
 
 	subsystem_crashed("venus");
-	if (response) {
-		core = get_vidc_core(response->device_id);
-		dprintk(VIDC_WARN, "SYS_ERROR received for core %p\n", core);
-		if (core) {
-			mutex_lock(&core->lock);
-			core->state = VIDC_CORE_INVALID;
-			mutex_unlock(&core->lock);
-			mutex_lock(&core->sync_lock);
-			list_for_each_entry(inst, &core->instances,
-					list) {
-				mutex_lock(&inst->lock);
-				inst->state = MSM_VIDC_CORE_INVALID;
-				if (inst->core)
-					hdev = inst->core->device;
-				if (hdev && inst->session) {
-					dprintk(VIDC_DBG,
-					"cleaning up inst: 0x%p", inst);
-					rc = call_hfi_op(hdev, session_clean,
-						(void *) inst->session);
-					if (rc)
-						dprintk(VIDC_ERR,
-							"Sess clean failed :%p",
-							inst);
-				}
-				inst->session = NULL;
-				mutex_unlock(&inst->lock);
-				msm_vidc_queue_v4l2_event(inst,
-						V4L2_EVENT_MSM_VIDC_SYS_ERROR);
-			}
-			mutex_unlock(&core->sync_lock);
-		} else {
-			dprintk(VIDC_ERR,
-				"Got SYS_ERR but unable to identify core");
-		}
-	} else {
+	if (!response) {
 		dprintk(VIDC_ERR,
 			"Failed to get valid response for sys error\n");
-	}
-}
-
-static void handle_sys_watchdog_timeout(enum command_response cmd, void *data)
-{
-	struct msm_vidc_cb_cmd_done *response = data;
-	struct msm_vidc_inst *inst;
-	struct msm_vidc_core *core = NULL;
-	struct hfi_device *hdev = NULL;
-	int rc = 0;
-	dprintk(VIDC_ERR, "Venus Subsystem crashed\n");
-	core = get_vidc_core(response->device_id);
-	if (!core) {
-		dprintk(VIDC_ERR, "Wrong device_id received\n");
 		return;
 	}
-	subsystem_crashed("venus");
+
+	core = get_vidc_core(response->device_id);
+	if (!core) {
+		dprintk(VIDC_ERR,
+				"Got SYS_ERR but unable to identify core\n");
+		return;
+	}
+
+	dprintk(VIDC_WARN, "SYS_ERROR %d received for core %p\n", cmd, core);
 	mutex_lock(&core->lock);
 	core->state = VIDC_CORE_INVALID;
 	mutex_unlock(&core->lock);
-	mutex_lock(&core->sync_lock);
-	list_for_each_entry(inst, &core->instances, list) {
-		if (inst) {
-			msm_vidc_queue_v4l2_event(inst,
-					V4L2_EVENT_MSM_VIDC_SYS_ERROR);
-			mutex_lock(&inst->lock);
-			inst->state = MSM_VIDC_CORE_INVALID;
-			if (inst->core)
-				hdev = inst->core->device;
-			if (hdev && inst->session) {
-				rc = call_hfi_op(hdev, session_clean,
-						(void *) inst->session);
-				if (rc)
-					dprintk(VIDC_ERR,
-						"Sess clean failed :%p",
-						inst);
 
-			}
-			inst->session = NULL;
-			mutex_unlock(&inst->lock);
+	/*
+	* 1. Delete each instance session from hfi list
+	* 2. Notify all clients about hardware error.
+	*/
+	mutex_lock(&core->sync_lock);
+	list_for_each_entry(inst, &core->instances,
+			list) {
+		mutex_lock(&inst->lock);
+		inst->state = MSM_VIDC_CORE_INVALID;
+		if (inst->core)
+			hdev = inst->core->device;
+		if (hdev && inst->session) {
+			dprintk(VIDC_DBG,
+			"cleaning up inst: 0x%p\n", inst);
+			rc = call_hfi_op(hdev, session_clean,
+				(void *) inst->session);
+			if (rc)
+				dprintk(VIDC_ERR,
+					"Sess clean failed :%p\n",
+					inst);
 		}
+		inst->session = NULL;
+		mutex_unlock(&inst->lock);
+		msm_vidc_queue_v4l2_event(inst,
+				V4L2_EVENT_MSM_VIDC_SYS_ERROR);
 	}
 	mutex_unlock(&core->sync_lock);
+
+
+	handler = kzalloc(sizeof(*handler), GFP_KERNEL);
+	if (!handler) {
+		dprintk(VIDC_ERR,
+				"%s - failed to allocate sys error handler\n",
+				__func__);
+		return;
+	}
+	handler->core = core;
+	INIT_DELAYED_WORK(&handler->work, hw_sys_error_handler);
+
+	/*
+	* Sleep for 5 sec to ensure venus has completed any
+	* pending cache operations. Without this sleep, we see
+	* device reset when firmware is unloaded after a sys
+	* error.
+	*/
+	schedule_delayed_work(&handler->work, msecs_to_jiffies(5000));
 }
 
 static void handle_session_close(enum command_response cmd, void *data)
@@ -1359,7 +1457,7 @@
 		handle_seq_hdr_done(cmd, data);
 		break;
 	case SYS_WATCHDOG_TIMEOUT:
-		handle_sys_watchdog_timeout(cmd, data);
+		handle_sys_error(cmd, data);
 		break;
 	case SYS_ERROR:
 		handle_sys_error(cmd, data);
@@ -1539,11 +1637,14 @@
 		goto fail_scale_bus;
 	}
 
-	rc = call_hfi_op(hdev, load_fw, hdev->hfi_device_data);
-	if (rc) {
-		dprintk(VIDC_ERR, "Failed to load video firmware\n");
-		goto fail_load_fw;
+	if (core->state < VIDC_CORE_LOADED) {
+		rc = call_hfi_op(hdev, load_fw, hdev->hfi_device_data);
+		if (rc) {
+			dprintk(VIDC_ERR, "Failed to load video firmware\n");
+			goto fail_load_fw;
+		}
 	}
+
 	rc = msm_comm_scale_clocks(core);
 	if (rc) {
 		dprintk(VIDC_ERR, "Failed to scale clocks: %d\n", rc);
@@ -1592,19 +1693,25 @@
 				core->id, core->state);
 		goto core_already_uninited;
 	}
+
 	msm_comm_scale_clocks_and_bus(inst);
 	if (list_empty(&core->instances)) {
-		if (core->resources.has_ocmem) {
-			if (inst->state != MSM_VIDC_CORE_INVALID)
-				msm_comm_unset_ocmem(core);
-			call_hfi_op(hdev, free_ocmem, hdev->hfi_device_data);
-		}
-		dprintk(VIDC_DBG, "Calling vidc_hal_core_release\n");
-		rc = call_hfi_op(hdev, core_release, hdev->hfi_device_data);
-		if (rc) {
-			dprintk(VIDC_ERR, "Failed to release core, id = %d\n",
-							core->id);
-			goto exit;
+		if (core->state > VIDC_CORE_INIT) {
+			if (core->resources.has_ocmem) {
+				if (inst->state != MSM_VIDC_CORE_INVALID)
+					msm_comm_unset_ocmem(core);
+				call_hfi_op(hdev, free_ocmem,
+						hdev->hfi_device_data);
+			}
+			dprintk(VIDC_DBG, "Calling vidc_hal_core_release\n");
+			rc = call_hfi_op(hdev, core_release,
+					hdev->hfi_device_data);
+			if (rc) {
+				dprintk(VIDC_ERR,
+					"Failed to release core, id = %d\n",
+					core->id);
+				goto exit;
+			}
 		}
 		mutex_lock(&core->lock);
 		core->state = VIDC_CORE_UNINIT;
@@ -1615,6 +1722,7 @@
 		else
 			msm_comm_unvote_buses(core, DDR_MEM);
 	}
+
 core_already_uninited:
 	change_inst_state(inst, MSM_VIDC_CORE_UNINIT);
 exit:
@@ -3336,19 +3444,25 @@
 				capability->height.min);
 			rc = -ENOTSUPP;
 		}
-		if (!rc) {
-			rc = call_hfi_op(hdev, capability_check,
-				inst->fmts[OUTPUT_PORT]->fourcc,
+		if (msm_vp8_low_tier &&
+			inst->fmts[OUTPUT_PORT]->fourcc == V4L2_PIX_FMT_VP8) {
+			capability->width.max = DEFAULT_WIDTH;
+			capability->width.max = DEFAULT_HEIGHT;
+		}
+		if (!rc && (inst->prop.width[CAPTURE_PORT] >
+			capability->width.max)) {
+			dprintk(VIDC_ERR,
+				"Unsupported width = %u supported max width = %u\n",
 				inst->prop.width[CAPTURE_PORT],
-				&capability->width.max,
-				&capability->height.max);
+				capability->width.max);
+				rc = -ENOTSUPP;
 		}
 
 		if (!rc && (inst->prop.height[CAPTURE_PORT]
 			* inst->prop.width[CAPTURE_PORT] >
 			capability->width.max * capability->height.max)) {
 			dprintk(VIDC_ERR,
-			"Unsupported WxH = (%u)x(%u), Max supported is - (%u)x(%u)",
+			"Unsupported WxH = (%u)x(%u), Max supported is - (%u)x(%u)\n",
 			inst->prop.width[CAPTURE_PORT],
 			inst->prop.height[CAPTURE_PORT],
 			capability->width.max, capability->height.max);
diff --git a/drivers/media/platform/msm/vidc/msm_vidc_common.h b/drivers/media/platform/msm/vidc/msm_vidc_common.h
index 07dae8c..da71424 100644
--- a/drivers/media/platform/msm/vidc/msm_vidc_common.h
+++ b/drivers/media/platform/msm/vidc/msm_vidc_common.h
@@ -32,6 +32,7 @@
 int msm_comm_set_scratch_buffers(struct msm_vidc_inst *inst);
 int msm_comm_set_persist_buffers(struct msm_vidc_inst *inst);
 int msm_comm_set_output_buffers(struct msm_vidc_inst *inst);
+int msm_comm_queue_output_buffers(struct msm_vidc_inst *inst);
 int msm_comm_qbuf(struct vb2_buffer *vb);
 void msm_comm_scale_clocks_and_bus(struct msm_vidc_inst *inst);
 int msm_comm_flush(struct msm_vidc_inst *inst, u32 flags);
diff --git a/drivers/media/platform/msm/vidc/msm_vidc_internal.h b/drivers/media/platform/msm/vidc/msm_vidc_internal.h
index 06181dd..e9bf91d 100644
--- a/drivers/media/platform/msm/vidc/msm_vidc_internal.h
+++ b/drivers/media/platform/msm/vidc/msm_vidc_internal.h
@@ -68,6 +68,7 @@
 
 enum vidc_core_state {
 	VIDC_CORE_UNINIT = 0,
+	VIDC_CORE_LOADED,
 	VIDC_CORE_INIT,
 	VIDC_CORE_INIT_DONE,
 	VIDC_CORE_INVALID
@@ -231,7 +232,7 @@
 	void *mem_client;
 	struct v4l2_ctrl_handler ctrl_handler;
 	struct completion completions[SESSION_MSG_END - SESSION_MSG_START + 1];
-	struct list_head ctrl_clusters;
+	struct v4l2_ctrl **cluster;
 	struct v4l2_fh event_handler;
 	struct msm_smem *extradata_handle;
 	wait_queue_head_t kernel_event_queue;
@@ -250,6 +251,7 @@
 	enum buffer_mode_type buffer_mode_set[MAX_PORT_NUM];
 	struct list_head registered_bufs;
 	bool map_output_buffer;
+	struct v4l2_ctrl **ctrls;
 };
 
 extern struct msm_vidc_drv *vidc_driver;
@@ -269,8 +271,6 @@
 	u32 step;
 	u32 menu_skip_mask;
 	const char * const *qmenu;
-	u32 cluster;
-	struct v4l2_ctrl *priv;
 };
 
 void handle_cmd_response(enum command_response cmd, void *data);
diff --git a/drivers/media/platform/msm/vidc/q6_hfi.c b/drivers/media/platform/msm/vidc/q6_hfi.c
index 5404af6..486d740 100644
--- a/drivers/media/platform/msm/vidc/q6_hfi.c
+++ b/drivers/media/platform/msm/vidc/q6_hfi.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2013, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2013-2014, 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
@@ -146,8 +146,8 @@
 	struct q6_iface_q_info *q_info;
 	unsigned long flags = 0;
 
-	if (!pkt) {
-		dprintk(VIDC_ERR, "Invalid Params");
+	if (!device || !pkt) {
+		dprintk(VIDC_ERR, "Invalid Params\n");
 		return -EINVAL;
 	}
 
diff --git a/drivers/media/platform/msm/vidc/venus_hfi.c b/drivers/media/platform/msm/vidc/venus_hfi.c
index 008407d..37b1e72 100644
--- a/drivers/media/platform/msm/vidc/venus_hfi.c
+++ b/drivers/media/platform/msm/vidc/venus_hfi.c
@@ -80,11 +80,28 @@
 	u32 spare; /*reserved for future, should be zero*/
 };
 
+#define VENUS_SET_STATE(__device, __state) {\
+		mutex_lock(&(__device)->write_lock);	\
+		mutex_lock(&(__device)->read_lock);		\
+		(__device)->state = __state;			\
+		mutex_unlock(&(__device)->write_lock);	\
+		mutex_unlock(&(__device)->read_lock); }
+
+#define IS_VENUS_IN_VALID_STATE(__device) (\
+		(__device)->state != VENUS_STATE_DEINIT)
+
+static int venus_hfi_power_enable(void *dev);
 
 static inline int venus_hfi_clk_gating_off(struct venus_hfi_device *device);
 
 static int venus_hfi_power_enable(void *dev);
 
+static inline int venus_hfi_prepare_enable_clks(
+	struct venus_hfi_device *device);
+
+static inline void venus_hfi_disable_unprepare_clks(
+	struct venus_hfi_device *device);
+
 static unsigned long venus_hfi_get_clock_rate(struct venus_core_clock *clock,
 		int num_mbs_per_sec);
 
@@ -477,7 +494,7 @@
 	}
 
 	base_addr = device->hal_data->register_base_addr;
-	if (!device->clocks_enabled) {
+	if (device->clk_state != ENABLED_PREPARED) {
 		dprintk(VIDC_WARN,
 			"HFI Write register failed : Clocks are OFF\n");
 		return;
@@ -517,7 +534,7 @@
 	}
 
 	base_addr = device->hal_data->register_base_addr;
-	if (!device->clocks_enabled) {
+	if (device->clk_state != ENABLED_PREPARED) {
 		dprintk(VIDC_WARN,
 			"HFI Read register failed : Clocks are OFF\n");
 		return -EINVAL;
@@ -808,6 +825,203 @@
 	return rc;
 }
 
+static int venus_hfi_iface_cmdq_write_nolock(struct venus_hfi_device *device,
+					void *pkt);
+
+static int venus_hfi_iface_cmdq_write(struct venus_hfi_device *device,
+					void *pkt)
+{
+	int result = -EPERM;
+	if (!device || !pkt) {
+		dprintk(VIDC_ERR, "Invalid Params");
+		return -EINVAL;
+	}
+	mutex_lock(&device->write_lock);
+	mutex_lock(&device->clk_pwr_lock);
+	result = venus_hfi_iface_cmdq_write_nolock(device, pkt);
+	mutex_unlock(&device->clk_pwr_lock);
+	mutex_unlock(&device->write_lock);
+	return result;
+}
+
+static int venus_hfi_core_set_resource(void *device,
+		struct vidc_resource_hdr *resource_hdr, void *resource_value,
+		int locked)
+{
+	struct hfi_cmd_sys_set_resource_packet *pkt;
+	u8 packet[VIDC_IFACEQ_VAR_SMALL_PKT_SIZE];
+	int rc = 0;
+	struct venus_hfi_device *dev;
+
+	if (!device || !resource_hdr || !resource_value) {
+		dprintk(VIDC_ERR, "set_res: Invalid Params");
+		return -EINVAL;
+	} else {
+		dev = device;
+	}
+
+	pkt = (struct hfi_cmd_sys_set_resource_packet *) packet;
+
+	rc = create_pkt_set_cmd_sys_resource(pkt, resource_hdr,
+						resource_value);
+	if (rc) {
+		dprintk(VIDC_ERR, "set_res: failed to create packet");
+		goto err_create_pkt;
+	}
+	rc = locked ? venus_hfi_iface_cmdq_write(dev, pkt) :
+			venus_hfi_iface_cmdq_write_nolock(dev, pkt);
+	if (rc)
+		rc = -ENOTEMPTY;
+
+err_create_pkt:
+	return rc;
+}
+
+static int venus_hfi_core_release_resource(void *device,
+			struct vidc_resource_hdr *resource_hdr)
+{
+	struct hfi_cmd_sys_release_resource_packet pkt;
+	int rc = 0;
+	struct venus_hfi_device *dev;
+
+	if (!device || !resource_hdr) {
+		dprintk(VIDC_ERR, "Inv-Params in rel_res");
+		return -EINVAL;
+	} else {
+		dev = device;
+	}
+
+	rc = create_pkt_cmd_sys_release_resource(&pkt, resource_hdr);
+	if (rc) {
+		dprintk(VIDC_ERR, "release_res: failed to create packet");
+		goto err_create_pkt;
+	}
+
+	if (venus_hfi_iface_cmdq_write(dev, &pkt))
+		rc = -ENOTEMPTY;
+
+err_create_pkt:
+	return rc;
+}
+
+static int venus_hfi_set_ocmem(void *dev, struct ocmem_buf *ocmem, int locked)
+{
+	struct vidc_resource_hdr rhdr;
+	struct venus_hfi_device *device = dev;
+	int rc = 0;
+	if (!device || !ocmem) {
+		dprintk(VIDC_ERR, "Invalid params, core:%p, ocmem: %p\n",
+			device, ocmem);
+		return -EINVAL;
+	}
+	rhdr.resource_id = VIDC_RESOURCE_OCMEM;
+	rhdr.resource_handle = (u32) &device->resources.ocmem;
+	rhdr.size =	ocmem->len;
+	rc = venus_hfi_core_set_resource(device, &rhdr, ocmem, locked);
+	if (rc) {
+		dprintk(VIDC_ERR, "Failed to set OCMEM on driver\n");
+		goto ocmem_set_failed;
+	}
+	dprintk(VIDC_DBG, "OCMEM set, addr = %lx, size: %ld\n",
+		ocmem->addr, ocmem->len);
+ocmem_set_failed:
+	return rc;
+}
+
+static int venus_hfi_unset_ocmem(void *dev)
+{
+	struct vidc_resource_hdr rhdr;
+	struct venus_hfi_device *device = dev;
+	int rc = 0;
+
+	if (!device) {
+		dprintk(VIDC_ERR, "%s Invalid params, device:%p\n",
+			__func__, device);
+		rc = -EINVAL;
+		goto ocmem_unset_failed;
+	}
+	if (!device->resources.ocmem.buf) {
+		dprintk(VIDC_INFO, "%s Trying to free OCMEM which is not set",
+			__func__);
+		rc = -EINVAL;
+		goto ocmem_unset_failed;
+	}
+	rhdr.resource_id = VIDC_RESOURCE_OCMEM;
+	rhdr.resource_handle = (u32) &device->resources.ocmem;
+	rc = venus_hfi_core_release_resource(device, &rhdr);
+	if (rc)
+		dprintk(VIDC_ERR, "Failed to unset OCMEM on driver\n");
+ocmem_unset_failed:
+	return rc;
+}
+
+static int __alloc_ocmem(void *dev, unsigned long size, int locked)
+{
+	int rc = 0;
+	struct ocmem_buf *ocmem_buffer;
+	struct venus_hfi_device *device = dev;
+
+	if (!device || !size) {
+		dprintk(VIDC_ERR, "%s Invalid param, core: %p, size: %lu\n",
+			__func__, device, size);
+		return -EINVAL;
+	}
+	ocmem_buffer = device->resources.ocmem.buf;
+	if (!ocmem_buffer ||
+		ocmem_buffer->len < size) {
+		ocmem_buffer = ocmem_allocate(OCMEM_VIDEO, size);
+		if (IS_ERR_OR_NULL(ocmem_buffer)) {
+			dprintk(VIDC_ERR,
+				"ocmem_allocate_nb failed: %d\n",
+				(u32) ocmem_buffer);
+			rc = -ENOMEM;
+			goto ocmem_alloc_failed;
+		}
+		device->resources.ocmem.buf = ocmem_buffer;
+		rc = venus_hfi_set_ocmem(device, ocmem_buffer, locked);
+		if (rc) {
+			dprintk(VIDC_ERR, "Failed to set ocmem: %d\n", rc);
+			goto ocmem_set_failed;
+		}
+		device->ocmem_size = size;
+	} else
+		dprintk(VIDC_DBG,
+			"OCMEM is enough. reqd: %lu, available: %lu\n",
+			size, ocmem_buffer->len);
+
+	return rc;
+ocmem_set_failed:
+	ocmem_free(OCMEM_VIDEO, device->resources.ocmem.buf);
+	device->resources.ocmem.buf = NULL;
+ocmem_alloc_failed:
+	return rc;
+}
+
+static int venus_hfi_alloc_ocmem(void *dev, unsigned long size)
+{
+	return __alloc_ocmem(dev, size, true);
+}
+
+static int venus_hfi_free_ocmem(void *dev)
+{
+	struct venus_hfi_device *device = dev;
+	int rc = 0;
+
+	if (!device) {
+		dprintk(VIDC_ERR, "%s invalid device handle %p",
+			__func__, device);
+		return -EINVAL;
+	}
+
+	if (device->resources.ocmem.buf) {
+		rc = ocmem_free(OCMEM_VIDEO, device->resources.ocmem.buf);
+		if (rc)
+			dprintk(VIDC_ERR, "Failed to free ocmem\n");
+		device->resources.ocmem.buf = NULL;
+	}
+	return rc;
+}
+
 static inline int venus_hfi_tzbsp_set_video_state(enum tzbsp_video_state state)
 {
 	struct tzbsp_video_set_state_req cmd = {0};
@@ -842,8 +1056,6 @@
 	return rc;
 }
 
-
-/*Calling function is responsible to acquire device->clk_pwr_lock*/
 static inline int venus_hfi_clk_enable(struct venus_hfi_device *device)
 {
 	int rc = 0;
@@ -854,7 +1066,9 @@
 		dprintk(VIDC_ERR, "Invalid params: %p\n", device);
 		return -EINVAL;
 	}
-	if (device->clocks_enabled) {
+	WARN(!mutex_is_locked(&device->clk_pwr_lock),
+				"Clock/power lock must be acquired");
+	if (device->clk_state == ENABLED_PREPARED) {
 		dprintk(VIDC_DBG, "Clocks already enabled");
 		return 0;
 	}
@@ -869,7 +1083,7 @@
 			dprintk(VIDC_DBG, "Clock: %s enabled\n", cl->name);
 		}
 	}
-	device->clocks_enabled = 1;
+	device->clk_state = ENABLED_PREPARED;
 	++device->clk_cnt;
 	return 0;
 fail_clk_enable:
@@ -878,10 +1092,10 @@
 		usleep(100);
 		clk_disable(cl->clk);
 	}
+	device->clk_state = DISABLED_PREPARED;
 	return rc;
 }
 
-/*Calling function is responsible to acquire device->clk_pwr_lock*/
 static inline void venus_hfi_clk_disable(struct venus_hfi_device *device)
 {
 	int i, rc = 0;
@@ -891,7 +1105,9 @@
 		dprintk(VIDC_ERR, "Invalid params: %p\n", device);
 		return;
 	}
-	if (!device->clocks_enabled) {
+	WARN(!mutex_is_locked(&device->clk_pwr_lock),
+			"Clock/power lock must be acquired");
+	if (device->clk_state != ENABLED_PREPARED) {
 		dprintk(VIDC_DBG, "Clocks already disabled");
 		return;
 	}
@@ -909,11 +1125,12 @@
 		usleep(100);
 		clk_disable(cl->clk);
 	}
-	device->clocks_enabled = 0;
+	device->clk_state = DISABLED_PREPARED;
 	--device->clk_cnt;
 }
 
 static DECLARE_COMPLETION(pc_prep_done);
+static DECLARE_COMPLETION(release_resources_done);
 
 static int venus_hfi_halt_axi(struct venus_hfi_device *device)
 {
@@ -923,9 +1140,11 @@
 		dprintk(VIDC_ERR, "Invalid input: %p\n", device);
 		return -EINVAL;
 	}
+	mutex_lock(&device->clk_pwr_lock);
 	if (venus_hfi_clk_gating_off(device)) {
 		dprintk(VIDC_ERR, "Failed to turn off clk gating\n");
-		return -EIO;
+		rc = -EIO;
+		goto err_clk_gating_off;
 	}
 	/* Halt AXI and AXI OCMEM VBIF Access */
 	reg = venus_hfi_read_register(device, VENUS_VBIF_AXI_HALT_CTRL0);
@@ -940,6 +1159,8 @@
 			VENUS_VBIF_AXI_HALT_ACK_TIMEOUT_US);
 	if (rc)
 		dprintk(VIDC_WARN, "AXI bus port halt timeout\n");
+err_clk_gating_off:
+	mutex_unlock(&device->clk_pwr_lock);
 	return rc;
 }
 
@@ -967,7 +1188,7 @@
 		venus_hfi_clk_disable(device);
 		return rc;
 	}
-	venus_hfi_clk_disable(device);
+	venus_hfi_disable_unprepare_clks(device);
 	venus_hfi_iommu_detach(device);
 	rc = regulator_disable(device->gdsc);
 	if (rc) {
@@ -979,7 +1200,7 @@
 	else
 		venus_hfi_unvote_buses(device, DDR_MEM);
 
-	device->power_enabled = 0;
+	device->power_enabled = false;
 	--device->pwr_cnt;
 	dprintk(VIDC_INFO, "entering power collapse\n");
 already_disabled:
@@ -1015,7 +1236,11 @@
 		goto err_iommu_attach;
 	}
 
-	rc = venus_hfi_clk_enable(device);
+	if (device->clk_state == DISABLED_UNPREPARED)
+		rc = venus_hfi_prepare_enable_clks(device);
+	else if (device->clk_state == DISABLED_PREPARED)
+		rc = venus_hfi_clk_enable(device);
+
 	if (rc) {
 		dprintk(VIDC_ERR, "Failed to enable clocks");
 		goto err_enable_clk;
@@ -1056,11 +1281,22 @@
 		dprintk(VIDC_ERR, "Failed to reset venus core");
 		goto err_reset_core;
 	}
-
-	device->power_enabled = 1;
+	/*
+	 * write_lock is already acquired at this point, so to avoid
+	 * recursive lock in cmdq_write function, call nolock version
+	 * of alloc_ocmem
+	 */
+	WARN_ON(!mutex_is_locked(&device->write_lock));
+	rc = __alloc_ocmem(device, device->ocmem_size, false);
+	if (rc) {
+		dprintk(VIDC_ERR, "Failed to allocate OCMEM");
+		goto err_alloc_ocmem;
+	}
+	device->power_enabled = true;
 	++device->pwr_cnt;
 	dprintk(VIDC_INFO, "resuming from power collapse\n");
 	return rc;
+err_alloc_ocmem:
 err_reset_core:
 	venus_hfi_tzbsp_set_video_state(TZBSP_VIDEO_STATE_SUSPEND);
 err_set_video_state:
@@ -1086,11 +1322,21 @@
 		dprintk(VIDC_ERR, "Invalid params: %p\n", device);
 		return -EINVAL;
 	}
-	mutex_lock(&device->clk_pwr_lock);
-	if (!device->power_enabled)
-		rc = venus_hfi_power_on(device);
-	mutex_unlock(&device->clk_pwr_lock);
 
+	mutex_lock(&device->clk_pwr_lock);
+	if (!device->power_enabled) {
+		rc = venus_hfi_power_on(device);
+		if (rc) {
+			dprintk(VIDC_ERR, "Failed venus power on");
+			goto fail_power_on;
+		}
+	}
+	rc = venus_hfi_clk_gating_off(device);
+	if (rc)
+		dprintk(VIDC_ERR, "%s : Clock enable failed\n", __func__);
+
+fail_power_on:
+	mutex_unlock(&device->clk_pwr_lock);
 	return rc;
 }
 
@@ -1104,7 +1350,7 @@
 		dprintk(VIDC_ERR, "Invalid params: %p\n", device);
 		return -EINVAL;
 	}
-	if (device->clocks_enabled) {
+	if (device->clk_state == ENABLED_PREPARED) {
 		dprintk(VIDC_DBG, "Clocks are already enabled");
 		goto already_enabled;
 	}
@@ -1126,7 +1372,7 @@
 			        VIDC_WRAPPER_INTR_MASK, VIDC_WRAPPER_INTR_MASK_A2HVCODEC_BMSK, 0);
 	}
 already_enabled:
-	device->clocks_enabled = 1;
+	device->clk_state = ENABLED_PREPARED;
 fail_clk_power_on:
 	return rc;
 }
@@ -1164,36 +1410,49 @@
 	return rc;
 }
 
-static int venus_hfi_iface_cmdq_write(struct venus_hfi_device *device,
+static int venus_hfi_iface_cmdq_write_nolock(struct venus_hfi_device *device,
 					void *pkt)
 {
 	u32 rx_req_is_set = 0;
 	struct vidc_iface_q_info *q_info;
 	int result = -EPERM;
+
 	if (!device || !pkt) {
 		dprintk(VIDC_ERR, "Invalid Params");
 		return -EINVAL;
 	}
+	WARN(!mutex_is_locked(&device->write_lock),
+			"Cmd queue write lock must be acquired");
+	if (!IS_VENUS_IN_VALID_STATE(device)) {
+		dprintk(VIDC_ERR, "%s - fw not in init state\n", __func__);
+		result = -EINVAL;
+		goto err_q_null;
+	}
 
-	mutex_lock(&device->write_lock);
 	q_info = &device->iface_queues[VIDC_IFACEQ_CMDQ_IDX];
 	if (!q_info) {
 		dprintk(VIDC_ERR, "cannot write to shared Q's");
 		goto err_q_null;
 	}
+
+	if (!q_info->q_array.align_virtual_addr) {
+		dprintk(VIDC_ERR, "cannot write to shared CMD Q's\n");
+		result = -ENODATA;
+		goto err_q_null;
+	}
+
 	if (!venus_hfi_write_queue(q_info, (u8 *)pkt, &rx_req_is_set)) {
-		mutex_lock(&device->clk_pwr_lock);
+		WARN(!mutex_is_locked(&device->clk_pwr_lock),
+					"Clock/power lock must be acquired");
 		result = venus_hfi_clk_gating_off(device);
 		if (result) {
 			dprintk(VIDC_ERR, "%s : Clock enable failed\n",
 					__func__);
-			mutex_unlock(&device->clk_pwr_lock);
 			goto err_q_write;
 		}
 		result = venus_hfi_scale_clocks(device, device->clk_load);
 		if (result) {
 			dprintk(VIDC_ERR, "Clock scaling failed\n");
-			mutex_unlock(&device->clk_pwr_lock);
 			goto err_q_write;
 		}
 		if (rx_req_is_set)
@@ -1202,13 +1461,11 @@
 				VIDC_CPU_IC_SOFTINT,
 				1 << VIDC_CPU_IC_SOFTINT_H2A_SHFT, 0);
 		result = 0;
-		mutex_unlock(&device->clk_pwr_lock);
 	} else {
 		dprintk(VIDC_ERR, "venus_hfi_iface_cmdq_write:queue_full");
 	}
 err_q_write:
 err_q_null:
-	mutex_unlock(&device->write_lock);
 	return result;
 }
 
@@ -1223,12 +1480,19 @@
 		return -EINVAL;
 	}
 	mutex_lock(&device->read_lock);
+	if (!IS_VENUS_IN_VALID_STATE(device)) {
+		dprintk(VIDC_ERR, "%s - fw not in init state\n", __func__);
+		rc = -EINVAL;
+		goto read_error_null;
+	}
+
 	if (device->iface_queues[VIDC_IFACEQ_MSGQ_IDX].
 		q_array.align_virtual_addr == 0) {
 		dprintk(VIDC_ERR, "cannot read from shared MSG Q's");
 		rc = -ENODATA;
 		goto read_error_null;
 	}
+
 	q_info = &device->iface_queues[VIDC_IFACEQ_MSGQ_IDX];
 	if (!venus_hfi_read_queue(q_info, (u8 *)pkt, &tx_req_is_set)) {
 		mutex_lock(&device->clk_pwr_lock);
@@ -1267,6 +1531,11 @@
 		return -EINVAL;
 	}
 	mutex_lock(&device->read_lock);
+	if (!IS_VENUS_IN_VALID_STATE(device)) {
+		dprintk(VIDC_ERR, "%s - fw not in init state\n", __func__);
+		rc = -EINVAL;
+		goto dbg_error_null;
+	}
 	if (device->iface_queues[VIDC_IFACEQ_DBGQ_IDX].
 		q_array.align_virtual_addr == 0) {
 		dprintk(VIDC_ERR, "cannot read from shared DBG Q's");
@@ -1352,15 +1621,19 @@
 		device->iface_queues[i].q_array.align_virtual_addr = NULL;
 		device->iface_queues[i].q_array.align_device_addr = NULL;
 	}
+	device->iface_q_table.mem_data = NULL;
 	device->iface_q_table.align_virtual_addr = NULL;
 	device->iface_q_table.align_device_addr = NULL;
 
+	device->qdss.mem_data = NULL;
 	device->qdss.align_virtual_addr = NULL;
 	device->qdss.align_device_addr = NULL;
 
+	device->sfr.mem_data = NULL;
 	device->sfr.align_virtual_addr = NULL;
 	device->sfr.align_device_addr = NULL;
 
+	device->mem_addr.mem_data = NULL;
 	device->mem_addr.align_virtual_addr = NULL;
 	device->mem_addr.align_device_addr = NULL;
 
@@ -1587,6 +1860,8 @@
 		return -ENODEV;
 	}
 
+	VENUS_SET_STATE(dev, VENUS_STATE_INIT);
+
 	dev->intr_status = 0;
 	INIT_LIST_HEAD(&dev->sess_head);
 	venus_hfi_set_registers(dev);
@@ -1639,6 +1914,7 @@
 
 	return rc;
 err_core_init:
+	VENUS_SET_STATE(dev, VENUS_STATE_DEINIT);
 	disable_irq_nosync(dev->hal_data->irq);
 	return rc;
 }
@@ -1653,6 +1929,7 @@
 		dprintk(VIDC_ERR, "invalid device");
 		return -ENODEV;
 	}
+
 	if (dev->hal_client) {
 		mutex_lock(&dev->clk_pwr_lock);
 		rc = venus_hfi_clk_gating_off(device);
@@ -1669,6 +1946,8 @@
 		dev->intr_status = 0;
 		mutex_unlock(&dev->clk_pwr_lock);
 	}
+	VENUS_SET_STATE(dev, VENUS_STATE_DEINIT);
+
 	dprintk(VIDC_INFO, "HAL exited\n");
 	return 0;
 }
@@ -1685,6 +1964,8 @@
 		return -ENOENT;
 	}
 
+	WARN(!mutex_is_locked(&dev->write_lock),
+			"Cmdq write lock should be acquired");
 	q_info = &dev->iface_queues[q_index];
 	if (!q_info) {
 		dprintk(VIDC_ERR, "cannot read shared Q's");
@@ -1707,7 +1988,7 @@
 		dprintk(VIDC_ERR, "Invalid params: %p\n", device);
 		return;
 	}
-	if (!device->clocks_enabled) {
+	if (device->clk_state != ENABLED_PREPARED) {
 		dprintk(VIDC_DBG, "Clocks are already disabled");
 		goto already_disabled;
 	}
@@ -1724,7 +2005,7 @@
 			msecs_to_jiffies(msm_vidc_pwr_collapse_delay)))
 		dprintk(VIDC_DBG, "PM work already scheduled\n");
 already_disabled:
-	device->clocks_enabled = 0;
+	device->clk_state = DISABLED_PREPARED;
 }
 
 static void venus_hfi_core_clear_interrupt(struct venus_hfi_device *device)
@@ -1770,63 +2051,6 @@
 	mutex_unlock(&device->write_lock);
 }
 
-static int venus_hfi_core_set_resource(void *device,
-		struct vidc_resource_hdr *resource_hdr, void *resource_value)
-{
-	struct hfi_cmd_sys_set_resource_packet *pkt;
-	u8 packet[VIDC_IFACEQ_VAR_SMALL_PKT_SIZE];
-	int rc = 0;
-	struct venus_hfi_device *dev;
-
-	if (!device || !resource_hdr || !resource_value) {
-		dprintk(VIDC_ERR, "set_res: Invalid Params");
-		return -EINVAL;
-	} else {
-		dev = device;
-	}
-
-	pkt = (struct hfi_cmd_sys_set_resource_packet *) packet;
-
-	rc = create_pkt_set_cmd_sys_resource(pkt, resource_hdr,
-						resource_value);
-	if (rc) {
-		dprintk(VIDC_ERR, "set_res: failed to create packet");
-		goto err_create_pkt;
-	}
-	if (venus_hfi_iface_cmdq_write(dev, pkt))
-		rc = -ENOTEMPTY;
-
-err_create_pkt:
-	return rc;
-}
-
-static int venus_hfi_core_release_resource(void *device,
-			struct vidc_resource_hdr *resource_hdr)
-{
-	struct hfi_cmd_sys_release_resource_packet pkt;
-	int rc = 0;
-	struct venus_hfi_device *dev;
-
-	if (!device || !resource_hdr) {
-		dprintk(VIDC_ERR, "Inv-Params in rel_res");
-		return -EINVAL;
-	} else {
-		dev = device;
-	}
-
-	rc = create_pkt_cmd_sys_release_resource(&pkt, resource_hdr);
-	if (rc) {
-		dprintk(VIDC_ERR, "release_res: failed to create packet");
-		goto err_create_pkt;
-	}
-
-	if (venus_hfi_iface_cmdq_write(dev, &pkt))
-		rc = -ENOTEMPTY;
-
-err_create_pkt:
-	return rc;
-}
-
 static int venus_hfi_core_ping(void *device)
 {
 	struct hfi_cmd_sys_ping_packet pkt;
@@ -2514,6 +2738,67 @@
 	return rc;
 }
 
+static int venus_hfi_unset_free_ocmem(struct venus_hfi_device *device)
+{
+	int rc = 0;
+
+	if (!device) {
+		dprintk(VIDC_ERR, "Invalid param: %p\n", device);
+		return -EINVAL;
+	}
+
+	init_completion(&release_resources_done);
+	rc = venus_hfi_unset_ocmem(device);
+	if (rc) {
+		dprintk(VIDC_ERR, "Failed to unset OCMEM during PC %d\n", rc);
+		goto ocmem_unset_failed;
+	}
+	rc = wait_for_completion_timeout(&release_resources_done,
+			msecs_to_jiffies(msm_vidc_hw_rsp_timeout));
+	if (!rc) {
+		dprintk(VIDC_ERR,
+				"Wait interrupted or timeout for RELEASE_RESOURCES: %d\n",
+				rc);
+		rc = -EIO;
+		goto release_resources_failed;
+	}
+
+	rc = venus_hfi_free_ocmem(device);
+	if (rc) {
+		dprintk(VIDC_ERR, "Failed to free OCMEM during PC\n");
+		goto ocmem_free_failed;
+	}
+	return rc;
+
+ocmem_free_failed:
+	venus_hfi_alloc_ocmem(device, device->ocmem_size);
+release_resources_failed:
+ocmem_unset_failed:
+	return rc;
+}
+
+static int venus_hfi_prepare_pc(struct venus_hfi_device *device)
+{
+	int rc = 0;
+	init_completion(&pc_prep_done);
+	rc = venus_hfi_core_pc_prep(device);
+	if (rc) {
+		dprintk(VIDC_ERR, "Failed to prepare venus for power off");
+		goto err_pc_prep;
+	}
+	rc = wait_for_completion_timeout(&pc_prep_done,
+			msecs_to_jiffies(msm_vidc_hw_rsp_timeout));
+	if (!rc) {
+		dprintk(VIDC_ERR,
+				"Wait interrupted or timeout for PC_PREP_DONE: %d\n",
+				rc);
+		rc = -EIO;
+		goto err_pc_prep;
+	}
+	rc = 0;
+err_pc_prep:
+	return rc;
+}
 
 static void venus_hfi_pm_hndlr(struct work_struct *work)
 {
@@ -2521,28 +2806,31 @@
 	struct venus_hfi_device *device = list_first_entry(
 			&hal_ctxt.dev_head, struct venus_hfi_device, list);
 	mutex_lock(&device->clk_pwr_lock);
-	if (device->clocks_enabled || !device->power_enabled) {
+	if (device->clk_state == ENABLED_PREPARED || !device->power_enabled) {
 		dprintk(VIDC_DBG,
 				"Clocks status: %d, Power status: %d, ignore power off\n",
-				device->clocks_enabled, device->power_enabled);
+				device->clk_state, device->power_enabled);
 		goto clks_enabled;
 	}
 	mutex_unlock(&device->clk_pwr_lock);
-	init_completion(&pc_prep_done);
-	rc = venus_hfi_core_pc_prep(device);
+
+	rc = venus_hfi_unset_free_ocmem(device);
 	if (rc) {
-		dprintk(VIDC_ERR, "Failed to prepare venus for power off");
+		dprintk(VIDC_ERR,
+				"Failed to unset and free OCMEM for PC %d\n",
+				rc);
 		return;
 	}
-	rc = wait_for_completion_timeout(&pc_prep_done,
-			msecs_to_jiffies(msm_vidc_hw_rsp_timeout));
-	if (!rc) {
-		dprintk(VIDC_ERR, "Wait interrupted or timeout: %d", rc);
+
+	rc = venus_hfi_prepare_pc(device);
+	if (rc) {
+		dprintk(VIDC_ERR, "Failed to prepare for PC %d\n", rc);
+		venus_hfi_alloc_ocmem(device, device->ocmem_size);
 		return;
 	}
 
 	mutex_lock(&device->clk_pwr_lock);
-	if (device->clocks_enabled) {
+	if (device->clk_state == ENABLED_PREPARED) {
 		dprintk(VIDC_ERR,
 				"Clocks are still enabled after PC_PREP_DONE, ignore power off");
 		goto clks_enabled;
@@ -2626,26 +2914,35 @@
 				device->device_id,
 				(struct vidc_hal_msg_pkt_hdr *) packet,
 				&device->sess_head, &device->session_lock);
-			if (rc == HFI_MSG_EVENT_NOTIFY)
+			if (rc == HFI_MSG_EVENT_NOTIFY) {
 				venus_hfi_process_msg_event_notify(
 					device, (void *)packet);
+			} else if (rc == HFI_MSG_SYS_RELEASE_RESOURCE) {
+				dprintk(VIDC_DBG,
+					"Received HFI_MSG_SYS_RELEASE_RESOURCE\n");
+				complete(&release_resources_done);
+			}
 		}
 		while (!venus_hfi_iface_dbgq_read(device, packet)) {
 			struct hfi_msg_sys_debug_packet *pkt =
 				(struct hfi_msg_sys_debug_packet *) packet;
 			dprintk(VIDC_FW, "FW-SAYS: %s", pkt->rg_msg_data);
 		}
-		if (rc == HFI_MSG_SYS_IDLE) {
-			dprintk(VIDC_DBG, "Received HFI_MSG_SYS_IDLE\n");
+		switch (rc) {
+		case HFI_MSG_SYS_IDLE:
+			dprintk(VIDC_DBG,
+					"Received HFI_MSG_SYS_IDLE\n");
 			rc = venus_hfi_try_clk_gating(device);
-		} else if (rc == HFI_MSG_SYS_PC_PREP_DONE) {
+			break;
+		case HFI_MSG_SYS_PC_PREP_DONE:
 			dprintk(VIDC_DBG,
 					"Received HFI_MSG_SYS_PC_PREP_DONE\n");
 			rc = venus_hfi_try_clk_gating(device);
 			if (rc)
 				dprintk(VIDC_ERR,
-					"Failed clk gating after PC_PREP_DONE");
+					"Failed clk gating after PC_PREP_DONE\n");
 			complete(&pc_prep_done);
+			break;
 		}
 	} else {
 		dprintk(VIDC_ERR, "SPURIOUS_INTERRUPT");
@@ -2819,7 +3116,9 @@
 		clk_put(device->resources.clock[i].clk);
 	}
 }
-static inline void venus_hfi_disable_clks(struct venus_hfi_device *device)
+
+static inline void venus_hfi_disable_unprepare_clks(
+	struct venus_hfi_device *device)
 {
 	int i;
 	struct venus_core_clock *cl;
@@ -2827,8 +3126,9 @@
 		dprintk(VIDC_ERR, "Invalid params: %p\n", device);
 		return;
 	}
-	mutex_lock(&device->clk_pwr_lock);
-	if (device->clocks_enabled) {
+
+	WARN_ON(!mutex_is_locked(&device->clk_pwr_lock));
+	if (device->clk_state == ENABLED_PREPARED) {
 		for (i = VCODEC_CLK; i < VCODEC_MAX_CLKS; i++) {
 			if (i == VCODEC_OCMEM_CLK && !device->res->has_ocmem)
 				continue;
@@ -2850,11 +3150,11 @@
 		cl = &device->resources.clock[i];
 		clk_unprepare(cl->clk);
 	}
-	device->clocks_enabled = 0;
+	device->clk_state = DISABLED_UNPREPARED;
 	--device->clk_cnt;
-	mutex_unlock(&device->clk_pwr_lock);
 }
-static inline int venus_hfi_enable_clks(struct venus_hfi_device *device)
+
+static inline int venus_hfi_prepare_enable_clks(struct venus_hfi_device *device)
 {
 	int i = 0;
 	struct venus_core_clock *cl;
@@ -2863,7 +3163,12 @@
 		dprintk(VIDC_ERR, "Invalid params: %p\n", device);
 		return -EINVAL;
 	}
-	mutex_lock(&device->clk_pwr_lock);
+	WARN_ON(!mutex_is_locked(&device->clk_pwr_lock));
+
+	if (device->clk_state == ENABLED_PREPARED) {
+		dprintk(VIDC_DBG, "Clocks already prepared and enabled\n");
+		return 0;
+	}
 	for (i = VCODEC_CLK; i < VCODEC_MAX_CLKS; i++) {
 		if (i == VCODEC_OCMEM_CLK && !device->res->has_ocmem)
 			continue;
@@ -2876,9 +3181,8 @@
 			dprintk(VIDC_DBG, "Clock: %s enabled\n", cl->name);
 		}
 	}
-	device->clocks_enabled = 1;
+	device->clk_state = ENABLED_PREPARED;
 	++device->clk_cnt;
-	mutex_unlock(&device->clk_pwr_lock);
 	return rc;
 fail_clk_enable:
 	for (; i >= 0; i--) {
@@ -2886,9 +3190,10 @@
 		usleep(100);
 		clk_disable_unprepare(cl->clk);
 	}
-	mutex_unlock(&device->clk_pwr_lock);
+	device->clk_state = DISABLED_UNPREPARED;
 	return rc;
 }
+
 static int venus_hfi_register_iommu_domains(struct venus_hfi_device *device,
 					struct msm_vidc_platform_resources *res)
 {
@@ -3035,57 +3340,6 @@
 	return -EINVAL;
 }
 
-static int venus_hfi_set_ocmem(void *dev, struct ocmem_buf *ocmem)
-{
-	struct vidc_resource_hdr rhdr;
-	struct venus_hfi_device *device = dev;
-	int rc = 0;
-	if (!device || !ocmem) {
-		dprintk(VIDC_ERR, "Invalid params, core:%p, ocmem: %p\n",
-			device, ocmem);
-		return -EINVAL;
-	}
-	rhdr.resource_id = VIDC_RESOURCE_OCMEM;
-	rhdr.resource_handle = (u32) &device->resources.ocmem;
-	rhdr.size =	ocmem->len;
-	rc = venus_hfi_core_set_resource(device, &rhdr, ocmem);
-	if (rc) {
-		dprintk(VIDC_ERR, "Failed to set OCMEM on driver\n");
-		goto ocmem_set_failed;
-	}
-	dprintk(VIDC_DBG, "OCMEM set, addr = %lx, size: %ld\n",
-		ocmem->addr, ocmem->len);
-ocmem_set_failed:
-	return rc;
-}
-
-static int venus_hfi_unset_ocmem(void *dev)
-{
-	struct vidc_resource_hdr rhdr;
-	struct venus_hfi_device *device = dev;
-	int rc = 0;
-
-	if (!device) {
-		dprintk(VIDC_ERR, "%s Invalid params, device:%p\n",
-			__func__, device);
-		rc = -EINVAL;
-		goto ocmem_unset_failed;
-	}
-	if (!device->resources.ocmem.buf) {
-		dprintk(VIDC_INFO, "%s Trying to free OCMEM which is not set",
-			__func__);
-		rc = -EINVAL;
-		goto ocmem_unset_failed;
-	}
-	rhdr.resource_id = VIDC_RESOURCE_OCMEM;
-	rhdr.resource_handle = (u32) &device->resources.ocmem;
-	rc = venus_hfi_core_release_resource(device, &rhdr);
-	if (rc)
-		dprintk(VIDC_ERR, "Failed to unset OCMEM on driver\n");
-ocmem_unset_failed:
-	return rc;
-}
-
 static int venus_hfi_ocmem_notify_handler(struct notifier_block *this,
 		unsigned long event, void *data)
 {
@@ -3105,7 +3359,7 @@
 			struct venus_resources, ocmem);
 		device = container_of(resources,
 			struct venus_hfi_device, resources);
-		if (venus_hfi_set_ocmem(device, buff)) {
+		if (venus_hfi_set_ocmem(device, buff, 1)) {
 			dprintk(VIDC_ERR, "Failed to set ocmem: %d\n", rc);
 			goto err_ocmem_notify;
 		}
@@ -3131,62 +3385,6 @@
 	}
 }
 
-static int venus_hfi_alloc_ocmem(void *dev, unsigned long size)
-{
-	int rc = 0;
-	struct ocmem_buf *ocmem_buffer;
-	struct venus_hfi_device *device = dev;
-
-	if (!device || !size) {
-		dprintk(VIDC_ERR, "%s Invalid param, core: %p, size: %lu\n",
-			__func__, device, size);
-		return -EINVAL;
-	}
-	ocmem_buffer = device->resources.ocmem.buf;
-	if (!ocmem_buffer || ocmem_buffer->len < size) {
-		ocmem_buffer = ocmem_allocate(OCMEM_VIDEO, size);
-		if (IS_ERR_OR_NULL(ocmem_buffer)) {
-			dprintk(VIDC_ERR,
-				"ocmem_allocate_nb failed: %d\n",
-				(u32) ocmem_buffer);
-			rc = -ENOMEM;
-			goto ocmem_set_failed;
-		}
-		device->resources.ocmem.buf = ocmem_buffer;
-		rc = venus_hfi_set_ocmem(device, ocmem_buffer);
-		if (rc) {
-			dprintk(VIDC_ERR, "Failed to set ocmem: %d\n", rc);
-			goto ocmem_set_failed;
-		}
-	} else
-		dprintk(VIDC_DBG,
-			"OCMEM is enough. reqd: %lu, available: %lu\n",
-			size, ocmem_buffer->len);
-
-ocmem_set_failed:
-	return rc;
-}
-
-static int venus_hfi_free_ocmem(void *dev)
-{
-	struct venus_hfi_device *device = dev;
-	int rc = 0;
-
-	if (!device) {
-		dprintk(VIDC_ERR, "%s invalid device handle %p",
-			__func__, device);
-		return -EINVAL;
-	}
-
-	if (device->resources.ocmem.buf) {
-		rc = ocmem_free(OCMEM_VIDEO, device->resources.ocmem.buf);
-		if (rc)
-			dprintk(VIDC_ERR, "Failed to free ocmem\n");
-		device->resources.ocmem.buf = NULL;
-	}
-	return rc;
-}
-
 static void venus_hfi_deinit_ocmem(struct venus_hfi_device *device)
 {
 	if (device->resources.ocmem.handle)
@@ -3354,17 +3552,16 @@
 		mutex_unlock(&device->clk_pwr_lock);
 		goto fail_load_fw;
 	}
-	device->power_enabled = 1;
+	device->power_enabled = true;
 	++device->pwr_cnt;
-	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);
+	rc = venus_hfi_prepare_enable_clks(device);
+	mutex_unlock(&device->clk_pwr_lock);
 	if (rc) {
 		dprintk(VIDC_ERR, "Failed to enable clocks: %d\n", rc);
 		goto fail_enable_clks;
 	}
-
 	rc = protect_cp_mem(device);
 	if (rc) {
 		dprintk(VIDC_ERR, "Failed to protect memory\n");
@@ -3373,14 +3570,16 @@
 
 	return rc;
 fail_protect_mem:
-	venus_hfi_disable_clks(device);
+	mutex_lock(&device->clk_pwr_lock);
+	venus_hfi_disable_unprepare_clks(device);
+	mutex_unlock(&device->clk_pwr_lock);
 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;
+	device->power_enabled = false;
 	--device->pwr_cnt;
 	mutex_unlock(&device->clk_pwr_lock);
 fail_enable_gdsc:
@@ -3409,16 +3608,60 @@
 		 */
 		if(venus_hfi_halt_axi(device))
 			dprintk(VIDC_WARN, "Failed to halt AXI\n");
-		venus_hfi_disable_clks(device);
 		mutex_lock(&device->clk_pwr_lock);
+		venus_hfi_disable_unprepare_clks(device);
 		regulator_disable(device->gdsc);
-		device->power_enabled = 0;
+		device->power_enabled = false;
 		--device->pwr_cnt;
 		mutex_unlock(&device->clk_pwr_lock);
 		device->resources.fw.cookie = NULL;
 	}
 }
 
+static int venus_hfi_resurrect_fw(void *dev)
+{
+	struct venus_hfi_device *device = dev;
+	int rc = 0;
+
+	if (!device) {
+		dprintk(VIDC_ERR, "%s Invalid paramter: %p\n",
+			__func__, device);
+		return -EINVAL;
+	}
+
+	rc = venus_hfi_free_ocmem(device);
+	if (rc)
+		dprintk(VIDC_WARN, "%s - failed to free ocmem\n", __func__);
+
+	rc = venus_hfi_core_release(device);
+	if (rc) {
+		dprintk(VIDC_ERR, "%s - failed to release venus core rc = %d\n",
+				__func__, rc);
+		goto exit;
+	}
+
+	dprintk(VIDC_ERR, "praying for firmware resurrection\n");
+
+	venus_hfi_unload_fw(device);
+
+	rc = venus_hfi_scale_buses(device, DDR_MEM);
+	if (rc) {
+		dprintk(VIDC_ERR, "Failed to scale buses");
+		goto exit;
+	}
+
+	rc = venus_hfi_load_fw(device);
+	if (rc) {
+		dprintk(VIDC_ERR, "%s - failed to load venus fw rc = %d\n",
+				__func__, rc);
+		goto exit;
+	}
+
+	dprintk(VIDC_ERR, "Hurray!! firmware has restarted\n");
+exit:
+	return rc;
+}
+
 static int venus_hfi_get_fw_info(void *dev, enum fw_info info)
 {
 	int rc = 0;
@@ -3469,7 +3712,10 @@
 		rc = device->clk_cnt;
 		break;
 	case DEV_CLOCK_ENABLED:
-		rc = device->clocks_enabled;
+		if (device->clk_state == ENABLED_PREPARED)
+			rc = 1;
+		else
+			rc = 0;
 		break;
 	case DEV_PWR_COUNT:
 		rc = device->pwr_cnt;
@@ -3535,28 +3781,6 @@
 	return rc;
 }
 
-int venus_hfi_capability_check(u32 fourcc, u32 width,
-		u32 *max_width, u32 *max_height)
-{
-	int rc = 0;
-	if (!max_width || !max_height) {
-		dprintk(VIDC_ERR, "%s - invalid parameter\n", __func__);
-		return -EINVAL;
-	}
-
-	if (msm_vp8_low_tier && fourcc == V4L2_PIX_FMT_VP8) {
-		*max_width = DEFAULT_WIDTH;
-		*max_height = DEFAULT_HEIGHT;
-	}
-	if (width > *max_width) {
-		dprintk(VIDC_ERR,
-		"Unsupported width = %u supported max width = %u",
-		width, *max_width);
-		rc = -ENOTSUPP;
-	}
-	return rc;
-}
-
 static void *venus_hfi_add_device(u32 device_id,
 			struct msm_vidc_platform_resources *res,
 			hfi_cmd_response_callback callback)
@@ -3584,9 +3808,9 @@
 
 	hdevice->device_id = device_id;
 	hdevice->callback = callback;
-	hdevice->clocks_enabled = 0;
+	hdevice->clk_state = DISABLED_UNPREPARED;
 	hdevice->clk_cnt = 0;
-	hdevice->power_enabled = 0;
+	hdevice->power_enabled = false;
 	hdevice->pwr_cnt = 0;
 
 	hdevice->vidc_workq = create_singlethread_workqueue(
@@ -3714,10 +3938,10 @@
 	hdev->iommu_get_domain_partition = venus_hfi_iommu_get_domain_partition;
 	hdev->load_fw = venus_hfi_load_fw;
 	hdev->unload_fw = venus_hfi_unload_fw;
+	hdev->resurrect_fw = venus_hfi_resurrect_fw;
 	hdev->get_fw_info = venus_hfi_get_fw_info;
 	hdev->get_info = venus_hfi_get_info;
 	hdev->get_stride_scanline = venus_hfi_get_stride_scanline;
-	hdev->capability_check = venus_hfi_capability_check;
 	hdev->get_core_capabilities = venus_hfi_get_core_capabilities;
 	hdev->power_enable = venus_hfi_power_enable;
 }
diff --git a/drivers/media/platform/msm/vidc/venus_hfi.h b/drivers/media/platform/msm/vidc/venus_hfi.h
index 4feda45..23a51ba 100644
--- a/drivers/media/platform/msm/vidc/venus_hfi.h
+++ b/drivers/media/platform/msm/vidc/venus_hfi.h
@@ -124,6 +124,12 @@
 	BUS_IDX_MAX
 };
 
+enum clock_state {
+	DISABLED_UNPREPARED,
+	ENABLED_PREPARED,
+	DISABLED_PREPARED
+};
+
 struct vidc_mem_addr {
 	u8 *align_device_addr;
 	u8 *align_virtual_addr;
@@ -177,6 +183,11 @@
 	struct on_chip_mem ocmem;
 };
 
+enum venus_hfi_state {
+	VENUS_STATE_DEINIT = 1,
+	VENUS_STATE_INIT,
+};
+
 struct venus_hfi_device {
 	struct list_head list;
 	struct list_head sess_head;
@@ -184,8 +195,9 @@
 	u32 device_id;
 	u32 clk_load;
 	u32 bus_load[MSM_VIDC_MAX_DEVICES];
-	u32 clocks_enabled;
-	u32 power_enabled;
+	unsigned long ocmem_size;
+	enum clock_state clk_state;
+	bool power_enabled;
 	enum vidc_clocks clk_gating_level;
 	struct mutex read_lock;
 	struct mutex write_lock;
@@ -212,6 +224,7 @@
 	struct venus_resources resources;
 	struct msm_vidc_platform_resources *res;
 	struct regulator *gdsc;
+	enum venus_hfi_state state;
 };
 
 void venus_hfi_delete_device(void *device);
diff --git a/drivers/media/platform/msm/vidc/vidc_hfi_api.h b/drivers/media/platform/msm/vidc/vidc_hfi_api.h
index 6ac4bf0..a1742ce 100644
--- a/drivers/media/platform/msm/vidc/vidc_hfi_api.h
+++ b/drivers/media/platform/msm/vidc/vidc_hfi_api.h
@@ -187,6 +187,7 @@
 	HAL_CONFIG_VENC_LTRPERIOD,
 	HAL_CONFIG_VENC_HIER_P_NUM_FRAMES,
 	HAL_PARAM_VENC_HIER_P_MAX_ENH_LAYERS,
+	HAL_PARAM_VENC_ENABLE_INITIAL_QP,
 };
 
 enum hal_domain {
@@ -632,6 +633,13 @@
 	u32 layer_id;
 };
 
+struct hal_initial_quantization {
+	u32 qpi;
+	u32 qpp;
+	u32 qpb;
+	u32 initqp_enable;
+};
+
 struct hal_quantization_range {
 	u32 min_qp;
 	u32 max_qp;
@@ -1155,12 +1163,11 @@
 			int *domain_num, int *partition_num);
 	int (*load_fw)(void *dev);
 	void (*unload_fw)(void *dev);
+	int (*resurrect_fw)(void *dev);
 	int (*get_fw_info)(void *dev, enum fw_info info);
 	int (*get_info) (void *dev, enum dev_info info);
 	int (*get_stride_scanline)(int color_fmt, int width,
 		int height,	int *stride, int *scanlines);
-	int (*capability_check)(u32 fourcc, u32 width,
-		u32 *max_width, u32 *max_height);
 	int (*session_clean)(void *sess);
 	int (*get_core_capabilities)(void);
 	int (*power_enable)(void *dev);
diff --git a/drivers/media/platform/msm/vidc/vidc_hfi_helper.h b/drivers/media/platform/msm/vidc/vidc_hfi_helper.h
index 7f4dd04..7c62e77 100644
--- a/drivers/media/platform/msm/vidc/vidc_hfi_helper.h
+++ b/drivers/media/platform/msm/vidc/vidc_hfi_helper.h
@@ -319,6 +319,8 @@
 	(HFI_PROPERTY_PARAM_VENC_COMMON_START + 0x020)
 #define HFI_PROPERTY_PARAM_VENC_HIER_P_MAX_NUM_ENH_LAYER	\
 	(HFI_PROPERTY_PARAM_VENC_COMMON_START + 0x026)
+#define HFI_PROPERTY_PARAM_VENC_INITIAL_QP	\
+	(HFI_PROPERTY_PARAM_VENC_COMMON_START + 0x028)
 #define HFI_PROPERTY_CONFIG_VENC_COMMON_START				\
 	(HFI_DOMAIN_BASE_VENC + HFI_ARCH_COMMON_OFFSET + 0x6000)
 #define HFI_PROPERTY_CONFIG_VENC_TARGET_BITRATE				\
@@ -533,6 +535,13 @@
 	u32 layer_id;
 };
 
+struct hfi_initial_quantization {
+	u32 qp_i;
+	u32 qp_p;
+	u32 qp_b;
+	u32 init_qp_enable;
+};
+
 struct hfi_quantization_range {
 	u32 min_qp;
 	u32 max_qp;
diff --git a/drivers/misc/qseecom.c b/drivers/misc/qseecom.c
index a9d6949..23edc8a 100644
--- a/drivers/misc/qseecom.c
+++ b/drivers/misc/qseecom.c
@@ -61,7 +61,7 @@
 #define QSEE_CE_CLK_100MHZ		100000000
 
 #define QSEECOM_MAX_SG_ENTRY	512
-#define QSEECOM_DISK_ENCRYTPION_KEY_ID 0
+#define QSEECOM_INVALID_KEY_ID  0xff
 
 /* Save partition image hash for authentication check */
 #define	SCM_SAVE_PARTITION_HASH_ID	0x01
@@ -157,6 +157,7 @@
 	uint32_t          qsee_version;
 	struct device *pdev;
 	bool  commonlib_loaded;
+	struct ion_handle *cmnlib_ion_handle;
 	struct ce_hw_usage_info ce_info;
 
 	int qsee_bw_count;
@@ -226,8 +227,22 @@
 	uint32_t len;
 };
 
-uint8_t *key_id_array[QSEECOM_KEY_ID_SIZE] = {
-	"Disk Encryption"
+struct qseecom_key_id_usage_desc {
+	uint8_t desc[QSEECOM_KEY_ID_SIZE];
+};
+
+static struct qseecom_key_id_usage_desc key_id_array[] = {
+	{
+		.desc = "Undefined Usage Index",
+	},
+
+	{
+		.desc = "Full Disk Encryption",
+	},
+
+	{
+		.desc = "Per File Encryption",
+	},
 };
 
 /* Function proto types */
@@ -297,7 +312,11 @@
 
 	/* Get the physical address of the ION BUF */
 	ret = ion_phys(qseecom.ion_clnt, svc->ihandle, &pa, &svc->sb_length);
-
+	if (ret) {
+		pr_err("Cannot get phys_addr for the Ion Client, ret = %d\n",
+			ret);
+		return ret;
+	}
 	/* Populate the structure for sending scm call to load image */
 	svc->sb_virt = (char *) ion_map_kernel(qseecom.ion_clnt, svc->ihandle);
 	svc->sb_phys = pa;
@@ -342,7 +361,6 @@
 		return -EFAULT;
 
 	data->listener.id = 0;
-	data->type = QSEECOM_LISTENER_SERVICE;
 	if (!__qseecom_is_svc_unique(data, &rcvd_lstnr)) {
 		pr_err("Service is not unique and is already registered\n");
 		data->released = true;
@@ -623,7 +641,8 @@
 	mutex_lock(&qsee_bw_mutex);
 	qseecom.bw_scale_down_timer.expires = jiffies +
 		msecs_to_jiffies(duration);
-	add_timer(&(qseecom.bw_scale_down_timer));
+	mod_timer(&(qseecom.bw_scale_down_timer),
+		qseecom.bw_scale_down_timer.expires);
 	qseecom.timer_running = true;
 	mutex_unlock(&qsee_bw_mutex);
 }
@@ -684,6 +703,12 @@
 	}
 	/* Get the physical address of the ION BUF */
 	ret = ion_phys(qseecom.ion_clnt, data->client.ihandle, &pa, &len);
+	if (ret) {
+
+		pr_err("Cannot get phys_addr for the Ion Client, ret = %d\n",
+			ret);
+		return ret;
+	}
 	/* Populate the structure for sending scm call to load image */
 	data->client.sb_virt = (char *) ion_map_kernel(qseecom.ion_clnt,
 							data->client.ihandle);
@@ -856,19 +881,27 @@
 		pr_err("copy_from_user failed\n");
 		return -EFAULT;
 	}
+
+	if (qseecom.support_bus_scaling) {
+		mutex_lock(&qsee_bw_mutex);
+		ret = __qseecom_register_bus_bandwidth_needs(data, MEDIUM);
+		mutex_unlock(&qsee_bw_mutex);
+		if (ret)
+			return ret;
+	}
+
 	/* Vote for the SFPB clock */
 	ret = __qseecom_enable_clk_scale_up(data);
 	if (ret)
-		return ret;
+		goto enable_clk_err;
+
 	req.qsee_cmd_id = QSEOS_APP_LOOKUP_COMMAND;
 	load_img_req.img_name[MAX_APP_NAME_SIZE-1] = '\0';
 	memcpy(req.app_name, load_img_req.img_name, MAX_APP_NAME_SIZE);
 
 	ret = __qseecom_check_app_exists(req);
-	if (ret < 0) {
-		__qseecom_disable_clk_scale_down(data);
-		return ret;
-	}
+	if (ret < 0)
+		goto loadapp_err;
 
 	app_id = ret;
 	if (app_id) {
@@ -892,12 +925,17 @@
 					load_img_req.ifd_data_fd);
 		if (IS_ERR_OR_NULL(ihandle)) {
 			pr_err("Ion client could not retrieve the handle\n");
-			__qseecom_disable_clk_scale_down(data);
-			return -ENOMEM;
+			ret = -ENOMEM;
+			goto loadapp_err;
 		}
 
 		/* Get the physical address of the ION BUF */
 		ret = ion_phys(qseecom.ion_clnt, ihandle, &pa, &len);
+		if (ret) {
+			pr_err("Cannot get phys_addr for the Ion Client, ret = %d\n",
+				ret);
+			goto loadapp_err;
+		}
 
 		/* Populate the structure for sending scm call to load image */
 		memcpy(load_req.app_name, load_img_req.img_name,
@@ -917,16 +955,16 @@
 			pr_err("scm_call to load app failed\n");
 			if (!IS_ERR_OR_NULL(ihandle))
 				ion_free(qseecom.ion_clnt, ihandle);
-			__qseecom_disable_clk_scale_down(data);
-			return -EINVAL;
+			ret = -EINVAL;
+			goto loadapp_err;
 		}
 
 		if (resp.result == QSEOS_RESULT_FAILURE) {
 			pr_err("scm_call rsp.result is QSEOS_RESULT_FAILURE\n");
 			if (!IS_ERR_OR_NULL(ihandle))
 				ion_free(qseecom.ion_clnt, ihandle);
-			__qseecom_disable_clk_scale_down(data);
-			return -EFAULT;
+			ret = -EFAULT;
+			goto loadapp_err;
 		}
 
 		if (resp.result == QSEOS_RESULT_INCOMPLETE) {
@@ -936,8 +974,8 @@
 					ret);
 				if (!IS_ERR_OR_NULL(ihandle))
 					ion_free(qseecom.ion_clnt, ihandle);
-				__qseecom_disable_clk_scale_down(data);
-				return ret;
+				ret = -EFAULT;
+				goto loadapp_err;
 			}
 		}
 
@@ -946,8 +984,8 @@
 				resp.result);
 			if (!IS_ERR_OR_NULL(ihandle))
 				ion_free(qseecom.ion_clnt, ihandle);
-			__qseecom_disable_clk_scale_down(data);
-			return -EFAULT;
+			ret = -EFAULT;
+			goto loadapp_err;
 		}
 
 		app_id = resp.data;
@@ -955,8 +993,8 @@
 		entry = kmalloc(sizeof(*entry), GFP_KERNEL);
 		if (!entry) {
 			pr_err("kmalloc failed\n");
-			__qseecom_disable_clk_scale_down(data);
-			return -ENOMEM;
+			ret = -ENOMEM;
+			goto loadapp_err;
 		}
 		entry->app_id = app_id;
 		entry->ref_cnt = 1;
@@ -978,11 +1016,18 @@
 	if (copy_to_user(argp, &load_img_req, sizeof(load_img_req))) {
 		pr_err("copy_to_user failed\n");
 		kzfree(entry);
-		__qseecom_disable_clk_scale_down(data);
-		return -EFAULT;
+		ret = -EFAULT;
 	}
+
+loadapp_err:
 	__qseecom_disable_clk_scale_down(data);
-	return 0;
+enable_clk_err:
+	if (qseecom.support_bus_scaling) {
+		mutex_lock(&qsee_bw_mutex);
+		qseecom_unregister_bus_bandwidth_needs(data);
+		mutex_unlock(&qsee_bw_mutex);
+	}
+	return ret;
 }
 
 static int __qseecom_cleanup_app(struct qseecom_dev_handle *data)
@@ -1011,7 +1056,8 @@
 	return ret;
 }
 
-static int qseecom_unload_app(struct qseecom_dev_handle *data)
+static int qseecom_unload_app(struct qseecom_dev_handle *data,
+				bool app_crash)
 {
 	unsigned long flags;
 	int ret = 0;
@@ -1023,17 +1069,23 @@
 	if (data->client.app_id > 0) {
 		spin_lock_irqsave(&qseecom.registered_app_list_lock, flags);
 		list_for_each_entry(ptr_app, &qseecom.registered_app_list_head,
-								list) {
+									list) {
 			if (ptr_app->app_id == data->client.app_id) {
 				found_app = true;
-				if (ptr_app->ref_cnt == 1) {
+				if (app_crash) {
+					ptr_app->ref_cnt = 0;
 					unload = true;
 					break;
 				} else {
-					ptr_app->ref_cnt--;
-					pr_debug("Can't unload app(%d) inuse\n",
-							ptr_app->app_id);
-					break;
+					if (ptr_app->ref_cnt == 1) {
+						unload = true;
+						break;
+					} else {
+						ptr_app->ref_cnt--;
+						pr_debug("Can't unload app(%d) inuse\n",
+						ptr_app->app_id);
+						break;
+					}
 				}
 			}
 		}
@@ -1041,7 +1093,7 @@
 								flags);
 		if (found_app == false) {
 			pr_err("Cannot find app with id = %d\n",
-						data->client.app_id);
+					data->client.app_id);
 			return -EINVAL;
 		}
 	}
@@ -1065,7 +1117,7 @@
 				&resp, sizeof(resp));
 		if (ret) {
 			pr_err("scm_call to unload app (id = %d) failed\n",
-							req.app_id);
+								req.app_id);
 			return -EFAULT;
 		} else {
 			pr_warn("App id %d now unloaded\n", req.app_id);
@@ -1074,7 +1126,7 @@
 			ret = __qseecom_process_incomplete_cmd(data, &resp);
 			if (ret) {
 				pr_err("process_incomplete_cmd fail err: %d\n",
-						ret);
+									ret);
 				return ret;
 			}
 		}
@@ -1521,6 +1573,13 @@
 		pr_err("response buffer address not within shared bufffer\n");
 		return -EINVAL;
 	}
+
+	if (req.cmd_req_len == 0 || req.cmd_req_len > data->client.sb_length ||
+		req.resp_len > data->client.sb_length) {
+		pr_err("cmd or response buffer length not valid\n");
+		return -EINVAL;
+	}
+
 	send_cmd_req.cmd_req_buf = req.cmd_req_buf;
 	send_cmd_req.cmd_req_len = req.cmd_req_len;
 	send_cmd_req.resp_buf = req.resp_buf;
@@ -1733,10 +1792,22 @@
 	/* Populate the remaining parameters */
 	load_req.qsee_cmd_id = QSEOS_APP_START_COMMAND;
 	memcpy(load_req.app_name, appname, MAX_APP_NAME_SIZE);
+
+	if (qseecom.support_bus_scaling) {
+		mutex_lock(&qsee_bw_mutex);
+		ret = __qseecom_register_bus_bandwidth_needs(data, MEDIUM);
+		mutex_unlock(&qsee_bw_mutex);
+		if (ret) {
+			kzfree(img_data);
+			return ret;
+		}
+	}
+
 	ret = __qseecom_enable_clk_scale_up(data);
 	if (ret) {
 		kzfree(img_data);
-		return -EIO;
+		ret = -EIO;
+		goto loadfw_err;
 	}
 
 	__cpuc_flush_dcache_area((void *)img_data, fw_size);
@@ -1747,8 +1818,8 @@
 	kzfree(img_data);
 	if (ret) {
 		pr_err("scm_call to load failed : ret %d\n", ret);
-		__qseecom_disable_clk_scale_down(data);
-		return -EIO;
+		ret = -EIO;
+		goto loadfw_err;
 	}
 
 	switch (resp.result) {
@@ -1770,39 +1841,76 @@
 		ret = -EINVAL;
 		break;
 	}
-	__qseecom_disable_clk_scale_down(data);
 
+loadfw_err:
+	__qseecom_disable_clk_scale_down(data);
+	if (qseecom.support_bus_scaling) {
+		mutex_lock(&qsee_bw_mutex);
+		qseecom_unregister_bus_bandwidth_needs(data);
+		mutex_unlock(&qsee_bw_mutex);
+	}
 	return ret;
 }
 
 static int qseecom_load_commonlib_image(struct qseecom_dev_handle *data)
 {
-	int32_t ret = 0;
+	int ret = 0;
+	int len = 0;
 	uint32_t fw_size = 0;
 	struct qseecom_load_app_ireq load_req = {0, 0, 0, 0};
 	struct qseecom_command_scm_resp resp;
 	u8 *img_data = NULL;
+	ion_phys_addr_t pa;
 
 	if (__qseecom_get_fw_size("cmnlib", &fw_size))
 		return -EIO;
 
-	img_data = kzalloc(fw_size, GFP_KERNEL);
-	if (!img_data) {
-		pr_err("Mem allocation for lib image data failed\n");
+	qseecom.cmnlib_ion_handle = ion_alloc(qseecom.ion_clnt, fw_size,
+					SZ_4K, ION_HEAP(ION_QSECOM_HEAP_ID), 0);
+	if (IS_ERR_OR_NULL(qseecom.cmnlib_ion_handle)) {
+		pr_err("ION alloc failed\n");
 		return -ENOMEM;
 	}
+
+	img_data = (u8 *)ion_map_kernel(qseecom.ion_clnt,
+					qseecom.cmnlib_ion_handle);
+	if (IS_ERR_OR_NULL(img_data)) {
+		pr_err("ION memory mapping for cmnlib failed\n");
+		ret = -ENOMEM;
+		goto exit_ion_free;
+	}
 	ret = __qseecom_get_fw_data("cmnlib", img_data, &load_req);
 	if (ret) {
-		kzfree(img_data);
-		return -EIO;
+		ret = -EIO;
+		goto exit_ion_unmap_kernel;
+	}
+	/* Get the physical address of the ION BUF */
+	ret = ion_phys(qseecom.ion_clnt, qseecom.cmnlib_ion_handle,
+					&pa, &len);
+	load_req.phy_addr = (s32)pa;
+	if (ret) {
+		pr_err("physical memory retrieval failure\n");
+		ret = -EIO;
+		goto exit_ion_unmap_kernel;
 	}
 	/* Populate the remaining parameters */
 	load_req.qsee_cmd_id = QSEOS_LOAD_SERV_IMAGE_COMMAND;
+
+	if (qseecom.support_bus_scaling) {
+		mutex_lock(&qsee_bw_mutex);
+		ret = __qseecom_register_bus_bandwidth_needs(data, MEDIUM);
+		mutex_unlock(&qsee_bw_mutex);
+		if (ret) {
+			ret = -EIO;
+			goto exit_ion_unmap_kernel;
+		}
+	}
+
 	/* Vote for the SFPB clock */
 	ret = __qseecom_enable_clk_scale_up(data);
 	if (ret) {
-		kzfree(img_data);
-		return -EIO;
+		ret = -EIO;
+		goto exit_unregister_bus_bw_need;
 	}
 
 	__cpuc_flush_dcache_area((void *)img_data, fw_size);
@@ -1813,30 +1921,52 @@
 	if (ret) {
 		pr_err("scm_call to load failed : ret %d\n", ret);
 		ret = -EIO;
-	} else {
-		switch (resp.result) {
-		case QSEOS_RESULT_SUCCESS:
-			break;
-		case QSEOS_RESULT_FAILURE:
-			pr_err("scm call failed w/response result%d\n",
-						resp.result);
-			ret = -EINVAL;
-			break;
-		case  QSEOS_RESULT_INCOMPLETE:
-			ret = __qseecom_process_incomplete_cmd(data, &resp);
-			if (ret)
-				pr_err("process_incomplete_cmd failed err: %d\n",
-					ret);
-			break;
-		default:
-			pr_err("scm call return unknown response %d\n",
-						resp.result);
-			ret = -EINVAL;
-			break;
-		}
+		goto exit_disable_clk_vote;
 	}
-	kzfree(img_data);
+
+	switch (resp.result) {
+	case QSEOS_RESULT_SUCCESS:
+		break;
+	case QSEOS_RESULT_FAILURE:
+		pr_err("scm call failed w/response result%d\n", resp.result);
+		ret = -EINVAL;
+		goto exit_disable_clk_vote;
+	case  QSEOS_RESULT_INCOMPLETE:
+		ret = __qseecom_process_incomplete_cmd(data, &resp);
+		if (ret) {
+			pr_err("process_incomplete_cmd failed err: %d\n", ret);
+			goto exit_disable_clk_vote;
+		}
+		break;
+	default:
+		pr_err("scm call return unknown response %d\n",	resp.result);
+		ret = -EINVAL;
+		goto exit_disable_clk_vote;
+	}
 	__qseecom_disable_clk_scale_down(data);
+	if (qseecom.support_bus_scaling) {
+		mutex_lock(&qsee_bw_mutex);
+		qseecom_unregister_bus_bandwidth_needs(data);
+		mutex_unlock(&qsee_bw_mutex);
+	}
+	return ret;
+
+exit_disable_clk_vote:
+	__qseecom_disable_clk_scale_down(data);
+
+exit_unregister_bus_bw_need:
+	if (qseecom.support_bus_scaling) {
+		mutex_lock(&qsee_bw_mutex);
+		qseecom_unregister_bus_bandwidth_needs(data);
+		mutex_unlock(&qsee_bw_mutex);
+	}
+
+exit_ion_unmap_kernel:
+	ion_unmap_kernel(qseecom.ion_clnt, qseecom.cmnlib_ion_handle);
+
+exit_ion_free:
+	ion_free(qseecom.ion_clnt, qseecom.cmnlib_ion_handle);
+	qseecom.cmnlib_ion_handle = NULL;
 	return ret;
 }
 
@@ -1869,6 +1999,11 @@
 			break;
 		}
 	}
+
+	ion_unmap_kernel(qseecom.ion_clnt, qseecom.cmnlib_ion_handle);
+	ion_free(qseecom.ion_clnt, qseecom.cmnlib_ion_handle);
+	qseecom.cmnlib_ion_handle = NULL;
+
 	return ret;
 }
 
@@ -1984,6 +2119,12 @@
 
 	/* Get the physical address of the ION BUF */
 	ret = ion_phys(qseecom.ion_clnt, data->client.ihandle, &pa, &len);
+	if (ret) {
+		pr_err("Cannot get phys_addr for the Ion Client, ret = %d\n",
+			ret);
+		goto err;
+	}
+
 	/* Populate the structure for sending scm call to load image */
 	data->client.sb_virt = (char *) ion_map_kernel(qseecom.ion_clnt,
 							data->client.ihandle);
@@ -2045,7 +2186,7 @@
 	if (!found_handle)
 		pr_err("Unable to find the handle, exiting\n");
 	else
-		ret = qseecom_unload_app(data);
+		ret = qseecom_unload_app(data, false);
 
 	if (qseecom.support_bus_scaling) {
 		mutex_lock(&qsee_bw_mutex);
@@ -2151,6 +2292,10 @@
 		if (!qseecom.support_bus_scaling) {
 			qsee_disable_clock_vote(handle->dev, CLK_DFAB);
 			qsee_disable_clock_vote(handle->dev, CLK_SFPB);
+		} else {
+			mutex_lock(&qsee_bw_mutex);
+			qseecom_unregister_bus_bandwidth_needs(handle->dev);
+			mutex_unlock(&qsee_bw_mutex);
 		}
 	}
 	return ret;
@@ -2498,7 +2643,11 @@
 
 	/* Get the physical address of the ION BUF */
 	ret = ion_phys(qseecom.ion_clnt, ihandle, &pa, &len);
-
+	if (ret) {
+		pr_err("Cannot get phys_addr for the Ion Client, ret = %d\n",
+			ret);
+		return ret;
+	}
 	/* Populate the structure for sending scm call to load image */
 	load_req.qsee_cmd_id = QSEOS_LOAD_EXTERNAL_ELF_COMMAND;
 	load_req.mdt_len = load_img_req.mdt_len;
@@ -2515,11 +2664,21 @@
 		goto exit_ion_free;
 	}
 
+	if (qseecom.support_bus_scaling) {
+		mutex_lock(&qsee_bw_mutex);
+		ret = __qseecom_register_bus_bandwidth_needs(data, MEDIUM);
+		mutex_unlock(&qsee_bw_mutex);
+		if (ret) {
+			ret = -EIO;
+			goto exit_cpu_restore;
+		}
+	}
+
 	/* Vote for the SFPB clock */
 	ret = __qseecom_enable_clk_scale_up(data);
 	if (ret) {
 		ret = -EIO;
-		goto exit_cpu_restore;
+		goto exit_register_bus_bandwidth_needs;
 	}
 	msm_ion_do_cache_op(qseecom.ion_clnt, ihandle, NULL, len,
 				ION_IOC_CLEAN_INV_CACHES);
@@ -2556,6 +2715,14 @@
 
 exit_disable_clock:
 	__qseecom_disable_clk_scale_down(data);
+
+exit_register_bus_bandwidth_needs:
+	if (qseecom.support_bus_scaling) {
+		mutex_lock(&qsee_bw_mutex);
+		ret = qseecom_unregister_bus_bandwidth_needs(data);
+		mutex_unlock(&qsee_bw_mutex);
+	}
+
 exit_cpu_restore:
 	/* Restore the CPU mask */
 	mask = CPU_MASK_ALL;
@@ -2749,13 +2916,13 @@
 	case QSEOS_RESULT_SUCCESS:
 		break;
 	case QSEOS_RESULT_FAIL_KEY_ID_EXISTS:
-		pr_debug("process_incomplete_cmd return Key ID exists.\n");
+		pr_debug("Key ID exists.\n");
 		break;
 	case QSEOS_RESULT_INCOMPLETE:
 		ret = __qseecom_process_incomplete_cmd(data, &resp);
 		if (ret) {
 			if (resp.result == QSEOS_RESULT_FAIL_KEY_ID_EXISTS) {
-				pr_debug("process_incomplete_cmd return Key ID exists.\n");
+				pr_debug("Key ID exists.\n");
 				ret = 0;
 			} else {
 				pr_err("process_incomplete_cmd FAILED, resp.result %d\n",
@@ -2907,8 +3074,6 @@
 	if (ret) {
 		pr_err("scm call to update key userinfo failed : %d\n", ret);
 		__qseecom_disable_clk(CLK_QSEE);
-		if (qseecom.qsee.instance != qseecom.ce_drv.instance)
-			__qseecom_disable_clk(CLK_CE_DRV);
 		return -EFAULT;
 	}
 
@@ -2966,7 +3131,7 @@
 	memset((void *)generate_key_ireq.key_id, 0, QSEECOM_KEY_ID_SIZE);
 	memset((void *)generate_key_ireq.hash32, 0, QSEECOM_HASH_SIZE);
 	memcpy((void *)generate_key_ireq.key_id,
-			(void *)key_id_array[create_key_req.usage - 1],
+			(void *)key_id_array[create_key_req.usage].desc,
 			QSEECOM_KEY_ID_SIZE);
 	memcpy((void *)generate_key_ireq.hash32,
 			(void *)create_key_req.hash32, QSEECOM_HASH_SIZE);
@@ -2988,8 +3153,8 @@
 	memset((void *)set_key_ireq.key_id, 0, QSEECOM_KEY_ID_SIZE);
 	memset((void *)set_key_ireq.hash32, 0, QSEECOM_HASH_SIZE);
 	memcpy((void *)set_key_ireq.key_id,
-			(void *)key_id_array[create_key_req.usage - 1],
-				QSEECOM_KEY_ID_SIZE);
+		(void *)key_id_array[create_key_req.usage].desc,
+		QSEECOM_KEY_ID_SIZE);
 	memcpy((void *)set_key_ireq.hash32, (void *)create_key_req.hash32,
 				QSEECOM_HASH_SIZE);
 
@@ -3034,19 +3199,22 @@
 		return -EINVAL;
 	}
 
-	delete_key_ireq.flags = flags;
-	delete_key_ireq.qsee_command_id = QSEOS_DELETE_KEY;
-	memset((void *)delete_key_ireq.key_id, 0, QSEECOM_KEY_ID_SIZE);
-	memcpy((void *)delete_key_ireq.key_id,
-			(void *)key_id_array[wipe_key_req.usage - 1],
+	if (wipe_key_req.wipe_key_flag) {
+		delete_key_ireq.flags = flags;
+		delete_key_ireq.qsee_command_id = QSEOS_DELETE_KEY;
+		memset((void *)delete_key_ireq.key_id, 0, QSEECOM_KEY_ID_SIZE);
+		memcpy((void *)delete_key_ireq.key_id,
+			(void *)key_id_array[wipe_key_req.usage].desc,
 			QSEECOM_KEY_ID_SIZE);
-	memset((void *)delete_key_ireq.hash32, 0, QSEECOM_HASH_SIZE);
+		memset((void *)delete_key_ireq.hash32, 0, QSEECOM_HASH_SIZE);
 
-	ret = __qseecom_delete_saved_key(data, wipe_key_req.usage,
+		ret = __qseecom_delete_saved_key(data, wipe_key_req.usage,
 					&delete_key_ireq);
-	if (ret) {
-		pr_err("Failed to delete key from ssd storage: %d\n", ret);
-		return -EFAULT;
+		if (ret) {
+			pr_err("Failed to delete key from ssd storage: %d\n",
+				ret);
+			return -EFAULT;
+		}
 	}
 
 	clear_key_ireq.qsee_command_id = QSEOS_SET_KEY;
@@ -3055,7 +3223,7 @@
 	clear_key_ireq.flags = flags;
 	clear_key_ireq.pipe_type = QSEOS_PIPE_ENC|QSEOS_PIPE_ENC_XTS;
 	for (i = 0; i < QSEECOM_KEY_ID_SIZE; i++)
-			clear_key_ireq.key_id[i] = 0xff;
+		clear_key_ireq.key_id[i] = QSEECOM_INVALID_KEY_ID;
 	memset((void *)clear_key_ireq.hash32, 0, QSEECOM_HASH_SIZE);
 
 	ret = __qseecom_set_clear_ce_key(data, wipe_key_req.usage,
@@ -3094,8 +3262,9 @@
 	memset(ireq.key_id, 0, QSEECOM_KEY_ID_SIZE);
 	memset((void *)ireq.current_hash32, 0, QSEECOM_HASH_SIZE);
 	memset((void *)ireq.new_hash32, 0, QSEECOM_HASH_SIZE);
-	memcpy(ireq.key_id, key_id_array[update_key_req.usage - 1],
-						QSEECOM_KEY_ID_SIZE);
+	memcpy((void *)ireq.key_id,
+		(void *)key_id_array[update_key_req.usage].desc,
+		QSEECOM_KEY_ID_SIZE);
 	memcpy((void *)ireq.current_hash32,
 		(void *)update_key_req.current_hash32, QSEECOM_HASH_SIZE);
 	memcpy((void *)ireq.new_hash32,
@@ -3239,6 +3408,13 @@
 		/* Only one client allowed here at a time */
 		mutex_lock(&app_access_lock);
 		if (qseecom.support_bus_scaling) {
+			/* register bus bw in case the client doesn't do it */
+			if (!data->mode) {
+				mutex_lock(&qsee_bw_mutex);
+				__qseecom_register_bus_bandwidth_needs(
+								data, HIGH);
+				mutex_unlock(&qsee_bw_mutex);
+			}
 			ret = qseecom_scale_bus_bandwidth_timer(INACTIVE);
 			if (ret) {
 				pr_err("Failed to set bw.\n");
@@ -3271,6 +3447,12 @@
 		/* Only one client allowed here at a time */
 		mutex_lock(&app_access_lock);
 		if (qseecom.support_bus_scaling) {
+			if (!data->mode) {
+				mutex_lock(&qsee_bw_mutex);
+				__qseecom_register_bus_bandwidth_needs(
+								data, HIGH);
+				mutex_unlock(&qsee_bw_mutex);
+			}
 			ret = qseecom_scale_bus_bandwidth_timer(INACTIVE);
 			if (ret) {
 				pr_err("Failed to set bw.\n");
@@ -3332,6 +3514,7 @@
 			ret = -EINVAL;
 			break;
 		}
+		data->type = QSEECOM_CLIENT_APP;
 		pr_debug("SET_MEM_PARAM: qseecom addr = 0x%x\n", (u32)data);
 		ret = qseecom_set_client_mem_param(data, argp);
 		if (ret)
@@ -3377,7 +3560,7 @@
 		pr_debug("UNLOAD_APP: qseecom_addr = 0x%x\n", (u32)data);
 		mutex_lock(&app_access_lock);
 		atomic_inc(&data->ioctl_count);
-		ret = qseecom_unload_app(data);
+		ret = qseecom_unload_app(data, false);
 		atomic_dec(&data->ioctl_count);
 		mutex_unlock(&app_access_lock);
 		if (ret)
@@ -3442,6 +3625,10 @@
 		if (!qseecom.support_bus_scaling) {
 			qsee_disable_clock_vote(data, CLK_DFAB);
 			qsee_disable_clock_vote(data, CLK_SFPB);
+		} else {
+			mutex_lock(&qsee_bw_mutex);
+			qseecom_unregister_bus_bandwidth_needs(data);
+			mutex_unlock(&qsee_bw_mutex);
 		}
 		atomic_dec(&data->ioctl_count);
 		break;
@@ -3497,6 +3684,7 @@
 	}
 	case QSEECOM_IOCTL_APP_LOADED_QUERY_REQ: {
 		data->type = QSEECOM_CLIENT_APP;
+		pr_debug("APP_LOAD_QUERY: qseecom_addr = 0x%x\n", (u32)data);
 		mutex_lock(&app_access_lock);
 		atomic_inc(&data->ioctl_count);
 		pr_debug("APP_LOAD_QUERY: qseecom_addr = 0x%x\n", (u32)data);
@@ -3673,20 +3861,20 @@
 	int ret = 0;
 
 	if (data->released == false) {
-		pr_warn("data: released=false, type=%d, mode=%d, data=0x%x\n",
-			data->type, data->mode, (u32)data);
+		pr_warn("data: released = false, type = %d, data = 0x%x\n",
+			data->type, (u32)data);
 		switch (data->type) {
 		case QSEECOM_LISTENER_SERVICE:
 			ret = qseecom_unregister_listener(data);
 			break;
 		case QSEECOM_CLIENT_APP:
-			ret = qseecom_unload_app(data);
+			ret = qseecom_unload_app(data, true);
 			break;
 		case QSEECOM_SECURE_SERVICE:
 		case QSEECOM_GENERIC:
 			ret = qseecom_unmap_ion_allocated_memory(data);
 			if (ret)
-				pr_err("Close failed\n");
+				pr_err("Ion Unmap failed\n");
 			break;
 		case QSEECOM_UNAVAILABLE_CLIENT_APP:
 			break;
@@ -4116,7 +4304,7 @@
 			goto exit_free_kc_handle;
 
 		list_del(&kclient->list);
-		ret = qseecom_unload_app(kclient->handle->dev);
+		ret = qseecom_unload_app(kclient->handle->dev, false);
 		if (!ret) {
 			kzfree(kclient->handle->dev);
 			kzfree(kclient->handle);
@@ -4172,13 +4360,19 @@
 	struct qseecom_clk *qclk;
 	qclk = &qseecom.qsee;
 
-	if (qseecom.cumulative_mode != INACTIVE) {
+	mutex_lock(&qsee_bw_mutex);
+	mutex_lock(&clk_access_lock);
+
+	if (qseecom.cumulative_mode != INACTIVE &&
+		qseecom.current_mode != INACTIVE) {
 		ret = msm_bus_scale_client_update_request(
 			qseecom.qsee_perf_client, INACTIVE);
 		if (ret)
 			pr_err("Fail to scale down bus\n");
+		else
+			qseecom.current_mode = INACTIVE;
 	}
-	mutex_lock(&clk_access_lock);
+
 	if (qclk->clk_access_cnt) {
 		if (qclk->ce_clk != NULL)
 			clk_disable_unprepare(qclk->ce_clk);
@@ -4186,12 +4380,14 @@
 			clk_disable_unprepare(qclk->ce_core_clk);
 		if (qclk->ce_bus_clk != NULL)
 			clk_disable_unprepare(qclk->ce_bus_clk);
-		if (qseecom.timer_running) {
-			del_timer_sync(&(qseecom.bw_scale_down_timer));
-			qseecom.timer_running = false;
-		}
 	}
+
+	del_timer_sync(&(qseecom.bw_scale_down_timer));
+	qseecom.timer_running = false;
+
 	mutex_unlock(&clk_access_lock);
+	mutex_unlock(&qsee_bw_mutex);
+
 	return 0;
 }
 
@@ -4202,6 +4398,8 @@
 	struct qseecom_clk *qclk;
 	qclk = &qseecom.qsee;
 
+	mutex_lock(&qsee_bw_mutex);
+	mutex_lock(&clk_access_lock);
 	if (qseecom.cumulative_mode >= HIGH)
 		mode = HIGH;
 	else
@@ -4209,13 +4407,13 @@
 
 	if (qseecom.cumulative_mode != INACTIVE) {
 		ret = msm_bus_scale_client_update_request(
-			qseecom.qsee_perf_client, qseecom.cumulative_mode);
+			qseecom.qsee_perf_client, mode);
 		if (ret)
-			pr_err("Fail to scale up bus to %d\n",
-				qseecom.cumulative_mode);
+			pr_err("Fail to scale up bus to %d\n", mode);
+		else
+			qseecom.current_mode = mode;
 	}
 
-	mutex_lock(&clk_access_lock);
 	if (qclk->clk_access_cnt) {
 
 		ret = clk_prepare_enable(qclk->ce_core_clk);
@@ -4238,13 +4436,20 @@
 			qclk->clk_access_cnt = 0;
 			goto ce_bus_clk_err;
 		}
+	}
+
+	if (qclk->clk_access_cnt || qseecom.cumulative_mode) {
 		qseecom.bw_scale_down_timer.expires = jiffies +
 			msecs_to_jiffies(QSEECOM_SEND_CMD_CRYPTO_TIMEOUT);
-		add_timer(&(qseecom.bw_scale_down_timer));
+		mod_timer(&(qseecom.bw_scale_down_timer),
+				qseecom.bw_scale_down_timer.expires);
 		qseecom.timer_running = true;
-
 	}
+
 	mutex_unlock(&clk_access_lock);
+	mutex_unlock(&qsee_bw_mutex);
+
+
 	return 0;
 
 ce_bus_clk_err:
@@ -4253,6 +4458,7 @@
 	clk_disable_unprepare(qclk->ce_core_clk);
 err:
 	mutex_unlock(&clk_access_lock);
+	mutex_unlock(&qsee_bw_mutex);
 	return -EIO;
 }
 static struct of_device_id qseecom_match[] = {
diff --git a/drivers/misc/tspp.c b/drivers/misc/tspp.c
index 19f26f2..2dfa404 100644
--- a/drivers/misc/tspp.c
+++ b/drivers/misc/tspp.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2011-2013, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2011-2014, 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
@@ -924,9 +924,11 @@
 	}
 
 	ctl = readl_relaxed(tsif_device->base + TSIF_STS_CTL_OFF);
-	tsif_device->ref_count++;
+	if (!(ctl & TSIF_STS_CTL_START))
+		return -EBUSY;
 
-	return (ctl & TSIF_STS_CTL_START) ? 0 : -EBUSY;
+	tsif_device->ref_count++;
+	return 0;
 }
 
 static void tspp_stop_tsif(struct tspp_tsif_device *tsif_device)
@@ -1339,6 +1341,56 @@
 	}
 }
 
+static int msm_tspp_req_irqs(struct tspp_device *device)
+{
+	int rc;
+	int i;
+	int j;
+
+	rc = request_irq(device->tspp_irq, tspp_isr, IRQF_SHARED,
+		dev_name(&device->pdev->dev), device);
+	if (rc) {
+		dev_err(&device->pdev->dev,
+			"failed to request TSPP IRQ %d : %d",
+			device->tspp_irq, rc);
+		return rc;
+	}
+
+	for (i = 0; i < TSPP_TSIF_INSTANCES; i++) {
+		rc = request_irq(device->tsif[i].tsif_irq,
+			tsif_isr, IRQF_SHARED, dev_name(&device->pdev->dev),
+			&device->tsif[i]);
+		if (rc) {
+			dev_err(&device->pdev->dev,
+				"failed to request TSIF%d IRQ: %d",
+				i, rc);
+			goto failed;
+		}
+	}
+
+	return 0;
+
+failed:
+	free_irq(device->tspp_irq, device);
+	for (j = 0; j < i; j++)
+		free_irq(device->tsif[j].tsif_irq, device);
+
+	return rc;
+}
+
+static inline void msm_tspp_free_irqs(struct tspp_device *device)
+{
+	int i;
+
+	for (i = 0; i < TSPP_TSIF_INSTANCES; i++) {
+		if (device->tsif[i].tsif_irq)
+			free_irq(device->tsif[i].tsif_irq,  &device->tsif[i]);
+	}
+
+	if (device->tspp_irq)
+		free_irq(device->tspp_irq, device);
+}
+
 /*** TSPP API functions ***/
 
 /**
@@ -1355,6 +1407,8 @@
 			struct tspp_select_source *source)
 {
 	u32 val;
+	int rc;
+	bool req_irq = false;
 	struct tspp_device *pdev;
 	struct tspp_channel *channel;
 
@@ -1383,16 +1437,30 @@
 			source->data_inverse, source->sync_inverse,
 			source->enable_inverse);
 
+	/* Request IRQ resources on first open */
+	if ((source->source == TSPP_SOURCE_TSIF0 ||
+		source->source == TSPP_SOURCE_TSIF1) &&
+		(pdev->tsif[0].ref_count + pdev->tsif[1].ref_count) == 0) {
+		rc = msm_tspp_req_irqs(pdev);
+		if (rc) {
+			pr_err("tspp: error requesting irqs\n");
+			return rc;
+		}
+		req_irq = true;
+	}
+
 	switch (source->source) {
 	case TSPP_SOURCE_TSIF0:
 		if (tspp_config_gpios(pdev, channel->src, 1) != 0) {
+			rc = -EBUSY;
 			pr_err("tspp: error enabling tsif0 GPIOs\n");
-			return -EBUSY;
+			goto free_irq;
 		}
 		/* make sure TSIF0 is running & enabled */
 		if (tspp_start_tsif(&pdev->tsif[0]) != 0) {
+			rc = -EBUSY;
 			pr_err("tspp: error starting tsif0");
-			return -EBUSY;
+			goto free_irq;
 		}
 		if (pdev->tsif[0].ref_count == 1) {
 			val = readl_relaxed(pdev->base + TSPP_CONTROL);
@@ -1403,13 +1471,15 @@
 		break;
 	case TSPP_SOURCE_TSIF1:
 		if (tspp_config_gpios(pdev, channel->src, 1) != 0) {
+			rc = -EBUSY;
 			pr_err("tspp: error enabling tsif1 GPIOs\n");
-			return -EBUSY;
+			goto free_irq;
 		}
 		/* make sure TSIF1 is running & enabled */
 		if (tspp_start_tsif(&pdev->tsif[1]) != 0) {
+			rc = -EBUSY;
 			pr_err("tspp: error starting tsif1");
-			return -EBUSY;
+			goto free_irq;
 		}
 		if (pdev->tsif[1].ref_count == 1) {
 			val = readl_relaxed(pdev->base + TSPP_CONTROL);
@@ -1427,6 +1497,11 @@
 	}
 
 	return 0;
+
+free_irq:
+	if (req_irq)
+		msm_tspp_free_irqs(pdev);
+	return rc;
 }
 EXPORT_SYMBOL(tspp_open_stream);
 
@@ -1442,7 +1517,7 @@
 int tspp_close_stream(u32 dev, u32 channel_id)
 {
 	u32 val;
-	u32 prev_ref_count;
+	u32 prev_ref_count = 0;
 	struct tspp_device *pdev;
 	struct tspp_channel *channel;
 
@@ -1491,6 +1566,12 @@
 	}
 
 	channel->src = TSPP_SOURCE_NONE;
+
+	/* Free requested interrupts to save power */
+	if ((pdev->tsif[0].ref_count + pdev->tsif[1].ref_count) == 0 &&
+		prev_ref_count)
+		msm_tspp_free_irqs(pdev);
+
 	return 0;
 }
 EXPORT_SYMBOL(tspp_close_stream);
@@ -2812,7 +2893,6 @@
 				struct tspp_device *device)
 {
 	int rc;
-	int i;
 
 	/* get IRQ numbers from platform information */
 
@@ -2820,15 +2900,6 @@
 	rc = platform_get_irq_byname(pdev, "TSIF_TSPP_IRQ");
 	if (rc > 0) {
 		device->tspp_irq = rc;
-		rc = request_irq(device->tspp_irq, tspp_isr, IRQF_SHARED,
-				 dev_name(&pdev->dev), device);
-		if (rc) {
-			dev_err(&pdev->dev,
-				"failed to request TSPP IRQ %d : %d",
-				device->tspp_irq, rc);
-			device->tspp_irq = 0;
-			return -EINVAL;
-		}
 	} else {
 		dev_err(&pdev->dev, "failed to get TSPP IRQ");
 		return -EINVAL;
@@ -2851,17 +2922,6 @@
 		return -EINVAL;
 	}
 
-	for (i = 0; i < TSPP_TSIF_INSTANCES; i++) {
-		rc = request_irq(device->tsif[i].tsif_irq,
-				tsif_isr, IRQF_SHARED,
-				dev_name(&pdev->dev), &device->tsif[i]);
-		if (rc) {
-			dev_warn(&pdev->dev, "failed to request TSIF%d IRQ: %d",
-				i, rc);
-			device->tsif[i].tsif_irq = 0;
-		}
-	}
-
 	/* map BAM IRQ */
 	rc = platform_get_irq_byname(pdev, "TSIF_BAM_IRQ");
 	if (rc > 0) {
@@ -3129,13 +3189,6 @@
 	for (i = 0; i < TSPP_TSIF_INSTANCES; i++)
 		tsif_debugfs_exit(&device->tsif[i]);
 err_irq:
-	for (i = 0; i < TSPP_TSIF_INSTANCES; i++) {
-		if (device->tsif[i].tsif_irq)
-			free_irq(device->tsif[i].tsif_irq,  &device->tsif[i]);
-	}
-	if (device->tspp_irq)
-		free_irq(device->tspp_irq, device);
-
 	iounmap(device->bam_props.virt_addr);
 err_map_bam:
 err_res_bam:
diff --git a/drivers/mmc/card/block.c b/drivers/mmc/card/block.c
index 9d07631..0c70746 100644
--- a/drivers/mmc/card/block.c
+++ b/drivers/mmc/card/block.c
@@ -2524,8 +2524,20 @@
 			break;
 		case MMC_BLK_CMD_ERR:
 			ret = mmc_blk_cmd_err(md, card, brq, req, ret);
-			if (!mmc_blk_reset(md, card->host, type))
+			if (!mmc_blk_reset(md, card->host, type)) {
+				if (!ret) {
+					/*
+					 * We have successfully completed block
+					 * request and notified to upper layers.
+					 * As the reset is successful, assume
+					 * h/w is in clean state and proceed
+					 * with new request.
+					 */
+					BUG_ON(card->host->areq);
+					goto start_new_req;
+				}
 				break;
+			}
 			goto cmd_abort;
 		case MMC_BLK_RETRY:
 			if (retry++ < 5)
diff --git a/drivers/mmc/core/cd-gpio.c b/drivers/mmc/core/cd-gpio.c
index 45ec5c2..9d813e9 100644
--- a/drivers/mmc/core/cd-gpio.c
+++ b/drivers/mmc/core/cd-gpio.c
@@ -19,8 +19,8 @@
 
 struct mmc_cd_gpio {
 	unsigned int gpio;
-	char label[0];
 	bool status;
+	char label[0];
 };
 
 static int mmc_cd_get_status(struct mmc_host *host)
diff --git a/drivers/mmc/core/core.c b/drivers/mmc/core/core.c
index 1feb26b..dbc7d5c 100644
--- a/drivers/mmc/core/core.c
+++ b/drivers/mmc/core/core.c
@@ -169,9 +169,35 @@
 
 #endif /* CONFIG_FAIL_MMC_REQUEST */
 
+static inline void
+mmc_clk_scaling_update_state(struct mmc_host *host, struct mmc_request *mrq)
+{
+	if (mrq) {
+		switch (mrq->cmd->opcode) {
+		case MMC_READ_SINGLE_BLOCK:
+		case MMC_READ_MULTIPLE_BLOCK:
+		case MMC_WRITE_BLOCK:
+		case MMC_WRITE_MULTIPLE_BLOCK:
+			host->clk_scaling.invalid_state = false;
+			break;
+		default:
+			host->clk_scaling.invalid_state = true;
+			break;
+		}
+	} else {
+		/*
+		 * force clock scaling transitions,
+		 * if other conditions are met
+		 */
+		host->clk_scaling.invalid_state = false;
+	}
+
+	return;
+}
+
 static inline void mmc_update_clk_scaling(struct mmc_host *host)
 {
-	if (host->clk_scaling.enable) {
+	if (host->clk_scaling.enable && !host->clk_scaling.invalid_state) {
 		host->clk_scaling.busy_time_us +=
 			ktime_to_us(ktime_sub(ktime_get(),
 					host->clk_scaling.start_busy));
@@ -333,8 +359,11 @@
 		 * frequency will be done after current thread
 		 * releases host.
 		 */
-		mmc_clk_scaling(host, false);
-		host->clk_scaling.start_busy = ktime_get();
+		mmc_clk_scaling_update_state(host, mrq);
+		if (!host->clk_scaling.invalid_state) {
+			mmc_clk_scaling(host, false);
+			host->clk_scaling.start_busy = ktime_get();
+		}
 	}
 
 	host->ops->request(host, mrq);
@@ -2826,7 +2855,8 @@
 	 * this mode.
 	 */
 	if (!card || (mmc_card_mmc(card) &&
-			card->part_curr == EXT_CSD_PART_CONFIG_ACC_RPMB))
+			card->part_curr == EXT_CSD_PART_CONFIG_ACC_RPMB)
+			|| host->clk_scaling.invalid_state)
 		goto out;
 
 	if (mmc_send_status(card, &status)) {
diff --git a/drivers/mmc/core/mmc.c b/drivers/mmc/core/mmc.c
index 88655c6..c26c1bb 100644
--- a/drivers/mmc/core/mmc.c
+++ b/drivers/mmc/core/mmc.c
@@ -74,6 +74,9 @@
 	MMC_FIXUP("H8G2d", CID_MANFID_HYNIX, CID_OEMID_ANY, add_quirk_mmc,
 		  MMC_QUIRK_CACHE_DISABLE),
 
+	MMC_FIXUP("MMC16G", CID_MANFID_KINGSTON, CID_OEMID_ANY, add_quirk_mmc,
+		  MMC_QUIRK_CACHE_DISABLE),
+
 	END_FIXUP
 };
 
@@ -1711,11 +1714,12 @@
 	BUG_ON(!host->card);
 
 	unregister_reboot_notifier(&host->card->reboot_notify);
+
+	mmc_exit_clk_scaling(host);
 	mmc_remove_card(host->card);
 
 	mmc_claim_host(host);
 	host->card = NULL;
-	mmc_exit_clk_scaling(host);
 	mmc_release_host(host);
 }
 
diff --git a/drivers/mmc/core/sd.c b/drivers/mmc/core/sd.c
index d4d7c18..179632c 100644
--- a/drivers/mmc/core/sd.c
+++ b/drivers/mmc/core/sd.c
@@ -1132,11 +1132,11 @@
 	BUG_ON(!host);
 	BUG_ON(!host->card);
 
+	mmc_exit_clk_scaling(host);
 	mmc_remove_card(host->card);
 
 	mmc_claim_host(host);
 	host->card = NULL;
-	mmc_exit_clk_scaling(host);
 	mmc_release_host(host);
 }
 
diff --git a/drivers/mmc/host/sdhci-msm.c b/drivers/mmc/host/sdhci-msm.c
index 9b41807..074b6a8 100644
--- a/drivers/mmc/host/sdhci-msm.c
+++ b/drivers/mmc/host/sdhci-msm.c
@@ -2854,7 +2854,7 @@
 	 * max. 1ms for reset completion.
 	 */
 	ret = readl_poll_timeout(msm_host->core_mem + CORE_POWER,
-			pwr, !(pwr & CORE_SW_RST), 100, 10);
+			pwr, !(pwr & CORE_SW_RST), 10, 1000);
 
 	if (ret) {
 		dev_err(&pdev->dev, "reset failed (%d)\n", ret);
diff --git a/drivers/net/wireless/wcnss/wcnss_wlan.c b/drivers/net/wireless/wcnss/wcnss_wlan.c
index 0f3eaea..e03d5be 100644
--- a/drivers/net/wireless/wcnss/wcnss_wlan.c
+++ b/drivers/net/wireless/wcnss/wcnss_wlan.c
@@ -186,6 +186,7 @@
 #define WCNSS_USR_CTRL_MSG_START  0x00000000
 #define WCNSS_USR_SERIAL_NUM      (WCNSS_USR_CTRL_MSG_START + 1)
 #define WCNSS_USR_HAS_CAL_DATA    (WCNSS_USR_CTRL_MSG_START + 2)
+#define WCNSS_USR_WLAN_MAC_ADDR   (WCNSS_USR_CTRL_MSG_START + 3)
 
 #define MAC_ADDRESS_STR "%02x:%02x:%02x:%02x:%02x:%02x"
 
@@ -241,6 +242,13 @@
 	{"LVS1", 0x060},
 };
 
+static int wcnss_notif_cb(struct notifier_block *this, unsigned long code,
+				void *ss_handle);
+
+static struct notifier_block wnb = {
+	.notifier_call = wcnss_notif_cb,
+};
+
 #define NVBIN_FILE "wlan/prima/WCNSS_qcom_wlan_nv.bin"
 
 /*
@@ -2090,6 +2098,16 @@
 		has_calibrated_data = buf[2];
 		break;
 
+	case WCNSS_USR_WLAN_MAC_ADDR:
+		memcpy(&penv->wlan_nv_macAddr,  &buf[2],
+				sizeof(penv->wlan_nv_macAddr));
+
+		pr_debug("%s: MAC Addr:" MAC_ADDRESS_STR "\n", __func__,
+			penv->wlan_nv_macAddr[0], penv->wlan_nv_macAddr[1],
+			penv->wlan_nv_macAddr[2], penv->wlan_nv_macAddr[3],
+			penv->wlan_nv_macAddr[4], penv->wlan_nv_macAddr[5]);
+		break;
+
 	default:
 		pr_err("%s: Invalid command %d\n", __func__, cmd);
 		break;
@@ -2347,6 +2365,10 @@
 	} while (pil_retry++ < WCNSS_MAX_PIL_RETRY && IS_ERR(penv->pil));
 
 	if (pil_retry >= WCNSS_MAX_PIL_RETRY) {
+		wcnss_reset_intr();
+		if (penv->wcnss_notif_hdle)
+			subsys_notif_unregister_notifier(penv->wcnss_notif_hdle,
+				&wnb);
 		penv->pil = NULL;
 		goto fail_pil;
 	}
@@ -2540,11 +2562,6 @@
 	return NOTIFY_DONE;
 }
 
-static struct notifier_block wnb = {
-	.notifier_call = wcnss_notif_cb,
-};
-
-
 static const struct file_operations wcnss_node_fops = {
 	.owner = THIS_MODULE,
 	.open = wcnss_node_open,
diff --git a/drivers/platform/msm/qpnp-power-on.c b/drivers/platform/msm/qpnp-power-on.c
index 462bd3b..1a3baf5 100644
--- a/drivers/platform/msm/qpnp-power-on.c
+++ b/drivers/platform/msm/qpnp-power-on.c
@@ -1150,6 +1150,7 @@
 		return rc;
 	}
 
+	boot_reason = ffs(pon_sts);
 	index = ffs(pon_sts) - 1;
 	cold_boot = !qpnp_pon_is_warm_reset();
 	if (index >= ARRAY_SIZE(qpnp_pon_reason) || index < 0)
diff --git a/drivers/power/Kconfig b/drivers/power/Kconfig
index e42337f..e744d04 100644
--- a/drivers/power/Kconfig
+++ b/drivers/power/Kconfig
@@ -396,6 +396,17 @@
 	help
 	  Say Y here to enable support for batteries with BQ27520 (I2C) chips.
 
+config SMB358_CHARGER
+	tristate "SMB358 Battery Charger"
+	depends on I2C
+	help
+	  Say Y to include support for SMB358 Battery Charger.
+	  SMB358 is a single path switching mode charger capable of charging
+	  the battery with 2Amps of current.
+	  The driver supports charger enable/disable.
+	  The driver reports the charger status via the power supply framework.
+	  A charger status change triggers an IRQ via the device STAT pin.
+
 config BQ27520_TEST_ENABLE
 	bool "Enable BQ27520 Fuel Gauge Chip Test"
 	depends on BATTERY_BQ27520
diff --git a/drivers/power/Makefile b/drivers/power/Makefile
index 990bd03..8f152aa 100644
--- a/drivers/power/Makefile
+++ b/drivers/power/Makefile
@@ -56,6 +56,7 @@
 obj-$(CONFIG_BATTERY_BQ28400)	+= bq28400_battery.o
 obj-$(CONFIG_SMB137B_CHARGER)   += smb137b.o
 obj-$(CONFIG_SMB137C_CHARGER)	+= smb137c-charger.o
+obj-$(CONFIG_SMB358_CHARGER)	+= smb358-charger.o
 obj-$(CONFIG_PM8XXX_CCADC)	+= pm8xxx-ccadc.o
 obj-$(CONFIG_PM8921_BMS)	+= pm8921-bms.o
 obj-$(CONFIG_QPNP_BMS)		+= qpnp-bms.o
diff --git a/drivers/power/power_supply_core.c b/drivers/power/power_supply_core.c
index 97e952e..f10e1d4 100644
--- a/drivers/power/power_supply_core.c
+++ b/drivers/power/power_supply_core.c
@@ -26,6 +26,28 @@
 static struct device_type power_supply_dev_type;
 
 /**
+ * power_supply_set_voltage_limit - set current limit
+ * @psy:	the power supply to control
+ * @limit:	current limit in uV from the power supply.
+ *		0 will disable the power supply.
+ *
+ * This function will set a maximum supply current from a source
+ * and it will disable the charger when limit is 0.
+ */
+int power_supply_set_voltage_limit(struct power_supply *psy, int limit)
+{
+	const union power_supply_propval ret = {limit,};
+
+	if (psy->set_property)
+		return psy->set_property(psy, POWER_SUPPLY_PROP_VOLTAGE_MAX,
+								&ret);
+
+	return -ENXIO;
+}
+EXPORT_SYMBOL(power_supply_set_voltage_limit);
+
+
+/**
  * power_supply_set_current_limit - set current limit
  * @psy:	the power supply to control
  * @limit:	current limit in uA from the power supply.
diff --git a/drivers/power/qpnp-bms.c b/drivers/power/qpnp-bms.c
index ed0279e..e227ecd 100644
--- a/drivers/power/qpnp-bms.c
+++ b/drivers/power/qpnp-bms.c
@@ -281,6 +281,7 @@
 	u8				charge_increase;
 	int				fcc_resolution;
 	bool				battery_removed;
+	bool				in_taper_charge;
 	struct bms_irq			sw_cc_thr_irq;
 	struct bms_irq			ocv_thr_irq;
 	struct qpnp_vadc_chip		*vadc_dev;
@@ -751,13 +752,18 @@
 static int get_battery_status(struct qpnp_bms_chip *chip)
 {
 	union power_supply_propval ret = {0,};
+	int rc;
 
 	if (chip->batt_psy == NULL)
 		chip->batt_psy = power_supply_get_by_name("battery");
 	if (chip->batt_psy) {
 		/* if battery has been registered, use the status property */
-		chip->batt_psy->get_property(chip->batt_psy,
+		rc = chip->batt_psy->get_property(chip->batt_psy,
 					POWER_SUPPLY_PROP_STATUS, &ret);
+		if (rc) {
+			pr_debug("Battery does not export status: %d\n", rc);
+			return POWER_SUPPLY_STATUS_UNKNOWN;
+		}
 		return ret.intval;
 	}
 
@@ -766,22 +772,33 @@
 	return POWER_SUPPLY_STATUS_UNKNOWN;
 }
 
-static bool is_battery_charging(struct qpnp_bms_chip *chip)
+static int get_battery_charge_type(struct qpnp_bms_chip *chip)
 {
 	union power_supply_propval ret = {0,};
+	int rc;
 
 	if (chip->batt_psy == NULL)
 		chip->batt_psy = power_supply_get_by_name("battery");
 	if (chip->batt_psy) {
-		/* if battery has been registered, use the status property */
-		chip->batt_psy->get_property(chip->batt_psy,
-					POWER_SUPPLY_PROP_CHARGE_TYPE, &ret);
-		return ret.intval != POWER_SUPPLY_CHARGE_TYPE_NONE;
+		/* if battery has been registered, use the type property */
+		rc = chip->batt_psy->get_property(chip->batt_psy,
+				POWER_SUPPLY_PROP_CHARGE_TYPE, &ret);
+		if (rc) {
+			pr_debug("Battery does not export charge type: %d\n"
+									, rc);
+			return POWER_SUPPLY_CHARGE_TYPE_NONE;
+		}
+		return ret.intval;
 	}
 
 	/* Default to false if the battery power supply is not registered. */
 	pr_debug("battery power supply is not registered\n");
-	return false;
+	return POWER_SUPPLY_CHARGE_TYPE_NONE;
+}
+
+static bool is_battery_charging(struct qpnp_bms_chip *chip)
+{
+	return get_battery_status(chip) == POWER_SUPPLY_STATUS_CHARGING;
 }
 
 static bool is_battery_full(struct qpnp_bms_chip *chip)
@@ -809,8 +826,12 @@
 		chip->batt_psy = power_supply_get_by_name("battery");
 	if (chip->batt_psy) {
 		/* if battery has been registered, use the present property */
-		chip->batt_psy->get_property(chip->batt_psy,
+		rc = chip->batt_psy->get_property(chip->batt_psy,
 					POWER_SUPPLY_PROP_PRESENT, &ret);
+		if (rc) {
+			pr_debug("battery does not export present: %d\n", rc);
+			return true;
+		}
 		return ret.intval;
 	}
 
@@ -851,13 +872,18 @@
 static bool is_batfet_closed(struct qpnp_bms_chip *chip)
 {
 	union power_supply_propval ret = {0,};
+	int rc;
 
 	if (chip->batt_psy == NULL)
 		chip->batt_psy = power_supply_get_by_name("battery");
 	if (chip->batt_psy) {
 		/* if battery has been registered, use the online property */
-		chip->batt_psy->get_property(chip->batt_psy,
+		rc = chip->batt_psy->get_property(chip->batt_psy,
 					POWER_SUPPLY_PROP_ONLINE, &ret);
+		if (rc) {
+			pr_debug("Battery does not export online: %d\n", rc);
+			return true;
+		}
 		return !!ret.intval;
 	}
 
@@ -907,13 +933,32 @@
 	return 0;
 }
 
-static int estimate_ocv(struct qpnp_bms_chip *chip)
+static int get_rbatt(struct qpnp_bms_chip *chip,
+					int soc_rbatt_mohm, int batt_temp)
 {
-	int ibat_ua, vbat_uv, ocv_est_uv;
-	int rc;
-	int rbatt_mohm = chip->default_rbatt_mohm + chip->r_conn_mohm
-					+ chip->rbatt_capacitive_mohm;
+	int rbatt_mohm, scalefactor;
 
+	rbatt_mohm = chip->default_rbatt_mohm;
+	if (chip->rbatt_sf_lut == NULL)  {
+		pr_debug("RBATT = %d\n", rbatt_mohm);
+		return rbatt_mohm;
+	}
+	/* Convert the batt_temp to DegC from deciDegC */
+	scalefactor = interpolate_scalingfactor(chip->rbatt_sf_lut,
+						batt_temp, soc_rbatt_mohm);
+	rbatt_mohm = (rbatt_mohm * scalefactor) / 100;
+
+	rbatt_mohm += chip->r_conn_mohm;
+	rbatt_mohm += chip->rbatt_capacitive_mohm;
+	return rbatt_mohm;
+}
+
+#define DEFAULT_RBATT_SOC	50
+static int estimate_ocv(struct qpnp_bms_chip *chip, int batt_temp)
+{
+	int ibat_ua, vbat_uv, ocv_est_uv, rbatt_mohm, rc;
+
+	rbatt_mohm = get_rbatt(chip, DEFAULT_RBATT_SOC, batt_temp);
 	rc = get_simultaneous_batt_v_and_i(chip, &ibat_ua, &vbat_uv);
 	if (rc) {
 		pr_err("simultaneous failed rc = %d\n", rc);
@@ -921,10 +966,12 @@
 	}
 
 	ocv_est_uv = vbat_uv + (ibat_ua * rbatt_mohm) / 1000;
-	pr_debug("estimated pon ocv = %d\n", ocv_est_uv);
+	pr_debug("estimated pon ocv = %d, vbat_uv = %d ibat_ua = %d rbatt_mohm = %d\n",
+			ocv_est_uv, vbat_uv, ibat_ua, rbatt_mohm);
 	return ocv_est_uv;
 }
 
+#define MIN_IAVG_MA 250
 static void reset_for_new_battery(struct qpnp_bms_chip *chip, int batt_temp)
 {
 	chip->last_ocv_uv = chip->insertion_ocv_uv;
@@ -935,7 +982,7 @@
 	chip->soc_at_cv = -EINVAL;
 	chip->shutdown_soc_invalid = true;
 	chip->shutdown_soc = 0;
-	chip->shutdown_iavg_ma = 0;
+	chip->shutdown_iavg_ma = MIN_IAVG_MA;
 	chip->prev_pc_unusable = -EINVAL;
 	reset_cc(chip, CLEAR_CC | CLEAR_SHDW_CC);
 	chip->software_cc_uah = 0;
@@ -963,16 +1010,15 @@
 static int find_ocv_for_pc(struct qpnp_bms_chip *chip, int batt_temp, int pc)
 {
 	int new_pc;
-	int batt_temp_degc = batt_temp / 10;
 	int ocv_mv;
 	int delta_mv = 5;
 	int max_spin_count;
 	int count = 0;
 	int sign, new_sign;
 
-	ocv_mv = interpolate_ocv(chip->pc_temp_ocv_lut, batt_temp_degc, pc);
+	ocv_mv = interpolate_ocv(chip->pc_temp_ocv_lut, batt_temp, pc);
 
-	new_pc = interpolate_pc(chip->pc_temp_ocv_lut, batt_temp_degc, ocv_mv);
+	new_pc = interpolate_pc(chip->pc_temp_ocv_lut, batt_temp, ocv_mv);
 	pr_debug("test revlookup pc = %d for ocv = %d\n", new_pc, ocv_mv);
 	max_spin_count = 1 + (chip->max_voltage_uv - chip->v_cutoff_uv)
 						/ UV_PER_SPIN;
@@ -1003,7 +1049,7 @@
 
 		ocv_mv = ocv_mv + delta_mv * sign;
 		new_pc = interpolate_pc(chip->pc_temp_ocv_lut,
-				batt_temp_degc, ocv_mv);
+				batt_temp, ocv_mv);
 		pr_debug("test revlookup pc = %d for ocv = %d\n",
 			new_pc, ocv_mv);
 		count++;
@@ -1028,14 +1074,14 @@
 			chip->base + BMS1_OCV_FOR_SOC_DATA0, 2);
 	if (rc) {
 		pr_err("Error reading ocv: rc = %d\n", rc);
-		return -ENXIO;
+		goto param_err;
 	}
 
 	rc = read_cc_raw(chip, &raw->cc, CC);
 	rc = read_cc_raw(chip, &raw->shdw_cc, SHDW_CC);
 	if (rc) {
 		pr_err("Failed to read raw cc data, rc = %d\n", rc);
-		return rc;
+		goto param_err;
 	}
 
 	unlock_output_data(chip);
@@ -1046,10 +1092,9 @@
 		pr_debug("PON_OCV_UV = %d, cc = %llx\n",
 				chip->last_ocv_uv, raw->cc);
 		warm_reset = qpnp_pon_is_warm_reset();
-		if (raw->last_good_ocv_uv < MIN_OCV_UV
-				|| warm_reset > 0) {
+		if (raw->last_good_ocv_uv < MIN_OCV_UV || warm_reset > 0) {
 			pr_debug("OCV is stale or bad, estimating new OCV.\n");
-			chip->last_ocv_uv = estimate_ocv(chip);
+			chip->last_ocv_uv = estimate_ocv(chip, batt_temp);
 			raw->last_good_ocv_uv = chip->last_ocv_uv;
 			reset_cc(chip, CLEAR_CC | CLEAR_SHDW_CC);
 			pr_debug("New PON_OCV_UV = %d, cc = %llx\n",
@@ -1093,6 +1138,11 @@
 			raw->last_good_ocv_raw, raw->last_good_ocv_uv);
 	pr_debug("cc_raw= 0x%llx\n", raw->cc);
 	return 0;
+
+param_err:
+	unlock_output_data(chip);
+	mutex_unlock(&chip->bms_output_lock);
+	return rc;
 }
 
 static int calculate_pc(struct qpnp_bms_chip *chip, int ocv_uv,
@@ -1101,7 +1151,7 @@
 	int pc;
 
 	pc = interpolate_pc(chip->pc_temp_ocv_lut,
-			batt_temp / 10, ocv_uv / 1000);
+			batt_temp, ocv_uv / 1000);
 	pr_debug("pc = %u %% for ocv = %d uv batt_temp = %d\n",
 					pc, ocv_uv, batt_temp);
 	/* Multiply the initial FCC value by the scale factor. */
@@ -1213,27 +1263,6 @@
 	}
 }
 
-static int get_rbatt(struct qpnp_bms_chip *chip,
-					int soc_rbatt_mohm, int batt_temp)
-{
-	int rbatt_mohm, scalefactor;
-
-	rbatt_mohm = chip->default_rbatt_mohm;
-	if (chip->rbatt_sf_lut == NULL)  {
-		pr_debug("RBATT = %d\n", rbatt_mohm);
-		return rbatt_mohm;
-	}
-	/* Convert the batt_temp to DegC from deciDegC */
-	batt_temp = batt_temp / 10;
-	scalefactor = interpolate_scalingfactor(chip->rbatt_sf_lut,
-						batt_temp, soc_rbatt_mohm);
-	rbatt_mohm = (rbatt_mohm * scalefactor) / 100;
-
-	rbatt_mohm += chip->r_conn_mohm;
-	rbatt_mohm += chip->rbatt_capacitive_mohm;
-	return rbatt_mohm;
-}
-
 #define IAVG_MINIMAL_TIME	2
 static void calculate_iavg(struct qpnp_bms_chip *chip, int cc_uah,
 				int *iavg_ua, int delta_time_s)
@@ -1268,7 +1297,6 @@
 	int unusable_uv, pc_unusable, uuc_uah;
 	int i = 0;
 	int ocv_mv;
-	int batt_temp_degc = batt_temp / 10;
 	int rbatt_mohm;
 	int delta_uv;
 	int prev_delta_uv = 0;
@@ -1277,7 +1305,7 @@
 
 	for (i = 0; i <= 100; i++) {
 		ocv_mv = interpolate_ocv(chip->pc_temp_ocv_lut,
-				batt_temp_degc, i);
+				batt_temp, i);
 		rbatt_mohm = get_rbatt(chip, i, batt_temp);
 		unusable_uv = (rbatt_mohm * uuc_iavg_ma)
 							+ (chip->v_cutoff_uv);
@@ -1314,13 +1342,12 @@
 			int batt_temp)
 {
 	int new_unusable_mv, new_iavg_ma;
-	int batt_temp_degc = batt_temp / 10;
 	int max_percent_change;
 
 	max_percent_change = max(params->delta_time_s
 				/ TIME_PER_PERCENT_UUC, 1);
 
-	if (chip->prev_pc_unusable == -EINVAL
+	if (chip->first_time_calc_uuc || chip->prev_pc_unusable == -EINVAL
 		|| abs(chip->prev_pc_unusable - new_pc_unusable)
 			<= max_percent_change) {
 		chip->prev_pc_unusable = new_pc_unusable;
@@ -1337,7 +1364,7 @@
 
 	/* also find update the iavg_ma accordingly */
 	new_unusable_mv = interpolate_ocv(chip->pc_temp_ocv_lut,
-			batt_temp_degc, chip->prev_pc_unusable);
+			batt_temp, chip->prev_pc_unusable);
 	if (new_unusable_mv < chip->v_cutoff_uv/1000)
 		new_unusable_mv = chip->v_cutoff_uv/1000;
 
@@ -1353,7 +1380,6 @@
 	return new_uuc_uah;
 }
 
-#define MIN_IAVG_MA 250
 static int calculate_unusable_charge_uah(struct qpnp_bms_chip *chip,
 					struct soc_params *params,
 					int batt_temp)
@@ -1503,7 +1529,7 @@
 
 	mutex_lock(&chip->bms_output_lock);
 	lock_output_data(chip);
-	read_cc_raw(chip, &cc_raw, false);
+	read_cc_raw(chip, &cc_raw, CC);
 	unlock_output_data(chip);
 	mutex_unlock(&chip->bms_output_lock);
 
@@ -1517,7 +1543,7 @@
 
 	mutex_lock(&chip->bms_output_lock);
 	lock_output_data(chip);
-	read_cc_raw(chip, &cc_raw, true);
+	read_cc_raw(chip, &cc_raw, SHDW_CC);
 	unlock_output_data(chip);
 	mutex_unlock(&chip->bms_output_lock);
 
@@ -1809,7 +1835,7 @@
 	last_change_sec = chip->last_soc_change_sec;
 	calculate_delta_time(&last_change_sec, &time_since_last_change_sec);
 
-	charging = is_battery_charging(chip);
+	charging = chip->battery_status == POWER_SUPPLY_STATUS_CHARGING;
 	charging_since_last_report = charging || (chip->last_soc_unbound
 			&& chip->was_charging_at_sleep);
 	/*
@@ -1918,7 +1944,8 @@
 	batt_terminal_uv = vbat_uv + (ibat_ua * chip->r_conn_mohm) / 1000;
 
 	if (chip->soc_at_cv == -EINVAL) {
-		if (batt_terminal_uv >= chip->max_voltage_uv - VDD_MAX_ERR) {
+		if (batt_terminal_uv >= chip->max_voltage_uv - VDD_MAX_ERR ||
+							chip->in_taper_charge) {
 			chip->soc_at_cv = soc;
 			chip->prev_chg_soc = soc;
 			chip->ibat_at_cv_ua = params->iavg_ua;
@@ -3138,7 +3165,7 @@
 
 	if (start) {
 		chip->start_pc = interpolate_pc(chip->pc_temp_ocv_lut,
-			batt_temp / 10, raw.last_good_ocv_uv / 1000);
+			batt_temp, raw.last_good_ocv_uv / 1000);
 		chip->start_cc_uah = calculate_cc(chip, raw.cc, CC, NORESET);
 		chip->start_real_soc = calculate_real_soc(chip,
 				batt_temp, &raw, chip->start_cc_uah);
@@ -3237,6 +3264,7 @@
 	mutex_lock(&chip->last_ocv_uv_mutex);
 	chip->soc_at_cv = -EINVAL;
 	chip->prev_chg_soc = -EINVAL;
+	chip->in_taper_charge = false;
 
 	/* update the chargecycles */
 	if (chip->end_soc > chip->start_soc) {
@@ -3368,6 +3396,11 @@
 	battery_insertion_check(chip);
 	batfet_status_check(chip);
 	battery_status_check(chip);
+
+	if (POWER_SUPPLY_CHARGE_TYPE_TAPER == get_battery_charge_type(chip))
+		chip->in_taper_charge = true;
+	else
+		chip->in_taper_charge = false;
 }
 
 static int qpnp_bms_power_get_property(struct power_supply *psy,
@@ -3532,6 +3565,7 @@
 	 * Do a quick run of SoC calculation to find whether the shutdown soc
 	 * is close enough.
 	 */
+	chip->shutdown_iavg_ma = MIN_IAVG_MA;
 	calculated_soc = recalculate_raw_soc(chip);
 	shutdown_soc_out_of_limit = (abs(shutdown_soc - calculated_soc)
 			> chip->shutdown_soc_valid_limit);
@@ -3905,8 +3939,10 @@
 	int rc;
 
 	SPMI_REQUEST_IRQ(chip, rc, sw_cc_thr);
+	disable_bms_irq(&chip->sw_cc_thr_irq);
 	enable_irq_wake(chip->sw_cc_thr_irq.irq);
 	SPMI_REQUEST_IRQ(chip, rc, ocv_thr);
+	disable_bms_irq(&chip->ocv_thr_irq);
 	enable_irq_wake(chip->ocv_thr_irq.irq);
 	return 0;
 }
diff --git a/drivers/power/qpnp-charger.c b/drivers/power/qpnp-charger.c
index 6301724..d5c753f 100644
--- a/drivers/power/qpnp-charger.c
+++ b/drivers/power/qpnp-charger.c
@@ -117,7 +117,7 @@
 #define USB_SPARE				0xDF
 #define DC_COMP_OVR1				0xE9
 #define CHGR_COMP_OVR1				0xEE
-
+#define USB_CHGPTH_CTL				0x40
 #define REG_OFFSET_PERP_SUBTYPE			0x05
 
 /* SMBB peripheral subtype values */
@@ -164,6 +164,7 @@
 #define OCP_THR_900_MA			0x02
 #define OCP_THR_500_MA			0x01
 #define OCP_THR_200_MA			0x00
+#define DC_HIGHER_PRIORITY		BIT(7)
 
 /* Interrupt definitions */
 /* smbb_chg_interrupts */
@@ -670,6 +671,25 @@
 }
 
 static bool
+qpnp_is_dc_higher_prio(struct qpnp_chg_chip *chip)
+{
+	int rc;
+	u8 usb_ctl;
+
+	if (!chip->type == SMBB)
+		return false;
+
+	rc = qpnp_chg_read(chip, &usb_ctl,
+			chip->usb_chgpth_base + USB_CHGPTH_CTL, 1);
+	if (rc) {
+		pr_err("failed to read usb ctl rc=%d\n", rc);
+		return 0;
+	}
+
+	return !!(usb_ctl & DC_HIGHER_PRIORITY);
+}
+
+static bool
 qpnp_chg_is_ibat_loop_active(struct qpnp_chg_chip *chip)
 {
 	int rc;
@@ -1578,7 +1598,10 @@
 	return rc;
 }
 
+#define USB_WALL_THRESHOLD_MA	500
 #define ENUM_T_STOP_BIT		BIT(0)
+#define USB_5V_UV	5000000
+#define USB_9V_UV	9000000
 static irqreturn_t
 qpnp_chg_usb_usbin_valid_irq_handler(int irq, void *_chip)
 {
@@ -1623,6 +1646,10 @@
 				qpnp_chg_set_appropriate_vddmax(chip);
 				chip->chg_done = false;
 			}
+
+			if (!qpnp_is_dc_higher_prio(chip))
+				qpnp_chg_idcmax_set(chip, chip->maxinput_dc_ma);
+
 			qpnp_chg_usb_suspend_enable(chip, 0);
 			qpnp_chg_iusbmax_set(chip, QPNP_CHG_I_MAX_MIN_100);
 			chip->prev_usb_max_ma = -EINVAL;
@@ -1800,6 +1827,23 @@
 				msecs_to_jiffies(EOC_CHECK_PERIOD_MS));
 			schedule_work(&chip->soc_check_work);
 		}
+
+		if (qpnp_is_dc_higher_prio(chip)) {
+			pr_debug("dc has higher priority\n");
+			if (dc_present) {
+				qpnp_chg_iusbmax_set(chip,
+						QPNP_CHG_I_MAX_MIN_100);
+				power_supply_set_voltage_limit(chip->usb_psy,
+						USB_5V_UV);
+			} else {
+				chip->aicl_settled = false;
+				qpnp_chg_iusbmax_set(chip,
+						USB_WALL_THRESHOLD_MA);
+				power_supply_set_voltage_limit(chip->usb_psy,
+						USB_9V_UV);
+			}
+		}
+
 		pr_debug("psy changed dc_psy\n");
 		power_supply_changed(&chip->dc_psy);
 		pr_debug("psy changed batt_psy\n");
@@ -2167,8 +2211,7 @@
 static int ext_ovp_present;
 module_param(ext_ovp_present, int, 0444);
 
-#define USB_WALL_THRESHOLD_MA	500
-#define OVP_USB_WALL_THRESHOLD_MA	200
+#define OVP_USB_WALL_TRSH_MA	200
 static int
 qpnp_power_get_property_mains(struct power_supply *psy,
 				  enum power_supply_property psp,
@@ -2540,15 +2583,23 @@
 			qpnp_chg_iusbmax_set(chip, QPNP_CHG_I_MAX_MIN_100);
 		} else {
 			qpnp_chg_usb_suspend_enable(chip, 0);
-			if (((ret.intval / 1000) > USB_WALL_THRESHOLD_MA)
+			if (qpnp_is_dc_higher_prio(chip)
+				&& qpnp_chg_is_dc_chg_plugged_in(chip)) {
+					pr_debug("dc has higher priority\n");
+					qpnp_chg_iusbmax_set(chip,
+							QPNP_CHG_I_MAX_MIN_100);
+			} else if (((ret.intval / 1000) > USB_WALL_THRESHOLD_MA)
 					&& (charger_monitor ||
 					!chip->charger_monitor_checked)) {
-				if (!ext_ovp_present)
-					qpnp_chg_iusbmax_set(chip,
-						USB_WALL_THRESHOLD_MA);
-				else
-					qpnp_chg_iusbmax_set(chip,
-						OVP_USB_WALL_THRESHOLD_MA);
+					if (!qpnp_is_dc_higher_prio(chip))
+						qpnp_chg_idcmax_set(chip,
+							QPNP_CHG_I_MAX_MIN_100);
+					if (!ext_ovp_present)
+						qpnp_chg_iusbmax_set(chip,
+							USB_WALL_THRESHOLD_MA);
+					else
+						qpnp_chg_iusbmax_set(chip,
+							OVP_USB_WALL_TRSH_MA);
 			} else {
 				qpnp_chg_iusbmax_set(chip, ret.intval / 1000);
 			}
@@ -3993,14 +4044,19 @@
 		qpnp_batt_system_temp_level_set(chip, val->intval);
 		break;
 	case POWER_SUPPLY_PROP_INPUT_CURRENT_MAX:
-		if (qpnp_chg_is_usb_chg_plugged_in(chip))
+		if (qpnp_chg_is_usb_chg_plugged_in(chip) &&
+			!(qpnp_is_dc_higher_prio(chip)
+			&& qpnp_chg_is_dc_chg_plugged_in(chip)))
 			qpnp_chg_iusbmax_set(chip, val->intval / 1000);
 		break;
 	case POWER_SUPPLY_PROP_INPUT_CURRENT_TRIM:
 		qpnp_chg_iusb_trim_set(chip, val->intval);
 		break;
 	case POWER_SUPPLY_PROP_INPUT_CURRENT_SETTLED:
-		qpnp_chg_input_current_settled(chip);
+		if (val->intval)
+			qpnp_chg_input_current_settled(chip);
+		else
+			chip->aicl_settled = false;
 		break;
 	case POWER_SUPPLY_PROP_VOLTAGE_MIN:
 		qpnp_chg_vinmin_set(chip, val->intval / 1000);
diff --git a/drivers/power/smb358-charger.c b/drivers/power/smb358-charger.c
new file mode 100644
index 0000000..6d241a0
--- /dev/null
+++ b/drivers/power/smb358-charger.c
@@ -0,0 +1,2491 @@
+/* Copyright (c) 2014 The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#define pr_fmt(fmt) "SMB358 %s: " fmt, __func__
+#include <linux/i2c.h>
+#include <linux/debugfs.h>
+#include <linux/gpio.h>
+#include <linux/errno.h>
+#include <linux/delay.h>
+#include <linux/module.h>
+#include <linux/interrupt.h>
+#include <linux/slab.h>
+#include <linux/power_supply.h>
+#include <linux/regulator/of_regulator.h>
+#include <linux/regulator/machine.h>
+#include <linux/regulator/consumer.h>
+#include <linux/regulator/driver.h>
+#include <linux/of.h>
+#include <linux/of_gpio.h>
+#include <linux/mutex.h>
+#include <linux/qpnp/qpnp-adc.h>
+
+/* Config/Control registers */
+#define CHG_CURRENT_CTRL_REG		0x0
+#define CHG_OTH_CURRENT_CTRL_REG	0x1
+#define VARIOUS_FUNC_REG		0x2
+#define VFLOAT_REG			0x3
+#define CHG_CTRL_REG			0x4
+#define STAT_AND_TIMER_CTRL_REG		0x5
+#define CHG_PIN_EN_CTRL_REG		0x6
+#define THERM_A_CTRL_REG		0x7
+#define SYSOK_AND_USB3_REG		0x8
+#define FAULT_INT_REG			0xC
+#define STATUS_INT_REG			0xD
+
+/* Command registers */
+#define CMD_A_REG			0x30
+#define CMD_B_REG			0x31
+
+/* IRQ status registers */
+#define IRQ_A_REG			0x35
+#define IRQ_B_REG			0x36
+#define IRQ_C_REG			0x37
+#define IRQ_D_REG			0x38
+#define IRQ_E_REG			0x39
+#define IRQ_F_REG			0x3A
+
+/* Status registers */
+#define STATUS_C_REG			0x3D
+#define STATUS_D_REG			0x3E
+#define STATUS_E_REG			0x3F
+
+/* Config bits */
+#define CHG_INHI_EN_MASK			BIT(1)
+#define CHG_INHI_EN_BIT				BIT(1)
+#define CMD_A_CHG_ENABLE_BIT			BIT(1)
+#define CMD_A_VOLATILE_W_PERM_BIT		BIT(7)
+#define CMD_A_CHG_SUSP_EN_BIT			BIT(2)
+#define CMD_A_CHG_SUSP_EN_MASK			BIT(2)
+#define CMD_A_OTG_ENABLE_BIT			BIT(4)
+#define CMD_A_OTG_ENABLE_MASK			BIT(4)
+#define CMD_B_CHG_HC_ENABLE_BIT			BIT(0)
+#define USB3_ENABLE_BIT				BIT(5)
+#define USB3_ENABLE_MASK			BIT(5)
+#define CMD_B_CHG_USB_500_900_ENABLE_BIT	BIT(1)
+#define CHG_CTRL_AUTO_RECHARGE_ENABLE_BIT	0x0
+#define CHG_CTRL_CURR_TERM_END_CHG_BIT		0x0
+#define CHG_CTRL_BATT_MISSING_DET_THERM_IO	(BIT(5) | BIT(4))
+#define CHG_CTRL_AUTO_RECHARGE_MASK		BIT(7)
+#define CHG_CTRL_CURR_TERM_END_MASK		BIT(6)
+#define CHG_CTRL_BATT_MISSING_DET_MASK		(BIT(5) | BIT(4))
+#define CHG_CTRL_APSD_EN_BIT			BIT(2)
+#define CHG_CTRL_APSD_EN_MASK			BIT(2)
+#define CHG_ITERM_MASK				0x07
+#define CHG_PIN_CTRL_USBCS_REG_BIT		0x0
+/* This is to select if use external pin EN to control CHG */
+#define CHG_PIN_CTRL_CHG_EN_LOW_PIN_BIT		(BIT(5) | BIT(6))
+#define CHG_PIN_CTRL_CHG_EN_LOW_REG_BIT		0x0
+#define CHG_PIN_CTRL_CHG_EN_MASK		(BIT(5) | BIT(6))
+
+#define CHG_PIN_CTRL_USBCS_REG_MASK		BIT(4)
+#define CHG_PIN_CTRL_APSD_IRQ_BIT		BIT(1)
+#define CHG_PIN_CTRL_APSD_IRQ_MASK		BIT(1)
+#define CHG_PIN_CTRL_CHG_ERR_IRQ_BIT		BIT(2)
+#define CHG_PIN_CTRL_CHG_ERR_IRQ_MASK		BIT(2)
+#define VARIOUS_FUNC_USB_SUSP_EN_REG_BIT	BIT(6)
+#define VARIOUS_FUNC_USB_SUSP_MASK		BIT(6)
+#define FAULT_INT_HOT_COLD_HARD_BIT		BIT(7)
+#define FAULT_INT_HOT_COLD_SOFT_BIT		BIT(6)
+#define FAULT_INT_INPUT_OV_BIT			BIT(3)
+#define FAULT_INT_INPUT_UV_BIT			BIT(2)
+#define FAULT_INT_AICL_COMPLETE_BIT		BIT(1)
+#define STATUS_INT_CHG_TIMEOUT_BIT		BIT(7)
+#define STATUS_INT_OTG_DETECT_BIT		BIT(6)
+#define STATUS_INT_BATT_OV_BIT			BIT(5)
+#define STATUS_INT_CHGING_BIT			BIT(4)
+#define STATUS_INT_CHG_INHI_BIT			BIT(3)
+#define STATUS_INT_INOK_BIT			BIT(2)
+#define STATUS_INT_MISSING_BATT_BIT		BIT(1)
+#define STATUS_INT_LOW_BATT_BIT			BIT(0)
+#define THERM_A_THERM_MONITOR_EN_BIT		0x0
+#define THERM_A_THERM_MONITOR_EN_MASK		BIT(4)
+#define VFLOAT_MASK				0x3F
+
+/* IRQ status bits */
+#define IRQ_A_HOT_HARD_BIT			BIT(6)
+#define IRQ_A_COLD_HARD_BIT			BIT(4)
+#define IRQ_A_HOT_SOFT_BIT			BIT(2)
+#define IRQ_A_COLD_SOFT_BIT			BIT(0)
+#define IRQ_B_BATT_MISSING_BIT			BIT(4)
+#define IRQ_B_BATT_LOW_BIT			BIT(2)
+#define IRQ_B_BATT_OV_BIT			BIT(6)
+#define IRQ_B_PRE_FAST_CHG_BIT			BIT(0)
+#define IRQ_C_TAPER_CHG_BIT			BIT(2)
+#define IRQ_C_TERM_BIT				BIT(0)
+#define IRQ_C_INT_OVER_TEMP_BIT			BIT(6)
+#define IRQ_D_CHG_TIMEOUT_BIT			(BIT(0) | BIT(2))
+#define IRQ_D_AICL_DONE_BIT			BIT(4)
+#define IRQ_D_APSD_COMPLETE			BIT(6)
+#define IRQ_E_INPUT_UV_BIT			BIT(0)
+#define IRQ_E_INPUT_OV_BIT			BIT(2)
+#define IRQ_E_AFVC_ACTIVE                       BIT(4)
+#define IRQ_F_OTG_VALID_BIT			BIT(2)
+#define IRQ_F_OTG_BATT_FAIL_BIT			BIT(4)
+#define IRQ_F_OTG_OC_BIT			BIT(6)
+#define IRQ_F_POWER_OK				BIT(0)
+
+/* Status  bits */
+#define STATUS_C_CHARGING_MASK			(BIT(1) | BIT(2))
+#define STATUS_C_FAST_CHARGING			BIT(2)
+#define STATUS_C_PRE_CHARGING			BIT(1)
+#define STATUS_C_TAPER_CHARGING			(BIT(2) | BIT(1))
+#define STATUS_C_CHG_ERR_STATUS_BIT		BIT(6)
+#define STATUS_C_CHG_ENABLE_STATUS_BIT		BIT(0)
+#define STATUS_C_CHG_HOLD_OFF_BIT		BIT(3)
+#define STATUS_D_PORT_OTHER			BIT(0)
+#define STATUS_D_PORT_SDP			BIT(1)
+#define STATUS_D_PORT_DCP			BIT(2)
+#define STATUS_D_PORT_CDP			BIT(3)
+#define STATUS_D_PORT_ACA_A			BIT(4)
+#define STATUS_D_PORT_ACA_B			BIT(5)
+#define STATUS_D_PORT_ACA_C			BIT(6)
+#define STATUS_D_PORT_ACA_DOCK			BIT(7)
+
+/* constants */
+#define USB2_MIN_CURRENT_MA		100
+#define USB2_MAX_CURRENT_MA		500
+#define USB3_MIN_CURRENT_MA		150
+#define USB3_MAX_CURRENT_MA		900
+#define AC_CHG_CURRENT_MASK		0x70
+#define AC_CHG_CURRENT_SHIFT		4
+#define SMB358_IRQ_REG_COUNT		6
+#define SMB358_FAST_CHG_MIN_MA		200
+#define SMB358_FAST_CHG_MAX_MA		2000
+#define SMB358_FAST_CHG_SHIFT		5
+#define SMB_FAST_CHG_CURRENT_MASK	0xE0
+#define SMB358_DEFAULT_BATT_CAPACITY	50
+
+enum {
+	USER	= BIT(0),
+	THERMAL = BIT(1),
+	CURRENT = BIT(2),
+};
+
+struct smb358_regulator {
+	struct regulator_desc	rdesc;
+	struct regulator_dev	*rdev;
+};
+
+struct smb358_charger {
+	struct i2c_client	*client;
+	struct device		*dev;
+
+	bool			recharge_disabled;
+	int			recharge_mv;
+	bool			iterm_disabled;
+	int			iterm_ma;
+	int			vfloat_mv;
+	int			chg_valid_gpio;
+	int			chg_valid_act_low;
+	int			chg_present;
+	int			fake_battery_soc;
+	bool			chg_autonomous_mode;
+	bool			disable_apsd;
+	bool			using_pmic_therm;
+	bool			battery_missing;
+	const char		*bms_psy_name;
+	bool			resume_completed;
+	bool			irq_waiting;
+	struct mutex		read_write_lock;
+	struct mutex		path_suspend_lock;
+	struct mutex		irq_complete;
+	u8			irq_cfg_mask[2];
+	int			irq_gpio;
+	int			charging_disabled;
+	int			fastchg_current_max_ma;
+
+	/* debugfs related */
+#if defined(CONFIG_DEBUG_FS)
+	struct dentry		*debug_root;
+	u32			peek_poke_address;
+#endif
+	/* status tracking */
+	bool			batt_full;
+	bool			batt_hot;
+	bool			batt_cold;
+	bool			batt_warm;
+	bool			batt_cool;
+	int			charging_disabled_status;
+	int			usb_suspended;
+
+	/* power supply */
+	struct power_supply	*usb_psy;
+	struct power_supply	*bms_psy;
+	struct power_supply	batt_psy;
+
+	/* otg 5V regulator */
+	struct smb358_regulator	otg_vreg;
+
+	/* adc_tm paramters */
+	struct qpnp_vadc_chip	*vadc_dev;
+	struct qpnp_adc_tm_chip	*adc_tm_dev;
+	struct qpnp_adc_tm_btm_param	adc_param;
+	int			cold_bat_decidegc;
+	int			hot_bat_decidegc;
+	int			bat_present_decidegc;
+	/* i2c pull up regulator */
+	struct regulator	*vcc_i2c;
+};
+
+struct smb_irq_info {
+	const char		*name;
+	int			(*smb_irq)(struct smb358_charger *chip,
+							u8 rt_stat);
+	int			high;
+	int			low;
+};
+
+struct irq_handler_info {
+	u8			stat_reg;
+	u8			val;
+	u8			prev_val;
+	struct smb_irq_info	irq_info[4];
+};
+
+static int chg_current[] = {
+	300, 500, 700, 1000, 1200, 1500, 1800, 2000,
+};
+
+static int fast_chg_current[] = {
+	200, 450, 600, 900, 1300, 1500, 1800, 2000,
+};
+
+/* add supplied to "bms" function */
+static char *pm_batt_supplied_to[] = {
+	"bms",
+};
+
+static int __smb358_read_reg(struct smb358_charger *chip, u8 reg, u8 *val)
+{
+	s32 ret;
+
+	ret = i2c_smbus_read_byte_data(chip->client, reg);
+	if (ret < 0) {
+		dev_err(chip->dev,
+			"i2c read fail: can't read from %02x: %d\n", reg, ret);
+		return ret;
+	} else {
+		*val = ret;
+	}
+
+	return 0;
+}
+
+static int __smb358_write_reg(struct smb358_charger *chip, int reg, u8 val)
+{
+	s32 ret;
+
+	ret = i2c_smbus_write_byte_data(chip->client, reg, val);
+	if (ret < 0) {
+		dev_err(chip->dev,
+			"i2c write fail: can't write %02x to %02x: %d\n",
+			val, reg, ret);
+		return ret;
+	}
+	return 0;
+}
+
+static int smb358_read_reg(struct smb358_charger *chip, int reg,
+						u8 *val)
+{
+	int rc;
+
+	mutex_lock(&chip->read_write_lock);
+	rc = __smb358_read_reg(chip, reg, val);
+	mutex_unlock(&chip->read_write_lock);
+
+	return rc;
+}
+
+static int smb358_write_reg(struct smb358_charger *chip, int reg,
+						u8 val)
+{
+	int rc;
+
+	mutex_lock(&chip->read_write_lock);
+	rc = __smb358_write_reg(chip, reg, val);
+	mutex_unlock(&chip->read_write_lock);
+
+	return rc;
+}
+
+static int smb358_masked_write(struct smb358_charger *chip, int reg,
+							u8 mask, u8 val)
+{
+	s32 rc;
+	u8 temp;
+
+	mutex_lock(&chip->read_write_lock);
+	rc = __smb358_read_reg(chip, reg, &temp);
+	if (rc) {
+		dev_err(chip->dev,
+			"smb358_read_reg Failed: reg=%03X, rc=%d\n", reg, rc);
+		goto out;
+	}
+	temp &= ~mask;
+	temp |= val & mask;
+	rc = __smb358_write_reg(chip, reg, temp);
+	if (rc) {
+		dev_err(chip->dev,
+			"smb358_write Failed: reg=%03X, rc=%d\n", reg, rc);
+	}
+out:
+	mutex_unlock(&chip->read_write_lock);
+	return rc;
+}
+
+static int smb358_enable_volatile_writes(struct smb358_charger *chip)
+{
+	int rc;
+
+	rc = smb358_masked_write(chip, CMD_A_REG, CMD_A_VOLATILE_W_PERM_BIT,
+						CMD_A_VOLATILE_W_PERM_BIT);
+	if (rc)
+		dev_err(chip->dev, "Couldn't write VOLATILE_W_PERM_BIT rc=%d\n",
+				rc);
+
+	return rc;
+}
+
+static int smb358_fastchg_current_set(struct smb358_charger *chip)
+{
+	int i;
+
+	if ((chip->fastchg_current_max_ma < SMB358_FAST_CHG_MIN_MA) ||
+		(chip->fastchg_current_max_ma >  SMB358_FAST_CHG_MAX_MA)) {
+		dev_dbg(chip->dev, "bad fastchg current mA=%d asked to set\n",
+					chip->fastchg_current_max_ma);
+		return -EINVAL;
+	}
+
+	for (i = ARRAY_SIZE(fast_chg_current) - 1; i >= 0; i--) {
+		if (fast_chg_current[i] <= chip->fastchg_current_max_ma)
+			break;
+	}
+
+	if (i < 0) {
+		dev_err(chip->dev, "Invalid current setting %dmA\n",
+					chip->fastchg_current_max_ma);
+		i = 0;
+	}
+
+	i = i << SMB358_FAST_CHG_SHIFT;
+	dev_dbg(chip->dev, "fastchg limit=%d setting %02x\n",
+			chip->fastchg_current_max_ma, i);
+
+	return smb358_masked_write(chip, CHG_CURRENT_CTRL_REG,
+				SMB_FAST_CHG_CURRENT_MASK, i);
+}
+
+#define MIN_FLOAT_MV		3500
+#define MAX_FLOAT_MV		4500
+#define VFLOAT_STEP_MV		20
+#define VFLOAT_4350MV		4350
+static int smb358_float_voltage_set(struct smb358_charger *chip, int vfloat_mv)
+{
+	u8 temp;
+
+	if ((vfloat_mv < MIN_FLOAT_MV) || (vfloat_mv > MAX_FLOAT_MV)) {
+		dev_err(chip->dev, "bad float voltage mv =%d asked to set\n",
+					vfloat_mv);
+		return -EINVAL;
+	}
+
+	if (VFLOAT_4350MV == vfloat_mv)
+		temp = 0x2B;
+	else if (vfloat_mv > VFLOAT_4350MV)
+		temp = (vfloat_mv - MIN_FLOAT_MV) / VFLOAT_STEP_MV - 1;
+	else
+		temp = (vfloat_mv - MIN_FLOAT_MV) / VFLOAT_STEP_MV;
+
+	return smb358_masked_write(chip, VFLOAT_REG, VFLOAT_MASK, temp);
+}
+
+#define CHG_ITERM_30MA			0x00
+#define CHG_ITERM_40MA			0x01
+#define CHG_ITERM_60MA			0x02
+#define CHG_ITERM_80MA			0x03
+#define CHG_ITERM_100MA			0x04
+#define CHG_ITERM_125MA			0x05
+#define CHG_ITERM_150MA			0x06
+#define CHG_ITERM_200MA			0x07
+static int smb358_term_current_set(struct smb358_charger *chip)
+{
+	u8 reg = 0;
+	int rc;
+
+	if (chip->iterm_ma != -EINVAL) {
+		if (chip->iterm_disabled)
+			dev_err(chip->dev, "Error: Both iterm_disabled and iterm_ma set\n");
+
+		if (chip->iterm_ma <= 30)
+			reg = CHG_ITERM_30MA;
+		else if (chip->iterm_ma <= 40)
+			reg = CHG_ITERM_40MA;
+		else if (chip->iterm_ma <= 60)
+			reg = CHG_ITERM_60MA;
+		else if (chip->iterm_ma <= 80)
+			reg = CHG_ITERM_80MA;
+		else if (chip->iterm_ma <= 100)
+			reg = CHG_ITERM_100MA;
+		else if (chip->iterm_ma <= 125)
+			reg = CHG_ITERM_125MA;
+		else if (chip->iterm_ma <= 150)
+			reg = CHG_ITERM_150MA;
+		else
+			reg = CHG_ITERM_200MA;
+
+		rc = smb358_masked_write(chip, CHG_CURRENT_CTRL_REG,
+							CHG_ITERM_MASK, reg);
+		if (rc) {
+			dev_err(chip->dev,
+				"Couldn't set iterm rc = %d\n", rc);
+			return rc;
+		}
+	}
+
+	if (chip->iterm_disabled) {
+		rc = smb358_masked_write(chip, CHG_CTRL_REG,
+					CHG_CTRL_CURR_TERM_END_MASK,
+					CHG_CTRL_CURR_TERM_END_MASK);
+		if (rc) {
+			dev_err(chip->dev, "Couldn't set iterm rc = %d\n",
+								rc);
+			return rc;
+		}
+	} else {
+		rc = smb358_masked_write(chip, CHG_CTRL_REG,
+					CHG_CTRL_CURR_TERM_END_MASK, 0);
+		if (rc) {
+			dev_err(chip->dev,
+				"Couldn't enable iterm rc = %d\n", rc);
+			return rc;
+		}
+	}
+
+	return 0;
+}
+
+#define VFLT_300MV			0x0C
+#define VFLT_200MV			0x08
+#define VFLT_100MV			0x04
+#define VFLT_50MV			0x00
+#define VFLT_MASK			0x0C
+static int smb358_recharge_set(struct smb358_charger *chip)
+{
+	u8 reg = 0;
+	int rc;
+
+	if (chip->recharge_disabled)
+		rc = smb358_masked_write(chip, CHG_OTH_CURRENT_CTRL_REG,
+					CHG_INHI_EN_MASK, 0x0);
+	else
+		rc = smb358_masked_write(chip, CHG_OTH_CURRENT_CTRL_REG,
+					CHG_INHI_EN_MASK, CHG_INHI_EN_BIT);
+	if (rc) {
+		dev_err(chip->dev,
+			"Couldn't set inhibit en reg rc = %d\n", rc);
+		return rc;
+	}
+
+	if (chip->recharge_mv != -EINVAL) {
+		if (chip->recharge_mv <= 50)
+			reg = VFLT_50MV;
+		else if (chip->recharge_mv <= 100)
+			reg = VFLT_100MV;
+		else if (chip->recharge_mv <= 200)
+			reg = VFLT_200MV;
+		else
+			reg = VFLT_300MV;
+
+		rc = smb358_masked_write(chip, CHG_OTH_CURRENT_CTRL_REG,
+						VFLT_MASK, reg);
+		if (rc) {
+			dev_err(chip->dev,
+				"Couldn't set inhibit threshold rc = %d\n", rc);
+			return rc;
+		}
+	}
+
+	return 0;
+}
+
+static int smb358_chg_otg_regulator_enable(struct regulator_dev *rdev)
+{
+	int rc = 0;
+	struct smb358_charger *chip = rdev_get_drvdata(rdev);
+
+	rc = smb358_masked_write(chip, CMD_A_REG, CMD_A_OTG_ENABLE_BIT,
+							CMD_A_OTG_ENABLE_BIT);
+	if (rc)
+		dev_err(chip->dev, "Couldn't enable OTG mode rc=%d, reg=%2x\n",
+								rc, CMD_A_REG);
+	return rc;
+}
+
+static int smb358_chg_otg_regulator_disable(struct regulator_dev *rdev)
+{
+	int rc = 0;
+	struct smb358_charger *chip = rdev_get_drvdata(rdev);
+
+	rc = smb358_masked_write(chip, CMD_A_REG, CMD_A_OTG_ENABLE_BIT, 0);
+	if (rc)
+		dev_err(chip->dev, "Couldn't disable OTG mode rc=%d, reg=%2x\n",
+								rc, CMD_A_REG);
+	return rc;
+}
+
+static int smb358_chg_otg_regulator_is_enable(struct regulator_dev *rdev)
+{
+	int rc = 0;
+	u8 reg = 0;
+	struct smb358_charger *chip = rdev_get_drvdata(rdev);
+
+	rc = smb358_read_reg(chip, CMD_A_REG, &reg);
+	if (rc) {
+		dev_err(chip->dev,
+			"Couldn't read OTG enable bit rc=%d, reg=%2x\n",
+							rc, CMD_A_REG);
+		return rc;
+	}
+
+	return  (reg & CMD_A_OTG_ENABLE_BIT) ? 1 : 0;
+}
+
+struct regulator_ops smb358_chg_otg_reg_ops = {
+	.enable		= smb358_chg_otg_regulator_enable,
+	.disable	= smb358_chg_otg_regulator_disable,
+	.is_enabled	= smb358_chg_otg_regulator_is_enable,
+};
+
+static int smb358_regulator_init(struct smb358_charger *chip)
+{
+	int rc = 0;
+	struct regulator_init_data *init_data;
+	struct regulator_config cfg;
+
+	init_data = of_get_regulator_init_data(chip->dev, chip->dev->of_node);
+	if (!init_data) {
+		dev_err(chip->dev, "Get regulator init data failed\n");
+		return -EINVAL;
+	}
+
+	/* Give the name, then will register */
+	if (init_data->constraints.name) {
+		chip->otg_vreg.rdesc.owner = THIS_MODULE;
+		chip->otg_vreg.rdesc.type = REGULATOR_VOLTAGE;
+		chip->otg_vreg.rdesc.ops = &smb358_chg_otg_reg_ops;
+		chip->otg_vreg.rdesc.name = init_data->constraints.name;
+
+		cfg.dev = chip->dev;
+		cfg.init_data = init_data;
+		cfg.driver_data = chip;
+		cfg.of_node = chip->dev->of_node;
+
+		init_data->constraints.valid_ops_mask
+			|= REGULATOR_CHANGE_STATUS;
+
+		chip->otg_vreg.rdev = regulator_register(
+					&chip->otg_vreg.rdesc, &cfg);
+		if (IS_ERR(chip->otg_vreg.rdev)) {
+			rc = PTR_ERR(chip->otg_vreg.rdev);
+			chip->otg_vreg.rdev = NULL;
+			if (rc != -EPROBE_DEFER)
+				dev_err(chip->dev,
+					"OTG reg failed, rc=%d\n", rc);
+		}
+	}
+	return rc;
+}
+
+static int __smb358_charging_disable(struct smb358_charger *chip, bool disable)
+{
+	int rc;
+
+	rc = smb358_masked_write(chip, CMD_A_REG, CMD_A_CHG_ENABLE_BIT,
+			disable ? 0 : CMD_A_CHG_ENABLE_BIT);
+	if (rc < 0)
+		pr_err("Couldn't set CHG_ENABLE_BIT diable = %d, rc = %d\n",
+				disable, rc);
+	return rc;
+}
+
+static int smb358_charging_disable(struct smb358_charger *chip,
+						int reason, int disable)
+{
+	int rc = 0;
+	int disabled;
+
+	disabled = chip->charging_disabled_status;
+
+	pr_debug("reason = %d requested_disable = %d disabled_status = %d\n",
+						reason, disable, disabled);
+
+	if (disable == true)
+		disabled |= reason;
+	else
+		disabled &= ~reason;
+
+	if (!!disabled == !!chip->charging_disabled_status)
+		goto skip;
+
+	rc = __smb358_charging_disable(chip, !!disabled);
+	if (rc) {
+		pr_err("Failed to disable charging rc = %d\n", rc);
+		return rc;
+	} else {
+	/* will not modify online status in this condition */
+		power_supply_changed(&chip->batt_psy);
+	}
+
+skip:
+	chip->charging_disabled_status = disabled;
+	return rc;
+}
+
+static int smb358_hw_init(struct smb358_charger *chip)
+{
+	int rc;
+	u8 reg = 0, mask = 0;
+
+	/*
+	 * If the charger is pre-configured for autonomous operation,
+	 * do not apply additonal settings
+	 */
+	if (chip->chg_autonomous_mode) {
+		dev_dbg(chip->dev, "Charger configured for autonomous mode\n");
+		return 0;
+	}
+
+	rc = smb358_enable_volatile_writes(chip);
+	if (rc) {
+		dev_err(chip->dev, "Couldn't configure volatile writes rc=%d\n",
+				rc);
+		return rc;
+	}
+
+	/* setup defaults for CHG_CNTRL_REG */
+	reg = CHG_CTRL_BATT_MISSING_DET_THERM_IO;
+	mask = CHG_CTRL_BATT_MISSING_DET_MASK;
+	rc = smb358_masked_write(chip, CHG_CTRL_REG, mask, reg);
+	if (rc) {
+		dev_err(chip->dev, "Couldn't set CHG_CTRL_REG rc=%d\n", rc);
+		return rc;
+	}
+	/* setup defaults for PIN_CTRL_REG */
+	reg = CHG_PIN_CTRL_USBCS_REG_BIT | CHG_PIN_CTRL_CHG_EN_LOW_REG_BIT |
+		CHG_PIN_CTRL_APSD_IRQ_BIT | CHG_PIN_CTRL_CHG_ERR_IRQ_BIT;
+	mask = CHG_PIN_CTRL_CHG_EN_MASK | CHG_PIN_CTRL_USBCS_REG_MASK |
+		CHG_PIN_CTRL_APSD_IRQ_MASK | CHG_PIN_CTRL_CHG_ERR_IRQ_MASK;
+	rc = smb358_masked_write(chip, CHG_PIN_EN_CTRL_REG, mask, reg);
+	if (rc) {
+		dev_err(chip->dev, "Couldn't set CHG_PIN_EN_CTRL_REG rc=%d\n",
+				rc);
+		return rc;
+	}
+
+	/* setup USB suspend and APSD  */
+	rc = smb358_masked_write(chip, VARIOUS_FUNC_REG,
+		VARIOUS_FUNC_USB_SUSP_MASK, VARIOUS_FUNC_USB_SUSP_EN_REG_BIT);
+	if (rc) {
+		dev_err(chip->dev, "Couldn't set VARIOUS_FUNC_REG rc=%d\n",
+				rc);
+		return rc;
+	}
+
+	if (!chip->disable_apsd)
+		reg = CHG_CTRL_APSD_EN_BIT;
+	rc = smb358_masked_write(chip, CHG_CTRL_REG,
+				CHG_CTRL_APSD_EN_MASK, reg);
+	if (rc) {
+		dev_err(chip->dev, "Couldn't set CHG_CTRL_REG rc=%d\n",
+				rc);
+		return rc;
+	}
+	/* Fault and Status IRQ configuration */
+	reg = FAULT_INT_HOT_COLD_HARD_BIT | FAULT_INT_HOT_COLD_SOFT_BIT
+		| FAULT_INT_INPUT_UV_BIT | FAULT_INT_AICL_COMPLETE_BIT
+		| FAULT_INT_INPUT_OV_BIT;
+	rc = smb358_write_reg(chip, FAULT_INT_REG, reg);
+	if (rc) {
+		dev_err(chip->dev, "Couldn't set FAULT_INT_REG rc=%d\n", rc);
+		return rc;
+	}
+	reg = STATUS_INT_CHG_TIMEOUT_BIT | STATUS_INT_OTG_DETECT_BIT |
+		STATUS_INT_BATT_OV_BIT | STATUS_INT_CHGING_BIT |
+		STATUS_INT_CHG_INHI_BIT | STATUS_INT_INOK_BIT |
+		STATUS_INT_LOW_BATT_BIT | STATUS_INT_MISSING_BATT_BIT;
+	rc = smb358_write_reg(chip, STATUS_INT_REG, reg);
+	if (rc) {
+		dev_err(chip->dev, "Couldn't set STATUS_INT_REG rc=%d\n", rc);
+		return rc;
+	}
+	/* setup THERM Monitor */
+	rc = smb358_masked_write(chip, THERM_A_CTRL_REG,
+		THERM_A_THERM_MONITOR_EN_MASK, THERM_A_THERM_MONITOR_EN_BIT);
+	if (rc) {
+		dev_err(chip->dev, "Couldn't set THERM_A_CTRL_REG rc=%d\n",
+				rc);
+		return rc;
+	}
+	/* set the fast charge current limit */
+	rc = smb358_fastchg_current_set(chip);
+	if (rc) {
+		dev_err(chip->dev, "Couldn't set fastchg current rc=%d\n", rc);
+		return rc;
+	}
+
+	/* set the float voltage */
+	rc = smb358_float_voltage_set(chip, chip->vfloat_mv);
+	if (rc < 0) {
+		dev_err(chip->dev,
+			"Couldn't set float voltage rc = %d\n", rc);
+		return rc;
+	}
+
+	/* set iterm */
+	rc = smb358_term_current_set(chip);
+	if (rc)
+		dev_err(chip->dev, "Couldn't set term current rc=%d\n", rc);
+
+	/* set recharge */
+	rc = smb358_recharge_set(chip);
+	if (rc)
+		dev_err(chip->dev, "Couldn't set recharge para rc=%d\n", rc);
+
+	/* enable/disable charging */
+	rc = smb358_charging_disable(chip, USER, !!chip->charging_disabled);
+	if (rc)
+		dev_err(chip->dev, "Couldn't '%s' charging rc = %d\n",
+			chip->charging_disabled ? "disable" : "enable", rc);
+
+	return rc;
+}
+
+static enum power_supply_property smb358_battery_properties[] = {
+	POWER_SUPPLY_PROP_STATUS,
+	POWER_SUPPLY_PROP_PRESENT,
+	POWER_SUPPLY_PROP_CHARGING_ENABLED,
+	POWER_SUPPLY_PROP_CHARGE_TYPE,
+	POWER_SUPPLY_PROP_CAPACITY,
+	POWER_SUPPLY_PROP_HEALTH,
+	POWER_SUPPLY_PROP_TECHNOLOGY,
+	POWER_SUPPLY_PROP_MODEL_NAME,
+	POWER_SUPPLY_PROP_TEMP,
+	POWER_SUPPLY_PROP_VOLTAGE_NOW,
+};
+
+static int smb358_get_prop_batt_status(struct smb358_charger *chip)
+{
+	int rc;
+	u8 reg = 0;
+
+	if (chip->batt_full)
+		return POWER_SUPPLY_STATUS_FULL;
+
+	rc = smb358_read_reg(chip, STATUS_C_REG, &reg);
+	if (rc) {
+		dev_err(chip->dev, "Couldn't read STAT_C rc = %d\n", rc);
+		return POWER_SUPPLY_STATUS_UNKNOWN;
+	}
+
+	dev_dbg(chip->dev, "%s: STATUS_C_REG=%x\n", __func__, reg);
+
+	if (reg & STATUS_C_CHG_HOLD_OFF_BIT)
+		return POWER_SUPPLY_STATUS_NOT_CHARGING;
+
+	if ((reg & STATUS_C_CHARGING_MASK) &&
+			!(reg & STATUS_C_CHG_ERR_STATUS_BIT))
+		return POWER_SUPPLY_STATUS_CHARGING;
+
+	return POWER_SUPPLY_STATUS_DISCHARGING;
+}
+
+static int smb358_get_prop_batt_present(struct smb358_charger *chip)
+{
+	return !chip->battery_missing;
+}
+
+static int smb358_get_prop_batt_capacity(struct smb358_charger *chip)
+{
+	union power_supply_propval ret = {0, };
+
+	if (chip->fake_battery_soc >= 0)
+		return chip->fake_battery_soc;
+
+	if (chip->bms_psy) {
+		chip->bms_psy->get_property(chip->bms_psy,
+				POWER_SUPPLY_PROP_CAPACITY, &ret);
+		return ret.intval;
+	}
+
+	dev_dbg(chip->dev,
+		"Couldn't get bms_psy, return default capacity\n");
+	return SMB358_DEFAULT_BATT_CAPACITY;
+}
+
+static int smb358_get_prop_charge_type(struct smb358_charger *chip)
+{
+	int rc;
+	u8 reg = 0;
+
+	rc = smb358_read_reg(chip, STATUS_C_REG, &reg);
+	if (rc) {
+		dev_err(chip->dev, "Couldn't read STAT_C rc = %d\n", rc);
+		return POWER_SUPPLY_CHARGE_TYPE_UNKNOWN;
+	}
+
+	dev_dbg(chip->dev, "%s: STATUS_C_REG=%x\n", __func__, reg);
+
+	reg &= STATUS_C_CHARGING_MASK;
+
+	if (reg == STATUS_C_FAST_CHARGING)
+		return POWER_SUPPLY_CHARGE_TYPE_FAST;
+	else if (reg == STATUS_C_TAPER_CHARGING)
+		return POWER_SUPPLY_CHARGE_TYPE_TAPER;
+	else if (reg == STATUS_C_PRE_CHARGING)
+		return POWER_SUPPLY_CHARGE_TYPE_TRICKLE;
+	else
+		return POWER_SUPPLY_CHARGE_TYPE_NONE;
+}
+
+static int smb358_get_prop_batt_health(struct smb358_charger *chip)
+{
+	union power_supply_propval ret = {0, };
+
+	if (chip->batt_hot)
+		ret.intval = POWER_SUPPLY_HEALTH_OVERHEAT;
+	else if (chip->batt_cold)
+		ret.intval = POWER_SUPPLY_HEALTH_COLD;
+	else if (chip->batt_warm)
+		ret.intval = POWER_SUPPLY_HEALTH_WARM;
+	else if (chip->batt_cool)
+		ret.intval = POWER_SUPPLY_HEALTH_COOL;
+	else
+		ret.intval = POWER_SUPPLY_HEALTH_GOOD;
+
+	return ret.intval;
+}
+
+#define DEFAULT_TEMP 250
+static int smb358_get_prop_batt_temp(struct smb358_charger *chip)
+{
+	int rc = 0;
+	struct qpnp_vadc_result results;
+
+	if (!smb358_get_prop_batt_present(chip))
+		return DEFAULT_TEMP;
+
+	rc = qpnp_vadc_read(chip->vadc_dev, LR_MUX1_BATT_THERM, &results);
+	if (rc) {
+		pr_debug("Unable to read batt temperature rc=%d\n", rc);
+		return DEFAULT_TEMP;
+	}
+	pr_debug("get_bat_temp %d, %lld\n",
+		results.adc_code, results.physical);
+
+	return (int)results.physical;
+}
+
+static int
+smb358_get_prop_battery_voltage_now(struct smb358_charger *chip)
+{
+	int rc = 0;
+	struct qpnp_vadc_result results;
+
+	rc = qpnp_vadc_read(chip->vadc_dev, VBAT_SNS, &results);
+	if (rc) {
+		pr_err("Unable to read vbat rc=%d\n", rc);
+		return 0;
+	}
+	return results.physical;
+}
+
+static int __smb358_path_suspend(struct smb358_charger *chip, bool suspend)
+{
+	int rc;
+
+	rc = smb358_masked_write(chip, CMD_A_REG,
+			CMD_A_CHG_SUSP_EN_MASK,
+				suspend ? CMD_A_CHG_SUSP_EN_BIT : 0);
+	if (rc < 0)
+		dev_err(chip->dev, "Couldn't set CMD_A reg, rc = %d\n", rc);
+	return rc;
+}
+
+static int smb358_path_suspend(struct smb358_charger *chip, int reason,
+							bool suspend)
+{
+	int rc = 0;
+	int suspended;
+
+	mutex_lock(&chip->path_suspend_lock);
+	suspended = chip->usb_suspended;
+
+	if (suspend == false)
+		suspended &= ~reason;
+	else
+		suspended |= reason;
+
+	if (!chip->usb_suspended && suspended) {
+		rc = __smb358_path_suspend(chip, true);
+		chip->usb_suspended = suspended;
+		power_supply_set_online(chip->usb_psy, !chip->usb_suspended);
+		power_supply_changed(chip->usb_psy);
+	} else if (chip->usb_suspended && !suspended) {
+		rc = __smb358_path_suspend(chip, false);
+		chip->usb_suspended = suspended;
+		power_supply_set_online(chip->usb_psy, !chip->usb_suspended);
+		power_supply_changed(chip->usb_psy);
+	}
+
+	if (rc)
+		dev_err(chip->dev, "Couldn't set/unset suspend rc = %d\n", rc);
+
+	mutex_unlock(&chip->path_suspend_lock);
+	return rc;
+}
+
+static int smb358_set_usb_chg_current(struct smb358_charger *chip,
+		int current_ma)
+{
+	int i, rc = 0;
+	u8 reg1 = 0, reg2 = 0, mask = 0;
+
+	dev_dbg(chip->dev, "%s: USB current_ma = %d\n", __func__, current_ma);
+
+	if (chip->chg_autonomous_mode) {
+		dev_dbg(chip->dev, "%s: Charger in autonmous mode\n", __func__);
+		return 0;
+	}
+
+	if (current_ma < USB3_MIN_CURRENT_MA && current_ma != 2)
+		current_ma = USB2_MIN_CURRENT_MA;
+
+	if (current_ma == USB2_MIN_CURRENT_MA) {
+		/* USB 2.0 - 100mA */
+		reg1 &= ~USB3_ENABLE_BIT;
+		reg2 &= ~CMD_B_CHG_USB_500_900_ENABLE_BIT;
+	} else if (current_ma == USB2_MAX_CURRENT_MA) {
+		/* USB 2.0 - 500mA */
+		reg1 &= ~USB3_ENABLE_BIT;
+		reg2 |= CMD_B_CHG_USB_500_900_ENABLE_BIT;
+	} else if (current_ma == USB3_MAX_CURRENT_MA) {
+		/* USB 3.0 - 900mA */
+		reg1 |= USB3_ENABLE_BIT;
+		reg2 |= CMD_B_CHG_USB_500_900_ENABLE_BIT;
+	} else if (current_ma > USB2_MAX_CURRENT_MA) {
+		/* HC mode  - if none of the above */
+		reg2 |= CMD_B_CHG_HC_ENABLE_BIT;
+
+		for (i = ARRAY_SIZE(chg_current) - 1; i >= 0; i--) {
+			if (chg_current[i] <= current_ma)
+				break;
+		}
+		if (i < 0) {
+			dev_err(chip->dev, "Cannot find %dmA\n", current_ma);
+			i = 0;
+		}
+
+		i = i << AC_CHG_CURRENT_SHIFT;
+		rc = smb358_masked_write(chip, CHG_OTH_CURRENT_CTRL_REG,
+						AC_CHG_CURRENT_MASK, i);
+		if (rc)
+			dev_err(chip->dev, "Couldn't set input mA rc=%d\n", rc);
+	}
+
+	mask = CMD_B_CHG_HC_ENABLE_BIT | CMD_B_CHG_USB_500_900_ENABLE_BIT;
+	rc = smb358_masked_write(chip, CMD_B_REG, mask, reg2);
+	if (rc < 0)
+		dev_err(chip->dev, "Couldn't set charging mode rc = %d\n", rc);
+
+	mask = USB3_ENABLE_MASK;
+	rc = smb358_masked_write(chip, SYSOK_AND_USB3_REG, mask, reg1);
+	if (rc < 0)
+		dev_err(chip->dev, "Couldn't set USB3 mode rc = %d\n", rc);
+
+	/* Only set suspend bit when chg present and current_ma = 2 */
+	if (current_ma == 2 && chip->chg_present) {
+		rc = smb358_path_suspend(chip, CURRENT, true);
+		if (rc < 0)
+			dev_err(chip->dev, "Couldn't suspend rc = %d\n", rc);
+	} else {
+		rc = smb358_path_suspend(chip, CURRENT, false);
+		if (rc < 0)
+			dev_err(chip->dev, "Couldn't set susp rc = %d\n", rc);
+	}
+
+	return rc;
+}
+
+static int
+smb358_batt_property_is_writeable(struct power_supply *psy,
+					enum power_supply_property psp)
+{
+	switch (psp) {
+	case POWER_SUPPLY_PROP_CHARGING_ENABLED:
+	case POWER_SUPPLY_PROP_CAPACITY:
+		return 1;
+	default:
+		break;
+	}
+
+	return 0;
+}
+
+static int bound_soc(int soc)
+{
+	soc = max(0, soc);
+	soc = min(soc, 100);
+	return soc;
+}
+
+static int smb358_battery_set_property(struct power_supply *psy,
+					enum power_supply_property prop,
+					const union power_supply_propval *val)
+{
+	struct smb358_charger *chip = container_of(psy,
+				struct smb358_charger, batt_psy);
+
+	switch (prop) {
+	case POWER_SUPPLY_PROP_CHARGING_ENABLED:
+		smb358_charging_disable(chip, USER, !val->intval);
+		smb358_path_suspend(chip, USER, !val->intval);
+		break;
+	case POWER_SUPPLY_PROP_CAPACITY:
+		chip->fake_battery_soc = bound_soc(val->intval);
+		power_supply_changed(&chip->batt_psy);
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+static int smb358_battery_get_property(struct power_supply *psy,
+				       enum power_supply_property prop,
+				       union power_supply_propval *val)
+{
+	struct smb358_charger *chip = container_of(psy,
+				struct smb358_charger, batt_psy);
+
+	switch (prop) {
+	case POWER_SUPPLY_PROP_STATUS:
+		val->intval = smb358_get_prop_batt_status(chip);
+		break;
+	case POWER_SUPPLY_PROP_PRESENT:
+		val->intval = smb358_get_prop_batt_present(chip);
+		break;
+	case POWER_SUPPLY_PROP_CAPACITY:
+		val->intval = smb358_get_prop_batt_capacity(chip);
+		break;
+	case POWER_SUPPLY_PROP_CHARGING_ENABLED:
+		val->intval = !(chip->charging_disabled_status & USER);
+		break;
+	case POWER_SUPPLY_PROP_CHARGE_TYPE:
+		val->intval = smb358_get_prop_charge_type(chip);
+		break;
+	case POWER_SUPPLY_PROP_HEALTH:
+		val->intval = smb358_get_prop_batt_health(chip);
+		break;
+	case POWER_SUPPLY_PROP_TECHNOLOGY:
+		val->intval = POWER_SUPPLY_TECHNOLOGY_LION;
+		break;
+	case POWER_SUPPLY_PROP_MODEL_NAME:
+		val->strval = "SMB358";
+		break;
+	case POWER_SUPPLY_PROP_TEMP:
+		val->intval = smb358_get_prop_batt_temp(chip);
+		break;
+	case POWER_SUPPLY_PROP_VOLTAGE_NOW:
+		val->intval = smb358_get_prop_battery_voltage_now(chip);
+		break;
+	default:
+		return -EINVAL;
+	}
+	return 0;
+}
+
+static int apsd_complete(struct smb358_charger *chip, u8 status)
+{
+	int rc;
+	u8 reg = 0;
+	enum power_supply_type type = POWER_SUPPLY_TYPE_UNKNOWN;
+
+	/*
+	 * If apsd is disabled, charger detection is done by
+	 * DCIN UV irq.
+	 * status = ZERO - indicates charger removed, handled
+	 * by DCIN UV irq
+	 */
+	if (chip->disable_apsd || status == 0) {
+		dev_dbg(chip->dev, "APSD %s, status = %d\n",
+			chip->disable_apsd ? "disabled" : "enabled", !!status);
+		return 0;
+	}
+
+	rc = smb358_read_reg(chip, STATUS_D_REG, &reg);
+	if (rc) {
+		dev_err(chip->dev, "Couldn't read STATUS D rc = %d\n", rc);
+		return rc;
+	}
+
+	dev_dbg(chip->dev, "%s: STATUS_D_REG=%x\n", __func__, reg);
+
+	switch (reg) {
+	case STATUS_D_PORT_ACA_DOCK:
+	case STATUS_D_PORT_ACA_C:
+	case STATUS_D_PORT_ACA_B:
+	case STATUS_D_PORT_ACA_A:
+		type = POWER_SUPPLY_TYPE_USB_ACA;
+		break;
+	case STATUS_D_PORT_CDP:
+		type = POWER_SUPPLY_TYPE_USB_CDP;
+		break;
+	case STATUS_D_PORT_DCP:
+		type = POWER_SUPPLY_TYPE_USB_DCP;
+		break;
+	case STATUS_D_PORT_SDP:
+		type = POWER_SUPPLY_TYPE_USB;
+		break;
+	case STATUS_D_PORT_OTHER:
+		type = POWER_SUPPLY_TYPE_USB_DCP;
+		break;
+	default:
+		type = POWER_SUPPLY_TYPE_USB;
+		break;
+	}
+
+	chip->chg_present = !!status;
+
+	dev_dbg(chip->dev, "APSD complete. USB type detected=%d chg_present=%d",
+						type, chip->chg_present);
+
+	power_supply_set_charge_type(chip->usb_psy, type);
+
+	 /* SMB is now done sampling the D+/D- lines, indicate USB driver */
+	dev_dbg(chip->dev, "%s updating usb_psy present=%d", __func__,
+			chip->chg_present);
+	power_supply_set_present(chip->usb_psy, chip->chg_present);
+
+	return 0;
+}
+
+static int chg_uv(struct smb358_charger *chip, u8 status)
+{
+	/* use this to detect USB insertion only if !apsd */
+	if (chip->disable_apsd && status == 0) {
+		chip->chg_present = true;
+		dev_dbg(chip->dev, "%s updating usb_psy present=%d",
+				__func__, chip->chg_present);
+		power_supply_set_supply_type(chip->usb_psy,
+						POWER_SUPPLY_TYPE_USB);
+		power_supply_set_present(chip->usb_psy, chip->chg_present);
+	}
+
+	if (status != 0) {
+		chip->chg_present = false;
+		dev_dbg(chip->dev, "%s updating usb_psy present=%d",
+				__func__, chip->chg_present);
+	/* we can't set usb_psy as UNKNOWN here, will lead USERSPACE issue */
+		power_supply_set_present(chip->usb_psy, chip->chg_present);
+	}
+
+	power_supply_changed(chip->usb_psy);
+	dev_dbg(chip->dev, "chip->chg_present = %d\n", chip->chg_present);
+
+	return 0;
+}
+
+static int chg_ov(struct smb358_charger *chip, u8 status)
+{
+	u8 psy_health_sts;
+	if (status)
+		psy_health_sts = POWER_SUPPLY_HEALTH_OVERVOLTAGE;
+	else
+		psy_health_sts = POWER_SUPPLY_HEALTH_GOOD;
+
+	power_supply_set_health_state(
+				chip->usb_psy, psy_health_sts);
+	power_supply_changed(chip->usb_psy);
+
+	return 0;
+}
+
+static int fast_chg(struct smb358_charger *chip, u8 status)
+{
+	dev_dbg(chip->dev, "%s\n", __func__);
+	return 0;
+}
+
+static int chg_term(struct smb358_charger *chip, u8 status)
+{
+	dev_dbg(chip->dev, "%s\n", __func__);
+	chip->batt_full = !!status;
+	return 0;
+}
+
+static int taper_chg(struct smb358_charger *chip, u8 status)
+{
+	dev_dbg(chip->dev, "%s\n", __func__);
+	return 0;
+}
+
+static int chg_recharge(struct smb358_charger *chip, u8 status)
+{
+	dev_dbg(chip->dev, "%s, status = %d\n", __func__, !!status);
+	/* to check the status mean */
+	chip->batt_full = !status;
+	return 0;
+}
+
+#define HYSTERISIS_DECIDEGC 20
+static void smb_chg_adc_notification(enum qpnp_tm_state state, void *ctx)
+{
+	struct smb358_charger *chip = ctx;
+	bool bat_hot = 0, bat_cold = 0, bat_present = 0;
+	int temp;
+
+	if (state >= ADC_TM_STATE_NUM) {
+		pr_err("invallid state parameter %d\n", state);
+		return;
+	}
+
+	temp = smb358_get_prop_batt_temp(chip);
+
+	pr_debug("temp = %d state = %s\n", temp,
+				state == ADC_TM_WARM_STATE ? "hot" : "cold");
+
+	if (state == ADC_TM_WARM_STATE) {
+		if (temp > chip->hot_bat_decidegc) {
+			/* Normal to hot */
+			bat_hot = true;
+			bat_cold = false;
+			bat_present = true;
+
+			chip->adc_param.low_temp =
+				chip->hot_bat_decidegc - HYSTERISIS_DECIDEGC;
+			/* shall we need add high_temp here? */
+			chip->adc_param.state_request =
+				ADC_TM_COOL_THR_ENABLE;
+		} else if (temp >
+			chip->cold_bat_decidegc + HYSTERISIS_DECIDEGC) {
+			/* Cool to normal */
+			bat_hot = false;
+			bat_cold = false;
+			bat_present = true;
+
+			chip->adc_param.low_temp = chip->cold_bat_decidegc;
+			chip->adc_param.high_temp = chip->hot_bat_decidegc;
+			chip->adc_param.state_request =
+					ADC_TM_HIGH_LOW_THR_ENABLE;
+		} else if (temp > chip->bat_present_decidegc) {
+			/* Present to cold */
+			bat_hot = false;
+			bat_cold = true;
+			bat_present = true;
+
+			chip->adc_param.high_temp = chip->cold_bat_decidegc;
+			chip->adc_param.low_temp = chip->bat_present_decidegc;
+			chip->adc_param.state_request =
+					ADC_TM_HIGH_LOW_THR_ENABLE;
+		}
+	} else {
+		if (temp <= chip->bat_present_decidegc) {
+			/* Cold to present */
+			bat_cold = true;
+			bat_hot = false;
+			bat_present = false;
+			chip->adc_param.high_temp =
+				chip->bat_present_decidegc;
+			chip->adc_param.state_request =
+				ADC_TM_WARM_THR_ENABLE;
+		} else if (chip->bat_present_decidegc < temp &&
+				temp < chip->cold_bat_decidegc) {
+			/* Normal to cold */
+			bat_hot = false;
+			bat_cold = true;
+			bat_present = true;
+			chip->adc_param.high_temp =
+				chip->cold_bat_decidegc + HYSTERISIS_DECIDEGC;
+			/* add low_temp to enable batt present check */
+			chip->adc_param.low_temp =
+				chip->bat_present_decidegc;
+			chip->adc_param.state_request =
+				ADC_TM_HIGH_LOW_THR_ENABLE;
+		} else if (temp <
+				chip->hot_bat_decidegc - HYSTERISIS_DECIDEGC) {
+			/* Warm to normal */
+			bat_hot = false;
+			bat_cold = false;
+			bat_present = true;
+
+			chip->adc_param.low_temp = chip->cold_bat_decidegc;
+			chip->adc_param.high_temp = chip->hot_bat_decidegc;
+			chip->adc_param.state_request =
+					ADC_TM_HIGH_LOW_THR_ENABLE;
+		}
+	}
+
+	if (bat_present)
+		chip->battery_missing = false;
+	else
+		chip->battery_missing = true;
+
+	if (bat_hot ^ chip->batt_hot || bat_cold ^ chip->batt_cold) {
+		chip->batt_hot = bat_hot;
+		chip->batt_cold = bat_cold;
+		/* stop charging explicitly since we use PMIC thermal pin*/
+		if (bat_hot || bat_cold || chip->battery_missing)
+			smb358_charging_disable(chip, THERMAL, 1);
+		else
+			smb358_charging_disable(chip, THERMAL, 0);
+	}
+
+	pr_debug("hot %d, cold %d, missing %d, low = %d deciDegC, high = %d deciDegC\n",
+			chip->batt_hot, chip->batt_cold, chip->battery_missing,
+			chip->adc_param.low_temp, chip->adc_param.high_temp);
+	if (qpnp_adc_tm_channel_measure(chip->adc_tm_dev, &chip->adc_param))
+		pr_err("request ADC error\n");
+}
+
+/* only for SMB thermal */
+static int hot_hard_handler(struct smb358_charger *chip, u8 status)
+{
+	pr_debug("status = 0x%02x\n", status);
+	chip->batt_hot = !!status;
+	return 0;
+}
+static int cold_hard_handler(struct smb358_charger *chip, u8 status)
+{
+	pr_debug("status = 0x%02x\n", status);
+	chip->batt_cold = !!status;
+	return 0;
+}
+static int hot_soft_handler(struct smb358_charger *chip, u8 status)
+{
+	pr_debug("status = 0x%02x\n", status);
+	chip->batt_warm = !!status;
+	return 0;
+}
+static int cold_soft_handler(struct smb358_charger *chip, u8 status)
+{
+	pr_debug("status = 0x%02x\n", status);
+	chip->batt_cool = !!status;
+	return 0;
+}
+
+static int battery_missing(struct smb358_charger *chip, u8 status)
+{
+	chip->battery_missing = !!status;
+	return 0;
+}
+
+static struct irq_handler_info handlers[] = {
+	[0] = {
+		.stat_reg	= IRQ_A_REG,
+		.val		= 0,
+		.prev_val	= 0,
+		.irq_info	= {
+			{
+				.name		= "cold_soft",
+				.smb_irq	= cold_soft_handler,
+			},
+			{
+				.name		= "hot_soft",
+				.smb_irq	= hot_soft_handler,
+			},
+			{
+				.name		= "cold_hard",
+				.smb_irq	= cold_hard_handler,
+			},
+			{
+				.name		= "hot_hard",
+				.smb_irq	= hot_hard_handler,
+			},
+		},
+	},
+	[1] = {
+		.stat_reg	= IRQ_B_REG,
+		.val		= 0,
+		.prev_val	= 0,
+		.irq_info	= {
+			{
+				.name		= "chg_hot",
+			},
+			{
+				.name		= "vbat_low",
+			},
+			{
+				.name		= "battery_missing",
+				.smb_irq	= battery_missing
+			},
+			{
+				.name		= "battery_ov",
+			},
+		},
+	},
+	[2] = {
+		.stat_reg	= IRQ_C_REG,
+		.val		= 0,
+		.prev_val	= 0,
+		.irq_info	= {
+			{
+				.name		= "chg_term",
+				.smb_irq	= chg_term,
+			},
+			{
+				.name		= "taper",
+				.smb_irq	= taper_chg,
+			},
+			{
+				.name		= "recharge",
+				.smb_irq	= chg_recharge,
+			},
+			{
+				.name		= "fast_chg",
+				.smb_irq	= fast_chg,
+			},
+		},
+	},
+	[3] = {
+		.stat_reg	= IRQ_D_REG,
+		.val		= 0,
+		.prev_val	= 0,
+		.irq_info	= {
+			{
+				.name		= "prechg_timeout",
+			},
+			{
+				.name		= "safety_timeout",
+			},
+			{
+				.name		= "aicl_complete",
+			},
+			{
+				.name		= "src_detect",
+				.smb_irq	= apsd_complete,
+			},
+		},
+	},
+	[4] = {
+		.stat_reg	= IRQ_E_REG,
+		.val		= 0,
+		.prev_val	= 0,
+		.irq_info	= {
+			{
+				.name		= "usbin_uv",
+				.smb_irq        = chg_uv,
+			},
+			{
+				.name		= "usbin_ov",
+				.smb_irq	= chg_ov,
+			},
+			{
+				.name		= "unknown",
+			},
+			{
+				.name		= "unknown",
+			},
+		},
+	},
+	[5] = {
+		.stat_reg	= IRQ_F_REG,
+		.val		= 0,
+		.prev_val	= 0,
+		.irq_info	= {
+			{
+				.name		= "power_ok",
+			},
+			{
+				.name		= "otg_det",
+			},
+			{
+				.name		= "otg_batt_uv",
+			},
+			{
+				.name		= "otg_oc",
+			},
+		},
+	},
+};
+
+#define IRQ_LATCHED_MASK	0x02
+#define IRQ_STATUS_MASK		0x01
+#define BITS_PER_IRQ		2
+static irqreturn_t smb358_chg_stat_handler(int irq, void *dev_id)
+{
+	struct smb358_charger *chip = dev_id;
+	int i, j;
+	u8 triggered;
+	u8 changed;
+	u8 rt_stat, prev_rt_stat;
+	int rc;
+	int handler_count = 0;
+
+	mutex_lock(&chip->irq_complete);
+
+	chip->irq_waiting = true;
+	if (!chip->resume_completed) {
+		dev_dbg(chip->dev, "IRQ triggered before device-resume\n");
+		disable_irq_nosync(irq);
+		mutex_unlock(&chip->irq_complete);
+		return IRQ_HANDLED;
+	}
+	chip->irq_waiting = false;
+
+	for (i = 0; i < ARRAY_SIZE(handlers); i++) {
+		rc = smb358_read_reg(chip, handlers[i].stat_reg,
+						&handlers[i].val);
+		if (rc < 0) {
+			dev_err(chip->dev, "Couldn't read %d rc = %d\n",
+					handlers[i].stat_reg, rc);
+			continue;
+		}
+
+		for (j = 0; j < ARRAY_SIZE(handlers[i].irq_info); j++) {
+			triggered = handlers[i].val
+			       & (IRQ_LATCHED_MASK << (j * BITS_PER_IRQ));
+			rt_stat = handlers[i].val
+				& (IRQ_STATUS_MASK << (j * BITS_PER_IRQ));
+			prev_rt_stat = handlers[i].prev_val
+				& (IRQ_STATUS_MASK << (j * BITS_PER_IRQ));
+			changed = prev_rt_stat ^ rt_stat;
+
+			if (triggered || changed)
+				rt_stat ? handlers[i].irq_info[j].high++ :
+						handlers[i].irq_info[j].low++;
+
+			if ((triggered || changed)
+				&& handlers[i].irq_info[j].smb_irq != NULL) {
+				handler_count++;
+				rc = handlers[i].irq_info[j].smb_irq(chip,
+								rt_stat);
+				if (rc < 0)
+					dev_err(chip->dev,
+						"Couldn't handle %d irq for reg 0x%02x rc = %d\n",
+						j, handlers[i].stat_reg, rc);
+			}
+		}
+		handlers[i].prev_val = handlers[i].val;
+	}
+
+	pr_debug("handler count = %d\n", handler_count);
+	if (handler_count) {
+		pr_debug("batt psy changed\n");
+		power_supply_changed(&chip->batt_psy);
+	}
+
+	mutex_unlock(&chip->irq_complete);
+
+	return IRQ_HANDLED;
+}
+
+static irqreturn_t smb358_chg_valid_handler(int irq, void *dev_id)
+{
+	struct smb358_charger *chip = dev_id;
+	int present;
+
+	present = gpio_get_value_cansleep(chip->chg_valid_gpio);
+	if (present < 0) {
+		dev_err(chip->dev, "Couldn't read chg_valid gpio=%d\n",
+						chip->chg_valid_gpio);
+		return IRQ_HANDLED;
+	}
+	present ^= chip->chg_valid_act_low;
+
+	dev_dbg(chip->dev, "%s: chg_present = %d\n", __func__, present);
+
+	if (present != chip->chg_present) {
+		chip->chg_present = present;
+		dev_dbg(chip->dev, "%s updating usb_psy present=%d",
+				__func__, chip->chg_present);
+		power_supply_set_present(chip->usb_psy, chip->chg_present);
+	}
+
+	return IRQ_HANDLED;
+}
+
+static void smb358_external_power_changed(struct power_supply *psy)
+{
+	struct smb358_charger *chip = container_of(psy,
+				struct smb358_charger, batt_psy);
+	union power_supply_propval prop = {0,};
+	int rc, current_limit = 0;
+
+	if (chip->bms_psy_name)
+		chip->bms_psy =
+			power_supply_get_by_name((char *)chip->bms_psy_name);
+
+	rc = chip->usb_psy->get_property(chip->usb_psy,
+				POWER_SUPPLY_PROP_CURRENT_MAX, &prop);
+	if (rc)
+		dev_err(chip->dev,
+			"Couldn't read USB current_max property, rc=%d\n", rc);
+	else
+		current_limit = prop.intval / 1000;
+
+
+	smb358_enable_volatile_writes(chip);
+	smb358_set_usb_chg_current(chip, current_limit);
+
+	dev_dbg(chip->dev, "current_limit = %d\n", current_limit);
+}
+
+#if defined(CONFIG_DEBUG_FS)
+#define LAST_CNFG_REG	0x13
+static int show_cnfg_regs(struct seq_file *m, void *data)
+{
+	struct smb358_charger *chip = m->private;
+	int rc;
+	u8 reg;
+	u8 addr;
+
+	for (addr = 0; addr <= LAST_CNFG_REG; addr++) {
+		rc = smb358_read_reg(chip, addr, &reg);
+		if (!rc)
+			seq_printf(m, "0x%02x = 0x%02x\n", addr, reg);
+	}
+
+	return 0;
+}
+
+static int cnfg_debugfs_open(struct inode *inode, struct file *file)
+{
+	struct smb358_charger *chip = inode->i_private;
+
+	return single_open(file, show_cnfg_regs, chip);
+}
+
+static const struct file_operations cnfg_debugfs_ops = {
+	.owner		= THIS_MODULE,
+	.open		= cnfg_debugfs_open,
+	.read		= seq_read,
+	.llseek		= seq_lseek,
+	.release	= single_release,
+};
+
+#define FIRST_CMD_REG	0x30
+#define LAST_CMD_REG	0x33
+static int show_cmd_regs(struct seq_file *m, void *data)
+{
+	struct smb358_charger *chip = m->private;
+	int rc;
+	u8 reg;
+	u8 addr;
+
+	for (addr = FIRST_CMD_REG; addr <= LAST_CMD_REG; addr++) {
+		rc = smb358_read_reg(chip, addr, &reg);
+		if (!rc)
+			seq_printf(m, "0x%02x = 0x%02x\n", addr, reg);
+	}
+
+	return 0;
+}
+
+static int cmd_debugfs_open(struct inode *inode, struct file *file)
+{
+	struct smb358_charger *chip = inode->i_private;
+
+	return single_open(file, show_cmd_regs, chip);
+}
+
+static const struct file_operations cmd_debugfs_ops = {
+	.owner		= THIS_MODULE,
+	.open		= cmd_debugfs_open,
+	.read		= seq_read,
+	.llseek		= seq_lseek,
+	.release	= single_release,
+};
+
+#define FIRST_STATUS_REG	0x35
+#define LAST_STATUS_REG		0x3F
+static int show_status_regs(struct seq_file *m, void *data)
+{
+	struct smb358_charger *chip = m->private;
+	int rc;
+	u8 reg;
+	u8 addr;
+
+	for (addr = FIRST_STATUS_REG; addr <= LAST_STATUS_REG; addr++) {
+		rc = smb358_read_reg(chip, addr, &reg);
+		if (!rc)
+			seq_printf(m, "0x%02x = 0x%02x\n", addr, reg);
+	}
+
+	return 0;
+}
+
+static int status_debugfs_open(struct inode *inode, struct file *file)
+{
+	struct smb358_charger *chip = inode->i_private;
+
+	return single_open(file, show_status_regs, chip);
+}
+
+static const struct file_operations status_debugfs_ops = {
+	.owner		= THIS_MODULE,
+	.open		= status_debugfs_open,
+	.read		= seq_read,
+	.llseek		= seq_lseek,
+	.release	= single_release,
+};
+
+static int show_irq_count(struct seq_file *m, void *data)
+{
+	int i, j, total = 0;
+
+	for (i = 0; i < ARRAY_SIZE(handlers); i++)
+		for (j = 0; j < 4; j++) {
+			seq_printf(m, "%s=%d\t(high=%d low=%d)\n",
+						handlers[i].irq_info[j].name,
+						handlers[i].irq_info[j].high
+						+ handlers[i].irq_info[j].low,
+						handlers[i].irq_info[j].high,
+						handlers[i].irq_info[j].low);
+			total += (handlers[i].irq_info[j].high
+					+ handlers[i].irq_info[j].low);
+		}
+
+	seq_printf(m, "\n\tTotal = %d\n", total);
+
+	return 0;
+}
+
+static int irq_count_debugfs_open(struct inode *inode, struct file *file)
+{
+	struct smb358_charger *chip = inode->i_private;
+
+	return single_open(file, show_irq_count, chip);
+}
+
+static const struct file_operations irq_count_debugfs_ops = {
+	.owner		= THIS_MODULE,
+	.open		= irq_count_debugfs_open,
+	.read		= seq_read,
+	.llseek		= seq_lseek,
+	.release	= single_release,
+};
+
+static int get_reg(void *data, u64 *val)
+{
+	struct smb358_charger *chip = data;
+	int rc;
+	u8 temp;
+
+	rc = smb358_read_reg(chip, chip->peek_poke_address, &temp);
+	if (rc < 0) {
+		dev_err(chip->dev,
+			"Couldn't read reg %x rc = %d\n",
+			chip->peek_poke_address, rc);
+		return -EAGAIN;
+	}
+	*val = temp;
+	return 0;
+}
+
+static int set_reg(void *data, u64 val)
+{
+	struct smb358_charger *chip = data;
+	int rc;
+	u8 temp;
+
+	temp = (u8) val;
+	rc = smb358_write_reg(chip, chip->peek_poke_address, temp);
+	if (rc < 0) {
+		dev_err(chip->dev,
+			"Couldn't write 0x%02x to 0x%02x rc= %d\n",
+			chip->peek_poke_address, temp, rc);
+		return -EAGAIN;
+	}
+	return 0;
+}
+DEFINE_SIMPLE_ATTRIBUTE(poke_poke_debug_ops, get_reg, set_reg, "0x%02llx\n");
+
+static int force_irq_set(void *data, u64 val)
+{
+	struct smb358_charger *chip = data;
+
+	smb358_chg_stat_handler(chip->client->irq, data);
+	return 0;
+}
+DEFINE_SIMPLE_ATTRIBUTE(force_irq_ops, NULL, force_irq_set, "0x%02llx\n");
+#endif
+
+#ifdef DEBUG
+static void dump_regs(struct smb358_charger *chip)
+{
+	int rc;
+	u8 reg;
+	u8 addr;
+
+	for (addr = 0; addr <= LAST_CNFG_REG; addr++) {
+		rc = smb358_read_reg(chip, addr, &reg);
+		if (rc)
+			dev_err(chip->dev, "Couldn't read 0x%02x rc = %d\n",
+					addr, rc);
+		else
+			pr_debug("0x%02x = 0x%02x\n", addr, reg);
+	}
+
+	for (addr = FIRST_STATUS_REG; addr <= LAST_STATUS_REG; addr++) {
+		rc = smb358_read_reg(chip, addr, &reg);
+		if (rc)
+			dev_err(chip->dev, "Couldn't read 0x%02x rc = %d\n",
+					addr, rc);
+		else
+			pr_debug("0x%02x = 0x%02x\n", addr, reg);
+	}
+
+	for (addr = FIRST_CMD_REG; addr <= LAST_CMD_REG; addr++) {
+		rc = smb358_read_reg(chip, addr, &reg);
+		if (rc)
+			dev_err(chip->dev, "Couldn't read 0x%02x rc = %d\n",
+					addr, rc);
+		else
+			pr_debug("0x%02x = 0x%02x\n", addr, reg);
+	}
+}
+#else
+static void dump_regs(struct smb358_charger *chip)
+{
+}
+#endif
+
+static int smb_parse_dt(struct smb358_charger *chip)
+{
+	int rc;
+	enum of_gpio_flags gpio_flags;
+	struct device_node *node = chip->dev->of_node;
+	int batt_present_degree_negative;
+
+	if (!node) {
+		dev_err(chip->dev, "device tree info. missing\n");
+		return -EINVAL;
+	}
+
+	chip->charging_disabled = of_property_read_bool(node,
+					"qcom,charger-disabled");
+
+	chip->chg_autonomous_mode = of_property_read_bool(node,
+					"qcom,chg-autonomous-mode");
+
+	chip->disable_apsd = of_property_read_bool(node, "qcom,disable-apsd");
+
+	chip->using_pmic_therm = of_property_read_bool(node,
+						"qcom,using-pmic-therm");
+
+	rc = of_property_read_string(node, "qcom,bms-psy-name",
+						&chip->bms_psy_name);
+	if (rc)
+		chip->bms_psy_name = NULL;
+
+	chip->chg_valid_gpio = of_get_named_gpio_flags(node,
+				"qcom,chg-valid-gpio", 0, &gpio_flags);
+	if (!gpio_is_valid(chip->chg_valid_gpio))
+		dev_dbg(chip->dev, "Invalid chg-valid-gpio");
+	else
+		chip->chg_valid_act_low = gpio_flags & OF_GPIO_ACTIVE_LOW;
+
+	rc = of_property_read_u32(node, "qcom,fastchg-current-max-ma",
+						&chip->fastchg_current_max_ma);
+	if (rc)
+		chip->fastchg_current_max_ma = SMB358_FAST_CHG_MAX_MA;
+
+	chip->ieerm_disabled = of_property_read_bool(node,
+					"qcom,iterm-disabled");
+
+	rc = of_property_read_u32(node, "qcom,iterm-ma", &chip->iterm_ma);
+	if (rc < 0)
+		chip->iterm_ma = -EINVAL;
+
+	rc = of_property_read_u32(node, "qcom,float-voltage-mv",
+						&chip->vfloat_mv);
+	if (rc < 0) {
+		chip->vfloat_mv = -EINVAL;
+		pr_err("float-voltage-mv property missing, exit\n");
+		return -EINVAL;
+	}
+
+	rc = of_property_read_u32(node, "qcom,recharge-mv",
+						&chip->recharge_mv);
+	if (rc < 0)
+		chip->recharge_mv = -EINVAL;
+
+	chip->recharge_disabled = of_property_read_bool(node,
+					"qcom,recharge-disabled");
+
+	rc = of_property_read_u32(node, "qcom,cold-bat-decidegc",
+						&chip->cold_bat_decidegc);
+	if (rc < 0)
+		chip->cold_bat_decidegc = -EINVAL;
+
+	rc = of_property_read_u32(node, "qcom,hot-bat-decidegc",
+						&chip->hot_bat_decidegc);
+	if (rc < 0)
+		chip->hot_bat_decidegc = -EINVAL;
+
+	rc = of_property_read_u32(node, "qcom,bat-present-decidegc",
+						&batt_present_degree_negative);
+	if (rc < 0)
+		chip->bat_present_decidegc = -EINVAL;
+	else
+		chip->bat_present_decidegc = -batt_present_degree_negative;
+
+	pr_debug("recharge-disabled = %d, recharge-mv = %d,",
+			chip->recharge_disabled, chip->recharge_mv);
+	pr_debug("vfloat-mv = %d, iterm-disabled = %d,",
+			chip->vfloat_mv, chip->iterm_ma);
+	pr_debug("fastchg-current = %d, charging-disabled = %d,",
+			chip->fastchg_current_max_ma,
+					chip->charging_disabled);
+	pr_debug("disable-apsd = %d bms = %s cold-bat-degree = %d,",
+		chip->disable_apsd, chip->bms_psy_name,
+					chip->cold_bat_decidegc);
+	pr_debug("hot-bat-degree = %d, bat-present-decidegc = %d\n",
+		chip->hot_bat_decidegc, chip->bat_present_decidegc);
+	return 0;
+}
+
+static int determine_initial_state(struct smb358_charger *chip)
+{
+	int rc;
+	u8 reg = 0;
+
+	rc = smb358_read_reg(chip, IRQ_B_REG, &reg);
+	if (rc) {
+		dev_err(chip->dev, "Couldn't read IRQ_B rc = %d\n", rc);
+		goto fail_init_status;
+	}
+
+	rc = smb358_read_reg(chip, IRQ_C_REG, &reg);
+	if (rc) {
+		dev_err(chip->dev, "Couldn't read IRQ_C rc = %d\n", rc);
+		goto fail_init_status;
+	}
+	chip->batt_full = (reg & IRQ_C_TERM_BIT) ? true : false;
+
+	rc = smb358_read_reg(chip, IRQ_A_REG, &reg);
+	if (rc < 0) {
+		dev_err(chip->dev, "Couldn't read irq A rc = %d\n", rc);
+		return rc;
+	}
+
+	/* For current design, can ignore this */
+	if (reg & IRQ_A_HOT_HARD_BIT)
+		chip->batt_hot = true;
+	if (reg & IRQ_A_COLD_HARD_BIT)
+		chip->batt_cold = true;
+	if (reg & IRQ_A_HOT_SOFT_BIT)
+		chip->batt_warm = true;
+	if (reg & IRQ_A_COLD_SOFT_BIT)
+		chip->batt_cool = true;
+
+	rc = smb358_read_reg(chip, IRQ_E_REG, &reg);
+	if (rc) {
+		dev_err(chip->dev, "Couldn't read IRQ_E rc = %d\n", rc);
+		goto fail_init_status;
+	}
+
+	if (reg & IRQ_E_INPUT_UV_BIT) {
+		chg_uv(chip, 1);
+	} else {
+		chg_uv(chip, 0);
+		apsd_complete(chip, 1);
+	}
+
+	return 0;
+
+fail_init_status:
+	dev_err(chip->dev, "Couldn't determine initial status\n");
+	return rc;
+}
+
+#if defined(CONFIG_DEBUG_FS)
+static void smb358_debugfs_init(struct smb358_charger *chip)
+{
+	int rc;
+	chip->debug_root = debugfs_create_dir("smb358", NULL);
+	if (!chip->debug_root)
+		dev_err(chip->dev, "Couldn't create debug dir\n");
+
+	if (chip->debug_root) {
+		struct dentry *ent;
+
+		ent = debugfs_create_file("config_registers", S_IFREG | S_IRUGO,
+					  chip->debug_root, chip,
+					  &cnfg_debugfs_ops);
+		if (!ent || IS_ERR(ent)) {
+			rc = PTR_ERR(ent);
+			dev_err(chip->dev,
+				"Couldn't create cnfg debug file rc = %d\n",
+				rc);
+		}
+
+		ent = debugfs_create_file("status_registers", S_IFREG | S_IRUGO,
+					  chip->debug_root, chip,
+					  &status_debugfs_ops);
+		if (!ent || IS_ERR(ent)) {
+			rc = PTR_ERR(ent);
+			dev_err(chip->dev,
+				"Couldn't create status debug file rc = %d\n",
+				rc);
+		}
+
+		ent = debugfs_create_file("cmd_registers", S_IFREG | S_IRUGO,
+					  chip->debug_root, chip,
+					  &cmd_debugfs_ops);
+		if (!ent || IS_ERR(ent)) {
+			rc = PTR_ERR(ent);
+			dev_err(chip->dev,
+				"Couldn't create cmd debug file rc = %d\n",
+				rc);
+		}
+
+		ent = debugfs_create_x32("address", S_IFREG | S_IWUSR | S_IRUGO,
+					  chip->debug_root,
+					  &(chip->peek_poke_address));
+		if (!ent || IS_ERR(ent)) {
+			rc = PTR_ERR(ent);
+			dev_err(chip->dev,
+				"Couldn't create address debug file rc = %d\n",
+				rc);
+		}
+
+		ent = debugfs_create_file("data", S_IFREG | S_IWUSR | S_IRUGO,
+					  chip->debug_root, chip,
+					  &poke_poke_debug_ops);
+		if (!ent || IS_ERR(ent)) {
+			rc = PTR_ERR(ent);
+			dev_err(chip->dev,
+				"Couldn't create data debug file rc = %d\n",
+				rc);
+		}
+
+		ent = debugfs_create_file("force_irq",
+					  S_IFREG | S_IWUSR | S_IRUGO,
+					  chip->debug_root, chip,
+					  &force_irq_ops);
+		if (!ent || IS_ERR(ent)) {
+			rc = PTR_ERR(ent);
+			dev_err(chip->dev,
+				"Couldn't create force_irq debug file rc =%d\n",
+				rc);
+		}
+
+		ent = debugfs_create_file("irq_count", S_IFREG | S_IRUGO,
+					  chip->debug_root, chip,
+					  &irq_count_debugfs_ops);
+		if (!ent || IS_ERR(ent)) {
+			rc = PTR_ERR(ent);
+			dev_err(chip->dev,
+				"Couldn't create cnfg irq_count file rc = %d\n",
+				rc);
+		}
+	}
+}
+#else
+static void smb358_debugfs_init(struct smb358_charger *chip)
+{
+}
+#endif
+
+#define SMB_I2C_VTG_MIN_UV 1800000
+#define SMB_I2C_VTG_MAX_UV 1800000
+static int smb358_charger_probe(struct i2c_client *client,
+				const struct i2c_device_id *id)
+{
+	int rc, irq;
+	struct smb358_charger *chip;
+	struct power_supply *usb_psy;
+	u8 reg = 0;
+
+	usb_psy = power_supply_get_by_name("usb");
+	if (!usb_psy) {
+		dev_dbg(&client->dev, "USB psy not found; deferring probe\n");
+		return -EPROBE_DEFER;
+	}
+
+	chip = devm_kzalloc(&client->dev, sizeof(*chip), GFP_KERNEL);
+	if (!chip) {
+		dev_err(&client->dev, "Couldn't allocate memory\n");
+		return -ENOMEM;
+	}
+
+	chip->client = client;
+	chip->dev = &client->dev;
+	chip->usb_psy = usb_psy;
+	chip->fake_battery_soc = -EINVAL;
+
+	/* early for VADC get, defer probe if needed */
+	chip->vadc_dev = qpnp_get_vadc(chip->dev, "chg");
+	if (IS_ERR(chip->vadc_dev)) {
+		rc = PTR_ERR(chip->vadc_dev);
+		if (rc != -EPROBE_DEFER)
+			pr_err("vadc property missing\n");
+		return rc;
+	}
+
+	/* i2c pull up Regulator configuration */
+	chip->vcc_i2c = regulator_get(&client->dev, "vcc-i2c");
+	if (IS_ERR(chip->vcc_i2c)) {
+		dev_err(&client->dev,
+				"%s: Failed to get vcc_i2c regulator\n",
+					__func__);
+		rc = PTR_ERR(chip->vcc_i2c);
+		goto err_get_vtg_i2c;
+	}
+
+	if (regulator_count_voltages(chip->vcc_i2c) > 0) {
+		rc = regulator_set_voltage(chip->vcc_i2c,
+				SMB_I2C_VTG_MIN_UV, SMB_I2C_VTG_MAX_UV);
+		if (rc) {
+			dev_err(&client->dev,
+				"regulator vcc_i2c set failed, rc = %d\n",
+					rc);
+			goto err_set_vtg_i2c;
+		}
+	}
+
+	rc = regulator_enable(chip->vcc_i2c);
+	if (rc) {
+		dev_err(&client->dev,
+			"Regulator vcc_i2c enable failed "
+				"rc=%d\n", rc);
+		goto err_set_vtg_i2c;
+	}
+
+	mutex_init(&chip->irq_complete);
+	mutex_init(&chip->read_write_lock);
+	mutex_init(&chip->path_suspend_lock);
+
+	/* probe the device to check if its actually connected */
+	rc = smb358_read_reg(chip, CHG_OTH_CURRENT_CTRL_REG, &reg);
+	if (rc) {
+		pr_err("Failed to detect SMB358, device absent, rc = %d\n", rc);
+		goto err_set_vtg_i2c;
+	}
+
+	rc = smb_parse_dt(chip);
+	if (rc) {
+		dev_err(&client->dev, "Couldn't parse DT nodes rc=%d\n", rc);
+		goto err_set_vtg_i2c;
+	}
+
+	/* using adc_tm for implementing pmic therm */
+	if (chip->using_pmic_therm) {
+		chip->adc_tm_dev = qpnp_get_adc_tm(chip->dev, "chg");
+		if (IS_ERR(chip->adc_tm_dev)) {
+			rc = PTR_ERR(chip->adc_tm_dev);
+			if (rc != -EPROBE_DEFER)
+				pr_err("adc_tm property missing\n");
+			return rc;
+		}
+	}
+
+	i2c_set_clientdata(client, chip);
+
+	chip->batt_psy.name		= "battery";
+	chip->batt_psy.type		= POWER_SUPPLY_TYPE_BATTERY;
+	chip->batt_psy.get_property	= smb358_battery_get_property;
+	chip->batt_psy.set_property	= smb358_battery_set_property;
+	chip->batt_psy.property_is_writeable =
+					smb358_batt_property_is_writeable;
+	chip->batt_psy.properties	= smb358_battery_properties;
+	chip->batt_psy.num_properties	= ARRAY_SIZE(smb358_battery_properties);
+	chip->batt_psy.external_power_changed = smb358_external_power_changed;
+	chip->batt_psy.supplied_to = pm_batt_supplied_to;
+	chip->batt_psy.num_supplicants = ARRAY_SIZE(pm_batt_supplied_to);
+
+	chip->resume_completed = true;
+
+	rc = power_supply_register(chip->dev, &chip->batt_psy);
+	if (rc < 0) {
+		dev_err(&client->dev, "Couldn't register batt psy rc = %d\n",
+				rc);
+		goto err_set_vtg_i2c;
+	}
+
+	dump_regs(chip);
+
+	rc = smb358_regulator_init(chip);
+	if  (rc) {
+		dev_err(&client->dev,
+			"Couldn't initialize smb358 ragulator rc=%d\n", rc);
+		goto err_set_vtg_i2c;
+	}
+
+	rc = smb358_hw_init(chip);
+	if (rc) {
+		dev_err(&client->dev,
+			"Couldn't intialize hardware rc=%d\n", rc);
+		goto fail_smb358_hw_init;
+	}
+
+	rc = determine_initial_state(chip);
+	if (rc) {
+		dev_err(&client->dev,
+			"Couldn't determine initial state rc=%d\n", rc);
+		goto fail_smb358_hw_init;
+	}
+
+	/* We will not use it by default */
+	if (gpio_is_valid(chip->chg_valid_gpio)) {
+		rc = gpio_request(chip->chg_valid_gpio, "smb358_chg_valid");
+		if (rc) {
+			dev_err(&client->dev,
+				"gpio_request for %d failed rc=%d\n",
+				chip->chg_valid_gpio, rc);
+			goto fail_chg_valid_irq;
+		}
+		irq = gpio_to_irq(chip->chg_valid_gpio);
+		if (irq < 0) {
+			dev_err(&client->dev,
+				"Invalid chg_valid irq = %d\n", irq);
+			goto fail_chg_valid_irq;
+		}
+		rc = devm_request_threaded_irq(&client->dev, irq,
+				NULL, smb358_chg_valid_handler,
+				IRQF_TRIGGER_FALLING | IRQF_TRIGGER_RISING,
+				"smb358_chg_valid_irq", chip);
+		if (rc) {
+			dev_err(&client->dev,
+				"Failed request_irq irq=%d, gpio=%d rc=%d\n",
+				irq, chip->chg_valid_gpio, rc);
+			goto fail_chg_valid_irq;
+		}
+		smb358_chg_valid_handler(irq, chip);
+		enable_irq_wake(irq);
+	}
+
+	chip->irq_gpio = of_get_named_gpio_flags(chip->dev->of_node,
+				"qcom,irq-gpio", 0, NULL);
+
+	/* STAT irq configuration */
+	if (gpio_is_valid(chip->irq_gpio)) {
+		rc = gpio_request(chip->irq_gpio, "smb358_irq");
+		if (rc) {
+			dev_err(&client->dev,
+					"irq gpio request failed, rc=%d", rc);
+			goto fail_smb358_hw_init;
+		}
+		rc = gpio_direction_input(chip->irq_gpio);
+		if (rc) {
+			dev_err(&client->dev,
+					"set_direction for irq gpio failed\n");
+			goto fail_irq_gpio;
+		}
+
+		irq = gpio_to_irq(chip->irq_gpio);
+		if (irq < 0) {
+			dev_err(&client->dev,
+				"Invalid irq_gpio irq = %d\n", irq);
+			goto fail_irq_gpio;
+		}
+		rc = devm_request_threaded_irq(&client->dev, irq, NULL,
+				smb358_chg_stat_handler,
+				IRQF_TRIGGER_FALLING | IRQF_ONESHOT,
+				"smb358_chg_stat_irq", chip);
+		if (rc) {
+			dev_err(&client->dev,
+				"Failed STAT irq=%d request rc = %d\n",
+				irq, rc);
+			goto fail_irq_gpio;
+		}
+		enable_irq_wake(irq);
+	} else {
+		goto fail_irq_gpio;
+	}
+
+	if (chip->using_pmic_therm) {
+		/* add hot/cold temperature monitor */
+		chip->adc_param.low_temp = chip->cold_bat_decidegc;
+		chip->adc_param.high_temp = chip->hot_bat_decidegc;
+		chip->adc_param.timer_interval = ADC_MEAS2_INTERVAL_1S;
+		chip->adc_param.state_request = ADC_TM_HIGH_LOW_THR_ENABLE;
+		chip->adc_param.btm_ctx = chip;
+		chip->adc_param.threshold_notification =
+				smb_chg_adc_notification;
+		chip->adc_param.channel = LR_MUX1_BATT_THERM;
+
+		/* update battery missing info in tm_channel_measure*/
+		rc = qpnp_adc_tm_channel_measure(chip->adc_tm_dev,
+							&chip->adc_param);
+		if (rc)
+			pr_err("requesting ADC error %d\n", rc);
+	}
+
+	smb358_debugfs_init(chip);
+
+	dump_regs(chip);
+
+	dev_info(chip->dev, "SMB358 successfully probed. charger=%d, batt=%d\n",
+			chip->chg_present, smb358_get_prop_batt_present(chip));
+	return 0;
+
+fail_chg_valid_irq:
+	if (gpio_is_valid(chip->chg_valid_gpio))
+		gpio_free(chip->chg_valid_gpio);
+fail_irq_gpio:
+	if (gpio_is_valid(chip->irq_gpio))
+		gpio_free(chip->irq_gpio);
+fail_smb358_hw_init:
+	power_supply_unregister(&chip->batt_psy);
+	regulator_unregister(chip->otg_vreg.rdev);
+err_set_vtg_i2c:
+	if (regulator_count_voltages(chip->vcc_i2c) > 0)
+		regulator_set_voltage(chip->vcc_i2c, 0, SMB_I2C_VTG_MAX_UV);
+err_get_vtg_i2c:
+	regulator_put(chip->vcc_i2c);
+	return rc;
+}
+
+static int smb358_charger_remove(struct i2c_client *client)
+{
+	struct smb358_charger *chip = i2c_get_clientdata(client);
+
+	power_supply_unregister(&chip->batt_psy);
+	if (gpio_is_valid(chip->chg_valid_gpio))
+		gpio_free(chip->chg_valid_gpio);
+
+	regulator_disable(chip->vcc_i2c);
+	regulator_put(chip->vcc_i2c);
+	mutex_destroy(&chip->irq_complete);
+	debugfs_remove_recursive(chip->debug_root);
+	return 0;
+}
+
+static int smb358_suspend(struct device *dev)
+{
+	struct i2c_client *client = to_i2c_client(dev);
+	struct smb358_charger *chip = i2c_get_clientdata(client);
+	int rc;
+	int i;
+
+	for (i = 0; i < 2; i++) {
+		rc = smb358_read_reg(chip, FAULT_INT_REG + i,
+					&chip->irq_cfg_mask[i]);
+		if (rc)
+			dev_err(chip->dev,
+				"Couldn't save irq cfg regs rc = %d\n", rc);
+	}
+
+	/* enable wake up IRQs */
+	rc = smb358_write_reg(chip, FAULT_INT_REG,
+			FAULT_INT_HOT_COLD_HARD_BIT | FAULT_INT_INPUT_UV_BIT);
+	if (rc < 0)
+		dev_err(chip->dev, "Couldn't set fault_irq_cfg rc = %d\n", rc);
+
+	rc = smb358_write_reg(chip, STATUS_INT_REG,
+			STATUS_INT_LOW_BATT_BIT | STATUS_INT_MISSING_BATT_BIT |
+			STATUS_INT_CHGING_BIT | STATUS_INT_INOK_BIT |
+			STATUS_INT_OTG_DETECT_BIT | STATUS_INT_CHG_INHI_BIT);
+	if (rc < 0)
+		dev_err(chip->dev,
+			"Couldn't set status_irq_cfg rc = %d\n", rc);
+
+	mutex_lock(&chip->irq_complete);
+	rc = regulator_disable(chip->vcc_i2c);
+	if (rc) {
+		dev_err(chip->dev,
+			"Regulator vcc_i2c disable failed rc=%d\n", rc);
+		mutex_unlock(&chip->irq_complete);
+		return rc;
+	}
+
+	chip->resume_completed = false;
+	mutex_unlock(&chip->irq_complete);
+	return 0;
+}
+
+static int smb358_suspend_noirq(struct device *dev)
+{
+	struct i2c_client *client = to_i2c_client(dev);
+	struct smb358_charger *chip = i2c_get_clientdata(client);
+
+	if (chip->irq_waiting) {
+		pr_err_ratelimited("Aborting suspend, an interrupt was detected while suspending\n");
+		return -EBUSY;
+	}
+	return 0;
+}
+
+static int smb358_resume(struct device *dev)
+{
+	struct i2c_client *client = to_i2c_client(dev);
+	struct smb358_charger *chip = i2c_get_clientdata(client);
+	int rc;
+	int i;
+
+	/* Restore IRQ config */
+	for (i = 0; i < 2; i++) {
+		rc = smb358_write_reg(chip, FAULT_INT_REG + i,
+					chip->irq_cfg_mask[i]);
+		if (rc)
+			dev_err(chip->dev,
+				"Couldn't restore irq cfg regs rc=%d\n", rc);
+	}
+
+	mutex_lock(&chip->irq_complete);
+	rc = regulator_enable(chip->vcc_i2c);
+	if (rc) {
+		dev_err(chip->dev,
+			"Regulator vcc_i2c enable failed rc=%d\n", rc);
+		mutex_unlock(&chip->irq_complete);
+		return rc;
+	}
+	chip->resume_completed = true;
+
+	mutex_unlock(&chip->irq_complete);
+	if (chip->irq_waiting) {
+		smb358_chg_stat_handler(client->irq, chip);
+		enable_irq(client->irq);
+	}
+	return 0;
+}
+
+static const struct dev_pm_ops smb358_pm_ops = {
+	.suspend	= smb358_suspend,
+	.suspend_noirq	= smb358_suspend_noirq,
+	.resume		= smb358_resume,
+};
+
+static struct of_device_id smb358_match_table[] = {
+	{ .compatible = "qcom,smb358-charger",},
+	{ },
+};
+
+static const struct i2c_device_id smb358_charger_id[] = {
+	{"smb358-charger", 0},
+	{},
+};
+MODULE_DEVICE_TABLE(i2c, smb358_charger_id);
+
+static struct i2c_driver smb358_charger_driver = {
+	.driver		= {
+		.name		= "smb358-charger",
+		.owner		= THIS_MODULE,
+		.of_match_table = smb358_match_table,
+		.pm		= &smb358_pm_ops,
+	},
+	.probe		= smb358_charger_probe,
+	.remove		= smb358_charger_remove,
+	.id_table	= smb358_charger_id,
+};
+
+module_i2c_driver(smb358_charger_driver);
+
+MODULE_DESCRIPTION("SMB358 Charger");
+MODULE_LICENSE("GPL v2");
+MODULE_ALIAS("i2c:smb358-charger");
diff --git a/drivers/regulator/Kconfig b/drivers/regulator/Kconfig
index e9994c2..f721a25 100644
--- a/drivers/regulator/Kconfig
+++ b/drivers/regulator/Kconfig
@@ -140,6 +140,15 @@
 	  Say y here to support the regulators found on the Freescale MC13892
 	  PMIC.
 
+config REGULATOR_MEM_ACC
+	tristate "QTI Memory accelerator regulator driver"
+	help
+	 Say y here to enable the memory accelerator driver for Qualcomm
+	 Technologies (QTI) chips. The accelerator controls delays applied
+	 for memory accesses.
+	 This driver configures the power-mode (corner) for the memory
+	 accelerator.
+
 config REGULATOR_ISL6271A
 	tristate "Intersil ISL6271A Power regulator"
 	depends on I2C
diff --git a/drivers/regulator/Makefile b/drivers/regulator/Makefile
index d96e793..1393f23 100644
--- a/drivers/regulator/Makefile
+++ b/drivers/regulator/Makefile
@@ -34,6 +34,7 @@
 obj-$(CONFIG_REGULATOR_MC13783) += mc13783-regulator.o
 obj-$(CONFIG_REGULATOR_MC13892) += mc13892-regulator.o
 obj-$(CONFIG_REGULATOR_MC13XXX_CORE) +=  mc13xxx-regulator-core.o
+obj-$(CONFIG_REGULATOR_MEM_ACC) += mem-acc-regulator.o
 obj-$(CONFIG_REGULATOR_ONSEMI_NCP6335D) += onsemi-ncp6335d.o
 obj-$(CONFIG_REGULATOR_PCAP) += pcap-regulator.o
 obj-$(CONFIG_REGULATOR_PCF50633) += pcf50633-regulator.o
diff --git a/drivers/regulator/mem-acc-regulator.c b/drivers/regulator/mem-acc-regulator.c
new file mode 100644
index 0000000..b66285a
--- /dev/null
+++ b/drivers/regulator/mem-acc-regulator.c
@@ -0,0 +1,461 @@
+/* Copyright (c) 2014, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+#define pr_fmt(fmt)	"ACC: %s: " fmt, __func__
+
+#include <linux/module.h>
+#include <linux/types.h>
+#include <linux/init.h>
+#include <linux/slab.h>
+#include <linux/err.h>
+#include <linux/of.h>
+#include <linux/of_device.h>
+#include <linux/io.h>
+#include <linux/platform_device.h>
+#include <linux/regulator/driver.h>
+#include <linux/regulator/machine.h>
+#include <linux/regulator/of_regulator.h>
+
+#define MEM_ACC_SEL_MASK	0x3
+
+enum {
+	MEMORY_L1,
+	MEMORY_L2,
+	MEMORY_MAX,
+};
+
+struct mem_acc_regulator {
+	struct device		*dev;
+	struct regulator_desc	rdesc;
+	struct regulator_dev	*rdev;
+
+	int			corner;
+	bool			mem_acc_supported[MEMORY_MAX];
+
+	u32			acc_sel_reg[MEMORY_MAX];
+	u32			*acc_sel_mask[MEMORY_MAX];
+	u32			*acc_sel_bit_pos[MEMORY_MAX];
+	u32			num_acc_sel[MEMORY_MAX];
+	u32			*acc_en_bit_pos;
+	u32			num_acc_en;
+	u32			*corner_acc_map;
+	u32			num_corners;
+
+	void __iomem		*acc_sel_base[MEMORY_MAX];
+	void __iomem		*acc_en_base;
+	phys_addr_t		acc_sel_addr[MEMORY_MAX];
+	phys_addr_t		acc_en_addr;
+};
+
+static inline u32 apc_to_acc_corner(struct mem_acc_regulator *mem_acc_vreg,
+								int corner)
+{
+	/*
+	 * corner_acc_map maps the corner from index 0 and  APC corner value
+	 * starts from the value 1
+	 */
+	return mem_acc_vreg->corner_acc_map[corner - 1];
+}
+
+static void __update_acc_sel(struct mem_acc_regulator *mem_acc_vreg,
+						int corner, int mem_type)
+{
+	u32 acc_data, i, bit, acc_corner;
+
+	acc_data = mem_acc_vreg->acc_sel_reg[mem_type];
+	for (i = 0; i < mem_acc_vreg->num_acc_sel[mem_type]; i++) {
+		bit = mem_acc_vreg->acc_sel_bit_pos[mem_type][i];
+		acc_data &= ~mem_acc_vreg->acc_sel_mask[mem_type][i];
+		acc_corner = apc_to_acc_corner(mem_acc_vreg, corner);
+		acc_data |= (acc_corner << bit) &
+			mem_acc_vreg->acc_sel_mask[mem_type][i];
+	}
+	pr_debug("corner=%d old_acc_sel=0x%02x new_acc_sel=0x%02x mem_type=%d\n",
+			corner, mem_acc_vreg->acc_sel_reg[mem_type],
+						acc_data, mem_type);
+	writel_relaxed(acc_data, mem_acc_vreg->acc_sel_base[mem_type]);
+	mem_acc_vreg->acc_sel_reg[mem_type] = acc_data;
+}
+
+static void update_acc_sel(struct mem_acc_regulator *mem_acc_vreg, int corner)
+{
+	int i;
+
+	for (i = 0; i < MEMORY_MAX; i++) {
+		if (mem_acc_vreg->mem_acc_supported[i])
+			__update_acc_sel(mem_acc_vreg, corner, i);
+	}
+}
+
+static int mem_acc_regulator_set_voltage(struct regulator_dev *rdev,
+		int corner, int corner_max, unsigned *selector)
+{
+	struct mem_acc_regulator *mem_acc_vreg = rdev_get_drvdata(rdev);
+	int i;
+
+	if (corner > mem_acc_vreg->num_corners) {
+		pr_err("Invalid corner=%d requested\n", corner);
+		return -EINVAL;
+	}
+
+	pr_debug("old corner=%d, new corner=%d\n",
+			mem_acc_vreg->corner, corner);
+
+	if (corner == mem_acc_vreg->corner)
+		return 0;
+
+	/* go up or down one level at a time */
+	if (corner > mem_acc_vreg->corner) {
+		for (i = mem_acc_vreg->corner + 1; i <= corner; i++) {
+			pr_debug("UP: to corner %d\n", i);
+			update_acc_sel(mem_acc_vreg, i);
+		}
+	} else {
+		for (i = mem_acc_vreg->corner - 1; i >= corner; i--) {
+			pr_debug("DOWN: to corner %d\n", i);
+			update_acc_sel(mem_acc_vreg, i);
+		}
+	}
+
+	pr_debug("new voltage corner set %d\n", corner);
+
+	mem_acc_vreg->corner = corner;
+
+	return 0;
+}
+
+static int mem_acc_regulator_get_voltage(struct regulator_dev *rdev)
+{
+	struct mem_acc_regulator *mem_acc_vreg = rdev_get_drvdata(rdev);
+
+	return mem_acc_vreg->corner;
+}
+
+static struct regulator_ops mem_acc_corner_ops = {
+	.set_voltage		= mem_acc_regulator_set_voltage,
+	.get_voltage		= mem_acc_regulator_get_voltage,
+};
+
+static int __mem_acc_sel_init(struct mem_acc_regulator *mem_acc_vreg,
+							int mem_type)
+{
+	int i;
+	u32 bit;
+
+	mem_acc_vreg->acc_sel_mask[mem_type] = devm_kzalloc(mem_acc_vreg->dev,
+		mem_acc_vreg->num_acc_sel[mem_type] * sizeof(u32), GFP_KERNEL);
+	if (!mem_acc_vreg->acc_sel_mask[mem_type]) {
+		pr_err("Unable to allocate memory for mem_type=%d\n", mem_type);
+		return -ENOMEM;
+	}
+
+	for (i = 0; i < mem_acc_vreg->num_acc_sel[mem_type]; i++) {
+		bit = mem_acc_vreg->acc_sel_bit_pos[mem_type][i];
+		mem_acc_vreg->acc_sel_mask[mem_type][i] =
+					MEM_ACC_SEL_MASK << bit;
+	}
+
+	mem_acc_vreg->acc_sel_reg[mem_type] =
+		readl_relaxed(mem_acc_vreg->acc_sel_base[mem_type]);
+
+	return 0;
+}
+
+static int mem_acc_sel_init(struct mem_acc_regulator *mem_acc_vreg)
+{
+	int i, rc;
+
+	for (i = 0; i < MEMORY_MAX; i++) {
+		if (mem_acc_vreg->mem_acc_supported[i]) {
+			rc = __mem_acc_sel_init(mem_acc_vreg, i);
+			if (rc) {
+				pr_err("Unable to intialize mem_type=%d rc=%d\n",
+								i, rc);
+				return rc;
+			}
+		}
+	}
+
+	return 0;
+}
+
+static void mem_acc_en_init(struct mem_acc_regulator *mem_acc_vreg)
+{
+	int i, bit;
+	u32 acc_data;
+
+	acc_data = readl_relaxed(mem_acc_vreg->acc_en_base);
+	pr_debug("init: acc_en_register=%x\n", acc_data);
+	for (i = 0; i < mem_acc_vreg->num_acc_en; i++) {
+		bit = mem_acc_vreg->acc_en_bit_pos[i];
+		acc_data |= BIT(bit);
+	}
+	pr_debug("final: acc_en_register=%x\n", acc_data);
+	writel_relaxed(acc_data, mem_acc_vreg->acc_en_base);
+}
+
+static int populate_acc_data(struct mem_acc_regulator *mem_acc_vreg,
+			const char *prop_name, u32 **value, u32 *len)
+{
+	int rc;
+
+	if (!of_get_property(mem_acc_vreg->dev->of_node, prop_name, len)) {
+		pr_err("Unable to find %s property\n", prop_name);
+		return -EINVAL;
+	}
+	*len /= sizeof(u32);
+	if (!(*len)) {
+		pr_err("Incorrect entries in %s\n", prop_name);
+		return -EINVAL;
+	}
+
+	*value = devm_kzalloc(mem_acc_vreg->dev, (*len) * sizeof(u32),
+							GFP_KERNEL);
+	if (!(*value)) {
+		pr_err("Unable to allocate memory for %s\n", prop_name);
+		return -ENOMEM;
+	}
+
+	pr_debug("Found %s, data-length = %d\n", prop_name, *len);
+
+	rc = of_property_read_u32_array(mem_acc_vreg->dev->of_node,
+					prop_name, *value, *len);
+	if (rc) {
+		pr_err("Unable to populate %s rc=%d\n", prop_name, rc);
+		return rc;
+	}
+
+	return 0;
+}
+
+static int mem_acc_sel_setup(struct mem_acc_regulator *mem_acc_vreg,
+			struct resource *res, int mem_type)
+{
+	int len, rc;
+	char *mem_select_str;
+
+	mem_acc_vreg->acc_sel_addr[mem_type] = res->start;
+	len = res->end - res->start + 1;
+	pr_debug("'acc_sel_addr' = %pa mem_type=%d (len=%d)\n",
+					&res->start, mem_type, len);
+
+	mem_acc_vreg->acc_sel_base[mem_type] = devm_ioremap(mem_acc_vreg->dev,
+			mem_acc_vreg->acc_sel_addr[mem_type], len);
+	if (!mem_acc_vreg->acc_sel_base[mem_type]) {
+		pr_err("Unable to map 'acc_sel_addr' %pa for mem_type=%d\n",
+			&mem_acc_vreg->acc_sel_addr[mem_type], mem_type);
+		return -EINVAL;
+	}
+
+	switch (mem_type) {
+	case MEMORY_L1:
+		mem_select_str = "qcom,acc-sel-l1-bit-pos";
+		break;
+	case MEMORY_L2:
+		mem_select_str = "qcom,acc-sel-l2-bit-pos";
+		break;
+	}
+
+	rc = populate_acc_data(mem_acc_vreg, mem_select_str,
+			&mem_acc_vreg->acc_sel_bit_pos[mem_type],
+			&mem_acc_vreg->num_acc_sel[mem_type]);
+	if (rc)
+		pr_err("Unable to populate '%s' rc=%d\n", mem_select_str, rc);
+
+	return rc;
+}
+
+static int mem_acc_init(struct platform_device *pdev,
+		struct mem_acc_regulator *mem_acc_vreg)
+{
+	struct resource *res;
+	int len, rc, i;
+
+	res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "acc-en");
+	if (!res || !res->start) {
+		pr_debug("'acc-en' resource missing or not used.\n");
+	} else {
+		mem_acc_vreg->acc_en_addr = res->start;
+		len = res->end - res->start + 1;
+		pr_debug("'acc_en_addr' = %pa (len=0x%x)\n", &res->start, len);
+
+		mem_acc_vreg->acc_en_base = devm_ioremap(mem_acc_vreg->dev,
+				mem_acc_vreg->acc_en_addr, len);
+		if (!mem_acc_vreg->acc_en_base) {
+			pr_err("Unable to map 'acc_en_addr' %pa\n",
+					&mem_acc_vreg->acc_en_addr);
+			return -EINVAL;
+		}
+
+		rc = populate_acc_data(mem_acc_vreg, "qcom,acc-en-bit-pos",
+				&mem_acc_vreg->acc_en_bit_pos,
+				&mem_acc_vreg->num_acc_en);
+		if (rc) {
+			pr_err("Unable to populate 'qcom,acc-en-bit-pos' rc=%d\n",
+					rc);
+			return rc;
+		}
+	}
+
+	res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "acc-sel-l1");
+	if (!res || !res->start) {
+		pr_debug("'acc-sel-l1' resource missing or not used.\n");
+	} else {
+		rc = mem_acc_sel_setup(mem_acc_vreg, res, MEMORY_L1);
+		if (rc) {
+			pr_err("Unable to setup mem-acc for mem_type=%d rc=%d\n",
+					MEMORY_L1, rc);
+			return rc;
+		}
+		mem_acc_vreg->mem_acc_supported[MEMORY_L1] = true;
+	}
+
+	res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "acc-sel-l2");
+	if (!res || !res->start) {
+		pr_debug("'acc-sel-l2' resource missing or not used.\n");
+	} else {
+		rc = mem_acc_sel_setup(mem_acc_vreg, res, MEMORY_L2);
+		if (rc) {
+			pr_err("Unable to setup mem-acc for mem_type=%d rc=%d\n",
+					MEMORY_L2, rc);
+			return rc;
+		}
+		mem_acc_vreg->mem_acc_supported[MEMORY_L2] = true;
+	}
+
+	rc = populate_acc_data(mem_acc_vreg, "qcom,corner-acc-map",
+			&mem_acc_vreg->corner_acc_map,
+			&mem_acc_vreg->num_corners);
+	if (rc) {
+		pr_err("Unable to find 'qcom,corner-acc-map' rc=%d\n", rc);
+		return rc;
+	}
+
+	pr_debug("num_corners = %d\n", mem_acc_vreg->num_corners);
+
+	/* Check if at least one valid mem-acc config. is specified */
+	for (i = 0; i < MEMORY_MAX; i++) {
+		if (mem_acc_vreg->mem_acc_supported[i])
+			break;
+	}
+	if (i == MEMORY_MAX) {
+		pr_err("No mem-acc configuration specified\n");
+		return -EINVAL;
+	}
+
+	if (mem_acc_vreg->num_acc_en)
+		mem_acc_en_init(mem_acc_vreg);
+
+	rc = mem_acc_sel_init(mem_acc_vreg);
+	if (rc) {
+		pr_err("Unable to intialize mem_acc_sel reg rc=%d\n", rc);
+		return rc;
+	}
+
+	return 0;
+}
+
+static int mem_acc_regulator_probe(struct platform_device *pdev)
+{
+	struct mem_acc_regulator *mem_acc_vreg;
+	struct regulator_desc *rdesc;
+	struct regulator_init_data *init_data;
+	int rc;
+
+	if (!pdev->dev.of_node) {
+		pr_err("Device tree node is missing\n");
+		return -EINVAL;
+	}
+
+	init_data = of_get_regulator_init_data(&pdev->dev, pdev->dev.of_node);
+	if (!init_data) {
+		pr_err("regulator init data is missing\n");
+		return -EINVAL;
+	} else {
+		init_data->constraints.input_uV
+			= init_data->constraints.max_uV;
+		init_data->constraints.valid_ops_mask
+			|= REGULATOR_CHANGE_VOLTAGE;
+	}
+
+	mem_acc_vreg = devm_kzalloc(&pdev->dev, sizeof(*mem_acc_vreg),
+			GFP_KERNEL);
+	if (!mem_acc_vreg) {
+		pr_err("Can't allocate mem_acc_vreg memory\n");
+		return -ENOMEM;
+	}
+	mem_acc_vreg->dev = &pdev->dev;
+
+	rc = mem_acc_init(pdev, mem_acc_vreg);
+	if (rc) {
+		pr_err("Unable to initialize mem_acc configuration rc=%d\n",
+				rc);
+		return rc;
+	}
+
+	rdesc			= &mem_acc_vreg->rdesc;
+	rdesc->owner		= THIS_MODULE;
+	rdesc->type		= REGULATOR_VOLTAGE;
+	rdesc->ops		= &mem_acc_corner_ops;
+	rdesc->name		= init_data->constraints.name;
+
+	mem_acc_vreg->rdev = regulator_register(rdesc, &pdev->dev,
+				init_data, mem_acc_vreg, pdev->dev.of_node);
+	if (IS_ERR(mem_acc_vreg->rdev)) {
+		rc = PTR_ERR(mem_acc_vreg->rdev);
+		if (rc != -EPROBE_DEFER)
+			pr_err("regulator_register failed: rc=%d\n", rc);
+		return rc;
+	}
+
+	platform_set_drvdata(pdev, mem_acc_vreg);
+
+	return 0;
+}
+
+static int mem_acc_regulator_remove(struct platform_device *pdev)
+{
+	struct mem_acc_regulator *mem_acc_vreg = platform_get_drvdata(pdev);
+
+	regulator_unregister(mem_acc_vreg->rdev);
+
+	return 0;
+}
+
+static struct of_device_id mem_acc_regulator_match_table[] = {
+	{ .compatible = "qcom,mem-acc-regulator", },
+	{}
+};
+
+static struct platform_driver mem_acc_regulator_driver = {
+	.probe		= mem_acc_regulator_probe,
+	.remove		= mem_acc_regulator_remove,
+	.driver		= {
+		.name		= "qcom,mem-acc-regulator",
+		.of_match_table = mem_acc_regulator_match_table,
+		.owner		= THIS_MODULE,
+	},
+};
+
+int __init mem_acc_regulator_init(void)
+{
+	return platform_driver_register(&mem_acc_regulator_driver);
+}
+postcore_initcall(mem_acc_regulator_init);
+
+static void __exit mem_acc_regulator_exit(void)
+{
+	platform_driver_unregister(&mem_acc_regulator_driver);
+}
+module_exit(mem_acc_regulator_exit);
+
+MODULE_DESCRIPTION("MEM-ACC-SEL regulator driver");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/rtc/alarm-dev.c b/drivers/rtc/alarm-dev.c
index 1e13ce1..b621547 100644
--- a/drivers/rtc/alarm-dev.c
+++ b/drivers/rtc/alarm-dev.c
@@ -49,6 +49,7 @@
 #define ANDROID_ALARM_SET_AND_WAIT_OLD      _IOW('a', 3, time_t)
 
 static int alarm_opened;
+static DEFINE_MUTEX(alarm_mutex);
 static DEFINE_SPINLOCK(alarm_slock);
 static struct wake_lock alarm_wake_lock;
 static DECLARE_WAIT_QUEUE_HEAD(alarm_wait_queue);
@@ -89,6 +90,7 @@
 
 	switch (ANDROID_ALARM_BASE_CMD(cmd)) {
 	case ANDROID_ALARM_CLEAR(0):
+		mutex_lock(&alarm_mutex);
 		spin_lock_irqsave(&alarm_slock, flags);
 		pr_alarm(IO, "alarm %d clear\n", alarm_type);
 		alarm_try_to_cancel(&alarms[alarm_type]);
@@ -98,11 +100,12 @@
 				wake_unlock(&alarm_wake_lock);
 		}
 		alarm_enabled &= ~alarm_type_mask;
+		spin_unlock_irqrestore(&alarm_slock, flags);
 		if (alarm_type == ANDROID_ALARM_RTC_POWEROFF_WAKEUP)
 			if (!copy_from_user(&new_alarm_time,
 				(void __user *)arg, sizeof(new_alarm_time)))
 				set_power_on_alarm(new_alarm_time.tv_sec, 0);
-		spin_unlock_irqrestore(&alarm_slock, flags);
+		mutex_unlock(&alarm_mutex);
 		break;
 
 	case ANDROID_ALARM_SET_OLD:
@@ -122,6 +125,7 @@
 			goto err1;
 		}
 from_old_alarm_set:
+		mutex_lock(&alarm_mutex);
 		spin_lock_irqsave(&alarm_slock, flags);
 		pr_alarm(IO, "alarm %d set %ld.%09ld\n", alarm_type,
 			new_alarm_time.tv_sec, new_alarm_time.tv_nsec);
@@ -129,11 +133,12 @@
 		alarm_start_range(&alarms[alarm_type],
 			timespec_to_ktime(new_alarm_time),
 			timespec_to_ktime(new_alarm_time));
+		spin_unlock_irqrestore(&alarm_slock, flags);
 		if ((alarm_type == ANDROID_ALARM_RTC_POWEROFF_WAKEUP) &&
 				(ANDROID_ALARM_BASE_CMD(cmd) ==
 				 ANDROID_ALARM_SET(0)))
 			set_power_on_alarm(new_alarm_time.tv_sec, 1);
-		spin_unlock_irqrestore(&alarm_slock, flags);
+		mutex_unlock(&alarm_mutex);
 		if (ANDROID_ALARM_BASE_CMD(cmd) != ANDROID_ALARM_SET_AND_WAIT(0)
 		    && cmd != ANDROID_ALARM_SET_AND_WAIT_OLD)
 			break;
diff --git a/drivers/rtc/alarm.c b/drivers/rtc/alarm.c
index 2cf1158..8531de9 100644
--- a/drivers/rtc/alarm.c
+++ b/drivers/rtc/alarm.c
@@ -65,15 +65,18 @@
 static struct rtc_device *alarm_rtc_dev;
 static DEFINE_SPINLOCK(alarm_slock);
 static DEFINE_MUTEX(alarm_setrtc_mutex);
+static DEFINE_MUTEX(power_on_alarm_mutex);
 static struct wake_lock alarm_rtc_wake_lock;
 static struct platform_device *alarm_platform_dev;
 struct alarm_queue alarms[ANDROID_ALARM_TYPE_COUNT];
 static bool suspended;
 static long power_on_alarm;
 
-static void alarm_shutdown(struct platform_device *dev);
+static int set_alarm_time_to_rtc(const long);
+
 void set_power_on_alarm(long secs, bool enable)
 {
+	mutex_lock(&power_on_alarm_mutex);
 	if (enable) {
 		power_on_alarm = secs;
 	} else {
@@ -85,7 +88,9 @@
 		else
 			power_on_alarm = 0;
 	}
-	alarm_shutdown(NULL);
+
+	set_alarm_time_to_rtc(power_on_alarm);
+	mutex_unlock(&power_on_alarm_mutex);
 }
 
 
@@ -521,28 +526,23 @@
 	return 0;
 }
 
-static void alarm_shutdown(struct platform_device *dev)
+static int set_alarm_time_to_rtc(const long power_on_time)
 {
 	struct timespec wall_time;
 	struct rtc_time rtc_time;
 	struct rtc_wkalrm alarm;
-	unsigned long flags;
 	long rtc_secs, alarm_delta, alarm_time;
-	int rc;
+	int rc = -EINVAL;
 
-	spin_lock_irqsave(&alarm_slock, flags);
-
-	if (!power_on_alarm) {
-		spin_unlock_irqrestore(&alarm_slock, flags);
+	if (power_on_time <= 0) {
 		goto disable_alarm;
 	}
-	spin_unlock_irqrestore(&alarm_slock, flags);
 
 	rtc_read_time(alarm_rtc_dev, &rtc_time);
 	getnstimeofday(&wall_time);
 	rtc_tm_to_time(&rtc_time, &rtc_secs);
 	alarm_delta = wall_time.tv_sec - rtc_secs;
-	alarm_time = power_on_alarm - alarm_delta;
+	alarm_time = power_on_time - alarm_delta;
 
 	/*
 	 * Substract ALARM_DELTA from actual alarm time
@@ -558,16 +558,19 @@
 	rtc_time_to_tm(alarm_time, &alarm.time);
 	alarm.enabled = 1;
 	rc = rtc_set_alarm(alarm_rtc_dev, &alarm);
-	if (rc)
+	if (rc){
 		pr_alarm(ERROR, "Unable to set power-on alarm\n");
+		goto disable_alarm;
+	}
 	else
 		pr_alarm(FLOW, "Power-on alarm set to %lu\n",
 				alarm_time);
 
-	return;
+	return 0;
 
 disable_alarm:
 	rtc_alarm_irq_enable(alarm_rtc_dev, 0);
+	return rc;
 }
 
 static struct rtc_task alarm_rtc_task = {
@@ -629,7 +632,6 @@
 static struct platform_driver alarm_driver = {
 	.suspend = alarm_suspend,
 	.resume = alarm_resume,
-	.shutdown = alarm_shutdown,
 	.driver = {
 		.name = "alarm"
 	}
diff --git a/drivers/slimbus/slim-msm-ngd.c b/drivers/slimbus/slim-msm-ngd.c
index aa61ab9..0035349 100644
--- a/drivers/slimbus/slim-msm-ngd.c
+++ b/drivers/slimbus/slim-msm-ngd.c
@@ -82,7 +82,7 @@
 };
 
 static int ngd_slim_runtime_resume(struct device *device);
-static int ngd_slim_power_up(struct msm_slim_ctrl *dev);
+static int ngd_slim_power_up(struct msm_slim_ctrl *dev, bool mdm_restart);
 
 static irqreturn_t ngd_slim_interrupt(int irq, void *d)
 {
@@ -97,7 +97,7 @@
 		writel_relaxed(stat, ngd + NGD_INT_CLR);
 		dev->err = -EIO;
 
-		dev_err(dev->dev, "NGD interrupt error:0x%x, err:%d", stat,
+		SLIM_WARN(dev, "NGD interrupt error:0x%x, err:%d\n", stat,
 								dev->err);
 		/* Guarantee that error interrupts are cleared */
 		mb();
@@ -119,7 +119,7 @@
 		for (i = 1; i < ((len + 3) >> 2); i++) {
 			rx_buf[i] = readl_relaxed(ngd + NGD_RX_MSG +
 						(4 * i));
-			dev_dbg(dev->dev, "REG-RX data: %x\n", rx_buf[i]);
+			SLIM_DBG(dev, "REG-RX data: %x\n", rx_buf[i]);
 		}
 		msm_slim_rx_enqueue(dev, rx_buf, len);
 		writel_relaxed(NGD_INT_RX_MSG_RCVD,
@@ -130,8 +130,7 @@
 		 */
 		mb();
 		if (dev->use_rx_msgqs == MSM_MSGQ_ENABLED)
-			dev_err(dev->dev,
-				"direct message received even with RX MSGQs");
+			SLIM_WARN(dev, "direct msg rcvd with RX MSGQs\n");
 		else
 			complete(&dev->rx_msgq_notify);
 	}
@@ -140,13 +139,13 @@
 		/* Guarantee RECONFIG DONE interrupt is cleared */
 		mb();
 		/* In satellite mode, just log the reconfig done IRQ */
-		dev_dbg(dev->dev, "reconfig done IRQ for NGD");
+		SLIM_DBG(dev, "reconfig done IRQ for NGD\n");
 	}
 	if (stat & NGD_INT_IE_VE_CHG) {
 		writel_relaxed(NGD_INT_IE_VE_CHG, ngd + NGD_INT_CLR);
 		/* Guarantee IE VE change interrupt is cleared */
 		mb();
-		dev_err(dev->dev, "NGD IE VE change");
+		SLIM_DBG(dev, "NGD IE VE change\n");
 	}
 
 	pstat = readl_relaxed(PGD_THIS_EE(PGD_PORT_INT_ST_EEn, dev->ver));
@@ -161,7 +160,7 @@
 	struct msm_slim_qmi *qmi = container_of(n, struct msm_slim_qmi, nb);
 	struct msm_slim_ctrl *dev =
 		container_of(qmi, struct msm_slim_ctrl, qmi);
-	pr_info("Slimbus QMI NGD CB received event:%ld", code);
+	SLIM_INFO(dev, "Slimbus QMI NGD CB received event:%ld\n", code);
 	switch (code) {
 	case QMI_SERVER_ARRIVE:
 		schedule_work(&qmi->ssr_up);
@@ -183,32 +182,54 @@
 static int mdm_ssr_notify_cb(struct notifier_block *n, unsigned long code,
 				void *_cmd)
 {
+	void __iomem *ngd;
 	struct msm_slim_mdm *mdm = container_of(n, struct msm_slim_mdm, nb);
 	struct msm_slim_ctrl *dev = container_of(mdm, struct msm_slim_ctrl,
 						mdm);
-	int ret;
+	struct slim_controller *ctrl = &dev->ctrl;
+	u32 laddr;
+	struct slim_device *sbdev;
 
 	switch (code) {
 	case SUBSYS_BEFORE_SHUTDOWN:
-		/* make sure runtime-pm doesn't suspend during modem SSR */
-		pm_runtime_get_noresume(dev->dev);
+		SLIM_INFO(dev, "SLIM %lu external_modem SSR notify cb\n", code);
+		/* vote for runtime-pm so that ADSP doesn't go down */
+		msm_slim_get_ctrl(dev);
+		/*
+		 * checking framer here will wake-up ADSP and may avoid framer
+		 * handover later
+		 */
+		msm_slim_qmi_check_framer_request(dev);
+		dev->mdm.state = MSM_CTRL_DOWN;
+		msm_slim_put_ctrl(dev);
 		break;
 	case SUBSYS_AFTER_POWERUP:
-		ret = msm_slim_qmi_check_framer_request(dev);
-		dev_err(dev->dev,
-			"%s:SLIM %lu external_modem SSR notify cb, ret %d",
-			__func__, code, ret);
-		/*
-		 * Next codec transaction will reinit the HW
-		 * if it was suspended
-		 */
-		if (pm_runtime_suspended(dev->dev) ||
-			dev->state >= MSM_CTRL_ASLEEP) {
-			break;
-		} else {
-			ngd_slim_power_up(dev);
-			msm_slim_put_ctrl(dev);
+		if (dev->mdm.state != MSM_CTRL_DOWN)
+			return NOTIFY_DONE;
+		SLIM_INFO(dev,
+			"SLIM %lu external_modem SSR notify cb\n", code);
+		/* vote for runtime-pm so that ADSP doesn't go down */
+		msm_slim_get_ctrl(dev);
+		msm_slim_qmi_check_framer_request(dev);
+		/* If NGD enumeration is lost, we will need to power us up */
+		ngd = dev->base + NGD_BASE(dev->ctrl.nr, dev->ver);
+		laddr = readl_relaxed(ngd + NGD_STATUS);
+		if (!(laddr & NGD_LADDR)) {
+			/* runtime-pm state should be consistent with HW */
+			pm_runtime_disable(dev->dev);
+			pm_runtime_set_suspended(dev->dev);
+			dev->state = MSM_CTRL_DOWN;
+			SLIM_INFO(dev,
+				"SLIM MDM SSR (active framer on MDM) dev-down\n");
+			list_for_each_entry(sbdev, &ctrl->devs, dev_list)
+				slim_report_absent(sbdev);
+			ngd_slim_power_up(dev, true);
+			pm_runtime_set_active(dev->dev);
+			pm_runtime_enable(dev->dev);
 		}
+		dev->mdm.state = MSM_CTRL_AWAKE;
+		msm_slim_put_ctrl(dev);
+		break;
 	default:
 		break;
 	}
@@ -302,7 +323,7 @@
 		if (dev->state == MSM_CTRL_DOWN) {
 			u8 mc = (u8)txn->mc;
 			int timeout;
-			dev_err(dev->dev, "ADSP slimbus not up yet");
+			SLIM_INFO(dev, "ADSP slimbus not up yet\n");
 			/*
 			 * Messages related to data channel management can't
 			 * wait since they are holding reconfiguration lock.
@@ -362,7 +383,7 @@
 	mutex_lock(&dev->tx_lock);
 
 	if (report_sat == false && dev->state != MSM_CTRL_AWAKE) {
-		dev_err(dev->dev, "controller not ready");
+		SLIM_ERR(dev, "controller not ready\n");
 		mutex_unlock(&dev->tx_lock);
 		msm_slim_put_ctrl(dev);
 		return -EREMOTEIO;
@@ -372,6 +393,14 @@
 		txn->mc == SLIM_MSG_MC_CONNECT_SINK ||
 		txn->mc == SLIM_MSG_MC_DISCONNECT_PORT)) {
 		int i = 0;
+		if (txn->mc != SLIM_MSG_MC_DISCONNECT_PORT)
+			SLIM_INFO(dev,
+				"Connect port: laddr 0x%x  port_num %d chan_num %d\n",
+					txn->la, txn->wbuf[0], txn->wbuf[1]);
+		else
+			SLIM_INFO(dev,
+				"Disconnect port: laddr 0x%x  port_num %d\n",
+					txn->la, txn->wbuf[0]);
 		txn->mt = SLIM_MSG_MT_DEST_REFERRED_USER;
 		if (txn->mc == SLIM_MSG_MC_CONNECT_SOURCE)
 			txn->mc = SLIM_USR_MC_CONNECT_SRC;
@@ -388,10 +417,11 @@
 				mutex_unlock(&dev->tx_lock);
 				ret = dev->ctrl.get_laddr(&dev->ctrl, ea, 6,
 						&dev->pgdla);
-				pr_debug("SLIM PGD LA:0x%x, ret:%d", dev->pgdla,
-						ret);
+				SLIM_DBG(dev, "SLIM PGD LA:0x%x, ret:%d\n",
+					dev->pgdla, ret);
 				if (ret) {
-					pr_err("Incorrect SLIM-PGD EAPC:0x%x",
+					SLIM_ERR(dev,
+						"Incorrect SLIM-PGD EAPC:0x%x\n",
 							dev->pdata.eapc);
 					return ret;
 				}
@@ -406,7 +436,8 @@
 			wbuf[i++] = txn->wbuf[1];
 		ret = ngd_get_tid(ctrl, txn, &wbuf[i++], &done);
 		if (ret) {
-			pr_err("TID for connect/disconnect fail:%d", ret);
+			SLIM_ERR(dev, "TID for connect/disconnect fail:%d\n",
+					ret);
 			goto ngd_xfer_err;
 		}
 		txn->len = i;
@@ -416,7 +447,7 @@
 	txn->rl--;
 	pbuf = msm_get_msg_buf(dev, txn->rl);
 	if (!pbuf) {
-		dev_err(dev->dev, "Message buffer unavailable");
+		SLIM_ERR(dev, "Message buffer unavailable\n");
 		ret = -ENOMEM;
 		goto ngd_xfer_err;
 	}
@@ -470,7 +501,7 @@
 			return 0;
 		}
 		if (dev->err) {
-			dev_err(dev->dev, "pipe-port connect err:%d", dev->err);
+			SLIM_ERR(dev, "pipe-port connect err:%d\n", dev->err);
 			goto ngd_xfer_err;
 		}
 		/* Add port-base to port number if this is manager side port */
@@ -509,7 +540,7 @@
 		u32 conf, stat, rx_msgq, int_stat, int_en, int_clr;
 		void __iomem *ngd = dev->base + NGD_BASE(dev->ctrl.nr,
 							dev->ver);
-		dev_err(dev->dev, "TX failed :MC:0x%x,mt:0x%x, ret:%d, ver:%d",
+		SLIM_WARN(dev, "TX failed :MC:0x%x,mt:0x%x, ret:%d, ver:%d\n",
 				txn_mc, txn_mt, ret, dev->ver);
 		conf = readl_relaxed(ngd);
 		stat = readl_relaxed(ngd + NGD_STATUS);
@@ -518,9 +549,10 @@
 		int_en = readl_relaxed(ngd + NGD_INT_EN);
 		int_clr = readl_relaxed(ngd + NGD_INT_CLR);
 
-		pr_err("conf:0x%x,stat:0x%x,rxmsgq:0x%x", conf, stat, rx_msgq);
-		pr_err("int_stat:0x%x,int_en:0x%x,int_cll:0x%x", int_stat,
-						int_en, int_clr);
+		SLIM_WARN(dev, "conf:0x%x,stat:0x%x,rxmsgq:0x%x\n",
+				conf, stat, rx_msgq);
+		SLIM_WARN(dev, "int_stat:0x%x,int_en:0x%x,int_cll:0x%x\n",
+				int_stat, int_en, int_clr);
 	} else if (txn_mt == SLIM_MSG_MT_DEST_REFERRED_USER &&
 		(txn_mc == SLIM_USR_MC_CONNECT_SRC ||
 		 txn_mc == SLIM_USR_MC_CONNECT_SINK ||
@@ -534,8 +566,9 @@
 		else
 			ret = txn->ec;
 		if (ret) {
-			pr_err("connect/disconnect:0x%x,tid:%d err:%d", txn->mc,
-					txn->tid, ret);
+			SLIM_INFO(dev,
+				"connect/disconnect:0x%x,tid:%d err:%d\n",
+					txn->mc, txn->tid, ret);
 			mutex_lock(&ctrl->m_ctrl);
 			ctrl->txnt[txn->tid] = NULL;
 			mutex_unlock(&ctrl->m_ctrl);
@@ -590,6 +623,7 @@
 static int ngd_xferandwait_ack(struct slim_controller *ctrl,
 				struct slim_msg_txn *txn)
 {
+	struct msm_slim_ctrl *dev = slim_get_ctrldata(ctrl);
 	int ret = ngd_xfer_msg(ctrl, txn);
 	if (!ret) {
 		int timeout;
@@ -602,8 +636,8 @@
 
 	if (ret) {
 		if (ret != -EREMOTEIO || txn->mc != SLIM_USR_MC_CHAN_CTRL)
-			pr_err("master msg:0x%x,tid:%d ret:%d", txn->mc,
-				txn->tid, ret);
+			SLIM_ERR(dev, "master msg:0x%x,tid:%d ret:%d\n",
+				txn->mc, txn->tid, ret);
 		mutex_lock(&ctrl->m_ctrl);
 		ctrl->txnt[txn->tid] = NULL;
 		mutex_unlock(&ctrl->m_ctrl);
@@ -614,12 +648,13 @@
 
 static int ngd_allocbw(struct slim_device *sb, int *subfrmc, int *clkgear)
 {
-	int ret;
+	int ret = 0, num_chan = 0;
 	struct slim_pending_ch *pch;
 	struct slim_msg_txn txn;
 	struct slim_controller *ctrl = sb->ctrl;
 	DECLARE_COMPLETION_ONSTACK(done);
 	u8 wbuf[SLIM_MSGQ_BUF_LEN];
+	struct msm_slim_ctrl *dev = slim_get_ctrldata(ctrl);
 
 	*clkgear = ctrl->clkgear;
 	*subfrmc = 0;
@@ -632,7 +667,7 @@
 	txn.rbuf = NULL;
 
 	if (ctrl->sched.msgsl != ctrl->sched.pending_msgsl) {
-		pr_debug("slim reserve BW for messaging: req: %d",
+		SLIM_DBG(dev, "slim reserve BW for messaging: req: %d\n",
 				ctrl->sched.pending_msgsl);
 		txn.mc = SLIM_USR_MC_REQ_BW;
 		wbuf[txn.len++] = ((sb->laddr & 0x1f) |
@@ -663,7 +698,7 @@
 		struct slim_ich *slc;
 		slc = &ctrl->chans[pch->chan];
 		if (!slc) {
-			pr_err("no channel in define?");
+			SLIM_WARN(dev, "no channel in define?\n");
 			return -ENXIO;
 		}
 		if (txn.len == 0) {
@@ -678,12 +713,14 @@
 			wbuf[txn.len++] = slc->prrate;
 			ret = ngd_get_tid(ctrl, &txn, &wbuf[txn.len++], &done);
 			if (ret) {
-				pr_err("no tid for channel define?");
+				SLIM_WARN(dev, "no tid for channel define?\n");
 				return -ENXIO;
 			}
 		}
+		num_chan++;
 		wbuf[txn.len++] = slc->chan;
-		pr_debug("slim define chan:%d, tid:0x%x", slc->chan, txn.tid);
+		SLIM_INFO(dev, "slim activate chan:%d, laddr: 0x%x\n",
+				slc->chan, sb->laddr);
 	}
 	if (txn.len) {
 		txn.mc = SLIM_USR_MC_DEF_ACT_CHAN;
@@ -708,7 +745,7 @@
 		struct slim_ich *slc;
 		slc = &ctrl->chans[pch->chan];
 		if (!slc) {
-			pr_err("no channel in removal?");
+			SLIM_WARN(dev, "no channel in removal?\n");
 			return -ENXIO;
 		}
 		if (txn.len == 0) {
@@ -717,12 +754,13 @@
 					(sb->laddr & 0x1f);
 			ret = ngd_get_tid(ctrl, &txn, &wbuf[txn.len++], &done);
 			if (ret) {
-				pr_err("no tid for channel define?");
+				SLIM_WARN(dev, "no tid for channel define?\n");
 				return -ENXIO;
 			}
 		}
 		wbuf[txn.len++] = slc->chan;
-		pr_debug("slim remove chan:%d, tid:0x%x", slc->chan, txn.tid);
+		SLIM_INFO(dev, "slim remove chan:%d, laddr: 0x%x\n",
+			   slc->chan, sb->laddr);
 	}
 	if (txn.len) {
 		txn.mc = SLIM_USR_MC_CHAN_CTRL;
@@ -830,7 +868,7 @@
 		wbuf[3] = SAT_MSG_PROT;
 		txn.wbuf = wbuf;
 		txn.len = 4;
-		pr_info("SLIM SAT: Received master capability");
+		SLIM_INFO(dev, "SLIM SAT: Rcvd master capability\n");
 		if (dev->state >= MSM_CTRL_ASLEEP) {
 			ngd_slim_setup_msg_path(dev);
 			if (dev->use_rx_msgqs == MSM_MSGQ_ENABLED)
@@ -847,18 +885,20 @@
 		ret = ngd_xfer_msg(&dev->ctrl, &txn);
 		if (!ret) {
 			enum msm_ctrl_state prev_state = dev->state;
-			pr_info("SLIM SAT: capability exchange successful");
+			SLIM_INFO(dev,
+				"SLIM SAT: capability exchange successful\n");
 			dev->state = MSM_CTRL_AWAKE;
 			if (prev_state >= MSM_CTRL_ASLEEP)
 				complete(&dev->reconf);
 			else
-				pr_err("SLIM: unexpected capability, state:%d",
-					prev_state);
+				SLIM_ERR(dev,
+					"SLIM: unexpected capability, state:%d\n",
+						prev_state);
 			/* ADSP SSR, send device_up notifications */
 			if (prev_state == MSM_CTRL_DOWN)
 				complete(&dev->qmi.slave_notify);
 		} else if (ret == -EIO) {
-			pr_info("capability message NACKed, retrying");
+			SLIM_WARN(dev, "capability message NACKed, retrying\n");
 			if (retries < INIT_MX_RETRIES) {
 				msleep(DEF_RETRY_MS);
 				retries++;
@@ -881,8 +921,9 @@
 		mutex_lock(&dev->ctrl.m_ctrl);
 		txn = dev->ctrl.txnt[buf[3]];
 		if (!txn) {
-			pr_err("LADDR response after timeout, tid:0x%x",
-				buf[3]);
+			SLIM_WARN(dev,
+				"LADDR response after timeout, tid:0x%x\n",
+					buf[3]);
 			mutex_unlock(&dev->ctrl.m_ctrl);
 			return;
 		}
@@ -898,7 +939,7 @@
 		mutex_lock(&dev->ctrl.m_ctrl);
 		txn = dev->ctrl.txnt[buf[3]];
 		if (!txn) {
-			pr_err("ACK received after timeout, tid:0x%x",
+			SLIM_WARN(dev, "ACK received after timeout, tid:0x%x\n",
 				buf[3]);
 			mutex_unlock(&dev->ctrl.m_ctrl);
 			return;
@@ -906,7 +947,7 @@
 		dev_dbg(dev->dev, "got response:tid:%d, response:0x%x",
 				(int)buf[3], buf[4]);
 		if (!(buf[4] & MSM_SAT_SUCCSS)) {
-			dev_err(dev->dev, "TID:%d, NACK code:0x%x", (int)buf[3],
+			SLIM_WARN(dev, "TID:%d, NACK code:0x%x\n", (int)buf[3],
 						buf[4]);
 			txn->ec = -EIO;
 		}
@@ -916,7 +957,7 @@
 	}
 }
 
-static int ngd_slim_power_up(struct msm_slim_ctrl *dev)
+static int ngd_slim_power_up(struct msm_slim_ctrl *dev, bool mdm_restart)
 {
 	void __iomem *ngd;
 	int timeout, ret = 0;
@@ -927,18 +968,20 @@
 			NGD_INT_IE_VE_CHG | NGD_INT_DEV_ERR |
 			NGD_INT_TX_MSG_SENT | NGD_INT_RX_MSG_RCVD);
 
-	if (cur_state == MSM_CTRL_DOWN) {
+	if (!mdm_restart && cur_state == MSM_CTRL_DOWN) {
 		int timeout = wait_for_completion_timeout(&dev->qmi.qmi_comp,
 						HZ);
 		if (!timeout)
-			pr_err("slimbus QMI init timed out");
+			SLIM_ERR(dev, "slimbus QMI init timed out\n");
 	}
 
 	/* No need to vote if contorller is not in low power mode */
-	if (cur_state == MSM_CTRL_DOWN || cur_state == MSM_CTRL_ASLEEP) {
+	if (!mdm_restart &&
+		(cur_state == MSM_CTRL_DOWN || cur_state == MSM_CTRL_ASLEEP)) {
 		ret = msm_slim_qmi_power_request(dev, true);
 		if (ret) {
-			pr_err("SLIM QMI power request failed:%d", ret);
+			SLIM_ERR(dev, "SLIM QMI power request failed:%d\n",
+					ret);
 			return ret;
 		}
 	}
@@ -955,7 +998,7 @@
 		 * For example, modem restarted when playback was active
 		 */
 		if (cur_state == MSM_CTRL_AWAKE) {
-			pr_err("SLIM MDM restart: ADSP active framer:NO OP");
+			SLIM_INFO(dev, "Subsys restart: ADSP active framer\n");
 			return 0;
 		}
 		/*
@@ -964,24 +1007,27 @@
 		 */
 		ngd_slim_setup_msg_path(dev);
 		return 0;
-	} else if (cur_state == MSM_CTRL_ASLEEP) {
-		pr_debug("ADSP P.C. CTRL state:%d NGD not enumerated:0x%x",
-					dev->state, laddr);
-	} else if (cur_state == MSM_CTRL_IDLE || cur_state == MSM_CTRL_AWAKE) {
+	}
+
+	if (mdm_restart) {
 		/*
-		 * external MDM SSR when only voice call is in progress.
+		 * external MDM SSR when MDM is active framer
 		 * ADSP will reset slimbus HW. disconnect BAM pipes so that
 		 * they can be connected after capability message is received.
 		 * Set device state to ASLEEP to be synchronous with the HW
 		 */
-		pr_err("SLIM MDM restart: MDM active framer: reinit HW");
-		dev->state = MSM_CTRL_ASLEEP;
-		msm_slim_disconnect_endp(dev, &dev->rx_msgq,
-					&dev->use_rx_msgqs);
-		msm_slim_disconnect_endp(dev, &dev->tx_msgq,
-					&dev->use_tx_msgqs);
+		/* make current state as DOWN */
+		cur_state = MSM_CTRL_DOWN;
+		SLIM_INFO(dev,
+			"SLIM MDM restart: MDM active framer: reinit HW\n");
+		/* disconnect BAM pipes */
+		if (dev->use_rx_msgqs == MSM_MSGQ_ENABLED)
+			dev->use_rx_msgqs = MSM_MSGQ_DOWN;
+		if (dev->use_tx_msgqs == MSM_MSGQ_ENABLED)
+			dev->use_tx_msgqs = MSM_MSGQ_DOWN;
+		dev->state = MSM_CTRL_DOWN;
 	}
-	/* ADSP SSR scenario, need to disconnect pipe before connecting */
+	/* SSR scenario, need to disconnect pipe before connecting */
 	if (dev->use_rx_msgqs == MSM_MSGQ_DOWN) {
 		struct msm_slim_endp *endpoint = &dev->rx_msgq;
 		sps_disconnect(endpoint->sps);
@@ -1010,11 +1056,14 @@
 
 	timeout = wait_for_completion_timeout(&dev->reconf, HZ);
 	if (!timeout) {
-		pr_err("Failed to receive master capability");
+		SLIM_ERR(dev, "Failed to receive master capability\n");
 		return -ETIMEDOUT;
 	}
-	if (cur_state == MSM_CTRL_DOWN)
+	if (cur_state == MSM_CTRL_DOWN) {
 		complete(&dev->ctrl_up);
+		/* Resetting the log level */
+		SLIM_RST_LOGLVL(dev);
+	}
 	return 0;
 }
 
@@ -1038,7 +1087,7 @@
 			 * framework state
 			 */
 			if (ret)
-				ngd_slim_power_up(dev);
+				ngd_slim_power_up(dev, false);
 			if (!pm_runtime_enabled(dev->dev) ||
 					!pm_runtime_suspended(dev->dev))
 				ngd_slim_runtime_resume(dev->dev);
@@ -1047,7 +1096,7 @@
 			pm_runtime_mark_last_busy(dev->dev);
 			pm_runtime_put(dev->dev);
 		} else
-			dev_err(dev->dev, "qmi init fail, ret:%d, state:%d",
+			SLIM_ERR(dev, "qmi init fail, ret:%d, state:%d\n",
 					ret, dev->state);
 	} else {
 		msm_slim_qmi_exit(dev);
@@ -1059,7 +1108,7 @@
 static int ngd_clk_pause_wakeup(struct slim_controller *ctrl)
 {
 	struct msm_slim_ctrl *dev = slim_get_ctrldata(ctrl);
-	return ngd_slim_power_up(dev);
+	return ngd_slim_power_up(dev, false);
 }
 
 static int ngd_slim_rx_msgq_thread(void *data)
@@ -1083,7 +1132,7 @@
 		}
 		ret = msm_slim_rx_msgq_get(dev, buffer, index);
 		if (ret) {
-			dev_err(dev->dev, "rx_msgq_get() failed 0x%x\n", ret);
+			SLIM_ERR(dev, "rx_msgq_get() failed 0x%x\n", ret);
 			continue;
 		}
 
@@ -1115,6 +1164,7 @@
 		wait_for_completion(&dev->qmi.slave_notify);
 		/* Probe devices for first notification */
 		if (!i) {
+			i++;
 			dev->err = 0;
 			if (dev->dev->of_node)
 				of_register_slim_devices(&dev->ctrl);
@@ -1127,12 +1177,12 @@
 		} else {
 			slim_framer_booted(ctrl);
 		}
-		i++;
 		mutex_lock(&ctrl->m_ctrl);
 		list_for_each_safe(pos, next, &ctrl->devs) {
+			int j;
 			sbdev = list_entry(pos, struct slim_device, dev_list);
 			mutex_unlock(&ctrl->m_ctrl);
-			for (i = 0; i < LADDR_RETRY; i++) {
+			for (j = 0; j < LADDR_RETRY; j++) {
 				ret = slim_get_logical_addr(sbdev,
 						sbdev->e_addr,
 						6, &sbdev->laddr);
@@ -1167,7 +1217,7 @@
 	/* device up should be called again after SSR */
 	list_for_each_entry(sbdev, &ctrl->devs, dev_list)
 		slim_report_absent(sbdev);
-	pr_info("SLIM ADSP SSR (DOWN) done");
+	SLIM_INFO(dev, "SLIM ADSP SSR (DOWN) done\n");
 }
 
 static void ngd_adsp_up(struct work_struct *work)
@@ -1179,6 +1229,28 @@
 	ngd_slim_enable(dev, true);
 }
 
+static ssize_t show_mask(struct device *device, struct device_attribute *attr,
+			char *buf)
+{
+	struct platform_device *pdev = to_platform_device(device);
+	struct msm_slim_ctrl *dev = platform_get_drvdata(pdev);
+	return snprintf(buf, sizeof(int), "%u\n", dev->ipc_log_mask);
+}
+
+static ssize_t set_mask(struct device *device, struct device_attribute *attr,
+			const char *buf, size_t count)
+{
+	struct platform_device *pdev = to_platform_device(device);
+	struct msm_slim_ctrl *dev = platform_get_drvdata(pdev);
+
+	dev->ipc_log_mask = buf[0] - '0';
+	if (dev->ipc_log_mask > DBG_LEV)
+		dev->ipc_log_mask = DBG_LEV;
+	return count;
+}
+
+static DEVICE_ATTR(debug_mask, S_IRUGO | S_IWUSR, show_mask, set_mask);
+
 static int __devinit ngd_slim_probe(struct platform_device *pdev)
 {
 	struct msm_slim_ctrl *dev;
@@ -1188,6 +1260,7 @@
 	struct resource		*irq, *bam_irq;
 	bool			rxreg_access = false;
 	bool			slim_mdm = false;
+	const char		*ext_modem_id = NULL;
 
 	slim_mem = platform_get_resource_byname(pdev, IORESOURCE_MEM,
 						"slimbus_physical");
@@ -1222,6 +1295,26 @@
 	dev->dev = &pdev->dev;
 	platform_set_drvdata(pdev, dev);
 	slim_set_ctrldata(&dev->ctrl, dev);
+
+	/* Create IPC log context */
+	dev->ipc_slimbus_log = ipc_log_context_create(IPC_SLIMBUS_LOG_PAGES,
+						dev_name(dev->dev));
+	if (!dev->ipc_slimbus_log)
+		dev_err(&pdev->dev, "error creating ipc_logging context\n");
+	else {
+		/* Initialize the log mask */
+		dev->ipc_log_mask = INFO_LEV;
+		dev->default_ipc_log_mask = INFO_LEV;
+		SLIM_INFO(dev, "start logging for slim dev %s\n",
+				dev_name(dev->dev));
+	}
+	ret = sysfs_create_file(&dev->dev->kobj, &dev_attr_debug_mask.attr);
+	if (ret) {
+		dev_err(&pdev->dev, "Failed to create dev. attr\n");
+		dev->sysfs_created = false;
+	} else
+		dev->sysfs_created = true;
+
 	dev->base = ioremap(slim_mem->start, resource_size(slim_mem));
 	if (!dev->base) {
 		dev_err(&pdev->dev, "IOremap failed\n");
@@ -1248,8 +1341,10 @@
 					&dev->pdata.apps_pipes);
 		of_property_read_u32(pdev->dev.of_node, "qcom,ea-pc",
 					&dev->pdata.eapc);
-		slim_mdm = of_property_read_bool(pdev->dev.of_node,
-					"qcom,slim-mdm");
+		ret = of_property_read_string(pdev->dev.of_node,
+					"qcom,slim-mdm", &ext_modem_id);
+		if (!ret)
+			slim_mdm = true;
 	} else {
 		dev->ctrl.nr = pdev->id;
 	}
@@ -1324,7 +1419,7 @@
 
 	if (slim_mdm) {
 		dev->mdm.nb.notifier_call = mdm_ssr_notify_cb;
-		dev->mdm.ssr = subsys_notif_register_notifier("external_modem",
+		dev->mdm.ssr = subsys_notif_register_notifier(ext_modem_id,
 							&dev->mdm.nb);
 		if (IS_ERR_OR_NULL(dev->mdm.ssr))
 			dev_err(dev->dev,
@@ -1362,7 +1457,7 @@
 		dev_err(dev->dev, "Failed to start notifier thread:%d\n", ret);
 		goto err_notify_thread_create_failed;
 	}
-	dev_dbg(dev->dev, "NGD SB controller is up!\n");
+	SLIM_INFO(dev, "NGD SB controller is up!\n");
 	return 0;
 
 err_notify_thread_create_failed:
@@ -1380,6 +1475,9 @@
 err_ioremap_bam_failed:
 	iounmap(dev->base);
 err_ioremap_failed:
+	if (dev->sysfs_created)
+		sysfs_remove_file(&dev->dev->kobj,
+				&dev_attr_debug_mask.attr);
 	kfree(dev);
 	return ret;
 }
@@ -1388,6 +1486,9 @@
 {
 	struct msm_slim_ctrl *dev = platform_get_drvdata(pdev);
 	ngd_slim_enable(dev, false);
+	if (dev->sysfs_created)
+		sysfs_remove_file(&dev->dev->kobj,
+				&dev_attr_debug_mask.attr);
 	qmi_svc_event_notifier_unregister(SLIMBUS_QMI_SVC_ID,
 				SLIMBUS_QMI_SVC_V1,
 				SLIMBUS_QMI_INS_ID, &dev->qmi.nb);
@@ -1433,10 +1534,11 @@
 		if (dev->state != MSM_CTRL_DOWN)
 			dev->state = MSM_CTRL_ASLEEP;
 		else
-			dev_err(device, "HW wakeup attempt during SSR");
+			SLIM_WARN(dev, "HW wakeup attempt during SSR\n");
 	} else {
 		dev->state = MSM_CTRL_AWAKE;
 	}
+	SLIM_INFO(dev, "Slim runtime resume: ret %d\n", ret);
 	return ret;
 }
 
@@ -1449,11 +1551,12 @@
 	ret = slim_ctrl_clk_pause(&dev->ctrl, false, SLIM_CLK_UNSPECIFIED);
 	if (ret) {
 		if (ret != -EBUSY)
-			dev_err(device, "clk pause not entered:%d", ret);
+			SLIM_INFO(dev, "clk pause not entered:%d\n", ret);
 		dev->state = MSM_CTRL_AWAKE;
 	} else {
 		dev->state = MSM_CTRL_ASLEEP;
 	}
+	SLIM_INFO(dev, "Slim runtime suspend: ret %d\n", ret);
 	return ret;
 }
 
@@ -1465,7 +1568,6 @@
 	if (!pm_runtime_enabled(dev) ||
 		(!pm_runtime_suspended(dev) &&
 			cdev->state == MSM_CTRL_IDLE)) {
-		dev_dbg(dev, "system suspend");
 		ret = ngd_slim_runtime_suspend(dev);
 		/*
 		 * If runtime-PM still thinks it's active, then make sure its
@@ -1492,16 +1594,20 @@
 		*/
 		ret = 0;
 	}
+	SLIM_INFO(cdev, "system suspend\n");
 	return ret;
 }
 
 static int ngd_slim_resume(struct device *dev)
 {
+	struct platform_device *pdev = to_platform_device(dev);
+	struct msm_slim_ctrl *cdev = platform_get_drvdata(pdev);
 	/*
 	 * Rely on runtime-PM to call resume in case it is enabled.
 	 * Even if it's not enabled, rely on 1st client transaction to do
 	 * clock/power on
 	 */
+	SLIM_INFO(cdev, "system resume\n");
 	return 0;
 }
 #endif /* CONFIG_PM_SLEEP */
diff --git a/drivers/slimbus/slim-msm.c b/drivers/slimbus/slim-msm.c
index 8589b9f..915bf88 100644
--- a/drivers/slimbus/slim-msm.c
+++ b/drivers/slimbus/slim-msm.c
@@ -51,7 +51,7 @@
 	if (ret >= 0) {
 		ref = atomic_read(&dev->dev->power.usage_count);
 		if (ref <= 0) {
-			dev_err(dev->dev, "reference count -ve:%d", ref);
+			SLIM_WARN(dev, "reference count -ve:%d", ref);
 			ret = -ENODEV;
 		}
 	}
@@ -67,7 +67,7 @@
 	pm_runtime_mark_last_busy(dev->dev);
 	ref = atomic_read(&dev->dev->power.usage_count);
 	if (ref <= 0)
-		dev_err(dev->dev, "reference count mismatch:%d", ref);
+		SLIM_WARN(dev, "reference count mismatch:%d", ref);
 	else
 		pm_runtime_put_sync(dev->dev);
 #endif
@@ -109,7 +109,7 @@
 	/* clear port interrupts */
 	writel_relaxed(pstat, PGD_THIS_EE(PGD_PORT_INT_CL_EEn,
 							dev->ver));
-	pr_info("disabled overflow/underflow for port 0x%x", pstat);
+	SLIM_INFO(dev, "disabled overflow/underflow for port 0x%x", pstat);
 
 	/*
 	 * Guarantee that port interrupt bit(s) clearing writes go
@@ -1133,13 +1133,13 @@
 	rc = qmi_send_req_wait(dev->qmi.handle, &req_desc, req, sizeof(*req),
 					&resp_desc, &resp, sizeof(resp), 5000);
 	if (rc < 0) {
-		pr_err("%s: QMI send req failed %d\n", __func__, rc);
+		SLIM_ERR(dev, "%s: QMI send req failed %d\n", __func__, rc);
 		return rc;
 	}
 
 	/* Check the response */
 	if (resp.resp.result != QMI_RESULT_SUCCESS_V01) {
-		pr_err("%s: QMI request failed 0x%x (%s)\n", __func__,
+		SLIM_ERR(dev, "%s: QMI request failed 0x%x (%s)\n", __func__,
 				resp.resp.result, get_qmi_error(&resp.resp));
 		return -EREMOTEIO;
 	}
@@ -1165,13 +1165,13 @@
 	rc = qmi_send_req_wait(dev->qmi.handle, &req_desc, req, sizeof(*req),
 					&resp_desc, &resp, sizeof(resp), 5000);
 	if (rc < 0) {
-		pr_err("%s: QMI send req failed %d\n", __func__, rc);
+		SLIM_ERR(dev, "%s: QMI send req failed %d\n", __func__, rc);
 		return rc;
 	}
 
 	/* Check the response */
 	if (resp.resp.result != QMI_RESULT_SUCCESS_V01) {
-		pr_err("%s: QMI request failed 0x%x (%s)\n", __func__,
+		SLIM_ERR(dev, "%s: QMI request failed 0x%x (%s)\n", __func__,
 				resp.resp.result, get_qmi_error(&resp.resp));
 		return -EREMOTEIO;
 	}
@@ -1208,7 +1208,7 @@
 						SLIMBUS_QMI_SVC_V1,
 						SLIMBUS_QMI_INS_ID);
 	if (rc < 0) {
-		pr_err("%s: QMI server not found\n", __func__);
+		SLIM_ERR(dev, "%s: QMI server not found\n", __func__);
 		goto qmi_connect_to_service_failed;
 	}
 
@@ -1281,12 +1281,12 @@
 	rc = qmi_send_req_wait(dev->qmi.handle, &req_desc, NULL, 0,
 					&resp_desc, &resp, sizeof(resp), 5000);
 	if (rc < 0) {
-		dev_err(dev->dev, "%s: QMI send req failed %d\n", __func__, rc);
+		SLIM_ERR(dev, "%s: QMI send req failed %d\n", __func__, rc);
 		return rc;
 	}
 	/* Check the response */
 	if (resp.resp.result != QMI_RESULT_SUCCESS_V01) {
-		dev_err(dev->dev, "%s: QMI request failed 0x%x (%s)\n",
+		SLIM_ERR(dev, "%s: QMI request failed 0x%x (%s)\n",
 			__func__, resp.resp.result, get_qmi_error(&resp.resp));
 		return -EREMOTEIO;
 	}
diff --git a/drivers/slimbus/slim-msm.h b/drivers/slimbus/slim-msm.h
index 63178cc..9673208 100644
--- a/drivers/slimbus/slim-msm.h
+++ b/drivers/slimbus/slim-msm.h
@@ -17,6 +17,7 @@
 #include <linux/kthread.h>
 #include <mach/msm_qmi_interface.h>
 #include <mach/subsystem_notif.h>
+#include <mach/msm_ipc_logging.h>
 
 /* Per spec.max 40 bytes per received message */
 #define SLIM_MSGQ_BUF_LEN	40
@@ -216,6 +217,7 @@
 struct msm_slim_mdm {
 	struct notifier_block nb;
 	void *ssr;
+	enum msm_ctrl_state state;
 };
 
 struct msm_slim_pdata {
@@ -266,6 +268,10 @@
 	struct msm_slim_qmi	qmi;
 	struct msm_slim_pdata	pdata;
 	struct msm_slim_mdm	mdm;
+	int			default_ipc_log_mask;
+	int			ipc_log_mask;
+	bool			sysfs_created;
+	void			*ipc_slimbus_log;
 };
 
 struct msm_sat_chan {
@@ -299,6 +305,57 @@
 };
 
 
+/* IPC logging stuff */
+#define IPC_SLIMBUS_LOG_PAGES 5
+
+/* Log levels */
+enum {
+	FATAL_LEV = 0U,
+	ERR_LEV = 1U,
+	WARN_LEV = 2U,
+	INFO_LEV = 3U,
+	DBG_LEV = 4U,
+};
+
+/* Default IPC log level INFO */
+#define SLIM_DBG(dev, x...) do { \
+	pr_debug(x); \
+	if (dev->ipc_slimbus_log && dev->ipc_log_mask >= DBG_LEV) { \
+		ipc_log_string(dev->ipc_slimbus_log, x); \
+	} \
+} while (0)
+
+#define SLIM_INFO(dev, x...) do { \
+	pr_debug(x); \
+	if (dev->ipc_slimbus_log && dev->ipc_log_mask >= INFO_LEV) {\
+		ipc_log_string(dev->ipc_slimbus_log, x); \
+	} \
+} while (0)
+
+/* warnings and errors show up on console always */
+#define SLIM_WARN(dev, x...) do { \
+	pr_warn(x); \
+	if (dev->ipc_slimbus_log && dev->ipc_log_mask >= WARN_LEV) \
+		ipc_log_string(dev->ipc_slimbus_log, x); \
+} while (0)
+
+/* ERROR condition in the driver sets the hs_serial_debug_mask
+ * to ERR_FATAL level, so that this message can be seen
+ * in IPC logging. Further errors continue to log on the console
+ */
+#define SLIM_ERR(dev, x...) do { \
+	pr_err(x); \
+	if (dev->ipc_slimbus_log && dev->ipc_log_mask >= ERR_LEV) { \
+		ipc_log_string(dev->ipc_slimbus_log, x); \
+		dev->default_ipc_log_mask = dev->ipc_log_mask; \
+		dev->ipc_log_mask = FATAL_LEV; \
+	} \
+} while (0)
+
+#define SLIM_RST_LOGLVL(dev) { \
+	dev->ipc_log_mask = dev->default_ipc_log_mask; \
+}
+
 int msm_slim_rx_enqueue(struct msm_slim_ctrl *dev, u32 *buf, u8 len);
 int msm_slim_rx_dequeue(struct msm_slim_ctrl *dev, u8 *buf);
 int msm_slim_get_ctrl(struct msm_slim_ctrl *dev);
diff --git a/drivers/spi/spi_qsd.c b/drivers/spi/spi_qsd.c
index d3e4612..d670f8b 100644
--- a/drivers/spi/spi_qsd.c
+++ b/drivers/spi/spi_qsd.c
@@ -1957,15 +1957,40 @@
 	}
 }
 
-/* workqueue - pull messages from queue & process */
-static void msm_spi_workq(struct work_struct *work)
+/**
+ * msm_spi_transfer_one_message: To process one spi message at a time
+ * @master: spi master controller reference
+ * @msg: one multi-segment SPI transaction
+ * @return zero on success or negative error value
+ *
+ */
+static int msm_spi_transfer_one_message(struct spi_master *master,
+					  struct spi_message *msg)
 {
-	struct msm_spi      *dd =
-		container_of(work, struct msm_spi, work_data);
+	struct msm_spi	*dd;
+	struct spi_transfer *tr;
 	unsigned long        flags;
-	u32                  status_error = 0;
+	u32	status_error = 0;
 
-	pm_runtime_get_sync(dd->dev);
+	dd = spi_master_get_devdata(master);
+
+	if (list_empty(&msg->transfers) || !msg->complete)
+		return -EINVAL;
+
+	list_for_each_entry(tr, &msg->transfers, transfer_list) {
+		/* Check message parameters */
+		if (tr->speed_hz > dd->pdata->max_clock_speed ||
+		    (tr->bits_per_word &&
+		     (tr->bits_per_word < 4 || tr->bits_per_word > 32)) ||
+		    (tr->tx_buf == NULL && tr->rx_buf == NULL)) {
+			dev_err(dd->dev,
+				"Invalid transfer: %d Hz, %d bpw tx=%p, rx=%p\n",
+				tr->speed_hz, tr->bits_per_word,
+				tr->tx_buf, tr->rx_buf);
+			status_error = -EINVAL;
+			goto out;
+		}
+	}
 
 	mutex_lock(&dd->core_lock);
 
@@ -1990,20 +2015,16 @@
 		status_error = 1;
 	}
 	spin_lock_irqsave(&dd->queue_lock, flags);
+	dd->transfer_pending = 1;
+	dd->cur_msg = msg;
+	spin_unlock_irqrestore(&dd->queue_lock, flags);
 
-	while (!list_empty(&dd->queue)) {
-		dd->cur_msg = list_entry(dd->queue.next,
-					 struct spi_message, queue);
-		list_del_init(&dd->cur_msg->queue);
-		spin_unlock_irqrestore(&dd->queue_lock, flags);
-		if (status_error)
+	if (status_error)
 			dd->cur_msg->status = -EIO;
-		else
-			msm_spi_process_message(dd);
-		if (dd->cur_msg->complete)
-			dd->cur_msg->complete(dd->cur_msg->context);
-		spin_lock_irqsave(&dd->queue_lock, flags);
-	}
+	else
+		msm_spi_process_message(dd);
+
+	spin_lock_irqsave(&dd->queue_lock, flags);
 	dd->transfer_pending = 0;
 	spin_unlock_irqrestore(&dd->queue_lock, flags);
 
@@ -2012,44 +2033,33 @@
 
 	mutex_unlock(&dd->core_lock);
 
-	pm_runtime_mark_last_busy(dd->dev);
-	pm_runtime_put_autosuspend(dd->dev);
-
-	/* If needed, this can be done after the current message is complete,
-	   and work can be continued upon resume. No motivation for now. */
+	/*
+	 * If needed, this can be done after the current message is complete,
+	 * and work can be continued upon resume. No motivation for now.
+	 */
 	if (dd->suspended)
 		wake_up_interruptible(&dd->continue_suspend);
+
+out:
+	dd->cur_msg->status = status_error;
+	spi_finalize_current_message(master);
+	return 0;
 }
 
-static int msm_spi_transfer(struct spi_device *spi, struct spi_message *msg)
+static int msm_spi_prepare_transfer_hardware(struct spi_master *master)
 {
-	struct msm_spi	*dd;
-	unsigned long    flags;
-	struct spi_transfer *tr;
+	struct msm_spi	*dd = spi_master_get_devdata(master);
 
-	dd = spi_master_get_devdata(spi->master);
+	pm_runtime_get_sync(dd->dev);
+	return 0;
+}
 
-	if (list_empty(&msg->transfers) || !msg->complete)
-		return -EINVAL;
+static int msm_spi_unprepare_transfer_hardware(struct spi_master *master)
+{
+	struct msm_spi	*dd = spi_master_get_devdata(master);
 
-	list_for_each_entry(tr, &msg->transfers, transfer_list) {
-		/* Check message parameters */
-		if (tr->speed_hz > dd->pdata->max_clock_speed ||
-		    (tr->bits_per_word &&
-		     (tr->bits_per_word < 4 || tr->bits_per_word > 32)) ||
-		    (tr->tx_buf == NULL && tr->rx_buf == NULL)) {
-			dev_err(&spi->dev, "Invalid transfer: %d Hz, %d bpw"
-					   "tx=%p, rx=%p\n",
-					    tr->speed_hz, tr->bits_per_word,
-					    tr->tx_buf, tr->rx_buf);
-			return -EINVAL;
-		}
-	}
-
-	spin_lock_irqsave(&dd->queue_lock, flags);
-	list_add_tail(&msg->queue, &dd->queue);
-	spin_unlock_irqrestore(&dd->queue_lock, flags);
-	queue_work(dd->workqueue, &dd->work_data);
+	pm_runtime_mark_last_busy(dd->dev);
+	pm_runtime_put_autosuspend(dd->dev);
 	return 0;
 }
 
@@ -2701,6 +2711,8 @@
 			&dd->cs_gpios[2].gpio_num,       DT_OPT,  DT_GPIO, -1},
 		{"qcom,gpio-cs3",
 			&dd->cs_gpios[3].gpio_num,       DT_OPT,  DT_GPIO, -1},
+		{"qcom,rt-priority",
+			&pdata->rt_priority,		 DT_OPT,  DT_BOOL,  0},
 		{NULL,  NULL,                            0,       0,        0},
 		};
 
@@ -2794,7 +2806,11 @@
 	master->mode_bits      = SPI_SUPPORTED_MODES;
 	master->num_chipselect = SPI_NUM_CHIPSELECTS;
 	master->setup          = msm_spi_setup;
-	master->transfer       = msm_spi_transfer;
+	master->prepare_transfer_hardware = msm_spi_prepare_transfer_hardware;
+	master->transfer_one_message = msm_spi_transfer_one_message;
+	master->unprepare_transfer_hardware
+			= msm_spi_unprepare_transfer_hardware;
+
 	platform_set_drvdata(pdev, master);
 	dd = spi_master_get_devdata(master);
 
@@ -2834,6 +2850,7 @@
 	for (i = 0; i < ARRAY_SIZE(spi_cs_rsrcs); ++i)
 		dd->cs_gpios[i].valid = 0;
 
+	master->rt = pdata->rt_priority;
 	dd->pdata = pdata;
 	resource = platform_get_resource(pdev, IORESOURCE_MEM, 0);
 	if (!resource) {
@@ -2895,13 +2912,6 @@
 
 	spin_lock_init(&dd->queue_lock);
 	mutex_init(&dd->core_lock);
-	INIT_LIST_HEAD(&dd->queue);
-	INIT_WORK(&dd->work_data, msm_spi_workq);
-	init_waitqueue_head(&dd->continue_suspend);
-	dd->workqueue = create_singlethread_workqueue(
-			dev_name(master->dev.parent));
-	if (!dd->workqueue)
-		goto err_probe_workq;
 
 	if (!devm_request_mem_region(&pdev->dev, dd->mem_phys_addr,
 					dd->mem_size, SPI_DRV_NAME)) {
@@ -3078,8 +3088,6 @@
 	}
 err_probe_rlock_init:
 err_probe_reqmem:
-	destroy_workqueue(dd->workqueue);
-err_probe_workq:
 err_probe_res:
 	spi_master_put(master);
 err_probe_exit:
@@ -3242,7 +3250,6 @@
 	clk_put(dd->clk);
 	clk_put(dd->pclk);
 	msm_spi_clk_path_teardown(dd);
-	destroy_workqueue(dd->workqueue);
 	platform_set_drvdata(pdev, 0);
 	spi_unregister_master(master);
 	spi_master_put(master);
diff --git a/drivers/spi/spi_qsd.h b/drivers/spi/spi_qsd.h
index 2a67a61..d538076 100644
--- a/drivers/spi/spi_qsd.h
+++ b/drivers/spi/spi_qsd.h
@@ -300,9 +300,6 @@
 	struct device           *dev;
 	spinlock_t               queue_lock;
 	struct mutex             core_lock;
-	struct list_head         queue;
-	struct workqueue_struct *workqueue;
-	struct work_struct       work_data;
 	struct spi_message      *cur_msg;
 	struct spi_transfer     *cur_transfer;
 	struct completion        transfer_complete;
diff --git a/drivers/thermal/msm_thermal.c b/drivers/thermal/msm_thermal.c
index 73513ec..b4a56ec 100644
--- a/drivers/thermal/msm_thermal.c
+++ b/drivers/thermal/msm_thermal.c
@@ -40,6 +40,7 @@
 #define MAX_CURRENT_UA 1000000
 #define MAX_RAILS 5
 #define MAX_THRESHOLD 2
+#define MONITOR_ALL_TSENS -1
 
 static struct msm_thermal_data msm_thermal_info;
 static struct delayed_work check_temp_work;
@@ -53,10 +54,13 @@
 static struct work_struct timer_work;
 static struct task_struct *hotplug_task;
 static struct task_struct *freq_mitigation_task;
+static struct task_struct *thermal_monitor_task;
 static struct completion hotplug_notify_complete;
 static struct completion freq_mitigation_complete;
+static struct completion thermal_monitor_complete;
 
 static int enabled;
+static int polling_enabled;
 static int rails_cnt;
 static int psm_rails_cnt;
 static int ocr_rail_cnt;
@@ -78,6 +82,8 @@
 static bool ocr_enabled;
 static bool ocr_nodes_called;
 static bool ocr_probed;
+static bool interrupt_mode_enable;
+static bool msm_thermal_probed;
 static int *tsens_id_map;
 static DEFINE_MUTEX(vdd_rstr_mutex);
 static DEFINE_MUTEX(psm_mutex);
@@ -92,9 +98,16 @@
 	THRESHOLD_MAX_NR,
 };
 
+enum sensor_id_type {
+	THERM_ZONE_ID,
+	THERM_TSENS_ID,
+	THERM_ID_MAX_NR,
+};
+
 struct cpu_info {
 	uint32_t cpu;
 	const char *sensor_type;
+	enum sensor_id_type id_type;
 	uint32_t sensor_id;
 	bool offline;
 	bool user_offline;
@@ -108,6 +121,21 @@
 	bool freq_thresh_clear;
 };
 
+struct threshold_info;
+struct therm_threshold {
+	int32_t sensor_id;
+	struct sensor_threshold threshold[MAX_THRESHOLD];
+	int32_t trip_triggered;
+	void (*notify)(struct therm_threshold *);
+	struct threshold_info *parent;
+};
+
+struct threshold_info {
+	uint32_t thresh_ct;
+	bool thresh_triggered;
+	struct therm_threshold *thresh_list;
+};
+
 struct rail {
 	const char *name;
 	uint32_t freq_req;
@@ -131,10 +159,16 @@
 	struct attribute_group attr_gp;
 };
 
+enum msm_thresh_list {
+	MSM_VDD_RESTRICTION,
+	MSM_LIST_MAX_NR,
+};
+
 static struct psm_rail *psm_rails;
 static struct psm_rail *ocr_rails;
 static struct rail *rails;
 static struct cpu_info cpus[NR_CPUS];
+static struct threshold_info *thresh;
 
 struct vdd_rstr_enable {
 	struct kobj_attribute ko_attr;
@@ -635,7 +669,7 @@
 static int check_sensor_id(int sensor_id)
 {
 	int i = 0;
-	bool hw_id_found;
+	bool hw_id_found = false;
 	int ret = 0;
 
 	for (i = 0; i < max_tsens_num; i++) {
@@ -774,31 +808,63 @@
 	return ret;
 }
 
-static int set_threshold(uint32_t sensor_id,
+static int therm_get_temp(uint32_t id, enum sensor_id_type type, long *temp)
+{
+	int ret = 0;
+	struct tsens_device tsens_dev;
+
+	if (!temp) {
+		pr_err("Invalid value\n");
+		ret = -EINVAL;
+		goto get_temp_exit;
+	}
+
+	switch (type) {
+	case THERM_ZONE_ID:
+		tsens_dev.sensor_num = tsens_id_map[id];
+		break;
+	case THERM_TSENS_ID:
+		tsens_dev.sensor_num = id;
+		break;
+	default:
+		pr_err("Invalid type\n");
+		ret = -EINVAL;
+		goto get_temp_exit;
+		break;
+	}
+
+	ret = tsens_get_temp(&tsens_dev, temp);
+	if (ret) {
+		pr_err("Unable to read TSENS sensor %d\n",
+			tsens_dev.sensor_num);
+		goto get_temp_exit;
+	}
+
+get_temp_exit:
+	return ret;
+}
+
+static int set_threshold(uint32_t zone_id,
 	struct sensor_threshold *threshold)
 {
-	struct tsens_device tsens_dev;
 	int i = 0, ret = 0;
 	long temp;
 
-	if ((!threshold) || check_sensor_id(sensor_id)) {
+	if ((!threshold) || (zone_id >= max_tsens_num)) {
 		pr_err("%s: Invalid input\n", KBUILD_MODNAME);
 		ret = -EINVAL;
 		goto set_threshold_exit;
 	}
 
-	tsens_dev.sensor_num = sensor_id;
-	ret = tsens_get_temp(&tsens_dev, &temp);
-	if (ret) {
-		pr_err("%s: Unable to read TSENS sensor %d\n",
-			KBUILD_MODNAME, tsens_dev.sensor_num);
+	ret = therm_get_temp(zone_id, THERM_ZONE_ID, &temp);
+	if (ret)
 		goto set_threshold_exit;
-	}
+
 	while (i < MAX_THRESHOLD) {
 		switch (threshold[i].trip) {
 		case THERMAL_TRIP_CONFIGURABLE_HI:
 			if (threshold[i].temp >= temp) {
-				ret = set_and_activate_threshold(sensor_id,
+				ret = set_and_activate_threshold(zone_id,
 					&threshold[i]);
 				if (ret)
 					goto set_threshold_exit;
@@ -806,7 +872,7 @@
 			break;
 		case THERMAL_TRIP_CONFIGURABLE_LOW:
 			if (threshold[i].temp <= temp) {
-				ret = set_and_activate_threshold(sensor_id,
+				ret = set_and_activate_threshold(zone_id,
 					&threshold[i]);
 				if (ret)
 					goto set_threshold_exit;
@@ -942,7 +1008,6 @@
 
 static int do_ocr(void)
 {
-	struct tsens_device tsens_dev;
 	long temp = 0;
 	int ret = 0;
 	int i = 0, j = 0;
@@ -953,11 +1018,10 @@
 
 	mutex_lock(&ocr_mutex);
 	for (i = 0; i < max_tsens_num; i++) {
-		tsens_dev.sensor_num = tsens_id_map[i];
-		ret = tsens_get_temp(&tsens_dev, &temp);
+		ret = therm_get_temp(tsens_id_map[i], THERM_TSENS_ID, &temp);
 		if (ret) {
 			pr_debug("%s: Unable to read TSENS sensor %d\n",
-					__func__, tsens_dev.sensor_num);
+					__func__, tsens_id_map[i]);
 			auto_cnt++;
 			continue;
 		}
@@ -999,7 +1063,6 @@
 
 static int do_vdd_restriction(void)
 {
-	struct tsens_device tsens_dev;
 	long temp = 0;
 	int ret = 0;
 	int i = 0;
@@ -1015,11 +1078,10 @@
 
 	mutex_lock(&vdd_rstr_mutex);
 	for (i = 0; i < max_tsens_num; i++) {
-		tsens_dev.sensor_num = tsens_id_map[i];
-		ret = tsens_get_temp(&tsens_dev, &temp);
+		ret = therm_get_temp(tsens_id_map[i], THERM_TSENS_ID, &temp);
 		if (ret) {
-			pr_debug("%s: Unable to read TSENS sensor %d\n",
-					__func__, tsens_dev.sensor_num);
+			pr_debug("Unable to read TSENS sensor %d\n",
+				tsens_id_map[i]);
 			dis_cnt++;
 			continue;
 		}
@@ -1048,7 +1110,6 @@
 
 static int do_psm(void)
 {
-	struct tsens_device tsens_dev;
 	long temp = 0;
 	int ret = 0;
 	int i = 0;
@@ -1056,11 +1117,10 @@
 
 	mutex_lock(&psm_mutex);
 	for (i = 0; i < max_tsens_num; i++) {
-		tsens_dev.sensor_num = tsens_id_map[i];
-		ret = tsens_get_temp(&tsens_dev, &temp);
+		ret = therm_get_temp(tsens_id_map[i], THERM_TSENS_ID, &temp);
 		if (ret) {
 			pr_debug("%s: Unable to read TSENS sensor %d\n",
-					__func__, tsens_dev.sensor_num);
+					__func__, tsens_id_map[i]);
 			auto_cnt++;
 			continue;
 		}
@@ -1137,15 +1197,13 @@
 static void __ref check_temp(struct work_struct *work)
 {
 	static int limit_init;
-	struct tsens_device tsens_dev;
 	long temp = 0;
 	int ret = 0;
 
-	tsens_dev.sensor_num = msm_thermal_info.sensor_id;
-	ret = tsens_get_temp(&tsens_dev, &temp);
+	ret = therm_get_temp(msm_thermal_info.sensor_id, THERM_TSENS_ID, &temp);
 	if (ret) {
-		pr_debug("%s: Unable to read TSENS sensor %d\n",
-				KBUILD_MODNAME, tsens_dev.sensor_num);
+		pr_debug("Unable to read TSENS sensor %d\n",
+				msm_thermal_info.sensor_id);
 		goto reschedule;
 	}
 
@@ -1164,7 +1222,7 @@
 	do_freq_control(temp);
 
 reschedule:
-	if (enabled)
+	if (polling_enabled)
 		schedule_delayed_work(&check_temp_work,
 				msecs_to_jiffies(msm_thermal_info.poll_ms));
 }
@@ -1258,7 +1316,6 @@
 /* Adjust cpus offlined bit based on temperature reading. */
 static int hotplug_init_cpu_offlined(void)
 {
-	struct tsens_device tsens_dev;
 	long temp = 0;
 	uint32_t cpu = 0;
 
@@ -1269,10 +1326,10 @@
 	for_each_possible_cpu(cpu) {
 		if (!(msm_thermal_info.core_control_mask & BIT(cpus[cpu].cpu)))
 			continue;
-		tsens_dev.sensor_num = cpus[cpu].sensor_id;
-		if (tsens_get_temp(&tsens_dev, &temp)) {
+		if (therm_get_temp(cpus[cpu].sensor_id, cpus[cpu].id_type,
+					&temp)) {
 			pr_err("%s: Unable to read TSENS sensor %d\n",
-				KBUILD_MODNAME, tsens_dev.sensor_num);
+				KBUILD_MODNAME, cpus[cpu].sensor_id);
 			mutex_unlock(&core_control_mutex);
 			return -EINVAL;
 		}
@@ -1309,6 +1366,7 @@
 	for_each_possible_cpu(cpu) {
 		cpus[cpu].sensor_id =
 			sensor_get_id((char *)cpus[cpu].sensor_type);
+		cpus[cpu].id_type = THERM_ZONE_ID;
 		if (!(msm_thermal_info.core_control_mask & BIT(cpus[cpu].cpu)))
 			continue;
 
@@ -1501,6 +1559,215 @@
 	return ret;
 }
 
+int therm_set_threshold(struct threshold_info *thresh_inp)
+{
+	int ret = 0, i = 0, err = 0;
+	struct therm_threshold *thresh_ptr;
+
+	if (!thresh_inp) {
+		pr_err("%s: %s: Invalid input\n",
+			KBUILD_MODNAME, __func__);
+		ret = -EINVAL;
+		goto therm_set_exit;
+	}
+
+	thresh_inp->thresh_triggered = false;
+	for (i = 0; i < thresh_inp->thresh_ct; i++) {
+		thresh_ptr = &thresh_inp->thresh_list[i];
+		thresh_ptr->trip_triggered = -1;
+		err = set_threshold(thresh_ptr->sensor_id,
+			thresh_ptr->threshold);
+		if (err) {
+			ret = err;
+			err = 0;
+		}
+	}
+
+therm_set_exit:
+	return ret;
+}
+
+static void vdd_restriction_notify(struct therm_threshold *trig_thresh)
+{
+	int ret = 0;
+	static uint32_t vdd_sens_status;
+
+	if (!vdd_rstr_enabled)
+		return;
+	if (!trig_thresh) {
+		pr_err("%s:%s Invalid input\n", KBUILD_MODNAME, __func__);
+		return;
+	}
+	if (trig_thresh->trip_triggered < 0)
+		goto set_and_exit;
+
+	mutex_lock(&vdd_rstr_mutex);
+	pr_debug("%s: sensor%d reached %d thresh for Vdd restriction\n",
+		KBUILD_MODNAME, trig_thresh->sensor_id,
+		trig_thresh->trip_triggered);
+	switch (trig_thresh->trip_triggered) {
+	case THERMAL_TRIP_CONFIGURABLE_HI:
+		if (vdd_sens_status & BIT(trig_thresh->sensor_id))
+			vdd_sens_status ^= BIT(trig_thresh->sensor_id);
+		break;
+	case THERMAL_TRIP_CONFIGURABLE_LOW:
+		vdd_sens_status |= BIT(trig_thresh->sensor_id);
+		break;
+	default:
+		pr_err("%s:%s: Unsupported trip type\n",
+			KBUILD_MODNAME, __func__);
+		goto unlock_and_exit;
+		break;
+	}
+
+	ret = vdd_restriction_apply_all((vdd_sens_status) ? 1 : 0);
+	if (ret) {
+		pr_err("%s vdd rstr votlage for all failed\n",
+			(vdd_sens_status) ?
+			"Enable" : "Disable");
+			goto unlock_and_exit;
+	}
+
+unlock_and_exit:
+	mutex_unlock(&vdd_rstr_mutex);
+set_and_exit:
+	set_threshold(trig_thresh->sensor_id, trig_thresh->threshold);
+	return;
+}
+
+static __ref int do_thermal_monitor(void *data)
+{
+	int ret = 0, i, j;
+	struct therm_threshold *sensor_list;
+
+	while (!kthread_should_stop()) {
+		wait_for_completion(&thermal_monitor_complete);
+		INIT_COMPLETION(thermal_monitor_complete);
+
+		for (i = 0; i < MSM_LIST_MAX_NR; i++) {
+			if (!thresh[i].thresh_triggered)
+				continue;
+			thresh[i].thresh_triggered = false;
+			for (j = 0; j < thresh[i].thresh_ct; j++) {
+				sensor_list = &thresh[i].thresh_list[j];
+				if (sensor_list->trip_triggered < 0)
+					continue;
+				sensor_list->notify(sensor_list);
+				sensor_list->trip_triggered = -1;
+			}
+		}
+	}
+	return ret;
+}
+
+static void thermal_monitor_init(void)
+{
+	if (thermal_monitor_task)
+		return;
+
+	init_completion(&thermal_monitor_complete);
+	thermal_monitor_task = kthread_run(do_thermal_monitor, NULL,
+		"msm_thermal:therm_monitor");
+	if (IS_ERR(thermal_monitor_task)) {
+		pr_err("%s: Failed to create thermal monitor thread\n",
+				KBUILD_MODNAME);
+		goto init_exit;
+	}
+
+	if (vdd_rstr_enabled)
+		therm_set_threshold(&thresh[MSM_VDD_RESTRICTION]);
+
+init_exit:
+	return;
+}
+
+static int msm_thermal_notify(enum thermal_trip_type type, int temp, void *data)
+{
+	struct therm_threshold *thresh_data = (struct therm_threshold *)data;
+
+	if (thermal_monitor_task) {
+		thresh_data->trip_triggered = type;
+		thresh_data->parent->thresh_triggered = true;
+		complete(&thermal_monitor_complete);
+	} else {
+		pr_err("%s: Thermal monitor task is not initialized\n",
+			KBUILD_MODNAME);
+	}
+	return 0;
+}
+
+static int init_threshold(enum msm_thresh_list index,
+	int sensor_id, int32_t hi_temp, int32_t low_temp,
+	void (*callback)(struct therm_threshold *))
+{
+	int ret = 0, i;
+	struct therm_threshold *thresh_ptr;
+
+	if (!callback || index >= MSM_LIST_MAX_NR || index < 0
+		|| sensor_id == -ENODEV) {
+		pr_err("%s: Invalid input to init_threshold\n",
+			KBUILD_MODNAME);
+		ret = -EINVAL;
+		goto init_thresh_exit;
+	}
+	if (thresh[index].thresh_list) {
+		pr_err("%s: threshold already initialized\n",
+			KBUILD_MODNAME);
+		ret = -EEXIST;
+		goto init_thresh_exit;
+	}
+
+	thresh[index].thresh_ct = (sensor_id == MONITOR_ALL_TSENS) ?
+						max_tsens_num : 1;
+	thresh[index].thresh_triggered = false;
+	thresh[index].thresh_list = kzalloc(sizeof(struct therm_threshold) *
+					thresh[index].thresh_ct, GFP_KERNEL);
+	if (!thresh[index].thresh_list) {
+		pr_err("%s: kzalloc failed\n", KBUILD_MODNAME);
+		ret = -ENOMEM;
+		goto init_thresh_exit;
+	}
+
+	thresh_ptr = thresh[index].thresh_list;
+	if (sensor_id == MONITOR_ALL_TSENS) {
+		for (i = 0; i < max_tsens_num; i++) {
+			thresh_ptr[i].sensor_id = tsens_id_map[i];
+			thresh_ptr[i].notify = callback;
+			thresh_ptr[i].trip_triggered = -1;
+			thresh_ptr[i].parent = &thresh[index];
+			thresh_ptr[i].threshold[0].temp = hi_temp;
+			thresh_ptr[i].threshold[0].trip =
+				THERMAL_TRIP_CONFIGURABLE_HI;
+			thresh_ptr[i].threshold[1].temp = low_temp;
+			thresh_ptr[i].threshold[1].trip =
+				THERMAL_TRIP_CONFIGURABLE_LOW;
+			thresh_ptr[i].threshold[0].notify =
+			thresh_ptr[i].threshold[1].notify = msm_thermal_notify;
+			thresh_ptr[i].threshold[0].data =
+			thresh_ptr[i].threshold[1].data =
+				(void *)&thresh_ptr[i];
+		}
+	} else {
+		thresh_ptr->sensor_id = sensor_id;
+		thresh_ptr->notify = callback;
+		thresh_ptr->trip_triggered = -1;
+		thresh_ptr->parent = &thresh[index];
+		thresh_ptr->threshold[0].temp = hi_temp;
+		thresh_ptr->threshold[0].trip =
+			THERMAL_TRIP_CONFIGURABLE_HI;
+		thresh_ptr->threshold[1].temp = low_temp;
+		thresh_ptr->threshold[1].trip =
+			THERMAL_TRIP_CONFIGURABLE_LOW;
+		thresh_ptr->threshold[0].notify =
+		thresh_ptr->threshold[1].notify = msm_thermal_notify;
+		thresh_ptr->threshold[0].data =
+		thresh_ptr->threshold[1].data = (void *)thresh_ptr;
+	}
+
+init_thresh_exit:
+	return ret;
+}
+
 /*
  * We will reset the cpu frequencies limits here. The core online/offline
  * status will be carried over to the process stopping the msm_thermal, as
@@ -1511,8 +1778,7 @@
 	uint32_t cpu = 0;
 
 	/* make sure check_temp is no longer running */
-	cancel_delayed_work(&check_temp_work);
-	flush_scheduled_work();
+	cancel_delayed_work_sync(&check_temp_work);
 
 	get_online_cpus();
 	for_each_possible_cpu(cpu) {
@@ -1526,16 +1792,30 @@
 	put_online_cpus();
 }
 
+static void interrupt_mode_init(void)
+{
+	if (!msm_thermal_probed) {
+		interrupt_mode_enable = true;
+		return;
+	}
+	if (polling_enabled) {
+		pr_info("%s: Interrupt mode init\n", KBUILD_MODNAME);
+		polling_enabled = 0;
+		disable_msm_thermal();
+		hotplug_init();
+		freq_mitigation_init();
+		thermal_monitor_init();
+	}
+}
+
 static int __ref set_enabled(const char *val, const struct kernel_param *kp)
 {
 	int ret = 0;
 
 	ret = param_set_bool(val, kp);
-	if (!enabled) {
-		disable_msm_thermal();
-		hotplug_init();
-		freq_mitigation_init();
-	} else
+	if (!enabled)
+		interrupt_mode_init();
+	else
 		pr_info("%s: no action for enabled = %d\n",
 			KBUILD_MODNAME, enabled);
 
@@ -1611,7 +1891,7 @@
 		goto done_cc;
 	}
 
-	if (enabled) {
+	if (polling_enabled) {
 		pr_err("%s: Ignoring request; polling thread is enabled.\n",
 				KBUILD_MODNAME);
 		goto done_cc;
@@ -1764,7 +2044,34 @@
 	return ret;
 }
 
-int __devinit msm_thermal_init(struct msm_thermal_data *pdata)
+int msm_thermal_pre_init(void)
+{
+	int ret = 0;
+
+	tsens_get_max_sensor_num(&max_tsens_num);
+	if (create_sensor_id_map()) {
+		ret = -EINVAL;
+		goto pre_init_exit;
+	}
+
+	if (!thresh) {
+		thresh = kzalloc(
+				sizeof(struct threshold_info) * MSM_LIST_MAX_NR,
+				GFP_KERNEL);
+		if (!thresh) {
+			pr_err("%s:%s: kzalloc failed\n",
+				KBUILD_MODNAME, __func__);
+			ret = -ENOMEM;
+			goto pre_init_exit;
+		}
+		memset(thresh, 0, sizeof(struct threshold_info) *
+			MSM_LIST_MAX_NR);
+	}
+pre_init_exit:
+	return ret;
+}
+
+int msm_thermal_init(struct msm_thermal_data *pdata)
 {
 	int ret = 0;
 	uint32_t cpu;
@@ -1782,15 +2089,13 @@
 		cpus[cpu].freq_thresh_clear = false;
 	}
 	BUG_ON(!pdata);
-	tsens_get_max_sensor_num(&max_tsens_num);
 	memcpy(&msm_thermal_info, pdata, sizeof(struct msm_thermal_data));
 
-	if (create_sensor_id_map())
-		return -EINVAL;
 	if (check_sensor_id(msm_thermal_info.sensor_id))
 		return -EINVAL;
 
 	enabled = 1;
+	polling_enabled = 1;
 	ret = cpufreq_register_notifier(&msm_thermal_cpufreq_notifier,
 			CPUFREQ_POLICY_NOTIFIER);
 	if (ret)
@@ -2240,6 +2545,11 @@
 				__func__);
 			goto read_node_fail;
 		}
+		ret = init_threshold(MSM_VDD_RESTRICTION, MONITOR_ALL_TSENS,
+			data->vdd_rstr_temp_hyst_degC, data->vdd_rstr_temp_degC,
+			vdd_restriction_notify);
+		if (ret)
+			goto read_node_fail;
 		vdd_rstr_enabled = true;
 	}
 read_node_fail:
@@ -2516,6 +2826,9 @@
 	struct msm_thermal_data data;
 
 	memset(&data, 0, sizeof(struct msm_thermal_data));
+	ret = msm_thermal_pre_init();
+	if (ret)
+		goto fail;
 
 	key = "qcom,sensor-id";
 	ret = of_property_read_u32(node, key, &data.sensor_id);
@@ -2584,6 +2897,12 @@
 	}
 	msm_thermal_ioctl_init();
 	ret = msm_thermal_init(&data);
+	msm_thermal_probed = true;
+
+	if (interrupt_mode_enable) {
+		interrupt_mode_init();
+		interrupt_mode_enable = false;
+	}
 
 	return ret;
 fail:
@@ -2597,6 +2916,12 @@
 static int msm_thermal_dev_exit(struct platform_device *inp_dev)
 {
 	msm_thermal_ioctl_cleanup();
+	if (thresh) {
+		if (vdd_rstr_enabled)
+			kfree(thresh[MSM_VDD_RESTRICTION].thresh_list);
+		kfree(thresh);
+		thresh = NULL;
+	}
 	return 0;
 }
 
@@ -2632,6 +2957,7 @@
 	INIT_WORK(&timer_work, timer_work_fn);
 	msm_thermal_add_timer_nodes();
 
+	interrupt_mode_init();
 	return 0;
 }
 late_initcall(msm_thermal_late_init);
diff --git a/drivers/usb/dwc3/core.c b/drivers/usb/dwc3/core.c
index 90dd115..e4f56b6 100644
--- a/drivers/usb/dwc3/core.c
+++ b/drivers/usb/dwc3/core.c
@@ -116,22 +116,32 @@
 	 * if it failed previously to operate in SS mode.
 	 */
 	reg |= DWC3_GCTL_U2RSTECN;
-	if (mode == DWC3_GCTL_PRTCAP_HOST) {
+	reg &= ~(DWC3_GCTL_SOFITPSYNC);
+	reg &= ~(DWC3_GCTL_PWRDNSCALEMASK);
+	reg |= DWC3_GCTL_PWRDNSCALE(2);
+	reg |= DWC3_GCTL_U2EXIT_LFPS;
+	dwc3_writel(dwc->regs, DWC3_GCTL, reg);
+
+	if (mode == DWC3_GCTL_PRTCAP_OTG || mode == DWC3_GCTL_PRTCAP_HOST) {
 		/*
 		 * Allow ITP generated off of ref clk based counter instead
 		 * of UTMI/ULPI clk based counter, when superspeed only is
 		 * active so that UTMI/ULPI PHY can be suspened.
+		 *
+		 * Starting with revision 2.50A, GFLADJ_REFCLK_LPM_SEL is used
+		 * instead.
 		 */
-		reg |= DWC3_GCTL_SOFITPSYNC;
-		reg &= ~(DWC3_GCTL_PWRDNSCALEMASK);
-		reg |= DWC3_GCTL_PWRDNSCALE(2);
-	} else if (mode == DWC3_GCTL_PRTCAP_DEVICE) {
-		reg &= ~(DWC3_GCTL_PWRDNSCALEMASK);
-		reg |= DWC3_GCTL_PWRDNSCALE(2);
-		reg &= ~(DWC3_GCTL_SOFITPSYNC);
+		if (dwc->revision < DWC3_REVISION_250A) {
+			reg = dwc3_readl(dwc->regs, DWC3_GCTL);
+			reg |= DWC3_GCTL_SOFITPSYNC;
+			dwc3_writel(dwc->regs, DWC3_GCTL, reg);
+		} else {
+			reg = dwc3_readl(dwc->regs, DWC3_GFLADJ);
+			reg |= DWC3_GFLADJ_REFCLK_LPM_SEL;
+			dwc3_writel(dwc->regs, DWC3_GFLADJ, reg);
+		}
 	}
-	reg |= DWC3_GCTL_U2EXIT_LFPS;
-	dwc3_writel(dwc->regs, DWC3_GCTL, reg);
+
 	reg = dwc3_readl(dwc->regs, DWC3_GUSB3PIPECTL(0));
 	reg |= DWC3_GUSB3PIPECTL_SUSPHY;
 	dwc3_writel(dwc->regs, DWC3_GUSB3PIPECTL(0), reg);
diff --git a/drivers/usb/dwc3/core.h b/drivers/usb/dwc3/core.h
index 4e84b94..b338c2d 100644
--- a/drivers/usb/dwc3/core.h
+++ b/drivers/usb/dwc3/core.h
@@ -138,6 +138,7 @@
 #define DWC3_GEVNTCOUNT(n)	(0xc40c + (n * 0x10))
 
 #define DWC3_GHWPARAMS8		0xc600
+#define DWC3_GFLADJ		0xc630
 
 /* Device Registers */
 #define DWC3_DCFG		0xc700
@@ -219,6 +220,12 @@
 /* Global HWPARAMS6 Register */
 #define DWC3_GHWPARAMS6_SRP_SUPPORT	(1 << 10)
 
+/* Global Frame Length Adjustment Register */
+#define DWC3_GFLADJ_REFCLK_240MHZDECR_PLS1	(1 << 31)
+#define DWC3_GFLADJ_REFCLK_240MHZ_DECR		(0x7F << 24)
+#define DWC3_GFLADJ_REFCLK_LPM_SEL		(1 << 23)
+#define DWC3_GFLADJ_REFCLK_FLADJ		(0x3FFF << 8)
+
 /* Device Configuration Register */
 #define DWC3_DCFG_LPM_CAP	(1 << 22)
 #define DWC3_DCFG_DEVADDR(addr)	((addr) << 3)
@@ -743,6 +750,7 @@
 #define DWC3_REVISION_210A	0x5533210a
 #define DWC3_REVISION_220A	0x5533220a
 #define DWC3_REVISION_230A	0x5533230a
+#define DWC3_REVISION_250A	0x5533250a
 
 	unsigned		is_selfpowered:1;
 	unsigned		three_stage_setup:1;
diff --git a/drivers/usb/dwc3/debugfs.c b/drivers/usb/dwc3/debugfs.c
index a192398..eb67c47 100644
--- a/drivers/usb/dwc3/debugfs.c
+++ b/drivers/usb/dwc3/debugfs.c
@@ -231,6 +231,7 @@
 	dump_register(GEVNTCOUNT(0)),
 
 	dump_register(GHWPARAMS8),
+	dump_register(GFLADJ),
 	dump_register(DCFG),
 	dump_register(DCTL),
 	dump_register(DEVTEN),
diff --git a/drivers/usb/dwc3/dwc3-msm.c b/drivers/usb/dwc3/dwc3-msm.c
index 0e371d5..7d4ecd6 100644
--- a/drivers/usb/dwc3/dwc3-msm.c
+++ b/drivers/usb/dwc3/dwc3-msm.c
@@ -187,6 +187,8 @@
 	struct clk		*sleep_clk;
 	struct clk		*hsphy_sleep_clk;
 	struct clk		*utmi_clk;
+	unsigned int		utmi_clk_rate;
+	struct clk		*utmi_clk_src;
 	struct regulator	*hsusb_3p3;
 	struct regulator	*hsusb_1p8;
 	struct regulator	*hsusb_vddcx;
@@ -238,6 +240,7 @@
 	unsigned long		lpm_flags;
 #define MDWC3_PHY_REF_AND_CORECLK_OFF	BIT(0)
 #define MDWC3_TCXO_SHUTDOWN		BIT(1)
+#define MDWC3_ASYNC_IRQ_WAKE_CAPABILITY	BIT(2)
 
 	u32 qscratch_ctl_val;
 	dev_t ext_chg_dev;
@@ -1091,7 +1094,7 @@
 	struct dwc3 *dwc = container_of(gadget, struct dwc3, gadget);
 	struct dwc3_msm *mdwc = dev_get_drvdata(dwc->dev->parent);
 
-	if (mdwc)
+	if (!mdwc)
 		return;
 
 	dev_dbg(mdwc->dev, "%s\n", __func__);
@@ -1445,6 +1448,48 @@
 				0x07f03f07, 0x07f01605);
 }
 
+static void dwc3_msm_update_ref_clk(struct dwc3_msm *mdwc)
+{
+	u32 guctl, gfladj = 0;
+
+	guctl = dwc3_msm_read_reg(mdwc->base, DWC3_GUCTL);
+	guctl &= ~DWC3_GUCTL_REFCLKPER;
+
+	/* GFLADJ register is used starting with revision 2.50a */
+	if (dwc3_msm_read_reg(mdwc->base, DWC3_GSNPSID) >= DWC3_REVISION_250A) {
+		gfladj = dwc3_msm_read_reg(mdwc->base, DWC3_GFLADJ);
+		gfladj &= ~DWC3_GFLADJ_REFCLK_240MHZDECR_PLS1;
+		gfladj &= ~DWC3_GFLADJ_REFCLK_240MHZ_DECR;
+		gfladj &= ~DWC3_GFLADJ_REFCLK_LPM_SEL;
+		gfladj &= ~DWC3_GFLADJ_REFCLK_FLADJ;
+	}
+
+	/* Refer to SNPS Databook Table 6-55 for calculations used */
+	switch (mdwc->utmi_clk_rate) {
+	case 19200000:
+		guctl |= 52 << __ffs(DWC3_GUCTL_REFCLKPER);
+		gfladj |= 12 << __ffs(DWC3_GFLADJ_REFCLK_240MHZ_DECR);
+		gfladj |= DWC3_GFLADJ_REFCLK_240MHZDECR_PLS1;
+		gfladj |= DWC3_GFLADJ_REFCLK_LPM_SEL;
+		gfladj |= 200 << __ffs(DWC3_GFLADJ_REFCLK_FLADJ);
+		break;
+	case 24000000:
+		guctl |= 41 << __ffs(DWC3_GUCTL_REFCLKPER);
+		gfladj |= 10 << __ffs(DWC3_GFLADJ_REFCLK_240MHZ_DECR);
+		gfladj |= DWC3_GFLADJ_REFCLK_LPM_SEL;
+		gfladj |= 2032 << __ffs(DWC3_GFLADJ_REFCLK_FLADJ);
+		break;
+	default:
+		dev_warn(mdwc->dev, "Unsupported utmi_clk_rate: %u\n",
+				mdwc->utmi_clk_rate);
+		break;
+	}
+
+	dwc3_msm_write_reg(mdwc->base, DWC3_GUCTL, guctl);
+	if (gfladj)
+		dwc3_msm_write_reg(mdwc->base, DWC3_GFLADJ, gfladj);
+}
+
 /* Initialize QSCRATCH registers for HSPHY and SSPHY operation */
 static void dwc3_msm_qscratch_reg_init(struct dwc3_msm *mdwc,
 						unsigned event_status)
@@ -1529,6 +1574,7 @@
 				"DWC3_CONTROLLER_POST_RESET_EVENT received\n");
 		dwc3_msm_qscratch_reg_init(mdwc,
 					DWC3_CONTROLLER_POST_RESET_EVENT);
+		dwc3_msm_update_ref_clk(mdwc);
 		dwc->tx_fifo_size = mdwc->tx_fifo_size;
 		break;
 	case DWC3_CONTROLLER_POST_INITIALIZATION_EVENT:
@@ -1823,6 +1869,7 @@
 	bool host_bus_suspend;
 	bool host_ss_active;
 	bool host_ss_suspend;
+	bool device_bus_suspend;
 
 	dev_dbg(mdwc->dev, "%s: entering lpm\n", __func__);
 
@@ -1850,6 +1897,8 @@
 	      (mdwc->charger.chg_type == DWC3_FLOATED_CHARGER));
 	host_bus_suspend = mdwc->host_mode == 1;
 	host_ss_suspend = host_bus_suspend && host_ss_active;
+	device_bus_suspend = ((mdwc->charger.chg_type == DWC3_SDP_CHARGER) ||
+				 (mdwc->charger.chg_type == DWC3_CDP_CHARGER));
 
 	if (!dcp && !host_bus_suspend)
 		dwc3_msm_write_reg(mdwc->base, QSCRATCH_CTRL_REG,
@@ -1952,10 +2001,16 @@
 	dev_info(mdwc->dev, "DWC3 in low power mode\n");
 
 	if (mdwc->hs_phy_irq) {
+		/*
+		 * with DCP or during cable disconnect, we dont require wakeup
+		 * using HS_PHY_IRQ. Hence enable wakeup only in case of host
+		 * bus suspend and device bus suspend.
+		 */
+		if (host_bus_suspend || device_bus_suspend) {
+			enable_irq_wake(mdwc->hs_phy_irq);
+			mdwc->lpm_flags |= MDWC3_ASYNC_IRQ_WAKE_CAPABILITY;
+		}
 		enable_irq(mdwc->hs_phy_irq);
-		/* with DCP we dont require wakeup using HS_PHY_IRQ */
-		if (dcp)
-			disable_irq_wake(mdwc->hs_phy_irq);
 	}
 
 	return 0;
@@ -2089,9 +2144,12 @@
 		enable_irq(mdwc->hs_phy_irq);
 		mdwc->lpm_irq_seen = false;
 	}
-	/* it must DCP disconnect, re-enable HS_PHY wakeup IRQ */
-	if (mdwc->hs_phy_irq && dcp)
-		enable_irq_wake(mdwc->hs_phy_irq);
+	/* Disable wakeup capable for HS_PHY IRQ, if enabled */
+	if (mdwc->hs_phy_irq &&
+			(mdwc->lpm_flags & MDWC3_ASYNC_IRQ_WAKE_CAPABILITY)) {
+			disable_irq_wake(mdwc->hs_phy_irq);
+			mdwc->lpm_flags &= ~MDWC3_ASYNC_IRQ_WAKE_CAPABILITY;
+	}
 
 	dev_info(mdwc->dev, "DWC3 exited from low power mode\n");
 
@@ -2685,6 +2743,18 @@
 		else
 			pr_debug("%s:voltage request failed\n", __func__);
 		break;
+	case MSM_USB_EXT_CHG_TYPE:
+		if (get_user(val, (int __user *)arg)) {
+			pr_err("%s: get_user failed\n\n", __func__);
+			ret = -EFAULT;
+			break;
+		}
+
+		if (val)
+			pr_debug("%s:charger is external charger\n", __func__);
+		else
+			pr_debug("%s:charger is not ext charger\n", __func__);
+		break;
 	default:
 		ret = -EINVAL;
 	}
@@ -2864,12 +2934,36 @@
 	}
 	clk_prepare_enable(mdwc->hsphy_sleep_clk);
 
+	ret = of_property_read_u32(node, "qcom,utmi-clk-rate",
+				   (u32 *)&mdwc->utmi_clk_rate);
+	if (ret)
+		mdwc->utmi_clk_rate = 60000000;
+
 	mdwc->utmi_clk = devm_clk_get(&pdev->dev, "utmi_clk");
 	if (IS_ERR(mdwc->utmi_clk)) {
 		dev_err(&pdev->dev, "failed to get utmi_clk\n");
 		ret = PTR_ERR(mdwc->utmi_clk);
 		goto disable_sleep_a_clk;
 	}
+
+	if (mdwc->utmi_clk_rate == 24000000) {
+		/*
+		 * For setting utmi clock to 24MHz, first set 48MHz on parent
+		 * clock "utmi_clk_src" and then set divider 2 on child branch
+		 * "utmi_clk".
+		 */
+		mdwc->utmi_clk_src = devm_clk_get(&pdev->dev, "utmi_clk_src");
+		if (IS_ERR(mdwc->utmi_clk_src)) {
+			dev_err(&pdev->dev, "failed to get utmi_clk_src\n");
+			ret = PTR_ERR(mdwc->utmi_clk_src);
+			goto disable_sleep_a_clk;
+		}
+		clk_set_rate(mdwc->utmi_clk_src, 48000000);
+		/* 1 means divide utmi_clk_src by 2 */
+		clk_set_rate(mdwc->utmi_clk, 1);
+	} else {
+		clk_set_rate(mdwc->utmi_clk, mdwc->utmi_clk_rate);
+	}
 	clk_prepare_enable(mdwc->utmi_clk);
 
 	mdwc->ref_clk = devm_clk_get(&pdev->dev, "ref_clk");
@@ -2981,7 +3075,6 @@
 			dev_err(&pdev->dev, "irqreq HSPHYINT failed\n");
 			goto disable_hs_ldo;
 		}
-		enable_irq_wake(mdwc->hs_phy_irq);
 	}
 
 	if (mdwc->ext_xceiv.otg_capability) {
diff --git a/drivers/usb/dwc3/dwc3_otg.c b/drivers/usb/dwc3/dwc3_otg.c
index 8a034d6..e373b9b 100644
--- a/drivers/usb/dwc3/dwc3_otg.c
+++ b/drivers/usb/dwc3/dwc3_otg.c
@@ -93,6 +93,17 @@
 	return 0;
 }
 
+static void dwc3_otg_set_hsphy_auto_suspend(struct dwc3_otg *dotg, bool susp);
+static int dwc3_otg_set_autosuspend(struct usb_phy *phy, int enable_autosuspend)
+{
+	struct usb_otg *otg = phy->otg;
+	struct dwc3_otg *dotg = container_of(otg, struct dwc3_otg, otg);
+
+	dwc3_otg_set_hsphy_auto_suspend(dotg, enable_autosuspend);
+
+	return 0;
+}
+
 static void dwc3_otg_set_hsphy_auto_suspend(struct dwc3_otg *dotg, bool susp)
 {
 	struct dwc3 *dwc = dotg->dwc;
@@ -998,6 +1009,7 @@
 	dotg->otg.phy->dev = dwc->dev;
 	dotg->otg.phy->set_power = dwc3_otg_set_power;
 	dotg->otg.phy->set_suspend = dwc3_otg_set_suspend;
+	dotg->otg.phy->set_phy_autosuspend = dwc3_otg_set_autosuspend;
 
 	ret = usb_set_transceiver(dotg->otg.phy);
 	if (ret) {
diff --git a/drivers/usb/gadget/android.c b/drivers/usb/gadget/android.c
index 877b944..6b01472 100644
--- a/drivers/usb/gadget/android.c
+++ b/drivers/usb/gadget/android.c
@@ -1762,6 +1762,7 @@
 	struct fsg_common *common;
 };
 
+#define MAX_LUN_NAME 8
 static int mass_storage_function_init(struct android_usb_function *f,
 					struct usb_composite_dev *cdev)
 {
@@ -1769,8 +1770,9 @@
 	struct mass_storage_function_config *config;
 	struct fsg_common *common;
 	int err;
-	int i;
-	const char *name[3];
+	int i, n;
+	char name[FSG_MAX_LUNS][MAX_LUN_NAME];
+	u8 uicc_nluns = dev->pdata ? dev->pdata->uicc_nluns : 0;
 
 	config = kzalloc(sizeof(struct mass_storage_function_config),
 								GFP_KERNEL);
@@ -1778,23 +1780,35 @@
 		return -ENOMEM;
 
 	config->fsg.nluns = 1;
-	name[0] = "lun";
+	snprintf(name[0], MAX_LUN_NAME, "lun");
+	config->fsg.luns[0].removable = 1;
+
 	if (dev->pdata && dev->pdata->cdrom) {
 		config->fsg.luns[config->fsg.nluns].cdrom = 1;
 		config->fsg.luns[config->fsg.nluns].ro = 1;
 		config->fsg.luns[config->fsg.nluns].removable = 0;
-		name[config->fsg.nluns] = "lun0";
+		snprintf(name[config->fsg.nluns], MAX_LUN_NAME, "lun0");
 		config->fsg.nluns++;
 	}
 	if (dev->pdata && dev->pdata->internal_ums) {
 		config->fsg.luns[config->fsg.nluns].cdrom = 0;
 		config->fsg.luns[config->fsg.nluns].ro = 0;
 		config->fsg.luns[config->fsg.nluns].removable = 1;
-		name[config->fsg.nluns] = "lun1";
+		snprintf(name[config->fsg.nluns], MAX_LUN_NAME, "lun1");
 		config->fsg.nluns++;
 	}
 
-	config->fsg.luns[0].removable = 1;
+	if (uicc_nluns > FSG_MAX_LUNS - config->fsg.nluns) {
+		uicc_nluns = FSG_MAX_LUNS - config->fsg.nluns;
+		pr_debug("limiting uicc luns to %d\n", uicc_nluns);
+	}
+
+	for (i = 0; i < uicc_nluns; i++) {
+		n = config->fsg.nluns;
+		snprintf(name[n], MAX_LUN_NAME, "uicc%d", i);
+		config->fsg.luns[n].removable = 1;
+		config->fsg.nluns++;
+	}
 
 	common = fsg_common_init(NULL, cdev, &config->fsg);
 	if (IS_ERR(common)) {
@@ -2973,6 +2987,10 @@
 		}
 
 		pdata->streaming_func_count = len;
+
+		ret = of_property_read_u32(pdev->dev.of_node,
+				"qcom,android-usb-uicc-nluns",
+				&pdata->uicc_nluns);
 	} else {
 		pdata = pdev->dev.platform_data;
 	}
diff --git a/drivers/usb/gadget/f_diag.c b/drivers/usb/gadget/f_diag.c
index 16f961e..993d9fb 100644
--- a/drivers/usb/gadget/f_diag.c
+++ b/drivers/usb/gadget/f_diag.c
@@ -511,11 +511,11 @@
 		/* If error add the link to linked list again*/
 		spin_lock_irqsave(&ctxt->lock, flags);
 		list_add_tail(&req->list, &ctxt->write_pool);
-		spin_unlock_irqrestore(&ctxt->lock, flags);
 		/* 1 error message for every 10 sec */
 		if (__ratelimit(&rl))
 			ERROR(ctxt->cdev, "%s: cannot queue"
 				" read request\n", __func__);
+		spin_unlock_irqrestore(&ctxt->lock, flags);
 		return -EIO;
 	}
 
diff --git a/drivers/usb/host/xhci-plat.c b/drivers/usb/host/xhci-plat.c
index cc0c1e0..1634fcf 100644
--- a/drivers/usb/host/xhci-plat.c
+++ b/drivers/usb/host/xhci-plat.c
@@ -51,6 +51,17 @@
 	return xhci_gen_setup(hcd, xhci_plat_quirks);
 }
 
+static void xhci_plat_phy_autosuspend(struct usb_hcd *hcd,
+						int enable_autosuspend)
+{
+	if (!phy || !phy->set_phy_autosuspend)
+		return;
+
+	usb_phy_set_autosuspend(phy, enable_autosuspend);
+
+	return;
+}
+
 static const struct hc_driver xhci_plat_xhci_driver = {
 	.description =		"xhci-hcd",
 	.product_desc =		"xHCI Host Controller",
@@ -98,6 +109,7 @@
 	.hub_status_data =	xhci_hub_status_data,
 	.bus_suspend =		xhci_bus_suspend,
 	.bus_resume =		xhci_bus_resume,
+	.set_autosuspend =	xhci_plat_phy_autosuspend,
 };
 
 static int xhci_plat_probe(struct platform_device *pdev)
diff --git a/drivers/usb/host/xhci-ring.c b/drivers/usb/host/xhci-ring.c
index b3f3fa8..e1c0096 100644
--- a/drivers/usb/host/xhci-ring.c
+++ b/drivers/usb/host/xhci-ring.c
@@ -647,6 +647,8 @@
 
 	struct xhci_dequeue_state deq_state;
 
+	if (xhci->main_hcd->driver->set_autosuspend)
+		xhci->main_hcd->driver->set_autosuspend(xhci->main_hcd, 1);
 	if (unlikely(TRB_TO_SUSPEND_PORT(
 			     le32_to_cpu(xhci->cmd_ring->dequeue->generic.field[3])))) {
 		slot_id = TRB_TO_SLOT_ID(
@@ -800,6 +802,8 @@
 
 	spin_lock_irqsave(&xhci->lock, flags);
 
+	if (xhci->main_hcd->driver->set_autosuspend)
+		xhci->main_hcd->driver->set_autosuspend(xhci->main_hcd, 1);
 	ep->stop_cmds_pending--;
 	if (xhci->xhc_state & XHCI_STATE_DYING) {
 		xhci_dbg(xhci, "Stop EP timer ran, but another timer marked "
diff --git a/drivers/usb/host/xhci.c b/drivers/usb/host/xhci.c
index 0a82e58..f8bc1c5 100644
--- a/drivers/usb/host/xhci.c
+++ b/drivers/usb/host/xhci.c
@@ -1386,6 +1386,8 @@
 		ep->stop_cmd_timer.expires = jiffies +
 			XHCI_STOP_EP_CMD_TIMEOUT * HZ;
 		add_timer(&ep->stop_cmd_timer);
+		if (hcd->driver->set_autosuspend)
+			hcd->driver->set_autosuspend(hcd, 0);
 		xhci_queue_stop_endpoint(xhci, urb->dev->slot_id, ep_index, 0);
 		xhci_ring_cmd_db(xhci);
 	}
diff --git a/drivers/usb/otg/msm_otg.c b/drivers/usb/otg/msm_otg.c
index 350fd41..486d99d 100644
--- a/drivers/usb/otg/msm_otg.c
+++ b/drivers/usb/otg/msm_otg.c
@@ -2573,8 +2573,10 @@
 	bool work = 0, srp_reqd, dcp;
 
 	pm_runtime_resume(otg->phy->dev);
-	if (motg->pm_done)
+	if (motg->pm_done) {
 		pm_runtime_get_sync(otg->phy->dev);
+		motg->pm_done = 0;
+	}
 	pr_debug("%s work\n", otg_state_string(otg->phy->state));
 	switch (otg->phy->state) {
 	case OTG_STATE_UNDEFINED:
@@ -4095,6 +4097,18 @@
 		else
 			pr_debug("%s:voltage request failed\n", __func__);
 		break;
+	case MSM_USB_EXT_CHG_TYPE:
+		if (get_user(val, (int __user *)arg)) {
+			pr_err("%s: get_user failed\n\n", __func__);
+			ret = -EFAULT;
+			break;
+		}
+
+		if (val)
+			pr_debug("%s:charger is external charger\n", __func__);
+		else
+			pr_debug("%s:charger is not ext charger\n", __func__);
+		break;
 	default:
 		ret = -EINVAL;
 	}
diff --git a/drivers/usb/storage/scsiglue.c b/drivers/usb/storage/scsiglue.c
index 669fca9..05292f9 100644
--- a/drivers/usb/storage/scsiglue.c
+++ b/drivers/usb/storage/scsiglue.c
@@ -235,6 +235,15 @@
 			sdev->use_rpm_auto = 1;
 			sdev->autosuspend_delay = us->sdev_autosuspend_delay;
 		}
+
+		/*
+		 * This quirk enables sending consecutive TEST_UNIT_READY
+		 * commands in WRITE(10) command processing context. Increase
+		 * the timeout to 60 seconds.
+		 */
+		if (us->fflags & US_FL_TUR_AFTER_WRITE)
+			blk_queue_rq_timeout(sdev->request_queue, (60 * HZ));
+
 	} else {
 
 		/* Non-disk-type devices don't need to blacklist any pages
diff --git a/drivers/usb/storage/transport.c b/drivers/usb/storage/transport.c
index c70109e..a710d9f 100644
--- a/drivers/usb/storage/transport.c
+++ b/drivers/usb/storage/transport.c
@@ -859,6 +859,42 @@
 		srb->result = DID_ERROR << 16;
 
 	last_sector_hacks(us, srb);
+
+	/*
+	 * TMC UICC cards expect 5 TEST_UNIT_READY commands after
+	 * writing some data. The card performs the flash related
+	 * house keeping operations after receiving these commands.
+	 * Send 5 TEST_UNIT_READY commands for every 8 WRITE_10
+	 * commands.
+	 */
+	if (unlikely((us->fflags & US_FL_TUR_AFTER_WRITE) &&
+				srb->cmnd[0] == WRITE_10)) {
+		int i;
+		int temp_result;
+		struct scsi_eh_save ses;
+		unsigned char cmd[] = {
+			TEST_UNIT_READY, 0, 0, 0, 0, 0,
+		};
+
+		us->tur_count[srb->device->lun]++;
+
+		if (++us->tur_count[srb->device->lun] == 8) {
+
+			us->tur_count[srb->device->lun] = 0;
+
+			scsi_eh_prep_cmnd(srb, &ses, cmd, 6, 0);
+			for (i = 0; i < 5; i++) {
+				temp_result = us->transport(us->srb, us);
+				if (temp_result != USB_STOR_TRANSPORT_GOOD) {
+					US_DEBUGP("TUR failed %d %d\n",
+							i, temp_result);
+					break;
+				}
+			}
+			scsi_eh_restore_cmnd(srb, &ses);
+		}
+	}
+
 	return;
 
 	/* Error and abort processing: try to resynchronize with the device
diff --git a/drivers/usb/storage/unusual_devs.h b/drivers/usb/storage/unusual_devs.h
index 856ad92..901f6fb 100644
--- a/drivers/usb/storage/unusual_devs.h
+++ b/drivers/usb/storage/unusual_devs.h
@@ -2018,6 +2018,12 @@
 		"Digital MP3 Audio Player",
 		USB_SC_DEVICE, USB_PR_DEVICE, NULL, US_FL_NOT_LOCKABLE ),
 
+/* Reported by Pavankumar Kondeti <pkondeti@codeaurora.org> */
+UNUSUAL_DEV(0x0925, 0x9011, 0x0100, 0x0100,
+		"TMC",
+		"USB DISK",
+		USB_SC_DEVICE, USB_PR_DEVICE, NULL, US_FL_TUR_AFTER_WRITE),
+
 /* Control/Bulk transport for all SubClass values */
 USUAL_DEV(USB_SC_RBC, USB_PR_CB, USB_US_TYPE_STOR),
 USUAL_DEV(USB_SC_8020, USB_PR_CB, USB_US_TYPE_STOR),
diff --git a/drivers/usb/storage/usb.h b/drivers/usb/storage/usb.h
index db75080..b079984 100644
--- a/drivers/usb/storage/usb.h
+++ b/drivers/usb/storage/usb.h
@@ -162,6 +162,8 @@
 	int			use_last_sector_hacks;
 	int			last_sector_retries;
 	int			sdev_autosuspend_delay;
+	/* consecutive TEST_UNIT_READY commands during write */
+	int			tur_count[16];
 };
 
 /* Convert between us_data and the corresponding Scsi_Host */
diff --git a/drivers/video/msm/mdss/Makefile b/drivers/video/msm/mdss/Makefile
index fd03b63..ddea735 100644
--- a/drivers/video/msm/mdss/Makefile
+++ b/drivers/video/msm/mdss/Makefile
@@ -1,8 +1,8 @@
-mdss-mdp3-objs = mdp3.o mdp3_dma.o mdp3_ctrl.o
+mdss-mdp3-objs = mdp3.o mdp3_dma.o mdp3_ctrl.o dsi_status_v2.o
 mdss-mdp3-objs += mdp3_ppp.o mdp3_ppp_hwio.o mdp3_ppp_data.o
 obj-$(CONFIG_FB_MSM_MDSS_MDP3) += mdss-mdp3.o
 
-mdss-mdp-objs := mdss_mdp.o mdss_mdp_ctl.o mdss_mdp_pipe.o mdss_mdp_util.o
+mdss-mdp-objs := mdss_mdp.o mdss_mdp_ctl.o mdss_mdp_pipe.o mdss_mdp_util.o dsi_status_6g.o
 mdss-mdp-objs += mdss_mdp_pp.o
 mdss-mdp-objs += mdss_mdp_intf_video.o
 mdss-mdp-objs += mdss_mdp_intf_cmd.o
@@ -13,7 +13,7 @@
 obj-$(CONFIG_FB_MSM_MDSS) += mdss-mdp.o
 
 ifeq ($(CONFIG_FB_MSM_MDSS),y)
-obj-$(CONFIG_DEBUG_FS) += mdss_debug.o
+obj-$(CONFIG_DEBUG_FS) += mdss_debug.o mdss_debug_xlog.o
 endif
 
 dsi-v2-objs = dsi_v2.o dsi_host_v2.o dsi_io_v2.o
@@ -42,8 +42,4 @@
 
 obj-$(CONFIG_FB_MSM_MDSS) += mdss_fb.o
 
-ifeq ($(CONFIG_FB_MSM_MDSS_MDP3),y)
-obj-$(CONFIG_FB_MSM_MDSS_DSI_CTRL_STATUS) += dsi_status_v2.o
-else
 obj-$(CONFIG_FB_MSM_MDSS_DSI_CTRL_STATUS) += mdss_dsi_status.o
-endif
diff --git a/drivers/video/msm/mdss/dsi_host_v2.c b/drivers/video/msm/mdss/dsi_host_v2.c
index e62cc59..99e1c21 100644
--- a/drivers/video/msm/mdss/dsi_host_v2.c
+++ b/drivers/video/msm/mdss/dsi_host_v2.c
@@ -26,6 +26,7 @@
 #include "dsi_io_v2.h"
 #include "dsi_host_v2.h"
 #include "mdss_debug.h"
+#include "mdp3.h"
 
 #define DSI_POLL_SLEEP_US 1000
 #define DSI_POLL_TIMEOUT_US 16000
@@ -971,7 +972,13 @@
 		mutex_unlock(&ctrl->cmd_mutex);
 		return ret;
 	}
-
+	/*
+	 * mdss interrupt is generated in mdp core clock domain
+	 * mdp clock need to be enabled to receive dsi interrupt
+	 * also, axi bus bandwidth need since dsi controller will
+	 * fetch dcs commands from axi bus
+	 */
+	mdp3_res_update(1, 1, MDP3_CLIENT_DMA_P);
 	msm_dsi_clk_ctrl(&ctrl->panel_data, 1);
 
 	if (0 == (req->flags & CMD_REQ_LP_MODE))
@@ -986,6 +993,7 @@
 		dsi_set_tx_power_mode(1);
 
 	msm_dsi_clk_ctrl(&ctrl->panel_data, 0);
+	mdp3_res_update(0, 1, MDP3_CLIENT_DMA_P);
 
 	mutex_unlock(&ctrl->cmd_mutex);
 	return 0;
@@ -1431,13 +1439,16 @@
 						&byteclk_rate, &pclk_rate);
 			msm_dsi_clk_set_rate(DSI_ESC_CLK_RATE, dsiclk_rate,
 						byteclk_rate, pclk_rate);
+			msm_dsi_prepare_clocks();
 			msm_dsi_clk_enable();
 		}
 	} else {
 		dsi_host_private->clk_count--;
 		if (dsi_host_private->clk_count == 0) {
+			msm_dsi_clear_irq(ctrl_pdata, ctrl_pdata->dsi_irq_mask);
 			msm_dsi_clk_set_rate(DSI_ESC_CLK_RATE, 0, 0, 0);
 			msm_dsi_clk_disable();
+			msm_dsi_unprepare_clocks();
 			msm_dsi_ahb_ctrl(0);
 		}
 	}
diff --git a/drivers/video/msm/mdss/dsi_status_6g.c b/drivers/video/msm/mdss/dsi_status_6g.c
new file mode 100644
index 0000000..31c9022
--- /dev/null
+++ b/drivers/video/msm/mdss/dsi_status_6g.c
@@ -0,0 +1,109 @@
+/* Copyright (c) 2013-2014, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/workqueue.h>
+#include <linux/delay.h>
+#include <linux/kobject.h>
+#include <linux/sysfs.h>
+
+#include "mdss_dsi.h"
+#include "mdss_mdp.h"
+
+/*
+ * mdss_check_dsi_ctrl_status() - Check MDP5 DSI controller status periodically.
+ * @work     : dsi controller status data
+ * @interval : duration in milliseconds to schedule work queue
+ *
+ * This function calls check_status API on DSI controller to send the BTA
+ * command. If DSI controller fails to acknowledge the BTA command, it sends
+ * the PANEL_ALIVE=0 status to HAL layer.
+ */
+void mdss_check_dsi_ctrl_status(struct work_struct *work, uint32_t interval)
+{
+	struct dsi_status_data *pstatus_data = NULL;
+	struct mdss_panel_data *pdata = NULL;
+	struct mdss_dsi_ctrl_pdata *ctrl_pdata = NULL;
+	struct mdss_overlay_private *mdp5_data = NULL;
+	struct mdss_mdp_ctl *ctl = NULL;
+	int ret = 0;
+
+	pstatus_data = container_of(to_delayed_work(work),
+		struct dsi_status_data, check_status);
+
+	pdata = dev_get_platdata(&pstatus_data->mfd->pdev->dev);
+	if (!pdata) {
+		pr_err("%s: Panel data not available\n", __func__);
+		return;
+	}
+
+	ctrl_pdata = container_of(pdata, struct mdss_dsi_ctrl_pdata,
+							panel_data);
+	if (!ctrl_pdata || !ctrl_pdata->check_status) {
+		pr_err("%s: DSI ctrl or status_check callback not available\n",
+								__func__);
+		return;
+	}
+
+	mdp5_data = mfd_to_mdp5_data(pstatus_data->mfd);
+	ctl = mfd_to_ctl(pstatus_data->mfd);
+
+	if (ctl->shared_lock)
+		mutex_lock(ctl->shared_lock);
+	mutex_lock(&mdp5_data->ov_lock);
+
+	if (pstatus_data->mfd->shutdown_pending) {
+		mutex_unlock(&mdp5_data->ov_lock);
+		if (ctl->shared_lock)
+			mutex_unlock(ctl->shared_lock);
+		pr_err("%s: DSI turning off, avoiding BTA status check\n",
+							__func__);
+		return;
+	}
+
+	/*
+	 * For the command mode panels, we return pan display
+	 * IOCTL on vsync interrupt. So, after vsync interrupt comes
+	 * and when DMA_P is in progress, if the panel stops responding
+	 * and if we trigger BTA before DMA_P finishes, then the DSI
+	 * FIFO will not be cleared since the DSI data bus control
+	 * doesn't come back to the host after BTA. This may cause the
+	 * display reset not to be proper. Hence, wait for DMA_P done
+	 * for command mode panels before triggering BTA.
+	 */
+	if (ctl->wait_pingpong)
+		ctl->wait_pingpong(ctl, NULL);
+
+	pr_debug("%s: DSI ctrl wait for ping pong done\n", __func__);
+
+	mdss_mdp_clk_ctrl(MDP_BLOCK_POWER_ON, false);
+	ret = ctrl_pdata->check_status(ctrl_pdata);
+	mdss_mdp_clk_ctrl(MDP_BLOCK_POWER_OFF, false);
+
+	mutex_unlock(&mdp5_data->ov_lock);
+	if (ctl->shared_lock)
+		mutex_unlock(ctl->shared_lock);
+
+	if ((pstatus_data->mfd->panel_power_on)) {
+		if (ret > 0) {
+			schedule_delayed_work(&pstatus_data->check_status,
+				msecs_to_jiffies(interval));
+		} else {
+			char *envp[2] = {"PANEL_ALIVE=0", NULL};
+			pdata->panel_info.panel_dead = true;
+			ret = kobject_uevent_env(
+				&pstatus_data->mfd->fbi->dev->kobj,
+							KOBJ_CHANGE, envp);
+			pr_err("%s: Panel has gone bad, sending uevent - %s\n",
+							__func__, envp[0]);
+		}
+	}
+}
diff --git a/drivers/video/msm/mdss/dsi_status_v2.c b/drivers/video/msm/mdss/dsi_status_v2.c
index 565401d..c8915e6 100644
--- a/drivers/video/msm/mdss/dsi_status_v2.c
+++ b/drivers/video/msm/mdss/dsi_status_v2.c
@@ -10,49 +10,26 @@
  * GNU General Public License for more details.
  */
 
-#include <linux/module.h>
-#include <linux/kernel.h>
-#include <linux/init.h>
-#include <linux/fb.h>
-#include <linux/notifier.h>
 #include <linux/workqueue.h>
 #include <linux/delay.h>
-#include <linux/debugfs.h>
-#include <linux/slab.h>
-#include <linux/uaccess.h>
-#include <linux/iopoll.h>
 #include <linux/kobject.h>
 #include <linux/string.h>
 #include <linux/sysfs.h>
 
-#include "mdss_fb.h"
 #include "mdss_dsi.h"
-#include "mdss_panel.h"
 #include "mdp3_ctrl.h"
 
-#define STATUS_CHECK_INTERVAL 5000
-
-/**
- * dsi_status_data - Stores all the data necessary for this module
- * @fb_notif: Used to egister for the fb events
- * @live_status: Delayed worker structure, used to associate the
- * delayed worker function
- * @mfd: Used to store the msm_fb_data_type received when the notifier
- * call back happens
- * @root: Stores the dir created by debuugfs
- * @debugfs_reset_panel: The debugfs variable used to inject errors
+/*
+ * mdp3_check_dsi_ctrl_status() - Check MDP3 DSI controller status periodically.
+ * @work     : dsi controller status data
+ * @interval : duration in milliseconds to schedule work queue
+ *
+ * This function calls check_status API on DSI controller to send the BTA
+ * command. If DSI controller fails to acknowledge the BTA command, it sends
+ * the PANEL_ALIVE=0 status to HAL layer.
  */
-
-struct dsi_status_data {
-	struct notifier_block fb_notifier;
-	struct delayed_work check_status;
-	struct msm_fb_data_type *mfd;
-	uint32_t check_interval;
-};
-struct dsi_status_data *pstatus_data;
-static uint32_t interval = STATUS_CHECK_INTERVAL;
-
-void check_dsi_ctrl_status(struct work_struct *work)
+void mdp3_check_dsi_ctrl_status(struct work_struct *work,
+				uint32_t interval)
 {
 	struct dsi_status_data *pdsi_status = NULL;
 	struct mdss_panel_data *pdata = NULL;
@@ -61,27 +38,25 @@
 	int ret = 0;
 
 	pdsi_status = container_of(to_delayed_work(work),
-		struct dsi_status_data, check_status);
-	if (!pdsi_status) {
-		pr_err("%s: DSI status data not available\n", __func__);
-		return;
-	}
+	struct dsi_status_data, check_status);
 
 	pdata = dev_get_platdata(&pdsi_status->mfd->pdev->dev);
 	if (!pdata) {
 		pr_err("%s: Panel data not available\n", __func__);
 		return;
 	}
+
 	ctrl_pdata = container_of(pdata, struct mdss_dsi_ctrl_pdata,
 							panel_data);
+
 	if (!ctrl_pdata || !ctrl_pdata->check_status) {
-		pr_err("%s: DSI ctrl or status_check callback not avilable\n",
+		pr_err("%s: DSI ctrl or status_check callback not available\n",
 								__func__);
 		return;
 	}
+
 	mdp3_session = pdsi_status->mfd->mdp.private1;
 	mutex_lock(&mdp3_session->lock);
-
 	if (!mdp3_session->status) {
 		pr_info("display off already\n");
 		mutex_unlock(&mdp3_session->lock);
@@ -94,107 +69,22 @@
 	if (!ret)
 		ret = ctrl_pdata->check_status(ctrl_pdata);
 	else
-		pr_err("wait_for_dma_done error\n");
-
+		pr_err("%s: wait_for_dma_done error\n", __func__);
 	mutex_unlock(&mdp3_session->lock);
 
 	if ((pdsi_status->mfd->panel_power_on)) {
 		if (ret > 0) {
 			schedule_delayed_work(&pdsi_status->check_status,
-				msecs_to_jiffies(pdsi_status->check_interval));
+						msecs_to_jiffies(interval));
 		} else {
 			char *envp[2] = {"PANEL_ALIVE=0", NULL};
 			pdata->panel_info.panel_dead = true;
 			ret = kobject_uevent_env(
-				&pdsi_status->mfd->fbi->dev->kobj,
-							KOBJ_CHANGE, envp);
+					&pdsi_status->mfd->fbi->dev->kobj,
+					KOBJ_CHANGE, envp);
 			pr_err("%s: Panel has gone bad, sending uevent - %s\n",
 							__func__, envp[0]);
 		}
 	}
 }
 
-/**
- * fb_notifier_callback() - Call back function for the fb_register_client()
- * notifying events
- * @self  : notifier block
- * @event : The event that was triggered
- * @data  : Of type struct fb_event
- *
- * - This function listens for FB_BLANK_UNBLANK and FB_BLANK_POWERDOWN events
- * - Based on the event the delayed work is either scheduled again after
- * PANEL_STATUS_CHECK_INTERVAL or cancelled
- */
-static int fb_event_callback(struct notifier_block *self,
-				unsigned long event, void *data)
-{
-	struct fb_event *evdata = (struct fb_event *)data;
-	struct dsi_status_data *pdata = container_of(self,
-				struct dsi_status_data, fb_notifier);
-	pdata->mfd = (struct msm_fb_data_type *)evdata->info->par;
-
-	if (event == FB_EVENT_BLANK && evdata) {
-		int *blank = evdata->data;
-		switch (*blank) {
-		case FB_BLANK_UNBLANK:
-			schedule_delayed_work(&pdata->check_status,
-			msecs_to_jiffies(STATUS_CHECK_INTERVAL));
-			break;
-		case FB_BLANK_POWERDOWN:
-			cancel_delayed_work(&pdata->check_status);
-			break;
-		}
-	}
-	return 0;
-}
-
-int __init mdss_dsi_status_init(void)
-{
-	int rc;
-
-	pstatus_data = kzalloc(sizeof(struct dsi_status_data),	GFP_KERNEL);
-	if (!pstatus_data) {
-		pr_err("%s: can't alloc mem\n", __func__);
-		rc = -ENOMEM;
-		return rc;
-	}
-
-	memset(pstatus_data, 0, sizeof(struct dsi_status_data));
-
-	pstatus_data->fb_notifier.notifier_call = fb_event_callback;
-
-	rc = fb_register_client(&pstatus_data->fb_notifier);
-	if (rc < 0) {
-		pr_err("%s: fb_register_client failed, returned with rc=%d\n",
-								__func__, rc);
-		kfree(pstatus_data);
-		return -EPERM;
-	}
-
-	pstatus_data->check_interval = interval;
-	pr_info("%s: DSI status check interval:%d\n", __func__, interval);
-
-	INIT_DELAYED_WORK(&pstatus_data->check_status, check_dsi_ctrl_status);
-
-	pr_debug("%s: DSI ctrl status thread initialized\n", __func__);
-
-	return rc;
-}
-
-void __exit mdss_dsi_status_exit(void)
-{
-	fb_unregister_client(&pstatus_data->fb_notifier);
-	cancel_delayed_work_sync(&pstatus_data->check_status);
-	kfree(pstatus_data);
-	pr_debug("%s: DSI ctrl status thread removed\n", __func__);
-}
-
-module_param(interval, uint, 0);
-MODULE_PARM_DESC(interval,
-	"Duration in milliseconds to send BTA command for checking"
-	"DSI status periodically");
-
-module_init(mdss_dsi_status_init);
-module_exit(mdss_dsi_status_exit);
-
-MODULE_LICENSE("GPL v2");
diff --git a/drivers/video/msm/mdss/mdp3.c b/drivers/video/msm/mdss/mdp3.c
index 9f608b8..8e2ae4d 100644
--- a/drivers/video/msm/mdss/mdp3.c
+++ b/drivers/video/msm/mdss/mdp3.c
@@ -47,6 +47,7 @@
 #include <mach/iommu.h>
 #include <mach/iommu_domains.h>
 #include <mach/msm_memtypes.h>
+#include <mach/rpm-regulator-smd.h>
 
 #include "mdp3.h"
 #include "mdss_fb.h"
@@ -189,11 +190,11 @@
 	u32 mdp_status = 0;
 
 	spin_lock(&mdata->irq_lock);
-	if (!mdata->irq_mask)
+	if (!mdata->irq_mask) {
 		pr_err("spurious interrupt\n");
-
-	clk_enable(mdp3_res->clocks[MDP3_CLK_AHB]);
-	clk_enable(mdp3_res->clocks[MDP3_CLK_CORE]);
+		spin_unlock(&mdata->irq_lock);
+		return IRQ_HANDLED;
+	}
 
 	mdp_status = MDP3_REG_READ(MDP3_REG_INTR_STATUS);
 	mdp_interrupt = mdp_status;
@@ -209,9 +210,6 @@
 	}
 	MDP3_REG_WRITE(MDP3_REG_INTR_CLEAR, mdp_status);
 
-	clk_disable(mdp3_res->clocks[MDP3_CLK_AHB]);
-	clk_disable(mdp3_res->clocks[MDP3_CLK_CORE]);
-
 	spin_unlock(&mdata->irq_lock);
 
 	return IRQ_HANDLED;
@@ -279,19 +277,51 @@
 
 	pr_debug("mdp3_irq_register\n");
 	spin_lock_irqsave(&mdp3_res->irq_lock, flag);
-	enable_irq(mdp3_res->irq);
+	mdp3_res->irq_ref_cnt++;
+	if (mdp3_res->irq_ref_cnt == 1) {
+		MDP3_REG_WRITE(MDP3_REG_INTR_ENABLE, mdp3_res->irq_mask);
+		enable_irq(mdp3_res->irq);
+	}
 	spin_unlock_irqrestore(&mdp3_res->irq_lock, flag);
 }
 
 void mdp3_irq_deregister(void)
 {
 	unsigned long flag;
+	bool irq_enabled = true;
 
 	pr_debug("mdp3_irq_deregister\n");
 	spin_lock_irqsave(&mdp3_res->irq_lock, flag);
 	memset(mdp3_res->irq_ref_count, 0, sizeof(u32) * MDP3_MAX_INTR);
 	mdp3_res->irq_mask = 0;
-	disable_irq_nosync(mdp3_res->irq);
+	MDP3_REG_WRITE(MDP3_REG_INTR_ENABLE, 0);
+	mdp3_res->irq_ref_cnt--;
+	/* This can happen if suspend is called first */
+	if (mdp3_res->irq_ref_cnt < 0) {
+		irq_enabled = false;
+		mdp3_res->irq_ref_cnt = 0;
+	}
+	if (mdp3_res->irq_ref_cnt == 0 && irq_enabled)
+		disable_irq_nosync(mdp3_res->irq);
+	spin_unlock_irqrestore(&mdp3_res->irq_lock, flag);
+}
+
+void mdp3_irq_suspend(void)
+{
+	unsigned long flag;
+	bool irq_enabled = true;
+
+	pr_debug("%s\n", __func__);
+	spin_lock_irqsave(&mdp3_res->irq_lock, flag);
+	mdp3_res->irq_ref_cnt--;
+	if (mdp3_res->irq_ref_cnt < 0) {
+		irq_enabled = false;
+		mdp3_res->irq_ref_cnt = 0;
+	}
+	if (mdp3_res->irq_ref_cnt == 0 && irq_enabled) {
+		MDP3_REG_WRITE(MDP3_REG_INTR_ENABLE, 0);
+		disable_irq_nosync(mdp3_res->irq);
+	}
 	spin_unlock_irqrestore(&mdp3_res->irq_lock, flag);
 }
 
@@ -401,6 +431,12 @@
 	}
 	bus_handle->current_bus_idx = bus_idx;
 	rc = msm_bus_scale_client_update_request(bus_handle->handle, bus_idx);
+
+	if (!rc && ab_quota != 0 && ib_quota != 0) {
+		bus_handle->restore_ab = ab_quota;
+		bus_handle->restore_ib = ib_quota;
+	}
+
 	return rc;
 }
 
@@ -423,10 +459,18 @@
 	count = mdp3_res->clock_ref_count[clk_idx];
 	if (count == 1 && enable) {
 		pr_debug("clk=%d en=%d\n", clk_idx, enable);
+		ret = clk_prepare(clk);
+		if (ret) {
+			pr_err("%s: Failed to prepare clock %d",
+						__func__, clk_idx);
+			mdp3_res->clock_ref_count[clk_idx]--;
+			return ret;
+		}
 		ret = clk_enable(clk);
 	} else if (count == 0) {
 		pr_debug("clk=%d disable\n", clk_idx);
 		clk_disable(clk);
+		clk_unprepare(clk);
 		ret = 0;
 	} else if (count < 0) {
 		pr_err("clk=%d count=%d\n", clk_idx, count);
@@ -578,62 +622,83 @@
 	return rc;
 }
 
-int mdp3_clk_prepare(void)
+void mdp3_bus_bw_iommu_enable(int enable, int client)
+{
+	struct mdp3_bus_handle_map *bus_handle;
+	int client_idx;
+	u64 ab, ib;
+	int ref_cnt;
+
+	if (client == MDP3_CLIENT_DMA_P) {
+		client_idx  = MDP3_BUS_HANDLE_DMA;
+	} else if (client == MDP3_CLIENT_PPP) {
+		client_idx  = MDP3_BUS_HANDLE_PPP;
+	} else {
+		pr_err("invalid client %d\n", client);
+		return;
+	}
+
+	bus_handle = &mdp3_res->bus_handle[client_idx];
+	if (bus_handle->handle < 1) {
+		pr_err("invalid bus handle %d\n", bus_handle->handle);
+		return;
+	}
+	mutex_lock(&mdp3_res->res_mutex);
+	if (enable)
+		bus_handle->ref_cnt++;
+	else
+		bus_handle->ref_cnt--;
+	ref_cnt = bus_handle->ref_cnt;
+	mutex_unlock(&mdp3_res->res_mutex);
+
+	if (enable && ref_cnt == 1) {
+		if (mdp3_res->allow_iommu_update)
+			mdp3_iommu_enable(client);
+		ab = bus_handle->restore_ab;
+		ib = bus_handle->restore_ib;
+		mdp3_bus_scale_set_quota(client, ab, ib);
+	} else if (!enable && ref_cnt == 0) {
+		mdp3_bus_scale_set_quota(client, 0, 0);
+		mdp3_iommu_disable(client);
+	} else if (ref_cnt < 0) {
+		pr_err("Ref count < 0, bus client=%d, ref_cnt=%d",
+				client_idx, ref_cnt);
+	}
+}
+
+int mdp3_res_update(int enable, int dsi_clk, int client)
 {
 	int rc = 0;
 
-	mutex_lock(&mdp3_res->res_mutex);
-	mdp3_res->clk_prepare_count++;
-	if (mdp3_res->clk_prepare_count == 1) {
-		rc = clk_prepare(mdp3_res->clocks[MDP3_CLK_AHB]);
-		if (rc < 0)
-			goto error0;
-		rc = clk_prepare(mdp3_res->clocks[MDP3_CLK_CORE]);
-		if (rc < 0)
-			goto error1;
-		rc = clk_prepare(mdp3_res->clocks[MDP3_CLK_VSYNC]);
-		if (rc < 0)
-			goto error2;
-		rc = clk_prepare(mdp3_res->clocks[MDP3_CLK_DSI]);
-		if (rc < 0)
-			goto error3;
+	if (enable) {
+		rc = mdp3_clk_enable(enable, dsi_clk);
+		if (rc < 0) {
+			pr_err("mdp3_clk_enable failed, enable=%d, dsi_clk=%d\n",
+				enable, dsi_clk);
+			goto done;
+		}
+		mdp3_irq_register();
+		mdp3_bus_bw_iommu_enable(enable, client);
+	} else {
+		mdp3_bus_bw_iommu_enable(enable, client);
+		mdp3_irq_suspend();
+		rc = mdp3_clk_enable(enable, dsi_clk);
+		if (rc < 0) {
+			pr_err("mdp3_clk_enable failed, enable=%d, dsi_clk=%d\n",
+				enable, dsi_clk);
+			goto done;
+		}
 	}
-	mutex_unlock(&mdp3_res->res_mutex);
-	return rc;
 
-error3:
-	clk_unprepare(mdp3_res->clocks[MDP3_CLK_VSYNC]);
-error2:
-	clk_unprepare(mdp3_res->clocks[MDP3_CLK_CORE]);
-error1:
-	clk_unprepare(mdp3_res->clocks[MDP3_CLK_AHB]);
-error0:
-	mdp3_res->clk_prepare_count--;
-	mutex_unlock(&mdp3_res->res_mutex);
+done:
 	return rc;
 }
 
-void mdp3_clk_unprepare(void)
-{
-	mutex_lock(&mdp3_res->res_mutex);
-	mdp3_res->clk_prepare_count--;
-	if (mdp3_res->clk_prepare_count == 0) {
-		clk_unprepare(mdp3_res->clocks[MDP3_CLK_AHB]);
-		clk_unprepare(mdp3_res->clocks[MDP3_CLK_CORE]);
-		clk_unprepare(mdp3_res->clocks[MDP3_CLK_VSYNC]);
-		clk_unprepare(mdp3_res->clocks[MDP3_CLK_DSI]);
-	} else if (mdp3_res->clk_prepare_count < 0) {
-		pr_err("mdp3 clk unprepare mismatch\n");
-	}
-	mutex_unlock(&mdp3_res->res_mutex);
-}
-
 int mdp3_get_mdp_dsi_clk(void)
 {
 	int rc;
 
 	mutex_lock(&mdp3_res->res_mutex);
-	clk_prepare(mdp3_res->clocks[MDP3_CLK_DSI]);
 	rc = mdp3_clk_update(MDP3_CLK_DSI, 1);
 	mutex_unlock(&mdp3_res->res_mutex);
 	return rc;
@@ -644,7 +709,6 @@
 	int rc;
 	mutex_lock(&mdp3_res->res_mutex);
 	rc = mdp3_clk_update(MDP3_CLK_DSI, 0);
-	clk_unprepare(mdp3_res->clocks[MDP3_CLK_DSI]);
 	mutex_unlock(&mdp3_res->res_mutex);
 	return rc;
 }
@@ -1141,6 +1205,54 @@
 	return 0;
 }
 
+void msm_mdp3_cx_ctrl(int enable)
+{
+	int rc;
+
+	if (!mdp3_res->vdd_cx) {
+		mdp3_res->vdd_cx = devm_regulator_get(&mdp3_res->pdev->dev,
+								"vdd-cx");
+		if (IS_ERR_OR_NULL(mdp3_res->vdd_cx)) {
+			pr_debug("unable to get CX reg. rc=%d\n",
+				PTR_RET(mdp3_res->vdd_cx));
+			mdp3_res->vdd_cx = NULL;
+			return;
+		}
+	}
+
+	if (enable) {
+		rc = regulator_set_voltage(
+				mdp3_res->vdd_cx,
+				RPM_REGULATOR_CORNER_SVS_SOC,
+				RPM_REGULATOR_CORNER_SUPER_TURBO);
+		if (rc < 0)
+			goto vreg_set_voltage_fail;
+
+		rc = regulator_enable(mdp3_res->vdd_cx);
+		if (rc) {
+			pr_err("Failed to enable regulator vdd_cx.\n");
+			return;
+		}
+	} else {
+		rc = regulator_disable(mdp3_res->vdd_cx);
+		if (rc) {
+			pr_err("Failed to disable regulator vdd_cx.\n");
+			return;
+		}
+		rc = regulator_set_voltage(
+				mdp3_res->vdd_cx,
+				RPM_REGULATOR_CORNER_NONE,
+				RPM_REGULATOR_CORNER_SUPER_TURBO);
+		if (rc < 0)
+			goto vreg_set_voltage_fail;
+	}
+
+	return;
+vreg_set_voltage_fail:
+	pr_err("Set vltg failed\n");
+	return;
+}
+
 void mdp3_batfet_ctrl(int enable)
 {
 	int rc;
@@ -1173,6 +1285,12 @@
 		pr_err("%s: reg enable/disable failed", __func__);
 }
 
+void mdp3_enable_regulator(int enable)
+{
+	msm_mdp3_cx_ctrl(enable);
+	mdp3_batfet_ctrl(enable);
+}
+
 static void mdp3_iommu_heap_unmap_iommu(struct mdp3_iommu_meta *meta)
 {
 	unsigned int domain_num;
@@ -1849,6 +1967,7 @@
 static int mdp3_continuous_splash_on(struct mdss_panel_data *pdata)
 {
 	struct mdss_panel_info *panel_info = &pdata->panel_info;
+	struct mdp3_bus_handle_map *bus_handle;
 	u64 ab, ib;
 	int rc;
 
@@ -1860,26 +1979,23 @@
 	mdp3_clk_set_rate(MDP3_CLK_CORE, MDP_CORE_CLK_RATE,
 			MDP3_CLIENT_DMA_P);
 
-	rc = mdp3_clk_prepare();
-	if (rc) {
-		pr_err("fail to prepare clk\n");
-		return rc;
-	}
-
-	rc = mdp3_clk_enable(1, 1);
-	if (rc) {
-		pr_err("fail to enable clk\n");
-		mdp3_clk_unprepare();
-		return rc;
+	bus_handle = &mdp3_res->bus_handle[MDP3_BUS_HANDLE_DMA];
+	if (bus_handle->handle < 1) {
+		pr_err("invalid bus handle %d\n", bus_handle->handle);
+		return -EINVAL;
 	}
 
 	ab = panel_info->xres * panel_info->yres * 4;
 	ab *= panel_info->mipi.frame_rate;
 	ib = (ab * 3) / 2;
 	rc = mdp3_bus_scale_set_quota(MDP3_CLIENT_DMA_P, ab, ib);
+	bus_handle->restore_ab = ab;
+	bus_handle->restore_ib = ib;
+
+	rc = mdp3_res_update(1, 1, MDP3_CLIENT_DMA_P);
 	if (rc) {
-		pr_err("fail to request bus bandwidth\n");
-		goto splash_on_err;
+		pr_err("fail to enable clk\n");
+		return rc;
 	}
 
 	rc = mdp3_ppp_init();
@@ -1888,8 +2004,6 @@
 		goto splash_on_err;
 	}
 
-	mdp3_irq_register();
-
 	if (pdata->event_handler) {
 		rc = pdata->event_handler(pdata, MDSS_EVENT_CONT_SPLASH_BEGIN,
 					NULL);
@@ -1904,15 +2018,14 @@
 	else
 		mdp3_res->intf[MDP3_DMA_OUTPUT_SEL_DSI_CMD].active = 1;
 
-	mdp3_batfet_ctrl(true);
+	mdp3_enable_regulator(true);
 	mdp3_res->cont_splash_en = 1;
 	return 0;
 
 splash_on_err:
-	if (mdp3_clk_enable(0, 1))
+	if (mdp3_res_update(0, 1, MDP3_CLIENT_DMA_P))
 		pr_err("%s: Unable to disable mdp3 clocks\n", __func__);
 
-	mdp3_clk_unprepare();
 	return rc;
 }
 
@@ -1932,6 +2045,12 @@
 			rc = mdp3_continuous_splash_on(pdata);
 		}
 	}
+	/*
+	 * We want to prevent iommu from being enabled if there is
+	 * continue splash screen. This would have happened in
+	 * res_update in continuous_splash_on without this flag.
+	 */
+	mdp3_res->allow_iommu_update = true;
 	return rc;
 }
 
@@ -1946,11 +2065,9 @@
 static void mdp3_debug_enable_clock(int on)
 {
 	if (on) {
-		mdp3_clk_prepare();
 		mdp3_clk_enable(1, 0);
 	} else {
 		mdp3_clk_enable(0, 0);
-		mdp3_clk_unprepare();
 	}
 }
 
@@ -2149,6 +2266,7 @@
 	.panel_register_done = mdp3_panel_register_done,
 	.fb_stride = mdp3_fb_stride,
 	.fb_mem_alloc_fnc = mdp3_alloc,
+	.check_dsi_status = mdp3_check_dsi_ctrl_status,
 	};
 
 	struct mdp3_intr_cb underrun_cb = {
@@ -2258,13 +2376,13 @@
 
 static  int mdp3_suspend_sub(struct mdp3_hw_resource *mdata)
 {
-	mdp3_batfet_ctrl(false);
+	mdp3_enable_regulator(false);
 	return 0;
 }
 
 static  int mdp3_resume_sub(struct mdp3_hw_resource *mdata)
 {
-	mdp3_batfet_ctrl(true);
+	mdp3_enable_regulator(true);
 	return 0;
 }
 
diff --git a/drivers/video/msm/mdss/mdp3.h b/drivers/video/msm/mdss/mdp3.h
index a253d8f..137a1b8 100644
--- a/drivers/video/msm/mdss/mdp3.h
+++ b/drivers/video/msm/mdss/mdp3.h
@@ -74,6 +74,9 @@
 	struct msm_bus_paths *usecases;
 	struct msm_bus_scale_pdata *scale_pdata;
 	int current_bus_idx;
+	int ref_cnt;
+	u64 restore_ab;
+	u64 restore_ib;
 	u32 handle;
 };
 
@@ -134,6 +137,7 @@
 	struct ion_client *ion_client;
 	struct mdp3_iommu_domain_map *domains;
 	struct mdp3_iommu_ctx_map *iommu_contexts;
+	bool allow_iommu_update;
 	struct ion_handle *ion_handle;
 	struct mutex iommu_lock;
 	struct rb_root iommu_root;
@@ -144,6 +148,7 @@
 	spinlock_t irq_lock;
 	u32 irq_ref_count[MDP3_MAX_INTR];
 	u32 irq_mask;
+	int irq_ref_cnt;
 	struct mdp3_intr_cb callbacks[MDP3_MAX_INTR];
 	u32 underrun_cnt;
 
@@ -159,6 +164,7 @@
 
 	bool batfet_required;
 	struct regulator *batfet;
+	struct regulator *vdd_cx;
 };
 
 struct mdp3_img_data {
@@ -183,8 +189,7 @@
 void mdp3_irq_deregister(void);
 int mdp3_clk_set_rate(int clk_type, unsigned long clk_rate, int client);
 int mdp3_clk_enable(int enable, int dsi_clk);
-int mdp3_clk_prepare(void);
-void mdp3_clk_unprepare(void);
+int mdp3_res_update(int enable, int dsi_clk, int client);
 int mdp3_bus_scale_set_quota(int client, u64 ab_quota, u64 ib_quota);
 int mdp3_put_img(struct mdp3_img_data *data, int client);
 int mdp3_get_img(struct msmfb_data *img, struct mdp3_img_data *data,
@@ -203,6 +208,9 @@
 
 int mdp3_misr_set(struct mdp_misr *misr_req);
 int mdp3_misr_get(struct mdp_misr *misr_resp);
+void mdp3_enable_regulator(int enable);
+void mdp3_check_dsi_ctrl_status(struct work_struct *work,
+				uint32_t interval);
 
 #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 697ac40..9cbff71 100644
--- a/drivers/video/msm/mdss/mdp3_ctrl.c
+++ b/drivers/video/msm/mdss/mdp3_ctrl.c
@@ -113,6 +113,7 @@
 static void mdp3_dispatch_dma_done(struct work_struct *work)
 {
 	struct mdp3_session_data *session;
+	int cnt = 0;
 
 	pr_debug("%s\n", __func__);
 	session = container_of(work, struct mdp3_session_data,
@@ -120,7 +121,13 @@
 	if (!session)
 		return;
 
-	mdp3_ctrl_notify(session, MDP_NOTIFY_FRAME_DONE);
+	cnt = atomic_read(&session->dma_done_cnt);
+
+	while (cnt > 0) {
+		mdp3_ctrl_notify(session, MDP_NOTIFY_FRAME_DONE);
+		atomic_dec(&session->dma_done_cnt);
+		cnt--;
+	}
 }
 
 static void mdp3_dispatch_clk_off(struct work_struct *work)
@@ -156,6 +163,7 @@
 void dma_done_notify_handler(void *arg)
 {
 	struct mdp3_session_data *session = (struct mdp3_session_data *)arg;
+	atomic_inc(&session->dma_done_cnt);
 	schedule_work(&session->dma_done_work);
 	complete(&session->dma_completion);
 }
@@ -297,7 +305,7 @@
 	vsync_ticks = ktime_to_ns(mdp3_session->vsync_time);
 
 	pr_debug("fb%d vsync=%llu", mfd->index, vsync_ticks);
-	rc = scnprintf(buf, PAGE_SIZE, "VSYNC=%llu", vsync_ticks);
+	rc = scnprintf(buf, PAGE_SIZE, "VSYNC=%llu\n", vsync_ticks);
 	return rc;
 }
 
@@ -330,7 +338,7 @@
 				(!enable && session->clk_on == 1)) {
 		rc = panel->event_handler(panel,
 			MDSS_EVENT_PANEL_CLK_CTRL, (void *)enable);
-		rc |= mdp3_clk_enable(enable, 1);
+		rc |= mdp3_res_update(enable, 1, MDP3_CLIENT_DMA_P);
 	} else {
 		pr_debug("enable = %d, clk_on=%d\n", enable, session->clk_on);
 	}
@@ -366,24 +374,15 @@
 		mdp3_clk_set_rate(MDP3_CLK_VSYNC, MDP_VSYNC_CLK_RATE,
 				MDP3_CLIENT_DMA_P);
 
-		rc = mdp3_clk_prepare();
-		if (rc) {
-			pr_err("mdp3 clk prepare fail\n");
-			return rc;
-		}
-
-		rc = mdp3_clk_enable(1, 1);
+		rc = mdp3_res_update(1, 1, MDP3_CLIENT_DMA_P);
 		if (rc) {
 			pr_err("mdp3 clk enable fail\n");
-			mdp3_clk_unprepare();
 			return rc;
 		}
 	} else {
-		rc = mdp3_clk_enable(0, 1);
+		rc = mdp3_res_update(0, 1, MDP3_CLIENT_DMA_P);
 		if (rc)
 			pr_err("mdp3 clk disable fail\n");
-		else
-			mdp3_clk_unprepare();
 	}
 	return rc;
 }
@@ -478,6 +477,7 @@
 		video->hsync_polarity = 1;
 		video->vsync_polarity = 1;
 		video->de_polarity = 1;
+		video->underflow_color = p->lcdc.underflow_clr;
 	} else if (cfg.type == MDP3_DMA_OUTPUT_SEL_DSI_CMD) {
 		cfg.dsi_cmd.primary_dsi_cmd_id = 0;
 		cfg.dsi_cmd.secondary_dsi_cmd_id = 1;
@@ -506,6 +506,7 @@
 	int vbp, vfp, vspw;
 	int vtotal, vporch;
 	struct mdp3_notification dma_done_callback;
+	struct mdp3_tear_check te;
 
 	vbp = panel_info->lcdc.v_back_porch;
 	vfp = panel_info->lcdc.v_front_porch;
@@ -537,12 +538,28 @@
 					(MDP3_DMA_OUTPUT_COMP_BITS_8 << 2)|
 					MDP3_DMA_OUTPUT_COMP_BITS_8;
 
+	te.frame_rate = panel_info->mipi.frame_rate;
+	te.hw_vsync_mode = panel_info->mipi.hw_vsync_mode;
+	te.tear_check_en = panel_info->te.tear_check_en;
+	te.sync_cfg_height = panel_info->te.sync_cfg_height;
+	te.vsync_init_val = panel_info->te.vsync_init_val;
+	te.sync_threshold_start = panel_info->te.sync_threshold_start;
+	te.sync_threshold_continue = panel_info->te.sync_threshold_continue;
+	te.start_pos = panel_info->te.start_pos;
+	te.rd_ptr_irq = panel_info->te.rd_ptr_irq;
+	te.refx100 = panel_info->te.refx100;
+
 	if (dma->dma_config)
 		rc = dma->dma_config(dma, &sourceConfig, &outputConfig);
 	else
 		rc = -EINVAL;
 
 	if (outputConfig.out_sel == MDP3_DMA_OUTPUT_SEL_DSI_CMD) {
+		if (dma->dma_sync_config)
+			rc = dma->dma_sync_config(dma,
+					&sourceConfig, &te);
+		else
+			rc = -EINVAL;
 		dma_done_callback.handler = dma_done_notify_handler;
 		dma_done_callback.arg = mfd->mdp.private1;
 		dma->dma_done_notifier(dma, &dma_done_callback);
@@ -575,16 +592,10 @@
 		goto on_error;
 	}
 
-	mdp3_batfet_ctrl(true);
+	mdp3_enable_regulator(true);
 	mdp3_ctrl_notifier_register(mdp3_session,
 		&mdp3_session->mfd->mdp_sync_pt_data.notifier);
 
-	rc = mdp3_iommu_enable(MDP3_CLIENT_DMA_P);
-	if (rc) {
-		pr_err("fail to attach MDP DMA SMMU\n");
-		goto on_error;
-	}
-
 	/* request bus bandwidth before DSI DMA traffic */
 	rc = mdp3_ctrl_res_req_bus(mfd, 1);
 	if (rc) {
@@ -607,8 +618,6 @@
 		goto on_error;
 	}
 
-	mdp3_irq_register();
-
 	rc = mdp3_ctrl_dma_init(mfd, mdp3_session->dma);
 	if (rc) {
 		pr_err("dma init failed\n");
@@ -626,7 +635,6 @@
 		pr_err("display interface init failed\n");
 		goto on_error;
 	}
-
 	mdp3_session->clk_on = 1;
 
 	mdp3_session->first_commit = true;
@@ -655,6 +663,9 @@
 	panel = mdp3_session->panel;
 	mutex_lock(&mdp3_session->lock);
 
+	if (panel && panel->set_backlight)
+		panel->set_backlight(panel, 0);
+
 	if (!mdp3_session->status) {
 		pr_debug("fb%d is off already", mfd->index);
 		goto off_error;
@@ -678,7 +689,7 @@
 
 	pr_debug("mdp3_ctrl_off stop clock\n");
 	if (mdp3_session->clk_on) {
-		rc = mdp3_clk_enable(0, 1);
+		rc = mdp3_res_update(0, 1, MDP3_CLIENT_DMA_P);
 		if (rc)
 			pr_err("mdp clock resource release failed\n");
 
@@ -689,22 +700,13 @@
 		if (rc)
 			pr_err("fail to turn off the panel\n");
 	}
-	mdp3_clk_unprepare();
-
-	pr_debug("mdp3_ctrl_off release bus\n");
-	rc = mdp3_ctrl_res_req_bus(mfd, 0);
-	if (rc)
-		pr_err("mdp bus resource release failed\n");
-
-	rc = mdp3_iommu_disable(MDP3_CLIENT_DMA_P);
-	if (rc)
-		pr_err("fail to dettach MDP DMA SMMU\n");
 
 	mdp3_ctrl_notifier_unregister(mdp3_session,
 		&mdp3_session->mfd->mdp_sync_pt_data.notifier);
-	mdp3_batfet_ctrl(false);
+	mdp3_enable_regulator(false);
 	mdp3_session->vsync_enabled = 0;
 	atomic_set(&mdp3_session->vsync_countdown, 0);
+	atomic_set(&mdp3_session->dma_done_cnt, 0);
 	mdp3_session->clk_on = 0;
 	mdp3_session->in_splash_screen = 0;
 off_error:
@@ -1283,7 +1285,7 @@
 		return -EBUSY;
 	}
 
-	mdp3_clk_enable(1, 0);
+	mdp3_res_update(1, 0, MDP3_CLIENT_DMA_P);
 	ret = session->dma->histo_op(session->dma, MDP3_DMA_HISTO_OP_RESET);
 	if (ret) {
 		pr_err("mdp3_histogram_start reset error\n");
@@ -1309,7 +1311,7 @@
 	session->histo_status = 1;
 
 histogram_start_err:
-	mdp3_clk_enable(0, 0);
+	mdp3_res_update(0, 0, MDP3_CLIENT_DMA_P);
 	mutex_unlock(&session->histo_lock);
 	return ret;
 }
diff --git a/drivers/video/msm/mdss/mdp3_ctrl.h b/drivers/video/msm/mdss/mdp3_ctrl.h
index 20649fc..93356e2 100644
--- a/drivers/video/msm/mdss/mdp3_ctrl.h
+++ b/drivers/video/msm/mdss/mdp3_ctrl.h
@@ -50,6 +50,7 @@
 	struct mdp3_buffer_queue bufq_out;
 	struct work_struct clk_off_work;
 	struct work_struct dma_done_work;
+	atomic_t dma_done_cnt;
 	int histo_status;
 	struct mutex histo_lock;
 	int lut_sel;
diff --git a/drivers/video/msm/mdss/mdp3_dma.c b/drivers/video/msm/mdss/mdp3_dma.c
index 8a13de2..2dd66f8 100644
--- a/drivers/video/msm/mdss/mdp3_dma.c
+++ b/drivers/video/msm/mdss/mdp3_dma.c
@@ -24,6 +24,11 @@
 #define DMA_CCS_CONFIG_MASK 0xfffffc17
 #define HIST_WAIT_TIMEOUT(frame) ((75 * HZ * (frame)) / 1000)
 
+#define VSYNC_SELECT 0x024
+#define VSYNC_TOTAL_LINES_SHIFT 21
+#define VSYNC_COUNT_MASK 0x7ffff
+#define VSYNC_THRESH_CONT_SHIFT 16
+
 static void mdp3_vsync_intr_handler(int type, void *arg)
 {
 	struct mdp3_dma *dma = (struct mdp3_dma *)arg;
@@ -266,32 +271,48 @@
 	}
 }
 
-static int mdp3_dma_sync_config(struct mdp3_dma *dma,
-			struct mdp3_dma_source *source_config)
+
+int mdp3_dma_sync_config(struct mdp3_dma *dma,
+	struct mdp3_dma_source *source_config, struct mdp3_tear_check *te)
 {
-	u32 sync_config;
+	u32 vsync_clk_speed_hz, vclks_line, cfg;
+	int porch = source_config->vporch;
+	int height = source_config->height;
+	int total_lines = height + porch;
 	int dma_sel = dma->dma_sel;
 
-	pr_debug("mdp3_dma_sync_config\n");
+	vsync_clk_speed_hz = MDP_VSYNC_CLK_RATE;
 
-	if (dma->output_config.out_sel == MDP3_DMA_OUTPUT_SEL_DSI_CMD) {
-		int porch = source_config->vporch;
-		int height = source_config->height;
-		int vtotal = height + porch;
-		sync_config = vtotal << 21;
-		sync_config |= source_config->vsync_count;
-		sync_config |= BIT(19);
-		sync_config |= BIT(20);
+	cfg = total_lines << VSYNC_TOTAL_LINES_SHIFT;
+	total_lines *= te->frame_rate;
 
-		MDP3_REG_WRITE(MDP3_REG_SYNC_CONFIG_0 + dma_sel, sync_config);
-		MDP3_REG_WRITE(MDP3_REG_VSYNC_SEL, 0x024);
-		MDP3_REG_WRITE(MDP3_REG_PRIMARY_VSYNC_INIT_VAL + dma_sel,
-				height);
-		MDP3_REG_WRITE(MDP3_REG_PRIMARY_RD_PTR_IRQ, 0x5);
-		MDP3_REG_WRITE(MDP3_REG_SYNC_THRESH_0 + dma_sel, (4 << 16 | 2));
-		MDP3_REG_WRITE(MDP3_REG_PRIMARY_START_P0S + dma_sel, porch);
-		MDP3_REG_WRITE(MDP3_REG_TEAR_CHECK_EN, 0x1);
+	vclks_line = (total_lines) ? vsync_clk_speed_hz / total_lines : 0;
+
+	cfg |= BIT(19);
+	if (te->hw_vsync_mode)
+		cfg |= BIT(20);
+
+	if (te->refx100) {
+		vclks_line = vclks_line * te->frame_rate *
+			100 / te->refx100;
+	} else {
+		pr_warn("refx100 cannot be zero! Use 6000 as default\n");
+		vclks_line = vclks_line * te->frame_rate *
+			100 / 6000;
 	}
+
+	cfg |= (vclks_line & VSYNC_COUNT_MASK);
+
+	MDP3_REG_WRITE(MDP3_REG_SYNC_CONFIG_0 + dma_sel, cfg);
+	MDP3_REG_WRITE(MDP3_REG_VSYNC_SEL, VSYNC_SELECT);
+	MDP3_REG_WRITE(MDP3_REG_PRIMARY_VSYNC_INIT_VAL + dma_sel,
+				te->vsync_init_val);
+	MDP3_REG_WRITE(MDP3_REG_PRIMARY_RD_PTR_IRQ, te->rd_ptr_irq);
+	MDP3_REG_WRITE(MDP3_REG_SYNC_THRESH_0 + dma_sel,
+		((te->sync_threshold_continue << VSYNC_THRESH_CONT_SHIFT) |
+				 te->sync_threshold_start));
+	MDP3_REG_WRITE(MDP3_REG_PRIMARY_START_P0S + dma_sel, te->start_pos);
+	MDP3_REG_WRITE(MDP3_REG_TEAR_CHECK_EN, te->tear_check_en);
 	return 0;
 }
 
@@ -324,8 +345,6 @@
 
 	dma->source_config = *source_config;
 	dma->output_config = *output_config;
-	mdp3_dma_sync_config(dma, source_config);
-
 	mdp3_irq_enable(MDP3_INTR_LCDC_UNDERFLOW);
 	mdp3_dma_callback_setup(dma);
 	return 0;
@@ -378,7 +397,6 @@
 
 	dma->source_config = *source_config;
 	dma->output_config = *output_config;
-	mdp3_dma_sync_config(dma, source_config);
 
 	mdp3_dma_callback_setup(dma);
 	return 0;
@@ -925,6 +943,7 @@
 	switch (dma->dma_sel) {
 	case MDP3_DMA_P:
 		dma->dma_config = mdp3_dmap_config;
+		dma->dma_sync_config = mdp3_dma_sync_config;
 		dma->dma_config_source = mdp3_dmap_config_source;
 		dma->config_cursor = mdp3_dmap_cursor_config;
 		dma->config_ccs = mdp3_dmap_ccs_config;
@@ -941,6 +960,7 @@
 		break;
 	case MDP3_DMA_S:
 		dma->dma_config = mdp3_dmas_config;
+		dma->dma_sync_config = mdp3_dma_sync_config;
 		dma->dma_config_source = mdp3_dmas_config_source;
 		dma->config_cursor = NULL;
 		dma->config_ccs = NULL;
@@ -1060,7 +1080,9 @@
 		temp |= BIT(2);
 	MDP3_REG_WRITE(MDP3_REG_DSI_VIDEO_CTL_POLARITY, temp);
 
-	MDP3_REG_WRITE(MDP3_REG_DSI_VIDEO_UNDERFLOW_CTL, 0x800000ff);
+	v->underflow_color |= 0x80000000;
+	MDP3_REG_WRITE(MDP3_REG_DSI_VIDEO_UNDERFLOW_CTL, v->underflow_color);
+
 	return 0;
 }
 
diff --git a/drivers/video/msm/mdss/mdp3_dma.h b/drivers/video/msm/mdss/mdp3_dma.h
index 80ebb9b..d07e06d 100644
--- a/drivers/video/msm/mdss/mdp3_dma.h
+++ b/drivers/video/msm/mdss/mdp3_dma.h
@@ -233,6 +233,19 @@
 	void *arg;
 };
 
+struct mdp3_tear_check {
+	int frame_rate;
+	bool hw_vsync_mode;
+	u32 tear_check_en;
+	u32 sync_cfg_height;
+	u32 vsync_init_val;
+	u32 sync_threshold_start;
+	u32 sync_threshold_continue;
+	u32 start_pos;
+	u32 rd_ptr_irq;
+	u32 refx100;
+};
+
 struct mdp3_intf;
 
 struct mdp3_dma {
@@ -265,6 +278,9 @@
 			struct mdp3_dma_source *source_config,
 			struct mdp3_dma_output_config *output_config);
 
+	int (*dma_sync_config)(struct mdp3_dma *dma, struct mdp3_dma_source
+				*source_config, struct mdp3_tear_check *te);
+
 	void (*dma_config_source)(struct mdp3_dma *dma);
 
 	int (*start)(struct mdp3_dma *dma, struct mdp3_intf *intf);
@@ -319,6 +335,7 @@
 	int hsync_polarity;
 	int vsync_polarity;
 	int de_polarity;
+	int underflow_color;
 };
 
 struct mdp3_dsi_cmd_intf_cfg {
diff --git a/drivers/video/msm/mdss/mdp3_ppp.c b/drivers/video/msm/mdss/mdp3_ppp.c
index 7e590b3a..afa0b7c 100644
--- a/drivers/video/msm/mdss/mdp3_ppp.c
+++ b/drivers/video/msm/mdss/mdp3_ppp.c
@@ -386,14 +386,14 @@
 			ab = req_bw;
 	}
 	mdp3_clk_set_rate(MDP3_CLK_CORE, rate, MDP3_CLIENT_PPP);
-	rc = mdp3_clk_enable(on_off, 0);
+	rc = mdp3_res_update(on_off, 0, MDP3_CLIENT_PPP);
 	if (rc < 0) {
 		pr_err("%s: mdp3_clk_enable failed\n", __func__);
 		return rc;
 	}
 	rc = mdp3_bus_scale_set_quota(MDP3_CLIENT_PPP, ab, ib);
 	if (rc < 0) {
-		mdp3_clk_enable(!on_off, 0);
+		mdp3_res_update(!on_off, 0, MDP3_CLIENT_PPP);
 		pr_err("%s: scale_set_quota failed\n", __func__);
 		return rc;
 	}
@@ -865,17 +865,17 @@
 
 	if (req->flags & MDP_ROT_90) {
 		if (((req->dst_rect.h == 1) && ((req->src_rect.w != 1) ||
-			(req->dst_rect.w != req->src_rect.h))) ||
+			(req->dst_rect.w == req->src_rect.h))) ||
 			((req->dst_rect.w == 1) && ((req->src_rect.h != 1) ||
-			(req->dst_rect.h != req->src_rect.w)))) {
+			(req->dst_rect.h == req->src_rect.w)))) {
 			pr_err("mdp_ppp: error scaling when size is 1!\n");
 			return -EINVAL;
 		}
 	} else {
 		if (((req->dst_rect.w == 1) && ((req->src_rect.w != 1) ||
-			(req->dst_rect.h != req->src_rect.h))) ||
+			(req->dst_rect.h == req->src_rect.h))) ||
 			((req->dst_rect.h == 1) && ((req->src_rect.h != 1) ||
-			(req->dst_rect.w != req->src_rect.w)))) {
+			(req->dst_rect.w == req->src_rect.w)))) {
 			pr_err("mdp_ppp: error scaling when size is 1!\n");
 			return -EINVAL;
 		}
@@ -1039,14 +1039,10 @@
 static void mdp3_free_bw_wq_handler(struct work_struct *work)
 {
 	struct msm_fb_data_type *mfd = ppp_stat->mfd;
-	int rc;
 
 	mutex_lock(&ppp_stat->config_ppp_mutex);
 	if (ppp_stat->bw_on) {
 		mdp3_ppp_turnon(mfd, 0);
-		rc = mdp3_iommu_disable(MDP3_CLIENT_PPP);
-		if (rc < 0)
-			WARN(1, "Unable to disable ppp iommu\n");
 	}
 	mutex_unlock(&ppp_stat->config_ppp_mutex);
 }
@@ -1065,16 +1061,9 @@
 	}
 
 	if (!ppp_stat->bw_on) {
-		rc = mdp3_iommu_enable(MDP3_CLIENT_PPP);
-		if (rc < 0) {
-			mutex_unlock(&ppp_stat->config_ppp_mutex);
-			pr_err("%s: mdp3_iommu_enable failed\n", __func__);
-			return;
-		}
 		ppp_stat->bw_optimal = mdp3_optimal_bw(req->count);
 		mdp3_ppp_turnon(mfd, 1);
 		if (rc < 0) {
-			mdp3_iommu_disable(MDP3_CLIENT_PPP);
 			mutex_unlock(&ppp_stat->config_ppp_mutex);
 			pr_err("%s: Enable ppp resources failed\n", __func__);
 			return;
diff --git a/drivers/video/msm/mdss/mdss.h b/drivers/video/msm/mdss/mdss.h
index 7e6faa8..72cceaa 100644
--- a/drivers/video/msm/mdss/mdss.h
+++ b/drivers/video/msm/mdss/mdss.h
@@ -117,6 +117,7 @@
 	u32 has_bwc;
 	u32 has_decimation;
 	u8 has_wfd_blk;
+	u32 has_no_lut_read;
 	u8 has_wb_ad;
 
 	u32 rotator_ot_limit;
@@ -148,8 +149,12 @@
 
 	struct mdss_fudge_factor ab_factor;
 	struct mdss_fudge_factor ib_factor;
+	struct mdss_fudge_factor ib_factor_overlap;
 	struct mdss_fudge_factor clk_factor;
 
+	u32 *clock_levels;
+	u32 nclk_lvl;
+
 	struct mdss_hw_settings *hw_settings;
 
 	struct mdss_mdp_pipe *vig_pipes;
diff --git a/drivers/video/msm/mdss/mdss_debug.c b/drivers/video/msm/mdss/mdss_debug.c
index 0d0240f..aeb3f86 100644
--- a/drivers/video/msm/mdss/mdss_debug.c
+++ b/drivers/video/msm/mdss/mdss_debug.c
@@ -30,21 +30,6 @@
 #define GROUP_BYTES 4
 #define ROW_BYTES 16
 #define MAX_VSYNC_COUNT 0xFFFFFFF
-struct mdss_debug_data {
-	struct dentry *root;
-	struct list_head base_list;
-};
-
-struct mdss_debug_base {
-	struct mdss_debug_data *mdd;
-	void __iomem *base;
-	size_t off;
-	size_t cnt;
-	size_t max_offset;
-	char *buf;
-	size_t buf_len;
-	struct list_head head;
-};
 
 static int mdss_debug_base_open(struct inode *inode, struct file *file)
 {
@@ -265,12 +250,14 @@
 	if (!dbg)
 		return -ENOMEM;
 
+	if (name)
+		strlcpy(dbg->name, name, sizeof(dbg->name));
 	dbg->base = base;
 	dbg->max_offset = max_offset;
 	dbg->off = 0;
 	dbg->cnt = DEFAULT_BASE_REG_CNT;
 
-	if (name)
+	if (name && strcmp(name, "mdp"))
 		prefix_len = snprintf(dn, sizeof(dn), "%s_", name);
 
 	strlcpy(dn + prefix_len, "off", sizeof(dn) - prefix_len);
@@ -395,6 +382,11 @@
 	debugfs_create_u32("min_mdp_clk", 0644, mdd->root,
 			(u32 *)&mdata->min_mdp_clk);
 
+	if (mdss_create_xlog_debug(mdd)) {
+		mdss_debugfs_cleanup(mdd);
+		return -ENODEV;
+	}
+
 	mdata->debug_inf.debug_data = mdd;
 
 	return 0;
@@ -410,6 +402,29 @@
 	return 0;
 }
 
+void mdss_dump_reg(char __iomem *base, int len)
+{
+	char *addr;
+	u32 x0, x4, x8, xc;
+	int i;
+
+	addr = base;
+	if (len % 16)
+		len += 16;
+	len /= 16;
+
+	mdss_mdp_clk_ctrl(MDP_BLOCK_POWER_ON, false);
+	for (i = 0; i < len; i++) {
+		x0 = readl_relaxed(addr+0x0);
+		x4 = readl_relaxed(addr+0x4);
+		x8 = readl_relaxed(addr+0x8);
+		xc = readl_relaxed(addr+0xc);
+		pr_info("%p : %08x %08x %08x %08x\n", addr, x0, x4, x8, xc);
+		addr += 16;
+	}
+	mdss_mdp_clk_ctrl(MDP_BLOCK_POWER_OFF, false);
+}
+
 int vsync_count;
 static struct mdss_mdp_misr_map {
 	u32 ctrl_reg;
diff --git a/drivers/video/msm/mdss/mdss_debug.h b/drivers/video/msm/mdss/mdss_debug.h
index 984caab..e2c9edd 100644
--- a/drivers/video/msm/mdss/mdss_debug.h
+++ b/drivers/video/msm/mdss/mdss_debug.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2012-2013, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2012-2014, The Linux Foundation. All rights reserved.
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 and
@@ -14,13 +14,48 @@
 #ifndef MDSS_DEBUG_H
 #define MDSS_DEBUG_H
 
+#include <stdarg.h>
 #include "mdss.h"
 
 #define MISR_POLL_SLEEP		2000
 #define MISR_POLL_TIMEOUT	32000
 #define MISR_CRC_BATCH_CFG	0x101
+#define DATA_LIMITER (-1)
+#define XLOG_TOUT_DATA_LIMITER (NULL)
+#define XLOG_FUNC_ENTRY	0x1111
+#define XLOG_FUNC_EXIT	0x2222
+#define MDSS_REG_BLOCK_NAME_LEN (5)
+
+#define MDSS_XLOG(...) mdss_xlog(__func__, ##__VA_ARGS__, DATA_LIMITER)
+#define MDSS_XLOG_TOUT_HANDLER(...)	\
+	mdss_xlog_tout_handler(__func__, ##__VA_ARGS__, XLOG_TOUT_DATA_LIMITER)
 
 #ifdef CONFIG_DEBUG_FS
+struct mdss_debug_base {
+	struct mdss_debug_data *mdd;
+	char name[80];
+	void __iomem *base;
+	size_t off;
+	size_t cnt;
+	size_t max_offset;
+	char *buf;
+	size_t buf_len;
+	struct list_head head;
+};
+
+struct debug_log {
+	struct dentry *xlog;
+	u32 xlog_enable;
+	u32 panic_on_err;
+	u32 enable_reg_dump;
+};
+
+struct mdss_debug_data {
+	struct dentry *root;
+	struct list_head base_list;
+	struct debug_log logd;
+};
+
 int mdss_debugfs_init(struct mdss_data_type *mdata);
 int mdss_debugfs_remove(struct mdss_data_type *mdata);
 int mdss_debug_register_base(const char *name, void __iomem *base,
@@ -30,6 +65,13 @@
 int mdss_misr_get(struct mdss_data_type *mdata, struct mdp_misr *resp,
 			struct mdss_mdp_ctl *ctl);
 void mdss_misr_crc_collect(struct mdss_data_type *mdata, int block_id);
+
+int mdss_create_xlog_debug(struct mdss_debug_data *mdd);
+void mdss_xlog(const char *name, ...);
+void mdss_xlog_dump(void);
+void mdss_dump_reg(char __iomem *base, int len);
+void mdss_dsi_debug_check_te(struct mdss_panel_data *pdata);
+void mdss_xlog_tout_handler(const char *name, ...);
 #else
 static inline int mdss_debugfs_init(struct mdss_data_type *mdata) { return 0; }
 static inline int mdss_debugfs_remove(struct mdss_data_type *mdata)
@@ -46,5 +88,12 @@
 { return 0; }
 static inline void mdss_misr_crc_collect(struct mdss_data_type *mdata,
 						int block_id) { }
+
+static inline int create_xlog_debug(struct mdss_data_type *mdata) { }
+static inline void mdss_xlog(const char *name, ...) { }
+static inline void mdss_xlog_dump(void) { }
+static inline void mdss_dump_reg(char __iomem *base, int len) { }
+static inline void mdss_dsi_debug_check_te(struct mdss_panel_data *pdata) { }
+static inline void mdss_xlog_tout_handler(const char *name, ...) { }
 #endif
 #endif /* MDSS_DEBUG_H */
diff --git a/drivers/video/msm/mdss/mdss_debug_xlog.c b/drivers/video/msm/mdss/mdss_debug_xlog.c
new file mode 100644
index 0000000..0c24e1e
--- /dev/null
+++ b/drivers/video/msm/mdss/mdss_debug_xlog.c
@@ -0,0 +1,196 @@
+/* Copyright (c) 2014, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ */
+
+#include <linux/delay.h>
+#include <linux/spinlock.h>
+#include <linux/ktime.h>
+#include <linux/debugfs.h>
+
+#include "mdss.h"
+#include "mdss_mdp.h"
+#include "mdss_debug.h"
+
+#define MDSS_XLOG_ENTRY	256
+#define MDSS_XLOG_MAX_DATA 6
+#define MDSS_XLOG_BUF_MAX 512
+
+struct tlog {
+	u32 tick;
+	const char *name;
+	u32 data[MDSS_XLOG_MAX_DATA];
+	u32 data_cnt;
+};
+
+struct mdss_dbg_xlog {
+	struct tlog logs[MDSS_XLOG_ENTRY];
+	int first;
+	int last;
+	spinlock_t xlock;
+} mdss_dbg_xlog;
+
+static int mdss_xlog_dump_open(struct inode *inode, struct file *file)
+{
+	/* non-seekable */
+	file->f_mode &= ~(FMODE_LSEEK | FMODE_PREAD | FMODE_PWRITE);
+	file->private_data = inode->i_private;
+	return 0;
+}
+
+static ssize_t mdss_xlog_dump_read(struct file *file, char __user *buff,
+		size_t count, loff_t *ppos)
+{
+	MDSS_XLOG_TOUT_HANDLER("mdp", "dsi0", "dsi1", "edp", "hdmi", "panic");
+	return 0;
+}
+
+static const struct file_operations mdss_xlog_fops = {
+	.open = mdss_xlog_dump_open,
+	.read = mdss_xlog_dump_read,
+};
+
+int mdss_create_xlog_debug(struct mdss_debug_data *mdd)
+{
+	spin_lock_init(&mdss_dbg_xlog.xlock);
+
+	mdd->logd.xlog = debugfs_create_dir("xlog", mdd->root);
+	if (IS_ERR_OR_NULL(mdd->logd.xlog)) {
+		pr_err("debugfs_create_dir fail, error %ld\n",
+		       PTR_ERR(mdd->logd.xlog));
+		mdd->logd.xlog = NULL;
+		return -ENODEV;
+	}
+	debugfs_create_file("dump", 0644, mdd->logd.xlog, NULL,
+						&mdss_xlog_fops);
+	debugfs_create_bool("enable", 0644, mdd->logd.xlog,
+			    &mdd->logd.xlog_enable);
+	debugfs_create_bool("panic", 0644, mdd->logd.xlog,
+			    &mdd->logd.panic_on_err);
+	debugfs_create_bool("reg_dump", 0644, mdd->logd.xlog,
+			    &mdd->logd.enable_reg_dump);
+	return 0;
+}
+
+void mdss_xlog(const char *name, ...)
+{
+	struct mdss_data_type *mdata = mdss_mdp_get_mdata();
+	struct mdss_debug_data *mdd = mdata->debug_inf.debug_data;
+	unsigned long flags;
+	int i, val = 0;
+	va_list args;
+	struct tlog *log;
+	ktime_t time;
+
+	if (!mdd->logd.xlog_enable)
+		return;
+
+	spin_lock_irqsave(&mdss_dbg_xlog.xlock, flags);
+
+	time = ktime_get();
+
+	log = &mdss_dbg_xlog.logs[mdss_dbg_xlog.first];
+	log->tick = ktime_to_us(time);
+	log->name = name;
+	log->data_cnt = 0;
+
+	va_start(args, name);
+	for (i = 0; i < MDSS_XLOG_MAX_DATA; i++) {
+
+		val = va_arg(args, int);
+		if (val == DATA_LIMITER)
+			break;
+
+		log->data[i] = val;
+	}
+	va_end(args);
+
+	log->data_cnt = i;
+
+	mdss_dbg_xlog.last = mdss_dbg_xlog.first;
+	mdss_dbg_xlog.first++;
+	mdss_dbg_xlog.first %= MDSS_XLOG_ENTRY;
+
+	spin_unlock_irqrestore(&mdss_dbg_xlog.xlock, flags);
+}
+
+void mdss_xlog_dump(void)
+{
+	struct mdss_data_type *mdata = mdss_mdp_get_mdata();
+	struct mdss_debug_data *mdd = mdata->debug_inf.debug_data;
+	int i, n, d_cnt, off;
+	unsigned long flags;
+	struct tlog *log;
+	char xlog_buf[MDSS_XLOG_BUF_MAX];
+
+	if (!mdd->logd.xlog_enable)
+		return;
+
+	spin_lock_irqsave(&mdss_dbg_xlog.xlock, flags);
+	i = mdss_dbg_xlog.first;
+	for (n = 0; n < MDSS_XLOG_ENTRY; n++) {
+		log = &mdss_dbg_xlog.logs[i];
+		off = snprintf(xlog_buf, MDSS_XLOG_BUF_MAX, "%-32s => %08d: ",
+							log->name, log->tick);
+		for (d_cnt = 0; d_cnt < log->data_cnt;) {
+			off += snprintf((xlog_buf + off),
+					(MDSS_XLOG_BUF_MAX - off),
+					"%x ", log->data[d_cnt]);
+			d_cnt++;
+		}
+		pr_err("%s\n", xlog_buf);
+
+		i = (i + 1) % MDSS_XLOG_ENTRY;
+	}
+	spin_unlock_irqrestore(&mdss_dbg_xlog.xlock, flags);
+}
+
+void mdss_xlog_tout_handler(const char *name, ...)
+{
+	struct mdss_data_type *mdata = mdss_mdp_get_mdata();
+	struct mdss_debug_data *mdd = mdata->debug_inf.debug_data;
+	struct mdss_debug_base *blk_base, *tmp;
+	int i, dead = 0;
+	va_list args;
+	char *blk_name = NULL;
+
+	if (!mdd->logd.xlog_enable)
+		return;
+
+	va_start(args, name);
+	for (i = 0; i < MDSS_XLOG_MAX_DATA; i++) {
+
+		blk_name = va_arg(args, char*);
+		if (IS_ERR_OR_NULL(blk_name))
+			break;
+
+		list_for_each_entry_safe(blk_base, tmp, &mdd->base_list, head) {
+
+			if (blk_base->name &&
+				!strcmp(blk_base->name, blk_name) &&
+				mdd->logd.enable_reg_dump) {
+				pr_info("\n%s  :   =========%s DUMP=========\n",
+						__func__, blk_base->name);
+				mdss_dump_reg(blk_base->base,
+						blk_base->max_offset);
+			}
+		}
+		if (!strcmp(blk_name, "panic"))
+			dead = 1;
+	}
+	va_end(args);
+
+	MDSS_XLOG(0xffff, 0xffff, 0xffff, 0xffff, 0xffff);
+	mdss_xlog_dump();
+
+	if (dead && mdd->logd.panic_on_err)
+		panic(name);
+}
diff --git a/drivers/video/msm/mdss/mdss_dsi.c b/drivers/video/msm/mdss/mdss_dsi.c
index 553ae09..dd8eec5 100644
--- a/drivers/video/msm/mdss/mdss_dsi.c
+++ b/drivers/video/msm/mdss/mdss_dsi.c
@@ -773,6 +773,12 @@
 		}
 	}
 
+	if (pdata->panel_info.type == MIPI_VIDEO_PANEL &&
+			ctrl_pdata->off_cmds.link_state == DSI_LP_MODE) {
+		mdss_dsi_sw_reset(pdata);
+		mdss_dsi_host_init(pdata);
+	}
+
 	mdss_dsi_op_mode_config(DSI_CMD_MODE, pdata);
 
 	if (pdata->panel_info.type == MIPI_CMD_PANEL) {
@@ -821,15 +827,6 @@
 	mdss_dsi_sw_reset(pdata);
 	mdss_dsi_host_init(pdata);
 	mdss_dsi_op_mode_config(mipi->mode, pdata);
-
-	if (ctrl_pdata->on_cmds.link_state == DSI_LP_MODE) {
-		ret = mdss_dsi_unblank(pdata);
-		if (ret) {
-			pr_err("%s: unblank failed\n", __func__);
-			return ret;
-		}
-	}
-
 	pr_debug("%s-:End\n", __func__);
 	return ret;
 }
@@ -969,6 +966,8 @@
 				panel_data);
 	pr_debug("%s+:event=%d\n", __func__, event);
 
+	MDSS_XLOG(event, arg, ctrl_pdata->ndx, 0x3333);
+
 	switch (event) {
 	case MDSS_EVENT_UNBLANK:
 		rc = mdss_dsi_on(pdata);
@@ -993,15 +992,10 @@
 		rc = mdss_dsi_off(pdata);
 		break;
 	case MDSS_EVENT_CONT_SPLASH_FINISH:
+		if (ctrl_pdata->off_cmds.link_state == DSI_LP_MODE)
+			rc = mdss_dsi_blank(pdata);
 		ctrl_pdata->ctrl_state &= ~CTRL_STATE_MDP_ACTIVE;
-		if (ctrl_pdata->on_cmds.link_state == DSI_LP_MODE) {
-			rc = mdss_dsi_cont_splash_on(pdata);
-		} else {
-			pr_debug("%s:event=%d, Dsi On not called: ctrl_state: %d\n",
-				 __func__, event,
-				 ctrl_pdata->on_cmds.link_state);
-			rc = -EINVAL;
-		}
+		rc = mdss_dsi_cont_splash_on(pdata);
 		break;
 	case MDSS_EVENT_PANEL_CLK_CTRL:
 		mdss_dsi_clk_req(ctrl_pdata, (int)arg);
diff --git a/drivers/video/msm/mdss/mdss_dsi.h b/drivers/video/msm/mdss/mdss_dsi.h
index b0b884f..962599d 100644
--- a/drivers/video/msm/mdss/mdss_dsi.h
+++ b/drivers/video/msm/mdss/mdss_dsi.h
@@ -302,6 +302,12 @@
 	struct dsi_buf rx_buf;
 };
 
+struct dsi_status_data {
+	struct notifier_block fb_notifier;
+	struct delayed_work check_status;
+	struct msm_fb_data_type *mfd;
+};
+
 int dsi_panel_device_register(struct device_node *pan_node,
 				struct mdss_dsi_ctrl_pdata *ctrl_pdata);
 
@@ -330,7 +336,7 @@
 irqreturn_t mdss_dsi_isr(int irq, void *ptr);
 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);
+void mdss_dsi_set_tx_power_mode(int mode, struct mdss_panel_data *pdata);
 int mdss_dsi_clk_div_config(struct mdss_panel_info *panel_info,
 			    int frame_rate);
 int mdss_dsi_clk_init(struct platform_device *pdev,
diff --git a/drivers/video/msm/mdss/mdss_dsi_host.c b/drivers/video/msm/mdss/mdss_dsi_host.c
index a570914..95e7c6e 100644
--- a/drivers/video/msm/mdss/mdss_dsi_host.c
+++ b/drivers/video/msm/mdss/mdss_dsi_host.c
@@ -26,6 +26,7 @@
 #include "mdss.h"
 #include "mdss_dsi.h"
 #include "mdss_panel.h"
+#include "mdss_debug.h"
 
 #define VSYNC_PERIOD 17
 
@@ -110,6 +111,7 @@
 
 void mdss_dsi_clk_req(struct mdss_dsi_ctrl_pdata *ctrl, int enable)
 {
+	MDSS_XLOG(ctrl->ndx, enable, ctrl->mdp_busy, current->pid);
 	if (enable == 0) {
 		/* need wait before disable */
 		mutex_lock(&ctrl->cmd_mutex);
@@ -117,6 +119,7 @@
 		mutex_unlock(&ctrl->cmd_mutex);
 	}
 
+	MDSS_XLOG(ctrl->ndx, enable, ctrl->mdp_busy, current->pid);
 	mdss_dsi_clk_ctrl(ctrl, DSI_ALL_CLKS, enable);
 }
 
@@ -149,6 +152,7 @@
 		return;
 	}
 	if (ctrl->dsi_irq_mask == 0) {
+		MDSS_XLOG(ctrl->ndx, term);
 		mdss_enable_irq(ctrl->dsi_hw);
 		pr_debug("%s: IRQ Enable, ndx=%d mask=%x term=%x\n", __func__,
 			ctrl->ndx, (int)ctrl->dsi_irq_mask, (int)term);
@@ -168,6 +172,7 @@
 	}
 	ctrl->dsi_irq_mask &= ~term;
 	if (ctrl->dsi_irq_mask == 0) {
+		MDSS_XLOG(ctrl->ndx, term);
 		mdss_disable_irq(ctrl->dsi_hw);
 		pr_debug("%s: IRQ Disable, ndx=%d mask=%x term=%x\n", __func__,
 			ctrl->ndx, (int)ctrl->dsi_irq_mask, (int)term);
@@ -188,6 +193,7 @@
 	}
 	ctrl->dsi_irq_mask &= ~term;
 	if (ctrl->dsi_irq_mask == 0) {
+		MDSS_XLOG(ctrl->ndx, term);
 		mdss_disable_irq_nosync(ctrl->dsi_hw);
 		pr_debug("%s: IRQ Disable, ndx=%d mask=%x term=%x\n", __func__,
 			ctrl->ndx, (int)ctrl->dsi_irq_mask, (int)term);
@@ -365,7 +371,7 @@
 	wmb();
 }
 
-void mdss_set_tx_power_mode(int mode, struct mdss_panel_data *pdata)
+void mdss_dsi_set_tx_power_mode(int mode, struct mdss_panel_data *pdata)
 {
 	struct mdss_dsi_ctrl_pdata *ctrl_pdata = NULL;
 	u32 data;
@@ -872,7 +878,7 @@
 
 	ctrl_restore = __mdss_dsi_cmd_mode_config(ctrl, 1);
 
-	if (rlen == 0) {
+	if (rlen <= 2) {
 		short_response = 1;
 		rx_byte = 4;
 	} else {
@@ -1153,6 +1159,7 @@
 	mdss_dsi_enable_irq(ctrl, DSI_MDP_TERM);
 	ctrl->mdp_busy = true;
 	INIT_COMPLETION(ctrl->mdp_comp);
+	MDSS_XLOG(ctrl->ndx, ctrl->mdp_busy, current->pid);
 	spin_unlock_irqrestore(&ctrl->mdp_lock, flag);
 }
 
@@ -1163,6 +1170,8 @@
 
 	pr_debug("%s: start pid=%d\n",
 				__func__, current->pid);
+
+	MDSS_XLOG(ctrl->ndx, ctrl->mdp_busy, current->pid, XLOG_FUNC_ENTRY);
 	spin_lock_irqsave(&ctrl->mdp_lock, flags);
 	if (ctrl->mdp_busy == true)
 		need_wait++;
@@ -1173,11 +1182,14 @@
 		pr_debug("%s: pending pid=%d\n",
 				__func__, current->pid);
 		if (!wait_for_completion_timeout(&ctrl->mdp_comp,
-					msecs_to_jiffies(DMA_TX_TIMEOUT)))
+					msecs_to_jiffies(DMA_TX_TIMEOUT))) {
 			pr_err("%s: timeout error\n", __func__);
+			MDSS_XLOG_TOUT_HANDLER("mdp", "dsi0", "dsi1",
+						"edp", "hdmi", "panic");
+		}
 	}
-	pr_debug("%s: done pid=%d\n",
-				__func__, current->pid);
+	pr_debug("%s: done pid=%d\n", __func__, current->pid);
+	MDSS_XLOG(ctrl->ndx, ctrl->mdp_busy, current->pid, XLOG_FUNC_EXIT);
 }
 
 int mdss_dsi_cmdlist_tx(struct mdss_dsi_ctrl_pdata *ctrl,
@@ -1231,6 +1243,9 @@
 	mutex_lock(&ctrl->cmd_mutex);
 	req = mdss_dsi_cmdlist_get(ctrl);
 
+	MDSS_XLOG(ctrl->ndx, from_mdp, ctrl->mdp_busy, current->pid,
+							XLOG_FUNC_ENTRY);
+
 	/* make sure dsi_cmd_mdp is idle */
 	mdss_dsi_cmd_mdp_busy(ctrl);
 
@@ -1239,6 +1254,8 @@
 	if (req == NULL)
 		goto need_lock;
 
+	MDSS_XLOG(ctrl->ndx, req->flags, req->cmds_cnt, from_mdp, current->pid);
+
 	/*
 	 * mdss interrupt is generated in mdp core clock domain
 	 * mdp clock need to be enabled to receive dsi interrupt
@@ -1263,10 +1280,46 @@
 	if (from_mdp) /* from pipe_commit */
 		mdss_dsi_cmd_mdp_start(ctrl);
 
+	MDSS_XLOG(ctrl->ndx, from_mdp, ctrl->mdp_busy, current->pid,
+							XLOG_FUNC_EXIT);
 	mutex_unlock(&ctrl->cmd_mutex);
 	return ret;
 }
 
+void mdss_dsi_debug_check_te(struct mdss_panel_data *pdata)
+{
+	struct mdss_dsi_ctrl_pdata *ctrl_pdata = NULL;
+	u8 rc, te_count = 0;
+	u8 te_max = 250;
+
+	if (pdata == NULL) {
+		pr_err("%s: Invalid input data\n", __func__);
+		return;
+	}
+	ctrl_pdata = container_of(pdata, struct mdss_dsi_ctrl_pdata,
+				panel_data);
+
+	pr_info(" ============ start waiting for TE ============\n");
+	for (te_count = 0; te_count < te_max; te_count++) {
+		rc = gpio_get_value(ctrl_pdata->disp_te_gpio);
+		if (rc != 0) {
+			pr_info("%s: gpio_get_value(disp_te_gpio) = %d ",
+								__func__, rc);
+			pr_info("te_count = %d\n", te_count);
+			break;
+		}
+		/* usleep suspends the calling thread whereas udelay is a
+		 * busy wait. Here the value of te_gpio is checked in a loop of
+		 * max count = 250. If this loop has to iterate multiple
+		 * times before the te_gpio is 1, the calling thread will end
+		 * up in suspend/wakeup sequence multiple times if usleep is
+		 * used, which is an overhead. So use udelay instead of usleep.
+		 */
+		udelay(80);
+	}
+	pr_info(" ============ finish waiting for TE ============\n");
+}
+
 static void dsi_send_events(struct mdss_dsi_ctrl_pdata *ctrl, u32 events)
 {
 	struct dsi_event_q *evq;
@@ -1328,11 +1381,11 @@
 		}
 
 		if (todo & DSI_EV_MDP_BUSY_RELEASE) {
-			spin_lock(&ctrl->mdp_lock);
+			spin_lock_irqsave(&ctrl->mdp_lock, flag);
 			ctrl->mdp_busy = false;
 			mdss_dsi_disable_irq_nosync(ctrl, DSI_MDP_TERM);
 			complete(&ctrl->mdp_comp);
-			spin_unlock(&ctrl->mdp_lock);
+			spin_unlock_irqrestore(&ctrl->mdp_lock, flag);
 
 			/* enable dsi error interrupt */
 			mdss_dsi_err_intr_ctrl(ctrl, DSI_INTR_ERROR_MASK, 1);
@@ -1405,6 +1458,8 @@
 		pr_err("%s: status=%x\n", __func__, status);
 		if (status & 0x0080)  /* CMD_DMA_FIFO_UNDERFLOW */
 			dsi_send_events(ctrl, DSI_EV_MDP_FIFO_UNDERFLOW);
+			MDSS_XLOG_TOUT_HANDLER("mdp", "dsi0", "dsi1",
+						"edp", "hdmi", "panic");
 	}
 }
 
@@ -1486,6 +1541,7 @@
 	pr_debug("%s: ndx=%d isr=%x\n", __func__, ctrl->ndx, isr);
 
 	if (isr & DSI_INTR_ERROR) {
+		MDSS_XLOG(ctrl->ndx, ctrl->mdp_busy, isr, 0x97);
 		pr_err("%s: ndx=%d isr=%x\n", __func__, ctrl->ndx, isr);
 		mdss_dsi_error(ctrl);
 	}
@@ -1498,6 +1554,7 @@
 	}
 
 	if (isr & DSI_INTR_CMD_DMA_DONE) {
+		MDSS_XLOG(ctrl->ndx, ctrl->mdp_busy, isr, 0x98);
 		spin_lock(&ctrl->mdp_lock);
 		mdss_dsi_disable_irq_nosync(ctrl, DSI_CMD_TERM);
 		complete(&ctrl->dma_comp);
@@ -1505,6 +1562,7 @@
 	}
 
 	if (isr & DSI_INTR_CMD_MDP_DONE) {
+		MDSS_XLOG(ctrl->ndx, ctrl->mdp_busy, isr, 0x99);
 		spin_lock(&ctrl->mdp_lock);
 		ctrl->mdp_busy = false;
 		mdss_dsi_disable_irq_nosync(ctrl, DSI_MDP_TERM);
diff --git a/drivers/video/msm/mdss/mdss_dsi_panel.c b/drivers/video/msm/mdss/mdss_dsi_panel.c
index f450dec..f58e2a1 100644
--- a/drivers/video/msm/mdss/mdss_dsi_panel.c
+++ b/drivers/video/msm/mdss/mdss_dsi_panel.c
@@ -664,6 +664,41 @@
 	return 0;
 }
 
+static void mdss_panel_parse_te_params(struct device_node *np,
+				       struct mdss_panel_info *panel_info)
+{
+
+	u32 tmp;
+	int rc = 0;
+	/*
+	 * TE default: dsi byte clock calculated base on 70 fps;
+	 * around 14 ms to complete a kickoff cycle if te disabled;
+	 * vclk_line base on 60 fps; write is faster than read;
+	 * init == start == rdptr;
+	 */
+	panel_info->te.tear_check_en =
+		!of_property_read_bool(np, "qcom,mdss-tear-check-disable");
+	rc = of_property_read_u32
+		(np, "qcom,mdss-tear-check-sync-cfg-height", &tmp);
+	panel_info->te.sync_cfg_height = (!rc ? tmp : 0xfff0);
+	rc = of_property_read_u32
+		(np, "qcom,mdss-tear-check-sync-init-val", &tmp);
+	panel_info->te.vsync_init_val = (!rc ? tmp : panel_info->yres);
+	rc = of_property_read_u32
+		(np, "qcom,mdss-tear-check-sync-threshold-start", &tmp);
+	panel_info->te.sync_threshold_start = (!rc ? tmp : 4);
+	rc = of_property_read_u32
+		(np, "qcom,mdss-tear-check-sync-threshold-continue", &tmp);
+	panel_info->te.sync_threshold_continue = (!rc ? tmp : 4);
+	rc = of_property_read_u32(np, "qcom,mdss-tear-check-start-pos", &tmp);
+	panel_info->te.start_pos = (!rc ? tmp : panel_info->yres);
+	rc = of_property_read_u32
+		(np, "qcom,mdss-tear-check-rd-ptr-trigger-intr", &tmp);
+	panel_info->te.rd_ptr_irq = (!rc ? tmp : panel_info->yres + 1);
+	rc = of_property_read_u32(np, "qcom,mdss-tear-check-frame-rate", &tmp);
+	panel_info->te.refx100 = (!rc ? tmp : 6000);
+}
+
 
 static int mdss_dsi_parse_reset_seq(struct device_node *np,
 		u32 rst_seq[MDSS_DSI_RST_SEQ_LEN], u32 *rst_len,
@@ -994,6 +1029,7 @@
 
 	mdss_dsi_parse_reset_seq(np, pinfo->rst_seq, &(pinfo->rst_seq_len),
 		"qcom,mdss-dsi-reset-sequence");
+	mdss_panel_parse_te_params(np, pinfo);
 
 	mdss_dsi_parse_dcs_cmds(np, &ctrl_pdata->on_cmds,
 		"qcom,mdss-dsi-on-command", "qcom,mdss-dsi-on-command-state");
diff --git a/drivers/video/msm/mdss/mdss_dsi_status.c b/drivers/video/msm/mdss/mdss_dsi_status.c
index 1dca08e..116b778 100644
--- a/drivers/video/msm/mdss/mdss_dsi_status.c
+++ b/drivers/video/msm/mdss/mdss_dsi_status.c
@@ -30,36 +30,26 @@
 #include "mdss_panel.h"
 #include "mdss_mdp.h"
 
-#define STATUS_CHECK_INTERVAL 5000
+#define STATUS_CHECK_INTERVAL_MS 5000
+#define STATUS_CHECK_INTERVAL_MIN_MS 200
+#define DSI_STATUS_CHECK_DISABLE 1
 
-struct dsi_status_data {
-	struct notifier_block fb_notifier;
-	struct delayed_work check_status;
-	struct msm_fb_data_type *mfd;
-	uint32_t check_interval;
-};
+static uint32_t interval = STATUS_CHECK_INTERVAL_MS;
+static uint32_t dsi_status_disable = DSI_STATUS_CHECK_DISABLE;
 struct dsi_status_data *pstatus_data;
-static uint32_t interval = STATUS_CHECK_INTERVAL;
 
 /*
- * check_dsi_ctrl_status() - Check DSI controller status periodically.
+ * check_dsi_ctrl_status() - Reads MFD structure and
+ * calls platform specific DSI ctrl Status function.
  * @work  : dsi controller status data
- *
- * This function calls check_status API on DSI controller to send the BTA
- * command. If DSI controller fails to acknowledge the BTA command, it sends
- * the PANEL_ALIVE=0 status to HAL layer.
  */
 static void check_dsi_ctrl_status(struct work_struct *work)
 {
 	struct dsi_status_data *pdsi_status = NULL;
-	struct mdss_panel_data *pdata = NULL;
-	struct mdss_dsi_ctrl_pdata *ctrl_pdata = NULL;
-	struct mdss_overlay_private *mdp5_data = NULL;
-	struct mdss_mdp_ctl *ctl = NULL;
-	int ret = 0;
 
 	pdsi_status = container_of(to_delayed_work(work),
 		struct dsi_status_data, check_status);
+
 	if (!pdsi_status) {
 		pr_err("%s: DSI status data not available\n", __func__);
 		return;
@@ -70,73 +60,7 @@
 		return;
 	}
 
-	pdata = dev_get_platdata(&pdsi_status->mfd->pdev->dev);
-	if (!pdata) {
-		pr_err("%s: Panel data not available\n", __func__);
-		return;
-	}
-
-	ctrl_pdata = container_of(pdata, struct mdss_dsi_ctrl_pdata,
-							panel_data);
-	if (!ctrl_pdata || !ctrl_pdata->check_status) {
-		pr_err("%s: DSI ctrl or status_check callback not available\n",
-								__func__);
-		return;
-	}
-
-	mdp5_data = mfd_to_mdp5_data(pdsi_status->mfd);
-	ctl = mfd_to_ctl(pdsi_status->mfd);
-
-	if (ctl->shared_lock)
-		mutex_lock(ctl->shared_lock);
-	mutex_lock(&mdp5_data->ov_lock);
-
-	if (pdsi_status->mfd->shutdown_pending) {
-		mutex_unlock(&mdp5_data->ov_lock);
-		if (ctl->shared_lock)
-			mutex_unlock(ctl->shared_lock);
-		pr_err("%s: DSI turning off, avoiding BTA status check\n",
-							__func__);
-		return;
-	}
-
-	/*
-	 * For the command mode panels, we return pan display
-	 * IOCTL on vsync interrupt. So, after vsync interrupt comes
-	 * and when DMA_P is in progress, if the panel stops responding
-	 * and if we trigger BTA before DMA_P finishes, then the DSI
-	 * FIFO will not be cleared since the DSI data bus control
-	 * doesn't come back to the host after BTA. This may cause the
-	 * display reset not to be proper. Hence, wait for DMA_P done
-	 * for command mode panels before triggering BTA.
-	 */
-	if (ctl->wait_pingpong)
-		ctl->wait_pingpong(ctl, NULL);
-
-	pr_debug("%s: DSI ctrl wait for ping pong done\n", __func__);
-
-	mdss_mdp_clk_ctrl(MDP_BLOCK_POWER_ON, false);
-	ret = ctrl_pdata->check_status(ctrl_pdata);
-	mdss_mdp_clk_ctrl(MDP_BLOCK_POWER_OFF, false);
-
-	mutex_unlock(&mdp5_data->ov_lock);
-	if (ctl->shared_lock)
-		mutex_unlock(ctl->shared_lock);
-
-	if ((pdsi_status->mfd->panel_power_on)) {
-		if (ret > 0) {
-			schedule_delayed_work(&pdsi_status->check_status,
-				msecs_to_jiffies(pdsi_status->check_interval));
-		} else {
-			char *envp[2] = {"PANEL_ALIVE=0", NULL};
-			pdata->panel_info.panel_dead = true;
-			ret = kobject_uevent_env(
-				&pdsi_status->mfd->fbi->dev->kobj,
-							KOBJ_CHANGE, envp);
-			pr_err("%s: Panel has gone bad, sending uevent - %s\n",
-							__func__, envp[0]);
-		}
-	}
+	pdsi_status->mfd->mdp.check_dsi_status(work, interval);
 }
 
 /*
@@ -156,6 +80,19 @@
 	struct fb_event *evdata = data;
 	struct dsi_status_data *pdata = container_of(self,
 				struct dsi_status_data, fb_notifier);
+	struct mdss_dsi_ctrl_pdata *ctrl_pdata = NULL;
+
+	pdata->mfd = evdata->info->par;
+	ctrl_pdata = container_of(dev_get_platdata(&pdata->mfd->pdev->dev),
+				struct mdss_dsi_ctrl_pdata, panel_data);
+	if (!ctrl_pdata) {
+		pr_err("%s: DSI ctrl not available\n", __func__);
+		return NOTIFY_BAD;
+	}
+	if (dsi_status_disable) {
+		pr_debug("%s: DSI status disabled\n", __func__);
+		return NOTIFY_DONE;
+	}
 
 	if (event == FB_EVENT_BLANK && evdata) {
 		int *blank = evdata->data;
@@ -166,7 +103,7 @@
 		switch (*blank) {
 		case FB_BLANK_UNBLANK:
 			schedule_delayed_work(&pdata->check_status,
-				msecs_to_jiffies(pdata->check_interval));
+				msecs_to_jiffies(interval));
 			break;
 		case FB_BLANK_POWERDOWN:
 			cancel_delayed_work(&pdata->check_status);
@@ -176,6 +113,41 @@
 	return 0;
 }
 
+static int param_dsi_status_disable(const char *val, struct kernel_param *kp)
+{
+	int ret = 0;
+	int int_val;
+
+	ret = kstrtos32(val, 0, &int_val);
+	if (ret)
+		return ret;
+
+	pr_info("%s: Set DSI status disable to %d\n",
+			__func__, int_val);
+	*((int *)kp->arg) = int_val;
+	return ret;
+}
+
+static int param_set_interval(const char *val, struct kernel_param *kp)
+{
+	int ret = 0;
+	int int_val;
+
+	ret = kstrtos32(val, 0, &int_val);
+	if (ret)
+		return ret;
+	if (int_val < STATUS_CHECK_INTERVAL_MIN_MS) {
+		pr_err("%s: Invalid value %d used, ignoring\n",
+						__func__, int_val);
+		ret = -EINVAL;
+	} else {
+		pr_info("%s: Set check interval to %d msecs\n",
+						__func__, int_val);
+		*((int *)kp->arg) = int_val;
+	}
+	return ret;
+}
+
 int __init mdss_dsi_status_init(void)
 {
 	int rc = 0;
@@ -196,7 +168,6 @@
 		return -EPERM;
 	}
 
-	pstatus_data->check_interval = interval;
 	pr_info("%s: DSI status check interval:%d\n", __func__,	interval);
 
 	INIT_DELAYED_WORK(&pstatus_data->check_status, check_dsi_ctrl_status);
@@ -214,11 +185,17 @@
 	pr_debug("%s: DSI ctrl status work queue removed\n", __func__);
 }
 
-module_param(interval, uint, 0);
+module_param_call(interval, param_set_interval, param_get_uint,
+						&interval, 0644);
 MODULE_PARM_DESC(interval,
 		"Duration in milliseconds to send BTA command for checking"
 		"DSI status periodically");
 
+module_param_call(dsi_status_disable, param_dsi_status_disable, param_get_uint,
+						&dsi_status_disable, 0644);
+MODULE_PARM_DESC(dsi_status_disable,
+		"Disable DSI status check");
+
 module_init(mdss_dsi_status_init);
 module_exit(mdss_dsi_status_exit);
 
diff --git a/drivers/video/msm/mdss/mdss_fb.c b/drivers/video/msm/mdss/mdss_fb.c
index 198e242..1927fe2 100644
--- a/drivers/video/msm/mdss/mdss_fb.c
+++ b/drivers/video/msm/mdss/mdss_fb.c
@@ -106,6 +106,31 @@
 	complete(&mfd->no_update.comp);
 }
 
+void mdss_fb_bl_update_notify(struct msm_fb_data_type *mfd)
+{
+	if (!mfd) {
+		pr_err("%s mfd NULL\n", __func__);
+		return;
+	}
+	mutex_lock(&mfd->update.lock);
+	if (mfd->update.ref_count > 0) {
+		mutex_unlock(&mfd->update.lock);
+		mfd->update.value = NOTIFY_TYPE_BL_UPDATE;
+		complete(&mfd->update.comp);
+		mutex_lock(&mfd->update.lock);
+	}
+	mutex_unlock(&mfd->update.lock);
+
+	mutex_lock(&mfd->no_update.lock);
+	if (mfd->no_update.ref_count > 0) {
+		mutex_unlock(&mfd->no_update.lock);
+		mfd->no_update.value = NOTIFY_TYPE_BL_UPDATE;
+		complete(&mfd->no_update.comp);
+		mutex_lock(&mfd->no_update.lock);
+	}
+	mutex_unlock(&mfd->no_update.lock);
+}
+
 static int mdss_fb_notify_update(struct msm_fb_data_type *mfd,
 							unsigned long *argp)
 {
@@ -127,8 +152,14 @@
 		ret = 1;
 	} else if (notify == NOTIFY_UPDATE_START) {
 		INIT_COMPLETION(mfd->update.comp);
+		mutex_lock(&mfd->update.lock);
+		mfd->update.ref_count++;
+		mutex_unlock(&mfd->update.lock);
 		ret = wait_for_completion_interruptible_timeout(
 						&mfd->update.comp, 4 * HZ);
+		mutex_lock(&mfd->update.lock);
+		mfd->update.ref_count--;
+		mutex_unlock(&mfd->update.lock);
 		to_user = (unsigned int)mfd->update.value;
 		if (mfd->update.type == NOTIFY_TYPE_SUSPEND) {
 			to_user = (unsigned int)mfd->update.type;
@@ -136,8 +167,14 @@
 		}
 	} else if (notify == NOTIFY_UPDATE_STOP) {
 		INIT_COMPLETION(mfd->no_update.comp);
+		mutex_lock(&mfd->no_update.lock);
+		mfd->no_update.ref_count++;
+		mutex_unlock(&mfd->no_update.lock);
 		ret = wait_for_completion_interruptible_timeout(
 						&mfd->no_update.comp, 4 * HZ);
+		mutex_lock(&mfd->no_update.lock);
+		mfd->no_update.ref_count--;
+		mutex_unlock(&mfd->no_update.lock);
 		to_user = (unsigned int)mfd->no_update.value;
 	} else {
 		if (mfd->panel_power_on) {
@@ -316,14 +353,75 @@
 	return ret;
 }
 
+static void __mdss_fb_idle_notify_work(struct work_struct *work)
+{
+	struct delayed_work *dw = to_delayed_work(work);
+	struct msm_fb_data_type *mfd = container_of(dw, struct msm_fb_data_type,
+		idle_notify_work);
+
+	/* Notify idle-ness here */
+	pr_debug("Idle timeout %dms expired!\n", mfd->idle_time);
+	sysfs_notify(&mfd->fbi->dev->kobj, NULL, "idle_notify");
+}
+
+static ssize_t mdss_fb_get_idle_time(struct device *dev,
+		struct device_attribute *attr, char *buf)
+{
+	struct fb_info *fbi = dev_get_drvdata(dev);
+	struct msm_fb_data_type *mfd = fbi->par;
+	int ret;
+
+	ret = scnprintf(buf, PAGE_SIZE, "%d", mfd->idle_time);
+
+	return ret;
+}
+
+static ssize_t mdss_fb_set_idle_time(struct device *dev,
+	struct device_attribute *attr, const char *buf, size_t count)
+{
+	struct fb_info *fbi = dev_get_drvdata(dev);
+	struct msm_fb_data_type *mfd = fbi->par;
+	int rc = 0;
+	int idle_time = 0;
+
+	rc = kstrtoint(buf, 10, &idle_time);
+	if (rc) {
+		pr_err("kstrtoint failed. rc=%d\n", rc);
+		return rc;
+	}
+
+	pr_debug("Idle time = %d\n", idle_time);
+	mfd->idle_time = idle_time;
+
+	return count;
+}
+
+static ssize_t mdss_fb_get_idle_notify(struct device *dev,
+		struct device_attribute *attr, char *buf)
+{
+	struct fb_info *fbi = dev_get_drvdata(dev);
+	struct msm_fb_data_type *mfd = fbi->par;
+	int ret;
+
+	ret = scnprintf(buf, PAGE_SIZE, "%s",
+		work_busy(&mfd->idle_notify_work.work) ? "no" : "yes");
+
+	return ret;
+}
+
 static DEVICE_ATTR(msm_fb_type, S_IRUGO, mdss_fb_get_type, NULL);
 static DEVICE_ATTR(msm_fb_split, S_IRUGO, mdss_fb_get_split, NULL);
 static DEVICE_ATTR(show_blank_event, S_IRUGO, mdss_mdp_show_blank_event, NULL);
+static DEVICE_ATTR(idle_time, S_IRUGO | S_IWUSR | S_IWGRP,
+	mdss_fb_get_idle_time, mdss_fb_set_idle_time);
+static DEVICE_ATTR(idle_notify, S_IRUGO, mdss_fb_get_idle_notify, NULL);
 
 static struct attribute *mdss_fb_attrs[] = {
 	&dev_attr_msm_fb_type.attr,
 	&dev_attr_msm_fb_split.attr,
 	&dev_attr_show_blank_event.attr,
+	&dev_attr_idle_time.attr,
+	&dev_attr_idle_notify.attr,
 	NULL,
 };
 
@@ -479,6 +577,8 @@
 		}
 	}
 
+	INIT_DELAYED_WORK(&mfd->idle_notify_work, __mdss_fb_idle_notify_work);
+
 	return rc;
 }
 
@@ -747,6 +847,7 @@
 			mutex_unlock(&mfd->bl_lock);
 			/* Will trigger ad_setup which will grab bl_lock */
 			update_ad_input(mfd);
+			mdss_fb_bl_update_notify(mfd);
 			mutex_lock(&mfd->bl_lock);
 		}
 	}
@@ -793,6 +894,11 @@
 			mfd->update.type = NOTIFY_TYPE_UPDATE;
 			mfd->update.is_suspend = 0;
 			mutex_unlock(&mfd->update.lock);
+
+			/* Start the work thread to signal idle time */
+			if (mfd->idle_time)
+				schedule_delayed_work(&mfd->idle_notify_work,
+					msecs_to_jiffies(mfd->idle_time));
 		}
 		break;
 
@@ -1181,16 +1287,22 @@
 	mutex_init(&mfd->mdp_sync_pt_data.sync_mutex);
 	atomic_set(&mfd->mdp_sync_pt_data.commit_cnt, 0);
 	atomic_set(&mfd->commits_pending, 0);
+	atomic_set(&mfd->ioctl_ref_cnt, 0);
+	atomic_set(&mfd->kickoff_pending, 0);
 
 	init_timer(&mfd->no_update.timer);
 	mfd->no_update.timer.function = mdss_fb_no_update_notify_timer_cb;
 	mfd->no_update.timer.data = (unsigned long)mfd;
+	mfd->update.ref_count = 0;
+	mfd->no_update.ref_count = 0;
 	init_completion(&mfd->update.comp);
 	init_completion(&mfd->no_update.comp);
 	init_completion(&mfd->power_off_comp);
 	init_completion(&mfd->power_set_comp);
 	init_waitqueue_head(&mfd->commit_wait_q);
 	init_waitqueue_head(&mfd->idle_wait_q);
+	init_waitqueue_head(&mfd->ioctl_q);
+	init_waitqueue_head(&mfd->kickoff_wait_q);
 
 	ret = fb_alloc_cmap(&fbi->cmap, 256, 0);
 	if (ret)
@@ -1309,6 +1421,12 @@
 		return -EINVAL;
 	}
 
+	if (!wait_event_timeout(mfd->ioctl_q,
+		!atomic_read(&mfd->ioctl_ref_cnt) || !release_all,
+		msecs_to_jiffies(1000)))
+		pr_warn("fb%d ioctl could not finish. waited 1 sec.\n",
+			mfd->index);
+
 	mdss_fb_pan_idle(mfd);
 
 	pr_debug("release_all = %s\n", release_all ? "true" : "false");
@@ -1386,6 +1504,7 @@
 				mfd->index, ret, task->comm, pid);
 			return ret;
 		}
+		atomic_set(&mfd->ioctl_ref_cnt, 0);
 	}
 
 	return ret;
@@ -1522,10 +1641,20 @@
 		unsigned long event, void *data)
 {
 	struct msm_sync_pt_data *sync_pt_data;
+	struct msm_fb_data_type *mfd;
 
 	sync_pt_data = container_of(p, struct msm_sync_pt_data, notifier);
+	mfd = container_of(sync_pt_data, struct msm_fb_data_type,
+		mdp_sync_pt_data);
 
 	switch (event) {
+	case MDP_NOTIFY_FRAME_BEGIN:
+		if (mfd->idle_time) {
+			cancel_delayed_work_sync(&mfd->idle_notify_work);
+			schedule_delayed_work(&mfd->idle_notify_work,
+				msecs_to_jiffies(mfd->idle_time));
+		}
+		break;
 	case MDP_NOTIFY_FRAME_READY:
 		if (sync_pt_data->async_wait_fences)
 			mdss_fb_wait_for_fence(sync_pt_data);
@@ -1576,6 +1705,25 @@
 	return 0;
 }
 
+static int mdss_fb_wait_for_kickoff(struct msm_fb_data_type *mfd)
+{
+	int ret = 0;
+
+	ret = wait_event_timeout(mfd->kickoff_wait_q,
+			(!atomic_read(&mfd->kickoff_pending) ||
+			 mfd->shutdown_pending),
+			msecs_to_jiffies(WAIT_DISP_OP_TIMEOUT / 2));
+	if (!ret) {
+		pr_err("wait for kickoff timeout %d pending=%d\n",
+				ret, atomic_read(&mfd->kickoff_pending));
+
+	} else if (mfd->shutdown_pending) {
+		pr_debug("Shutdown signalled\n");
+		return -EPERM;
+	}
+
+	return 0;
+}
 
 static int mdss_fb_pan_display_ex(struct fb_info *info,
 		struct mdp_display_commit *disp_commit)
@@ -1614,6 +1762,7 @@
 
 	atomic_inc(&mfd->mdp_sync_pt_data.commit_cnt);
 	atomic_inc(&mfd->commits_pending);
+	atomic_inc(&mfd->kickoff_pending);
 	wake_up_all(&mfd->commit_wait_q);
 	mutex_unlock(&mfd->mdp_sync_pt_data.sync_mutex);
 	if (wait_for_finish)
@@ -1706,6 +1855,8 @@
 		if (ret)
 			pr_err("pan display failed %x on fb%d\n", ret,
 					mfd->index);
+		atomic_set(&mfd->kickoff_pending, 0);
+		wake_up_all(&mfd->kickoff_wait_q);
 	}
 	if (!ret)
 		mdss_fb_update_backlight(mfd);
@@ -1742,6 +1893,7 @@
 	}
 
 	atomic_set(&mfd->commits_pending, 0);
+	atomic_set(&mfd->kickoff_pending, 0);
 	wake_up_all(&mfd->idle_wait_q);
 
 	return ret;
@@ -2201,6 +2353,27 @@
 	return ret;
 }
 
+static int __ioctl_wait_idle(struct msm_fb_data_type *mfd, u32 cmd)
+{
+	int ret = 0;
+
+	if (mfd->wait_for_kickoff &&
+		((cmd == MSMFB_OVERLAY_PREPARE) ||
+		(cmd == MSMFB_BUFFER_SYNC) ||
+		(cmd == MSMFB_OVERLAY_SET))) {
+		ret = mdss_fb_wait_for_kickoff(mfd);
+	} else if ((cmd != MSMFB_VSYNC_CTRL) &&
+		(cmd != MSMFB_OVERLAY_VSYNC_CTRL) &&
+		(cmd != MSMFB_ASYNC_BLIT) &&
+		(cmd != MSMFB_BLIT) &&
+		(cmd != MSMFB_NOTIFY_UPDATE)) {
+		ret = mdss_fb_pan_idle(mfd);
+	}
+
+	if (ret)
+		pr_debug("Shutdown pending. Aborting operation %x\n", cmd);
+	return ret;
+}
 
 static int mdss_fb_ioctl(struct fb_info *info, unsigned int cmd,
 			 unsigned long arg)
@@ -2211,21 +2384,24 @@
 	int ret = -ENOSYS;
 	struct mdp_buf_sync buf_sync;
 	struct msm_sync_pt_data *sync_pt_data = NULL;
+
 	if (!info || !info->par)
 		return -EINVAL;
+
 	mfd = (struct msm_fb_data_type *)info->par;
+	if (!mfd)
+		return -EINVAL;
+
+	if (mfd->shutdown_pending)
+		return -EPERM;
+
+	atomic_inc(&mfd->ioctl_ref_cnt);
+
 	mdss_fb_power_setting_idle(mfd);
-	if ((cmd != MSMFB_VSYNC_CTRL) && (cmd != MSMFB_OVERLAY_VSYNC_CTRL) &&
-			(cmd != MSMFB_ASYNC_BLIT) && (cmd != MSMFB_BLIT) &&
-			(cmd != MSMFB_NOTIFY_UPDATE) &&
-			(cmd != MSMFB_OVERLAY_PREPARE)) {
-		ret = mdss_fb_pan_idle(mfd);
-		if (ret) {
-			pr_debug("Shutdown pending. Aborting operation %x\n",
-				cmd);
-			return ret;
-		}
-	}
+
+	ret = __ioctl_wait_idle(mfd, cmd);
+	if (ret)
+		goto exit;
 
 	switch (cmd) {
 	case MSMFB_CURSOR:
@@ -2242,15 +2418,19 @@
 		ret = copy_to_user(argp, &fb_page_protection,
 				   sizeof(fb_page_protection));
 		if (ret)
-			return ret;
+			goto exit;
 		break;
 
 	case MSMFB_BUFFER_SYNC:
 		ret = copy_from_user(&buf_sync, argp, sizeof(buf_sync));
 		if (ret)
-			return ret;
-		if ((!mfd->op_enable) || (!mfd->panel_power_on))
-			return -EPERM;
+			goto exit;
+
+		if ((!mfd->op_enable) || (!mfd->panel_power_on)) {
+			ret = -EPERM;
+			goto exit;
+		}
+
 		if (mfd->mdp.get_sync_fnc)
 			sync_pt_data = mfd->mdp.get_sync_fnc(mfd, &buf_sync);
 		if (!sync_pt_data)
@@ -2279,6 +2459,10 @@
 	if (ret == -ENOSYS)
 		pr_err("unsupported ioctl (%x)\n", cmd);
 
+exit:
+	if (!atomic_dec_return(&mfd->ioctl_ref_cnt))
+		wake_up_all(&mfd->ioctl_q);
+
 	return ret;
 }
 
diff --git a/drivers/video/msm/mdss/mdss_fb.h b/drivers/video/msm/mdss/mdss_fb.h
index 2e024c9..894dbbc 100644
--- a/drivers/video/msm/mdss/mdss_fb.h
+++ b/drivers/video/msm/mdss/mdss_fb.h
@@ -86,6 +86,7 @@
 	struct mutex lock;
 	int value;
 	int is_suspend;
+	int ref_count;
 };
 
 struct msm_sync_pt_data {
@@ -134,6 +135,7 @@
 	int (*splash_fnc) (struct msm_fb_data_type *mfd, int *index, int req);
 	struct msm_sync_pt_data *(*get_sync_fnc)(struct msm_fb_data_type *mfd,
 				const struct mdp_buf_sync *buf_sync);
+	void (*check_dsi_status)(struct work_struct *work, uint32_t interval);
 	void *private1;
 };
 
@@ -169,6 +171,9 @@
 	u32 dest;
 	struct fb_info *fbi;
 
+	int idle_time;
+	struct delayed_work idle_notify_work;
+
 	int op_enable;
 	u32 fb_imgType;
 	int panel_reconfig;
@@ -210,19 +215,25 @@
 	/* for non-blocking */
 	struct task_struct *disp_thread;
 	atomic_t commits_pending;
+	atomic_t kickoff_pending;
 	wait_queue_head_t commit_wait_q;
 	wait_queue_head_t idle_wait_q;
+	wait_queue_head_t kickoff_wait_q;
 	bool shutdown_pending;
 
 	struct task_struct *splash_thread;
 	bool splash_logo_enabled;
 
+	wait_queue_head_t ioctl_q;
+	atomic_t ioctl_ref_cnt;
+
 	struct msm_fb_backup_type msm_fb_backup;
 	struct completion power_set_comp;
 	u32 is_power_setting;
 
 	u32 dcm_state;
 	struct list_head proc_list;
+	u32 wait_for_kickoff;
 };
 
 static inline void mdss_fb_update_notify_update(struct msm_fb_data_type *mfd)
diff --git a/drivers/video/msm/mdss/mdss_mdp.c b/drivers/video/msm/mdss/mdss_mdp.c
index 8a215bc..97d4dc9 100644
--- a/drivers/video/msm/mdss/mdss_mdp.c
+++ b/drivers/video/msm/mdss/mdss_mdp.c
@@ -68,6 +68,7 @@
 	.fb_mem_get_iommu_domain = mdss_fb_mem_get_iommu_domain,
 	.panel_register_done = mdss_panel_register_done,
 	.fb_stride = mdss_mdp_fb_stride,
+	.check_dsi_status = mdss_check_dsi_ctrl_status,
 };
 
 #define DEFAULT_TOTAL_RGB_PIPES 3
@@ -689,6 +690,7 @@
 		}
 	}
 
+	MDSS_XLOG(mdp_clk_cnt, changed, enable, current->pid);
 	pr_debug("%s: clk_cnt=%d changed=%d enable=%d\n",
 			__func__, mdp_clk_cnt, changed, enable);
 
@@ -792,6 +794,8 @@
 	int i;
 
 	mutex_lock(&mdp_iommu_lock);
+	MDSS_XLOG(mdata->iommu_attached);
+
 	if (mdata->iommu_attached) {
 		pr_debug("mdp iommu already attached\n");
 		mutex_unlock(&mdp_iommu_lock);
@@ -823,6 +827,8 @@
 	int i;
 
 	mutex_lock(&mdp_iommu_lock);
+	MDSS_XLOG(mdata->iommu_attached);
+
 	if (!mdata->iommu_attached) {
 		pr_debug("mdp iommu already dettached\n");
 		mutex_unlock(&mdp_iommu_lock);
@@ -965,7 +971,7 @@
 	if (rc)
 		return rc;
 
-	mdss_debug_register_base(NULL, mdata->mdp_base, mdata->mdp_reg_size);
+	mdss_debug_register_base("mdp", mdata->mdp_base, mdata->mdp_reg_size);
 
 	return 0;
 }
@@ -2216,6 +2222,8 @@
 		"qcom,mdss-has-decimation");
 	mdata->has_wfd_blk = of_property_read_bool(pdev->dev.of_node,
 		"qcom,mdss-has-wfd-blk");
+	mdata->has_no_lut_read = of_property_read_bool(pdev->dev.of_node,
+		"qcom,mdss-no-lut-read");
 	prop = of_find_property(pdev->dev.of_node, "batfet-supply", NULL);
 	mdata->batfet_required = prop ? true : false;
 	rc = of_property_read_u32(pdev->dev.of_node,
@@ -2242,6 +2250,17 @@
 	mdss_mdp_parse_dt_fudge_factors(pdev, "qcom,mdss-ib-factor",
 		&mdata->ib_factor);
 
+	/*
+	 * Set overlap ib value equal to ib by default. This value can
+	 * be tuned in device tree to be different from ib.
+	 * This factor apply when the max bandwidth per pipe
+	 * is the overlap BW.
+	 */
+	mdata->ib_factor_overlap.numer = mdata->ib_factor.numer;
+	mdata->ib_factor_overlap.denom = mdata->ib_factor.denom;
+	mdss_mdp_parse_dt_fudge_factors(pdev, "qcom,mdss-ib-factor-overlap",
+		&mdata->ib_factor_overlap);
+
 	mdata->clk_factor.numer = 1;
 	mdata->clk_factor.denom = 1;
 	mdss_mdp_parse_dt_fudge_factors(pdev, "qcom,mdss-clk-factor",
@@ -2257,6 +2276,23 @@
 	if (rc)
 		pr_debug("max bandwidth (high) property not specified\n");
 
+	mdata->nclk_lvl = mdss_mdp_parse_dt_prop_len(pdev,
+					"qcom,mdss-clk-levels");
+
+	if (mdata->nclk_lvl) {
+		mdata->clock_levels = kzalloc(sizeof(u32) * mdata->nclk_lvl,
+							GFP_KERNEL);
+		if (!mdata->clock_levels) {
+			pr_err("no mem assigned for mdata clock_levels\n");
+			return -ENOMEM;
+		}
+
+		rc = mdss_mdp_parse_dt_handler(pdev, "qcom,mdss-clk-levels",
+			mdata->clock_levels, mdata->nclk_lvl);
+		if (rc)
+			pr_debug("clock levels not found\n");
+	}
+
 	return 0;
 }
 
diff --git a/drivers/video/msm/mdss/mdss_mdp.h b/drivers/video/msm/mdss/mdss_mdp.h
index beb3cac..ebdc2b8 100644
--- a/drivers/video/msm/mdss/mdss_mdp.h
+++ b/drivers/video/msm/mdss/mdss_mdp.h
@@ -19,6 +19,7 @@
 #include <linux/msm_mdp.h>
 #include <linux/platform_device.h>
 #include <linux/notifier.h>
+#include <linux/kref.h>
 
 #include "mdss.h"
 #include "mdss_mdp_hwio.h"
@@ -75,6 +76,13 @@
 #define MDSS_MDP_REG_WRITE(addr, val)	MDSS_REG_WRITE((u32)(addr), (u32)(val))
 #define MDSS_MDP_REG_READ(addr)		MDSS_REG_READ((u32)(addr))
 #endif
+#define PERF_STATUS_DONE 0
+#define PERF_STATUS_BUSY 1
+
+enum mdss_mdp_perf_state_type {
+	PERF_SW_COMMIT_STATE = 0,
+	PERF_HW_MDP_STATE,
+};
 
 enum mdss_mdp_block_power_state {
 	MDP_BLOCK_POWER_OFF = 0,
@@ -180,7 +188,7 @@
 	int force_screen_state;
 	struct mdss_mdp_perf_params cur_perf;
 	struct mdss_mdp_perf_params new_perf;
-	int perf_status;
+	u32 perf_transaction_status;
 
 	struct mdss_data_type *mdata;
 	struct msm_fb_data_type *mfd;
@@ -192,8 +200,12 @@
 
 	struct mdss_panel_data *panel_data;
 	struct mdss_mdp_vsync_handler vsync_handler;
+	struct mdss_mdp_vsync_handler recover_underrun_handler;
+	struct work_struct recover_work;
+	struct work_struct remove_underrun_handler;
 
 	struct mdss_mdp_img_rect roi;
+	struct mdss_mdp_img_rect roi_bkup;
 	u8 roi_changed;
 
 	int (*start_fnc) (struct mdss_mdp_ctl *ctl);
@@ -364,7 +376,8 @@
 	struct mdss_mdp_shared_reg_ctrl clk_ctrl;
 	struct mdss_mdp_shared_reg_ctrl clk_status;
 
-	atomic_t ref_cnt;
+	struct kref kref;
+
 	u32 play_cnt;
 	int pid;
 	bool is_handed_off;
@@ -564,8 +577,8 @@
 
 int mdss_mdp_scan_pipes(void);
 
-void mdss_mdp_ctl_perf_taken(struct mdss_mdp_ctl *ctl);
-void mdss_mdp_ctl_perf_done(struct mdss_mdp_ctl *ctl);
+void mdss_mdp_ctl_perf_set_transaction_status(struct mdss_mdp_ctl *ctl,
+	enum mdss_mdp_perf_state_type component, bool new_status);
 void mdss_mdp_ctl_perf_release_bw(struct mdss_mdp_ctl *ctl);
 
 struct mdss_mdp_mixer *mdss_mdp_wb_mixer_alloc(int rotator);
@@ -681,6 +694,7 @@
 
 int mdss_mdp_get_ctl_mixers(u32 fb_num, u32 *mixer_id);
 u32 mdss_mdp_fb_stride(u32 fb_index, u32 xres, int bpp);
+void mdss_check_dsi_ctrl_status(struct work_struct *work, uint32_t interval);
 
 int mdss_panel_register_done(struct mdss_panel_data *pdata);
 int mdss_mdp_limited_lut_igc_config(struct mdss_mdp_ctl *ctl);
@@ -695,7 +709,7 @@
 void mdss_mdp_set_roi(struct mdss_mdp_ctl *ctl,
 					struct mdp_display_commit *data);
 
-int mdss_mdp_wb_set_format(struct msm_fb_data_type *mfd, int dst_format);
+int mdss_mdp_wb_set_format(struct msm_fb_data_type *mfd, u32 dst_format);
 int mdss_mdp_wb_get_format(struct msm_fb_data_type *mfd,
 					struct mdp_mixer_cfg *mixer_cfg);
 
diff --git a/drivers/video/msm/mdss/mdss_mdp_ctl.c b/drivers/video/msm/mdss/mdss_mdp_ctl.c
index 96e9bc7..9cf745e 100644
--- a/drivers/video/msm/mdss/mdss_mdp_ctl.c
+++ b/drivers/video/msm/mdss/mdss_mdp_ctl.c
@@ -22,7 +22,9 @@
 
 #include "mdss_fb.h"
 #include "mdss_mdp.h"
+#include "mdss_debug.h"
 
+static void mdss_mdp_xlog_mixer_reg(struct mdss_mdp_ctl *ctl);
 static inline u64 fudge_factor(u64 val, u32 numer, u32 denom)
 {
 	u64 result = (val * (u64)numer);
@@ -30,14 +32,11 @@
 	return result;
 }
 
-#define AB_FUDGE_FACTOR(val)		fudge_factor((val),		\
-	(mdss_res->ab_factor.numer), (mdss_res->ab_factor.denom))
-
-#define IB_FUDGE_FACTOR(val)		fudge_factor((val),		\
-	(mdss_res->ib_factor.numer), (mdss_res->ib_factor.denom))
-
-#define CLK_FUDGE_FACTOR(val)		fudge_factor((val),		\
-	(mdss_res->clk_factor.numer), (mdss_res->clk_factor.denom))
+static inline u64 apply_fudge_factor(u64 val,
+	struct mdss_fudge_factor *factor)
+{
+		return fudge_factor(val, factor->numer, factor->denom);
+}
 
 static DEFINE_MUTEX(mdss_mdp_ctl_lock);
 
@@ -50,6 +49,11 @@
 	writel_relaxed(val, mixer->base + reg);
 }
 
+static inline u32 mdp_mixer_read(struct mdss_mdp_mixer *mixer, u32 reg)
+{
+	return readl_relaxed(mixer->base + reg);
+}
+
 static inline u32 mdss_mdp_get_pclk_rate(struct mdss_mdp_ctl *ctl)
 {
 	struct mdss_panel_info *pinfo = &ctl->panel_data->panel_info;
@@ -64,7 +68,7 @@
 {
 	struct mdss_panel_info *pinfo = &mixer->ctl->panel_data->panel_info;
 
-	rate = CLK_FUDGE_FACTOR(rate);
+	rate = apply_fudge_factor(rate, &mdss_res->clk_factor);
 
 	/*
 	 * If the panel is video mode and its back porch period is
@@ -73,7 +77,7 @@
 	 */
 	if (mixer->ctl->is_video_mode && pinfo &&
 		(pinfo->lcdc.v_back_porch < MDP_MIN_VBP))
-		rate = CLK_FUDGE_FACTOR(rate);
+		rate = apply_fudge_factor(rate, &mdss_res->clk_factor);
 
 	return rate;
 }
@@ -694,87 +698,116 @@
 			left_plist, (left_plist ? MDSS_MDP_MAX_STAGE : 0),
 			right_plist, (right_plist ? MDSS_MDP_MAX_STAGE : 0));
 
-	if (ctl->is_video_mode)
-		perf->bw_ctl = IB_FUDGE_FACTOR(perf->bw_ctl);
-
+	if (ctl->is_video_mode) {
+		if (perf->bw_overlap > perf->bw_prefill)
+			perf->bw_ctl = apply_fudge_factor(perf->bw_ctl,
+				&mdss_res->ib_factor_overlap);
+		else
+			perf->bw_ctl = apply_fudge_factor(perf->bw_ctl,
+				&mdss_res->ib_factor);
+	}
 	pr_debug("ctl=%d clk_rate=%u\n", ctl->num, perf->mdp_clk_rate);
-	pr_debug("bw_overlap=%llu bw_prefill=%llu prefill_byptes=%d\n",
+	pr_debug("bw_overlap=%llu bw_prefill=%llu prefill_bytes=%d\n",
 		 perf->bw_overlap, perf->bw_prefill, perf->prefill_bytes);
 }
 
-static bool mdss_mdp_ctl_perf_bw_released(struct mdss_mdp_ctl *ctl)
+static void set_status(u32 *value, bool status, u32 bit_num)
 {
-	unsigned long flags;
-	bool released = false;
-
-	if (!ctl || !ctl->panel_data ||
-		(ctl->panel_data->panel_info.type != MIPI_CMD_PANEL))
-		return released;
-
-	spin_lock_irqsave(&ctl->spin_lock, flags);
-	if (ctl->perf_status == 0) {
-		released = true;
-		ctl->perf_status++;
-	} else if (ctl->perf_status <= 2) {
-		ctl->perf_status++;
-	} else {
-		pr_err("pervious commit was not done\n");
-	}
-
-	pr_debug("perf_status=%d\n", ctl->perf_status);
-	spin_unlock_irqrestore(&ctl->spin_lock, flags);
-
-	return released;
+	if (status)
+		*value |= BIT(bit_num);
+	else
+		*value &= ~BIT(bit_num);
 }
 
 /**
- * @mdss_mdp_ctl_perf_taken() - indicates a committed buffer is taken
- *                              by h/w
- * @ctl - pointer to ctl data structure
- *
- * A committed buffer to be displayed is taken at a vsync or reader
- * pointer interrupt by h/w. This function must be called in vsync
- * interrupt context to indicate the buf status is changed.
- */
-void mdss_mdp_ctl_perf_taken(struct mdss_mdp_ctl *ctl)
-{
-	if (!ctl || !ctl->panel_data ||
-		(ctl->panel_data->panel_info.type != MIPI_CMD_PANEL))
-		return;
-
-	spin_lock(&ctl->spin_lock);
-	if (ctl->perf_status)
-		ctl->perf_status++;
-	pr_debug("perf_status=%d\n", ctl->perf_status);
-	spin_unlock(&ctl->spin_lock);
-}
-
-/**
- * @mdss_mdp_ctl_perf_done() - indicates a committed buffer is
- *                             displayed, so resources such as
- *                             bandwidth that are associated to this
- *                             buffer can be released.
+ * @ mdss_mdp_ctl_perf_set_transaction_status() -
+ *                             Set the status of the on-going operations
+ *                             for the command mode panels.
  * @ctl - pointer to a ctl
  *
- * When pingping done interrupt is trigged, mdp finishes displaying a
- * buffer which was committed by user and taken by h/w and calling
- * this function to clear those two states. This function must be
- * called in pinppong done interrupt context.
+ * This function is called to set the status bit in the perf_transaction_status
+ * according to the operation that it is on-going for the command mode
+ * panels, where:
+ *
+ * PERF_SW_COMMIT_STATE:
+ *           1 - If SW operation has been commited and bw
+ *               has been requested (HW transaction have not started yet).
+ *           0 - If there is no SW operation pending
+ * PERF_HW_MDP_STATE:
+ *           1 - If HW transaction is on-going
+ *           0 - If there is no HW transaction on going (ping-pong interrupt
+ *               has finished)
+ * Only if both states are zero there are no pending operations and
+ * BW could be released.
+ * State can be queried calling "mdss_mdp_ctl_perf_get_transaction_status"
  */
-void mdss_mdp_ctl_perf_done(struct mdss_mdp_ctl *ctl)
+void mdss_mdp_ctl_perf_set_transaction_status(struct mdss_mdp_ctl *ctl,
+	enum mdss_mdp_perf_state_type component, bool new_status)
 {
+	u32  previous_transaction;
+	bool previous_status;
+	unsigned long flags;
+
 	if (!ctl || !ctl->panel_data ||
 		(ctl->panel_data->panel_info.type != MIPI_CMD_PANEL))
 		return;
 
-	spin_lock(&ctl->spin_lock);
-	if (ctl->perf_status) {
-		ctl->perf_status--;
-		if (ctl->perf_status)
-			ctl->perf_status--;
+	spin_lock_irqsave(&ctl->spin_lock, flags);
+
+	previous_transaction = ctl->perf_transaction_status;
+	previous_status = previous_transaction & BIT(component) ?
+		PERF_STATUS_BUSY : PERF_STATUS_DONE;
+
+	/*
+	 * If we set "done" state when previous state was not "busy",
+	 * we want to print a warning since maybe there is a state
+	 * that we are not considering
+	 */
+	WARN((PERF_STATUS_DONE == new_status) &&
+		(PERF_STATUS_BUSY != previous_status),
+		"unexpected previous state for component: %d\n", component);
+
+	set_status(&ctl->perf_transaction_status, new_status,
+		(u32)component);
+
+	pr_debug("component:%d previous_transaction:%d transaction_status:%d\n",
+		component, previous_transaction, ctl->perf_transaction_status);
+	pr_debug("new_status:%d prev_status:%d\n",
+		new_status, previous_status);
+
+	spin_unlock_irqrestore(&ctl->spin_lock, flags);
+}
+
+/**
+ * @ mdss_mdp_ctl_perf_get_transaction_status() -
+ *                             Get the status of the on-going operations
+ *                             for the command mode panels.
+ * @ctl - pointer to a ctl
+ *
+ * Return:
+ * The status of the transactions for the command mode panels,
+ * note that the bandwidth can be released only if all transaction
+ * status bits are zero.
+ */
+u32 mdss_mdp_ctl_perf_get_transaction_status(struct mdss_mdp_ctl *ctl)
+{
+	unsigned long flags;
+	u32 transaction_status;
+
+	/*
+	 * If Video Mode or not valid data to determine the status, return busy
+	 * status, so the bandwidth cannot be freed by the caller
+	 */
+	if (!ctl || !ctl->panel_data ||
+		(ctl->panel_data->panel_info.type != MIPI_CMD_PANEL)) {
+		return PERF_STATUS_BUSY;
 	}
-	pr_debug("perf_status=%d\n", ctl->perf_status);
-	spin_unlock(&ctl->spin_lock);
+
+	spin_lock_irqsave(&ctl->spin_lock, flags);
+	transaction_status = ctl->perf_transaction_status;
+	spin_unlock_irqrestore(&ctl->spin_lock, flags);
+
+	return transaction_status;
 }
 
 static inline void mdss_mdp_ctl_perf_update_bus(struct mdss_mdp_ctl *ctl)
@@ -798,7 +831,8 @@
 		}
 	}
 	bus_ib_quota = bw_sum_of_intfs;
-	bus_ab_quota = AB_FUDGE_FACTOR(bw_sum_of_intfs);
+	bus_ab_quota = apply_fudge_factor(bw_sum_of_intfs,
+		&mdss_res->ab_factor);
 	mdss_mdp_bus_scale_set_quota(bus_ab_quota, bus_ib_quota);
 	pr_debug("ab=%llu ib=%llu\n", bus_ab_quota, bus_ib_quota);
 }
@@ -808,13 +842,12 @@
  * @ctl - pointer to a ctl
  *
  * Function checks a state variable for the ctl, if all pending commit
- * requests are done, meanning no more bandwidth is needed, release
+ * requests are done, meaning no more bandwidth is needed, release
  * bandwidth request.
  */
 void mdss_mdp_ctl_perf_release_bw(struct mdss_mdp_ctl *ctl)
 {
-	unsigned long flags;
-	int need_release = 0;
+	int transaction_status;
 	struct mdss_data_type *mdata;
 	int i;
 
@@ -832,24 +865,45 @@
 	for (i = 0; i < mdata->nctl; i++) {
 		struct mdss_mdp_ctl *ctl = mdata->ctl_off + i;
 
-		if (ctl->power_on && ctl->is_video_mode) {
-			mutex_unlock(&mdss_mdp_ctl_lock);
-			return;
+		if (ctl->power_on && ctl->is_video_mode)
+			goto exit;
+	}
+
+	transaction_status = mdss_mdp_ctl_perf_get_transaction_status(ctl);
+	pr_debug("transaction_status=0x%x\n", transaction_status);
+
+	/*Release the bandwidth only if there are no transactions pending*/
+	if (!transaction_status) {
+		ctl->cur_perf.bw_ctl = 0;
+		ctl->new_perf.bw_ctl = 0;
+		pr_debug("Release BW ctl=%d\n", ctl->num);
+		mdss_mdp_ctl_perf_update_bus(ctl);
+	}
+exit:
+	mutex_unlock(&mdss_mdp_ctl_lock);
+}
+
+static int mdss_mdp_select_clk_lvl(struct mdss_mdp_ctl *ctl,
+			u32 clk_rate)
+{
+	int i;
+	struct mdss_data_type *mdata;
+
+	if (!ctl)
+		return -ENODEV;
+
+	mdata = ctl->mdata;
+
+	for (i = 0; i < mdata->nclk_lvl; i++) {
+		if (clk_rate > mdata->clock_levels[i]) {
+			continue;
+		} else {
+			clk_rate = mdata->clock_levels[i];
+			break;
 		}
 	}
 
-	spin_lock_irqsave(&ctl->spin_lock, flags);
-	if (!ctl->perf_status)
-		need_release = 1;
-	pr_debug("need release=%d\n", need_release);
-	spin_unlock_irqrestore(&ctl->spin_lock, flags);
-
-	if (need_release) {
-		ctl->cur_perf.bw_ctl = 0;
-		ctl->new_perf.bw_ctl = 0;
-		mdss_mdp_ctl_perf_update_bus(ctl);
-	}
-	mutex_unlock(&mdss_mdp_ctl_lock);
+	return clk_rate;
 }
 
 static void mdss_mdp_ctl_perf_update(struct mdss_mdp_ctl *ctl,
@@ -858,6 +912,7 @@
 	struct mdss_mdp_perf_params *new, *old;
 	int update_bus = 0, update_clk = 0;
 	struct mdss_data_type *mdata;
+	bool is_bw_released;
 
 	if (!ctl || !ctl->mdata)
 		return;
@@ -868,8 +923,14 @@
 	old = &ctl->cur_perf;
 	new = &ctl->new_perf;
 
+	/*
+	 * We could have released the bandwidth if there were no transactions
+	 * pending, so we want to re-calculate the bandwidth in this situation
+	 */
+	is_bw_released = !mdss_mdp_ctl_perf_get_transaction_status(ctl);
+
 	if (ctl->power_on) {
-		if (params_changed || mdss_mdp_ctl_perf_bw_released(ctl))
+		if (is_bw_released || params_changed)
 			mdss_mdp_perf_calc_ctl(ctl, new);
 		/*
 		 * if params have just changed delay the update until
@@ -912,6 +973,8 @@
 				clk_rate = max(ctl->cur_perf.mdp_clk_rate,
 					       clk_rate);
 		}
+
+		clk_rate  = mdss_mdp_select_clk_lvl(ctl, clk_rate);
 		mdss_mdp_set_clk_rate(clk_rate);
 		pr_debug("update clk rate = %d HZ\n", clk_rate);
 	}
@@ -1621,11 +1684,13 @@
 {
 	u32 temp;
 
+	mdss_mdp_clk_ctrl(MDP_BLOCK_POWER_ON, false);
 	temp = readl_relaxed(ctl->mdata->mdp_base +
 		MDSS_MDP_REG_DISP_INTF_SEL);
 	temp |= (ctl->intf_type << ((ctl->intf_num - MDSS_MDP_INTF0) * 8));
 	writel_relaxed(temp, ctl->mdata->mdp_base +
 		MDSS_MDP_REG_DISP_INTF_SEL);
+	mdss_mdp_clk_ctrl(MDP_BLOCK_POWER_OFF, false);
 }
 
 static int mdss_mdp_ctl_start_sub(struct mdss_mdp_ctl *ctl, bool handoff)
@@ -1894,6 +1959,7 @@
 	int stage, secure = 0;
 	int screen_state;
 	int outsize = 0;
+	u32 op_mode;
 
 	screen_state = ctl->force_screen_state;
 
@@ -2027,6 +2093,11 @@
 	else
 		ctl->flush_bits |= BIT(6) << mixer->num;
 
+	op_mode = mdp_mixer_read(mixer, MDSS_MDP_REG_LM_OP_MODE);
+	/* Read GC enable/disable status on LM */
+	op_mode = (op_mode & BIT(0));
+	blend_color_out |= op_mode;
+
 	mdp_mixer_write(mixer, MDSS_MDP_REG_LM_OP_MODE, blend_color_out);
 	off = __mdss_mdp_ctl_get_mixer_off(mixer);
 	mdss_mdp_ctl_write(ctl, off, mixercfg);
@@ -2448,6 +2519,7 @@
 	struct mdss_mdp_ctl *sctl = NULL;
 	int mixer1_changed, mixer2_changed;
 	int ret = 0;
+	bool is_bw_released;
 
 	if (!ctl) {
 		pr_err("display function not set\n");
@@ -2469,7 +2541,15 @@
 
 	mdss_mdp_clk_ctrl(MDP_BLOCK_POWER_ON, false);
 
-	if (mixer1_changed || mixer2_changed
+	/*
+	 * We could have released the bandwidth if there were no transactions
+	 * pending, so we want to re-calculate the bandwidth in this situation
+	 */
+	is_bw_released = !mdss_mdp_ctl_perf_get_transaction_status(ctl);
+	mdss_mdp_ctl_perf_set_transaction_status(ctl, PERF_SW_COMMIT_STATE,
+		PERF_STATUS_BUSY);
+
+	if (is_bw_released || mixer1_changed || mixer2_changed
 			|| ctl->force_screen_state) {
 		if (ctl->prepare_fnc)
 			ret = ctl->prepare_fnc(ctl, arg);
@@ -2500,6 +2580,9 @@
 	if (ctl->wait_pingpong)
 		ctl->wait_pingpong(ctl, NULL);
 
+	ctl->roi_bkup.w = ctl->roi.w;
+	ctl->roi_bkup.h = ctl->roi.h;
+
 	if (ctl->mfd && ctl->mfd->dcm_state != DTM_ENTER)
 		/* postprocessing setup, including dspp */
 		mdss_mdp_pp_setup_locked(ctl);
@@ -2512,6 +2595,8 @@
 	wmb();
 	ctl->flush_bits = 0;
 
+	mdss_mdp_xlog_mixer_reg(ctl);
+
 	if (ctl->display_fnc)
 		ret = ctl->display_fnc(ctl, arg); /* kickoff */
 	if (ret)
@@ -2677,3 +2762,18 @@
 
 	return rc;
 }
+
+static void mdss_mdp_xlog_mixer_reg(struct mdss_mdp_ctl *ctl)
+{
+	int i, off;
+	u32 data[MDSS_MDP_INTF_MAX_LAYERMIXER];
+
+	for (i = 0; i < MDSS_MDP_INTF_MAX_LAYERMIXER; i++) {
+		off =  MDSS_MDP_REG_CTL_LAYER(i);
+		data[i] = mdss_mdp_ctl_read(ctl, off);
+	}
+	MDSS_XLOG(data[MDSS_MDP_INTF_LAYERMIXER0],
+		data[MDSS_MDP_INTF_LAYERMIXER1],
+		data[MDSS_MDP_INTF_LAYERMIXER2],
+		data[MDSS_MDP_INTF_LAYERMIXER3], off);
+}
diff --git a/drivers/video/msm/mdss/mdss_mdp_hwio.h b/drivers/video/msm/mdss/mdss_mdp_hwio.h
index 4b9ea20..c11b438 100644
--- a/drivers/video/msm/mdss/mdss_mdp_hwio.h
+++ b/drivers/video/msm/mdss/mdss_mdp_hwio.h
@@ -109,7 +109,8 @@
 #define MDSS_MDP_REG_CTL_OFFSET(ctl) (0x00600 + ((ctl) * \
 					 MDSS_MDP_CTL_ADDRESS_OFFSET))
 
-#define MDSS_MDP_REG_CTL_LAYER(lm)			((lm) * 0x004)
+#define MDSS_MDP_REG_CTL_LAYER(lm)	\
+			((lm == 5) ? (0x024) : ((lm) * 0x004))
 #define MDSS_MDP_REG_CTL_TOP				0x014
 #define MDSS_MDP_REG_CTL_FLUSH				0x018
 #define MDSS_MDP_REG_CTL_START				0x01C
diff --git a/drivers/video/msm/mdss/mdss_mdp_intf_cmd.c b/drivers/video/msm/mdss/mdss_mdp_intf_cmd.c
index 96da27e..e2a8d56 100644
--- a/drivers/video/msm/mdss/mdss_mdp_intf_cmd.c
+++ b/drivers/video/msm/mdss/mdss_mdp_intf_cmd.c
@@ -15,12 +15,10 @@
 
 #include "mdss_mdp.h"
 #include "mdss_panel.h"
+#include "mdss_debug.h"
 
 #define VSYNC_EXPIRE_TICK 4
 
-#define START_THRESHOLD 4
-#define CONTINUE_THRESHOLD 4
-
 #define MAX_SESSIONS 2
 
 /* wait for at most 2 vsync for lowest refresh rate (24hz) */
@@ -104,96 +102,86 @@
 	return cnt;
 }
 
-/*
- * TE configuration:
- * dsi byte clock calculated base on 70 fps
- * around 14 ms to complete a kickoff cycle if te disabled
- * vclk_line base on 60 fps
- * write is faster than read
- * init == start == rdptr
- */
-static int mdss_mdp_cmd_tearcheck_cfg(struct mdss_mdp_mixer *mixer,
-			struct mdss_mdp_cmd_ctx *ctx, int enable)
-{
-	u32 cfg;
 
-	cfg = BIT(19); /* VSYNC_COUNTER_EN */
-	if (ctx->tear_check)
-		cfg |= BIT(20);	/* VSYNC_IN_EN */
-	cfg |= ctx->vclk_line;
+static int mdss_mdp_cmd_tearcheck_cfg(struct mdss_mdp_ctl *ctl,
+				      struct mdss_mdp_mixer *mixer)
+{
+	struct mdss_mdp_pp_tear_check *te;
+	struct mdss_panel_info *pinfo;
+	u32 vsync_clk_speed_hz, total_lines, vclks_line, cfg;
+
+	if (IS_ERR_OR_NULL(ctl->panel_data)) {
+		pr_err("no panel data\n");
+		return -ENODEV;
+	}
+
+	pinfo = &ctl->panel_data->panel_info;
+	te = &ctl->panel_data->panel_info.te;
+
+	mdss_mdp_vsync_clk_enable(1);
+
+	vsync_clk_speed_hz =
+		mdss_mdp_get_clk_rate(MDSS_CLK_MDP_VSYNC);
+
+	total_lines = mdss_panel_get_vtotal(pinfo);
+
+	total_lines *= pinfo->mipi.frame_rate;
+
+	vclks_line = (total_lines) ? vsync_clk_speed_hz / total_lines : 0;
+
+	cfg = BIT(19);
+	if (pinfo->mipi.hw_vsync_mode)
+		cfg |= BIT(20);
+
+	if (te->refx100)
+		vclks_line = vclks_line * pinfo->mipi.frame_rate *
+			100 / te->refx100;
+	else {
+		pr_warn("refx100 cannot be zero! Use 6000 as default\n");
+		vclks_line = vclks_line * pinfo->mipi.frame_rate *
+			100 / 6000;
+	}
+
+	cfg |= vclks_line;
+
+	pr_debug("%s: yres=%d vclks=%x height=%d init=%d rd=%d start=%d ",
+		__func__, pinfo->yres, vclks_line, te->sync_cfg_height,
+		 te->vsync_init_val, te->rd_ptr_irq, te->start_pos);
+	pr_debug("thrd_start =%d thrd_cont=%d\n",
+		te->sync_threshold_start, te->sync_threshold_continue);
 
 	mdss_mdp_pingpong_write(mixer, MDSS_MDP_REG_PP_SYNC_CONFIG_VSYNC, cfg);
 	mdss_mdp_pingpong_write(mixer, MDSS_MDP_REG_PP_SYNC_CONFIG_HEIGHT,
-				0xfff0); /* set to verh height */
-
+				te->sync_cfg_height);
 	mdss_mdp_pingpong_write(mixer, MDSS_MDP_REG_PP_VSYNC_INIT_VAL,
-						ctx->height);
-
+				te->vsync_init_val);
 	mdss_mdp_pingpong_write(mixer, MDSS_MDP_REG_PP_RD_PTR_IRQ,
-						ctx->height + 1);
-
+				te->rd_ptr_irq);
 	mdss_mdp_pingpong_write(mixer, MDSS_MDP_REG_PP_START_POS,
-						ctx->height);
-
+				te->start_pos);
 	mdss_mdp_pingpong_write(mixer, MDSS_MDP_REG_PP_SYNC_THRESH,
-		   (CONTINUE_THRESHOLD << 16) | (ctx->start_threshold));
-
-	mdss_mdp_pingpong_write(mixer, MDSS_MDP_REG_PP_TEAR_CHECK_EN, enable);
+				((te->sync_threshold_continue << 16) |
+				 te->sync_threshold_start));
+	mdss_mdp_pingpong_write(mixer, MDSS_MDP_REG_PP_TEAR_CHECK_EN,
+				te->tear_check_en);
 	return 0;
 }
 
-static int mdss_mdp_cmd_tearcheck_setup(struct mdss_mdp_ctl *ctl, int enable)
+static int mdss_mdp_cmd_tearcheck_setup(struct mdss_mdp_ctl *ctl)
 {
-	struct mdss_mdp_cmd_ctx *ctx = ctl->priv_data;
-	struct mdss_panel_info *pinfo;
 	struct mdss_mdp_mixer *mixer;
-
-	pinfo = &ctl->panel_data->panel_info;
-
-	if (pinfo->mipi.vsync_enable && enable) {
-		u32 mdp_vsync_clk_speed_hz, total_lines;
-
-		mdss_mdp_vsync_clk_enable(1);
-
-		mdp_vsync_clk_speed_hz =
-		mdss_mdp_get_clk_rate(MDSS_CLK_MDP_VSYNC);
-		pr_debug("%s: vsync_clk_rate=%d\n", __func__,
-					mdp_vsync_clk_speed_hz);
-
-		if (mdp_vsync_clk_speed_hz == 0) {
-			pr_err("can't get clk speed\n");
-			return -EINVAL;
-		}
-
-		ctx->tear_check = pinfo->mipi.hw_vsync_mode;
-		ctx->height = pinfo->yres;
-		ctx->vporch = pinfo->lcdc.v_back_porch +
-				    pinfo->lcdc.v_front_porch +
-				    pinfo->lcdc.v_pulse_width;
-
-		ctx->start_threshold = START_THRESHOLD;
-
-		total_lines = ctx->height + ctx->vporch;
-		total_lines *= pinfo->mipi.frame_rate;
-		ctx->vclk_line = mdp_vsync_clk_speed_hz / total_lines;
-
-		pr_debug("%s: fr=%d tline=%d vcnt=%d thold=%d vrate=%d\n",
-			__func__, pinfo->mipi.frame_rate, total_lines,
-				ctx->vclk_line, ctx->start_threshold,
-				mdp_vsync_clk_speed_hz);
-	} else {
-		enable = 0;
-	}
-
+	int rc = 0;
 	mixer = mdss_mdp_mixer_get(ctl, MDSS_MDP_MIXER_MUX_LEFT);
-	if (mixer)
-		mdss_mdp_cmd_tearcheck_cfg(mixer, ctx, enable);
-
+	if (mixer) {
+		rc = mdss_mdp_cmd_tearcheck_cfg(ctl, mixer);
+		if (rc)
+			goto err;
+	}
 	mixer = mdss_mdp_mixer_get(ctl, MDSS_MDP_MIXER_MUX_RIGHT);
 	if (mixer)
-		mdss_mdp_cmd_tearcheck_cfg(mixer, ctx, enable);
-
-	return 0;
+		rc = mdss_mdp_cmd_tearcheck_cfg(ctl, mixer);
+ err:
+	return rc;
 }
 
 static inline void mdss_mdp_cmd_clk_on(struct mdss_mdp_cmd_ctx *ctx)
@@ -205,6 +193,8 @@
 		return;
 
 	mutex_lock(&ctx->clk_mtx);
+	MDSS_XLOG(ctx->pp_num, ctx->koff_cnt, ctx->clk_enabled,
+						ctx->rdptr_enabled);
 	if (!ctx->clk_enabled) {
 		ctx->clk_enabled = 1;
 		if (cancel_delayed_work_sync(&ctx->ulps_work))
@@ -213,7 +203,7 @@
 		mdss_mdp_clk_ctrl(MDP_BLOCK_POWER_ON, false);
 
 		if (ctx->ulps) {
-			if (mdss_mdp_cmd_tearcheck_setup(ctx->ctl, 1))
+			if (mdss_mdp_cmd_tearcheck_setup(ctx->ctl))
 				pr_warn("tearcheck setup failed\n");
 			mdss_mdp_ctl_intf_event(ctx->ctl,
 				MDSS_EVENT_DSI_ULPS_CTRL, (void *)0);
@@ -240,6 +230,8 @@
 	int set_clk_off = 0;
 
 	mutex_lock(&ctx->clk_mtx);
+	MDSS_XLOG(ctx->pp_num, ctx->koff_cnt, ctx->clk_enabled,
+						ctx->rdptr_enabled);
 	spin_lock_irqsave(&ctx->clk_lock, flags);
 	if (!ctx->rdptr_enabled)
 		set_clk_off = 1;
@@ -269,10 +261,10 @@
 		return;
 	}
 
-	mdss_mdp_ctl_perf_taken(ctl);
-
 	vsync_time = ktime_get();
 	ctl->vsync_cnt++;
+	MDSS_XLOG(ctl->num, ctx->koff_cnt, ctx->clk_enabled,
+				ctx->rdptr_enabled);
 
 	spin_lock(&ctx->clk_lock);
 	list_for_each_entry(tmp, &ctx->vsync_handlers, list) {
@@ -336,7 +328,8 @@
 		return;
 	}
 
-	mdss_mdp_ctl_perf_done(ctl);
+	mdss_mdp_ctl_perf_set_transaction_status(ctl,
+		PERF_HW_MDP_STATE, PERF_STATUS_DONE);
 
 	spin_lock(&ctx->clk_lock);
 	list_for_each_entry(tmp, &ctx->vsync_handlers, list) {
@@ -346,6 +339,8 @@
 	mdss_mdp_irq_disable_nosync(MDSS_MDP_IRQ_PING_PONG_COMP, ctx->pp_num);
 
 	complete_all(&ctx->pp_comp);
+	MDSS_XLOG(ctl->num, ctx->koff_cnt, ctx->clk_enabled,
+					ctx->rdptr_enabled);
 
 	if (ctx->koff_cnt) {
 		atomic_inc(&ctx->pp_done_cnt);
@@ -436,6 +431,9 @@
 		return -ENODEV;
 	}
 
+	MDSS_XLOG(ctl->num, ctx->koff_cnt, ctx->clk_enabled,
+					ctx->rdptr_enabled);
+
 	spin_lock_irqsave(&ctx->clk_lock, flags);
 	if (!handle->enabled) {
 		handle->enabled = true;
@@ -465,6 +463,9 @@
 		return -ENODEV;
 	}
 
+	MDSS_XLOG(ctl->num, ctx->koff_cnt, ctx->clk_enabled,
+				ctx->rdptr_enabled, 0x88888);
+
 	spin_lock_irqsave(&ctx->clk_lock, flags);
 	if (handle->enabled) {
 		handle->enabled = false;
@@ -498,6 +499,7 @@
 static int mdss_mdp_cmd_wait4pingpong(struct mdss_mdp_ctl *ctl, void *arg)
 {
 	struct mdss_mdp_cmd_ctx *ctx;
+	struct mdss_panel_data *pdata;
 	unsigned long flags;
 	int need_wait = 0;
 	int rc = 0;
@@ -508,11 +510,20 @@
 		return -ENODEV;
 	}
 
+	pdata = ctl->panel_data;
+
 	spin_lock_irqsave(&ctx->clk_lock, flags);
 	if (ctx->koff_cnt > 0)
 		need_wait = 1;
 	spin_unlock_irqrestore(&ctx->clk_lock, flags);
 
+	ctl->roi_bkup.w = ctl->width;
+	ctl->roi_bkup.h = ctl->height;
+
+	MDSS_XLOG(ctl->num, ctx->koff_cnt, ctx->clk_enabled,
+			ctx->rdptr_enabled, ctl->roi_bkup.w,
+			ctl->roi_bkup.h);
+
 	pr_debug("%s: need_wait=%d  intf_num=%d ctx=%p\n",
 			__func__, need_wait, ctl->intf_num, ctx);
 
@@ -523,6 +534,9 @@
 		if (rc <= 0) {
 			WARN(1, "cmd kickoff timed out (%d) ctl=%d\n",
 						rc, ctl->num);
+			mdss_dsi_debug_check_te(pdata);
+			MDSS_XLOG_TOUT_HANDLER("mdp", "dsi0", "dsi1",
+						"edp", "hdmi", "panic");
 			rc = -EPERM;
 			mdss_mdp_ctl_notify(ctl, MDP_NOTIFY_FRAME_TIMEOUT);
 		} else {
@@ -530,6 +544,8 @@
 		}
 	}
 
+	MDSS_XLOG(ctl->num, ctx->koff_cnt, ctx->clk_enabled,
+					ctx->rdptr_enabled, rc);
 	return rc;
 }
 
@@ -561,6 +577,9 @@
 		return -ENODEV;
 	}
 
+	mdss_mdp_ctl_perf_set_transaction_status(ctl,
+		PERF_HW_MDP_STATE, PERF_STATUS_BUSY);
+
 	if (ctx->panel_on == 0) {
 		rc = mdss_mdp_ctl_intf_event(ctl, MDSS_EVENT_UNBLANK, NULL);
 		WARN(rc, "intf %d unblank error (%d)\n", ctl->intf_num, rc);
@@ -571,6 +590,9 @@
 		WARN(rc, "intf %d panel on error (%d)\n", ctl->intf_num, rc);
 	}
 
+	MDSS_XLOG(ctl->num, ctl->roi.x, ctl->roi.y, ctl->roi.w,
+						ctl->roi.h);
+
 	spin_lock_irqsave(&ctx->clk_lock, flags);
 	ctx->koff_cnt++;
 	spin_unlock_irqrestore(&ctx->clk_lock, flags);
@@ -587,7 +609,11 @@
 	INIT_COMPLETION(ctx->pp_comp);
 	mdss_mdp_irq_enable(MDSS_MDP_IRQ_PING_PONG_COMP, ctx->pp_num);
 	mdss_mdp_ctl_write(ctl, MDSS_MDP_REG_CTL_START, 1);
+	mdss_mdp_ctl_perf_set_transaction_status(ctl,
+		PERF_SW_COMMIT_STATE, PERF_STATUS_DONE);
 	mb();
+	MDSS_XLOG(ctl->num,  ctx->koff_cnt, ctx->clk_enabled,
+						ctx->rdptr_enabled);
 
 	return 0;
 }
@@ -609,6 +635,8 @@
 
 	list_for_each_entry_safe(handle, tmp, &ctx->vsync_handlers, list)
 		mdss_mdp_cmd_remove_vsync_handler(ctl, handle);
+	MDSS_XLOG(ctl->num, ctx->koff_cnt, ctx->clk_enabled,
+				ctx->rdptr_enabled, XLOG_FUNC_ENTRY);
 
 	spin_lock_irqsave(&ctx->clk_lock, flags);
 	if (ctx->rdptr_enabled) {
@@ -668,6 +696,8 @@
 	ctl->add_vsync_handler = NULL;
 	ctl->remove_vsync_handler = NULL;
 
+	MDSS_XLOG(ctl->num, ctx->koff_cnt, ctx->clk_enabled,
+				ctx->rdptr_enabled, XLOG_FUNC_EXIT);
 	pr_debug("%s:-\n", __func__);
 
 	return 0;
@@ -722,6 +752,8 @@
 
 	pr_debug("%s: ctx=%p num=%d mixer=%d\n", __func__,
 				ctx, ctx->pp_num, mixer->num);
+	MDSS_XLOG(ctl->num, ctx->koff_cnt, ctx->clk_enabled,
+					ctx->rdptr_enabled);
 
 	mdss_mdp_set_intr_callback(MDSS_MDP_IRQ_PING_PONG_RD_PTR, ctx->pp_num,
 				   mdss_mdp_cmd_readptr_done, ctl);
@@ -729,7 +761,8 @@
 	mdss_mdp_set_intr_callback(MDSS_MDP_IRQ_PING_PONG_COMP, ctx->pp_num,
 				   mdss_mdp_cmd_pingpong_done, ctl);
 
-	ret = mdss_mdp_cmd_tearcheck_setup(ctl, 1);
+	ret = mdss_mdp_cmd_tearcheck_setup(ctl);
+
 	if (ret) {
 		pr_err("tearcheck setup failed\n");
 		return ret;
diff --git a/drivers/video/msm/mdss/mdss_mdp_intf_video.c b/drivers/video/msm/mdss/mdss_mdp_intf_video.c
index f8bdc04..e41bd49 100644
--- a/drivers/video/msm/mdss/mdss_mdp_intf_video.c
+++ b/drivers/video/msm/mdss/mdss_mdp_intf_video.c
@@ -22,6 +22,7 @@
 #include "mdss_fb.h"
 #include "mdss_mdp.h"
 #include "mdss_panel.h"
+#include "mdss_debug.h"
 
 /* wait for at least 2 vsyncs for lowest refresh rate (24hz) */
 #define VSYNC_TIMEOUT_US 100000
@@ -256,6 +257,8 @@
 		goto exit;
 	}
 
+	MDSS_XLOG(ctl->num, ctl->vsync_cnt, handle->enabled);
+
 	spin_lock_irqsave(&ctx->vsync_lock, flags);
 	if (!handle->enabled) {
 		handle->enabled = true;
@@ -282,6 +285,8 @@
 		return -ENODEV;
 	}
 
+	MDSS_XLOG(ctl->num, ctl->vsync_cnt, handle->enabled);
+
 	spin_lock_irqsave(&ctx->vsync_lock, flags);
 	if (handle->enabled) {
 		handle->enabled = false;
@@ -309,7 +314,7 @@
 		pr_err("invalid ctx for ctl=%d\n", ctl->num);
 		return -ENODEV;
 	}
-
+	MDSS_XLOG(ctl->num, ctl->vsync_cnt);
 	if (ctx->timegen_en) {
 		rc = mdss_mdp_ctl_intf_event(ctl, MDSS_EVENT_BLANK, NULL);
 		if (rc == -EBUSY) {
@@ -372,6 +377,8 @@
 	vsync_time = ktime_get();
 	ctl->vsync_cnt++;
 
+	MDSS_XLOG(ctl->num, ctl->vsync_cnt, ctl->vsync_cnt);
+
 	pr_debug("intr ctl=%d vsync cnt=%u vsync_time=%d\n",
 		 ctl->num, ctl->vsync_cnt, (int)ktime_to_ms(vsync_time));
 
@@ -401,6 +408,7 @@
 	mdss_mdp_clk_ctrl(MDP_BLOCK_POWER_OFF, false);
 
 	if (rc == 0) {
+		MDSS_XLOG(ctl->num, ctl->vsync_cnt);
 		pr_debug("vsync poll successful! rc=%d status=0x%x\n",
 				rc, status);
 		ctx->poll_cnt++;
@@ -438,8 +446,10 @@
 	if (ctx->polling_en) {
 		rc = mdss_mdp_video_pollwait(ctl);
 	} else {
+		mutex_unlock(&ctl->lock);
 		rc = wait_for_completion_timeout(&ctx->vsync_comp,
 				usecs_to_jiffies(VSYNC_TIMEOUT_US));
+		mutex_lock(&ctl->lock);
 		if (rc == 0) {
 			pr_warn("vsync wait timeout %d, fallback to poll mode\n",
 					ctl->num);
@@ -460,6 +470,21 @@
 	return rc;
 }
 
+static void recover_underrun_work(struct work_struct *work)
+{
+	struct mdss_mdp_ctl *ctl =
+		container_of(work, typeof(*ctl), recover_work);
+
+	if (!ctl || !ctl->add_vsync_handler) {
+		pr_err("ctl or vsync handler is NULL\n");
+		return;
+	}
+
+	mdss_mdp_clk_ctrl(MDP_BLOCK_POWER_ON, false);
+	ctl->add_vsync_handler(ctl, &ctl->recover_underrun_handler);
+	mdss_mdp_clk_ctrl(MDP_BLOCK_POWER_OFF, false);
+}
+
 static void mdss_mdp_video_underrun_intr_done(void *arg)
 {
 	struct mdss_mdp_ctl *ctl = arg;
@@ -467,8 +492,13 @@
 		return;
 
 	ctl->underrun_cnt++;
+	MDSS_XLOG(ctl->num, ctl->underrun_cnt);
+	MDSS_XLOG_TOUT_HANDLER("mdp", "dsi0", "dsi1", "edp", "hdmi", "panic");
 	pr_debug("display underrun detected for ctl=%d count=%d\n", ctl->num,
 			ctl->underrun_cnt);
+
+	if (ctl->opmode & MDSS_MDP_CTL_OP_PACK_3D_ENABLE)
+		schedule_work(&ctl->recover_work);
 }
 
 static int mdss_mdp_video_vfp_fps_update(struct mdss_mdp_ctl *ctl, int new_fps)
@@ -640,9 +670,6 @@
 	return rc;
 }
 
-
-
-
 static int mdss_mdp_video_display(struct mdss_mdp_ctl *ctl, void *arg)
 {
 	struct mdss_mdp_video_ctx *ctx;
@@ -665,6 +692,8 @@
 		WARN(1, "commit without wait! ctl=%d", ctl->num);
 	}
 
+	MDSS_XLOG(ctl->num, ctl->underrun_cnt);
+
 	if (!ctx->timegen_en) {
 		rc = mdss_mdp_ctl_intf_event(ctl, MDSS_EVENT_UNBLANK, NULL);
 		if (rc) {
@@ -783,6 +812,7 @@
 		return -EINVAL;
 	}
 
+	MDSS_XLOG(ctl->num, ctl->vsync_cnt);
 	pr_debug("start ctl=%u\n", ctl->num);
 
 	ctl->priv_data = ctx;
@@ -791,6 +821,7 @@
 	spin_lock_init(&ctx->vsync_lock);
 	mutex_init(&ctx->vsync_mtx);
 	atomic_set(&ctx->vsync_ref, 0);
+	INIT_WORK(&ctl->recover_work, recover_underrun_work);
 
 	mdss_mdp_set_intr_callback(MDSS_MDP_IRQ_INTF_VSYNC, ctl->intf_num,
 				   mdss_mdp_video_vsync_intr_done, ctl);
diff --git a/drivers/video/msm/mdss/mdss_mdp_overlay.c b/drivers/video/msm/mdss/mdss_mdp_overlay.c
index ce4f814..cb45374 100644
--- a/drivers/video/msm/mdss/mdss_mdp_overlay.c
+++ b/drivers/video/msm/mdss/mdss_mdp_overlay.c
@@ -1146,14 +1146,18 @@
 	else
 		ret = mdss_mdp_display_commit(mdp5_data->ctl, NULL);
 
+	atomic_set(&mfd->kickoff_pending, 0);
+	wake_up_all(&mfd->kickoff_wait_q);
 	mutex_unlock(&mfd->lock);
 
 	if (IS_ERR_VALUE(ret))
 		goto commit_fail;
 
+	mutex_unlock(&mdp5_data->ov_lock);
 	mdss_mdp_overlay_update_pm(mdp5_data);
 
 	ret = mdss_mdp_display_wait4comp(mdp5_data->ctl);
+	mutex_lock(&mdp5_data->ov_lock);
 
 	if (ret == 0) {
 		mutex_lock(&mfd->lock);
@@ -1402,8 +1406,13 @@
 
 	for (i = 0; i < mdata->ndma_pipes; i++) {
 		pipe = mdata->dma_pipes + i;
-		if (atomic_read(&pipe->ref_cnt) && pipe->mfd)
-			mdss_mdp_overlay_force_cleanup(pipe->mfd);
+
+		if (!mdss_mdp_pipe_map(pipe)) {
+			struct msm_fb_data_type *mfd = pipe->mfd;
+			mdss_mdp_pipe_unmap(pipe);
+			if (mfd)
+				mdss_mdp_overlay_force_cleanup(mfd);
+		}
 	}
 }
 
@@ -1593,6 +1602,7 @@
 		return;
 	}
 
+	mdss_mdp_clk_ctrl(MDP_BLOCK_POWER_ON, false);
 	bpp = fbi->var.bits_per_pixel / 8;
 	offset = fbi->var.xoffset * bpp +
 		 fbi->var.yoffset * fbi->fix.line_length;
@@ -1665,6 +1675,7 @@
 	    (fbi->var.activate & FB_ACTIVATE_FORCE))
 		mfd->mdp.kickoff_fnc(mfd, NULL);
 
+	mdss_mdp_clk_ctrl(MDP_BLOCK_POWER_OFF, false);
 	return;
 
 attach_err:
@@ -1672,11 +1683,42 @@
 	mdss_mdp_overlay_unset(mfd, pipe->ndx);
 	if (pipe_ndx)
 		pipe_ndx[0] = INVALID_PIPE_INDEX;
+	mdss_mdp_clk_ctrl(MDP_BLOCK_POWER_OFF, false);
 	return;
 pan_display_error:
+	mdss_mdp_clk_ctrl(MDP_BLOCK_POWER_OFF, false);
 	mutex_unlock(&mdp5_data->ov_lock);
 }
 
+static void remove_underrun_vsync_handler(struct work_struct *work)
+{
+	int rc;
+	struct mdss_mdp_ctl *ctl =
+		container_of(work, typeof(*ctl), remove_underrun_handler);
+
+	if (!ctl || !ctl->remove_vsync_handler) {
+		pr_err("ctl or vsync handler is NULL\n");
+		return;
+	}
+
+	mdss_mdp_clk_ctrl(MDP_BLOCK_POWER_ON, false);
+	rc = ctl->remove_vsync_handler(ctl,
+			&ctl->recover_underrun_handler);
+	mdss_mdp_clk_ctrl(MDP_BLOCK_POWER_OFF, false);
+}
+
+static void mdss_mdp_recover_underrun_handler(struct mdss_mdp_ctl *ctl,
+						ktime_t t)
+{
+	if (!ctl) {
+		pr_err("ctl is NULL\n");
+		return;
+	}
+
+	mdss_mdp_ctl_reset(ctl);
+	schedule_work(&ctl->remove_underrun_handler);
+}
+
 /* function is called in irq context should have minimum processing */
 static void mdss_mdp_overlay_handle_vsync(struct mdss_mdp_ctl *ctl,
 						ktime_t t)
@@ -2642,6 +2684,13 @@
 					mdss_mdp_overlay_handle_vsync;
 	ctl->vsync_handler.cmd_post_flush = false;
 
+	ctl->recover_underrun_handler.vsync_handler =
+			mdss_mdp_recover_underrun_handler;
+	ctl->recover_underrun_handler.cmd_post_flush = false;
+
+	INIT_WORK(&ctl->remove_underrun_handler,
+				remove_underrun_vsync_handler);
+
 	if (mfd->split_display && pdata->next) {
 		/* enable split display */
 		rc = mdss_mdp_ctl_split_display_setup(ctl, pdata->next);
@@ -3100,6 +3149,7 @@
 		goto init_fail;
 	}
 	mfd->mdp.private1 = mdp5_data;
+	mfd->wait_for_kickoff = true;
 
 	rc = mdss_mdp_overlay_fb_parse_dt(mfd);
 	if (rc)
diff --git a/drivers/video/msm/mdss/mdss_mdp_pipe.c b/drivers/video/msm/mdss/mdss_mdp_pipe.c
index 50bee17..2d98600 100644
--- a/drivers/video/msm/mdss/mdss_mdp_pipe.c
+++ b/drivers/video/msm/mdss/mdss_mdp_pipe.c
@@ -37,7 +37,7 @@
 static DEFINE_MUTEX(mdss_mdp_sspp_lock);
 static DEFINE_MUTEX(mdss_mdp_smp_lock);
 
-static int mdss_mdp_pipe_free(struct mdss_mdp_pipe *pipe);
+static void mdss_mdp_pipe_free(struct kref *kref);
 static int mdss_mdp_smp_mmb_set(int client_id, unsigned long *smp);
 static void mdss_mdp_smp_mmb_free(unsigned long *smp, bool write);
 static struct mdss_mdp_pipe *mdss_mdp_pipe_search_by_client_id(
@@ -481,21 +481,17 @@
 
 void mdss_mdp_pipe_unmap(struct mdss_mdp_pipe *pipe)
 {
-	int tmp;
-
-	tmp = atomic_dec_return(&pipe->ref_cnt);
-
-	WARN(tmp < 0, "Invalid unmap with ref_cnt=%d", tmp);
-	if (tmp == 0)
-		mdss_mdp_pipe_free(pipe);
+	if (kref_put_mutex(&pipe->kref, mdss_mdp_pipe_free,
+			&mdss_mdp_sspp_lock)) {
+		WARN(1, "Unexpected free pipe during unmap");
+		mutex_unlock(&mdss_mdp_sspp_lock);
+	}
 }
 
 int mdss_mdp_pipe_map(struct mdss_mdp_pipe *pipe)
 {
-	if (!atomic_inc_not_zero(&pipe->ref_cnt)) {
-		pr_err("attempting to map unallocated pipe (%d)", pipe->num);
+	if (!kref_get_unless_zero(&pipe->kref))
 		return -EINVAL;
-	}
 	return 0;
 }
 
@@ -541,7 +537,7 @@
 
 	for (i = off; i < npipes; i++) {
 		pipe = pipe_pool + i;
-		if (atomic_cmpxchg(&pipe->ref_cnt, 0, 1) == 0) {
+		if (atomic_read(&pipe->kref.refcount) == 0) {
 			pipe->mixer = mixer;
 			break;
 		}
@@ -551,7 +547,6 @@
 	if (pipe && mdss_mdp_pipe_fetch_halt(pipe)) {
 		pr_err("%d failed because pipe is in bad state\n",
 			pipe->num);
-		atomic_dec(&pipe->ref_cnt);
 		return NULL;
 	}
 
@@ -559,13 +554,14 @@
 		pr_debug("type=%x   pnum=%d\n", pipe->type, pipe->num);
 		mutex_init(&pipe->pp_res.hist.hist_mutex);
 		spin_lock_init(&pipe->pp_res.hist.hist_lock);
+		kref_init(&pipe->kref);
 	} else if (pipe_share) {
 		/*
 		 * when there is no dedicated wfd blk, DMA pipe can be
 		 * shared as long as its attached to a writeback mixer
 		 */
 		pipe = mdata->dma_pipes + mixer->num;
-		atomic_inc(&pipe->ref_cnt);
+		kref_get(&pipe->kref);
 		pr_debug("pipe sharing for pipe=%d\n", pipe->num);
 	} else {
 		pr_err("no %d type pipes available\n", type);
@@ -587,7 +583,7 @@
 	} else if (pipe != &mdata->dma_pipes[mixer->num]) {
 		pr_err("Requested DMA pnum=%d not available\n",
 			mdata->dma_pipes[mixer->num].num);
-		mdss_mdp_pipe_unmap(pipe);
+		kref_put(&pipe->kref, mdss_mdp_pipe_free);
 		pipe = NULL;
 	} else {
 		pipe->mixer = mixer;
@@ -674,10 +670,13 @@
 	return NULL;
 }
 
-static int mdss_mdp_pipe_free(struct mdss_mdp_pipe *pipe)
+static void mdss_mdp_pipe_free(struct kref *kref)
 {
-	pr_debug("ndx=%x pnum=%d ref_cnt=%d\n", pipe->ndx, pipe->num,
-			atomic_read(&pipe->ref_cnt));
+	struct mdss_mdp_pipe *pipe;
+
+	pipe = container_of(kref, struct mdss_mdp_pipe, kref);
+
+	pr_debug("ndx=%x pnum=%d\n", pipe->ndx, pipe->num);
 
 	if (pipe->play_cnt) {
 		mdss_mdp_clk_ctrl(MDP_BLOCK_POWER_ON, false);
@@ -693,8 +692,6 @@
 	pipe->bwc_mode = 0;
 	pipe->mfd = NULL;
 	memset(&pipe->scale, 0, sizeof(struct mdp_scale_data));
-
-	return 0;
 }
 
 static int mdss_mdp_is_pipe_idle(struct mdss_mdp_pipe *pipe,
@@ -802,19 +799,16 @@
 
 int mdss_mdp_pipe_destroy(struct mdss_mdp_pipe *pipe)
 {
-	int tmp;
-
-	tmp = atomic_dec_return(&pipe->ref_cnt);
-
-	if (tmp != 0) {
-		pr_err("unable to free pipe %d while still in use (%d)\n",
-				pipe->num, tmp);
+	if (!kref_put_mutex(&pipe->kref, mdss_mdp_pipe_free,
+			&mdss_mdp_sspp_lock)) {
+		pr_err("unable to free pipe %d while still in use\n",
+				pipe->num);
 		return -EBUSY;
 	}
-	mdss_mdp_pipe_free(pipe);
+
+	mutex_unlock(&mdss_mdp_sspp_lock);
 
 	return 0;
-
 }
 
 /**
@@ -873,7 +867,7 @@
 
 	pipe->is_handed_off = true;
 	pipe->play_cnt = 1;
-	atomic_inc(&pipe->ref_cnt);
+	kref_init(&pipe->kref);
 
 error:
 	return rc;
diff --git a/drivers/video/msm/mdss/mdss_mdp_pp.c b/drivers/video/msm/mdss/mdss_mdp_pp.c
index 37b71c7..6b497bb 100644
--- a/drivers/video/msm/mdss/mdss_mdp_pp.c
+++ b/drivers/video/msm/mdss/mdss_mdp_pp.c
@@ -181,6 +181,7 @@
 #define MDSS_MDP_GAMUT_SIZE		0x5C
 #define MDSS_MDP_IGC_DSPP_SIZE		0x28
 #define MDSS_MDP_IGC_SSPP_SIZE		0x88
+#define MDSS_MDP_VIG_QSEED2_SHARP_SIZE	0x0C
 #define TOTAL_BLEND_STAGES		0x4
 
 #define PP_FLAGS_DIRTY_PA	0x1
@@ -789,9 +790,15 @@
 	unsigned long flags = 0;
 	char __iomem *offset;
 	struct mdss_data_type *mdata;
+	u32 current_opmode;
+	u32 csc_reset;
+	u32 dcm_state = DCM_UNINIT;
 
 	pr_debug("pnum=%x\n", pipe->num);
 
+	if (pipe->mixer && pipe->mixer->ctl && pipe->mixer->ctl->mfd)
+		dcm_state = pipe->mixer->ctl->mfd->dcm_state;
+
 	mdata = mdss_mdp_get_mdata();
 	if ((pipe->flags & MDP_OVERLAY_PP_CFG_EN) &&
 		(pipe->pp_cfg.config_ops & MDP_OVERLAY_PP_CSC_CFG)) {
@@ -825,6 +832,16 @@
 
 	pp_histogram_setup(&opmode, MDSS_PP_SSPP_CFG | pipe->num, pipe->mixer);
 
+	/* Update CSC state only if tuning mode is enable */
+	if (dcm_state == DTM_ENTER) {
+		/* Reset bit 16 to 19 for CSC_STATE in VIG_OP_MODE */
+		csc_reset = 0xFFF0FFFF;
+		current_opmode = readl_relaxed(pipe->base +
+						MDSS_MDP_REG_VIG_OP_MODE);
+		*op |= ((current_opmode & csc_reset) | opmode);
+		return 0;
+	}
+
 	if (pipe->flags & MDP_OVERLAY_PP_CFG_EN) {
 		if ((pipe->pp_cfg.config_ops & MDP_OVERLAY_PP_PA_CFG) &&
 				(mdata->mdp_rev < MDSS_MDP_HW_REV_103)) {
@@ -910,10 +927,15 @@
 	u32 filter_mode;
 	struct mdss_data_type *mdata;
 	u32 src_w, src_h;
+	u32 dcm_state = DCM_UNINIT;
 
 	pr_debug("pipe=%d, change pxl ext=%d\n", pipe->num,
 			pipe->scale.enable_pxl_ext);
 	mdata = mdss_mdp_get_mdata();
+
+	if (pipe->mixer && pipe->mixer->ctl && pipe->mixer->ctl->mfd)
+		dcm_state = pipe->mixer->ctl->mfd->dcm_state;
+
 	if (mdata->mdp_rev >= MDSS_MDP_HW_REV_102 && pipe->src_fmt->is_yuv)
 		filter_mode = MDSS_MDP_SCALE_FILTER_CA;
 	else
@@ -948,12 +970,13 @@
 		pipe->pp_cfg.sharp_cfg.noise_thr = SHARP_NOISE_THR_DEFAULT;
 	}
 
-	if ((pipe->src_fmt->is_yuv) &&
-		!((pipe->dst.w < src_w) || (pipe->dst.h < src_h))) {
-		pp_sharp_config(pipe->base +
-		   MDSS_MDP_REG_VIG_QSEED2_SHARP,
-		   &pipe->pp_res.pp_sts,
-		   &pipe->pp_cfg.sharp_cfg);
+	if (dcm_state != DTM_ENTER &&
+		((pipe->src_fmt->is_yuv) &&
+		!((pipe->dst.w < src_w) || (pipe->dst.h < src_h)))) {
+			pp_sharp_config(pipe->base +
+			   MDSS_MDP_REG_VIG_QSEED2_SHARP,
+			   &pipe->pp_res.pp_sts,
+			   &pipe->pp_cfg.sharp_cfg);
 	}
 
 	if ((src_h != pipe->dst.h) ||
@@ -1155,10 +1178,23 @@
 	char __iomem *pipe_base;
 	u32 pipe_num;
 	struct mdss_data_type *mdata = mdss_mdp_get_mdata();
+	u32 current_opmode;
+	u32 dcm_state = DCM_UNINIT;
 
 	if (pipe == NULL)
 		return -EINVAL;
 
+	if (pipe->mixer && pipe->mixer->ctl && pipe->mixer->ctl->mfd)
+		dcm_state = pipe->mixer->ctl->mfd->dcm_state;
+
+	/* Read IGC state and update the same if tuning mode is enable */
+	if (dcm_state == DTM_ENTER) {
+		current_opmode = readl_relaxed(pipe->base +
+						MDSS_MDP_REG_SSPP_SRC_OP_MODE);
+		*op |= (current_opmode & BIT(16));
+		return ret;
+	}
+
 	/*
 	 * TODO: should this function be responsible for masking multiple
 	 * pipes to be written in dual pipe case?
@@ -2208,6 +2244,20 @@
 	return ret;
 }
 
+static void pp_read_igc_lut_cached(struct mdp_igc_lut_data *cfg)
+{
+	int i;
+	u32 disp_num;
+
+	disp_num = cfg->block - MDP_LOGICAL_BLOCK_DISP_0;
+	for (i = 0; i < IGC_LUT_ENTRIES; i++) {
+		cfg->c0_c1_data[i] =
+			mdss_pp_res->igc_disp_cfg[disp_num].c0_c1_data[i];
+		cfg->c2_data[i] =
+			mdss_pp_res->igc_disp_cfg[disp_num].c2_data[i];
+	}
+}
+
 static void pp_read_igc_lut(struct mdp_igc_lut_data *cfg,
 				char __iomem *addr, u32 blk_idx)
 {
@@ -2328,14 +2378,17 @@
 			&mdss_pp_res->igc_lut_c0c1[disp_num][0];
 		local_cfg.c2_data =
 			&mdss_pp_res->igc_lut_c2[disp_num][0];
-		pp_read_igc_lut(&local_cfg, igc_addr, dspp_num);
-		if (copy_to_user(config->c0_c1_data, local_cfg.c2_data,
+		if (mdata->has_no_lut_read)
+			pp_read_igc_lut_cached(&local_cfg);
+		else
+			pp_read_igc_lut(&local_cfg, igc_addr, dspp_num);
+		if (copy_to_user(config->c0_c1_data, local_cfg.c0_c1_data,
 			config->len * sizeof(u32))) {
 			ret = -EFAULT;
 			mdss_mdp_clk_ctrl(MDP_BLOCK_POWER_OFF, false);
 			goto igc_config_exit;
 		}
-		if (copy_to_user(config->c2_data, local_cfg.c0_c1_data,
+		if (copy_to_user(config->c2_data, local_cfg.c2_data,
 			config->len * sizeof(u32))) {
 			ret = -EFAULT;
 			mdss_mdp_clk_ctrl(MDP_BLOCK_POWER_OFF, false);
@@ -2475,6 +2528,41 @@
 	return ret;
 }
 
+static int pp_read_argc_lut_cached(struct mdp_pgc_lut_data *config)
+{
+	int i;
+	u32 disp_num;
+	struct mdp_pgc_lut_data *pgc_ptr;
+
+	disp_num = PP_BLOCK(config->block) - MDP_LOGICAL_BLOCK_DISP_0;
+	switch (PP_LOCAT(config->block)) {
+	case MDSS_PP_LM_CFG:
+		pgc_ptr = &mdss_pp_res->argc_disp_cfg[disp_num];
+		break;
+	case MDSS_PP_DSPP_CFG:
+		pgc_ptr = &mdss_pp_res->pgc_disp_cfg[disp_num];
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	for (i = 0; i < GC_LUT_SEGMENTS; i++) {
+		config->r_data[i].x_start = pgc_ptr->r_data[i].x_start;
+		config->r_data[i].slope   = pgc_ptr->r_data[i].slope;
+		config->r_data[i].offset  = pgc_ptr->r_data[i].offset;
+
+		config->g_data[i].x_start = pgc_ptr->g_data[i].x_start;
+		config->g_data[i].slope   = pgc_ptr->g_data[i].slope;
+		config->g_data[i].offset  = pgc_ptr->g_data[i].offset;
+
+		config->b_data[i].x_start = pgc_ptr->b_data[i].x_start;
+		config->b_data[i].slope   = pgc_ptr->b_data[i].slope;
+		config->b_data[i].offset  = pgc_ptr->b_data[i].offset;
+	}
+
+	return 0;
+}
+
 /* Note: Assumes that its inputs have been checked by calling function */
 static void pp_update_hist_lut(char __iomem *addr,
 				struct mdp_hist_lut_data *cfg)
@@ -2498,6 +2586,10 @@
 	struct mdp_pgc_lut_data *pgc_ptr;
 	u32 tbl_size, r_size, g_size, b_size;
 	char __iomem *argc_addr = 0;
+	struct mdss_data_type *mdata = mdss_mdp_get_mdata();
+
+	if (mdata == NULL)
+		return -EPERM;
 
 	if ((PP_BLOCK(config->block) < MDP_LOGICAL_BLOCK_DISP_0) ||
 		(PP_BLOCK(config->block) >= MDP_BLOCK_MAX))
@@ -2511,6 +2603,12 @@
 	mutex_lock(&mdss_pp_mutex);
 
 	disp_num = PP_BLOCK(config->block) - MDP_LOGICAL_BLOCK_DISP_0;
+	ret = pp_get_dspp_num(disp_num, &dspp_num);
+	if (ret) {
+		pr_err("%s, no dspp connects to disp %d", __func__, disp_num);
+		goto argc_config_exit;
+	}
+
 	switch (PP_LOCAT(config->block)) {
 	case MDSS_PP_LM_CFG:
 		argc_addr = mdss_mdp_get_mixer_addr_off(dspp_num) +
@@ -2536,12 +2634,6 @@
 	tbl_size = GC_LUT_SEGMENTS * sizeof(struct mdp_ar_gc_lut_data);
 
 	if (config->flags & MDP_PP_OPS_READ) {
-		ret = pp_get_dspp_num(disp_num, &dspp_num);
-		if (ret) {
-			pr_err("%s, no dspp connects to disp %d",
-				__func__, disp_num);
-			goto argc_config_exit;
-		}
 		mdss_mdp_clk_ctrl(MDP_BLOCK_POWER_ON, false);
 		local_cfg = *config;
 		local_cfg.r_data =
@@ -2550,21 +2642,31 @@
 			&mdss_pp_res->gc_lut_g[disp_num][0];
 		local_cfg.b_data =
 			&mdss_pp_res->gc_lut_b[disp_num][0];
-		pp_read_argc_lut(&local_cfg, argc_addr);
-		if (copy_to_user(config->r_data,
-			&mdss_pp_res->gc_lut_r[disp_num][0], tbl_size)) {
+		if (mdata->has_no_lut_read)
+			pp_read_argc_lut_cached(&local_cfg);
+		else
+			pp_read_argc_lut(&local_cfg, argc_addr);
+
+		if ((tbl_size != local_cfg.num_r_stages *
+			sizeof(struct mdp_ar_gc_lut_data)) ||
+			(copy_to_user(config->r_data, local_cfg.r_data,
+				tbl_size))) {
 			mdss_mdp_clk_ctrl(MDP_BLOCK_POWER_OFF, false);
 			ret = -EFAULT;
 			goto argc_config_exit;
 		}
-		if (copy_to_user(config->g_data,
-			&mdss_pp_res->gc_lut_g[disp_num][0], tbl_size)) {
+		if ((tbl_size != local_cfg.num_g_stages *
+			sizeof(struct mdp_ar_gc_lut_data)) ||
+			(copy_to_user(config->g_data, local_cfg.g_data,
+				tbl_size))) {
 			mdss_mdp_clk_ctrl(MDP_BLOCK_POWER_OFF, false);
 			ret = -EFAULT;
 			goto argc_config_exit;
 		}
-		if (copy_to_user(config->b_data,
-			&mdss_pp_res->gc_lut_b[disp_num][0], tbl_size)) {
+		if ((tbl_size != local_cfg.num_b_stages *
+			sizeof(struct mdp_ar_gc_lut_data)) ||
+			(copy_to_user(config->b_data, local_cfg.b_data,
+				tbl_size))) {
 			mdss_mdp_clk_ctrl(MDP_BLOCK_POWER_OFF, false);
 			ret = -EFAULT;
 			goto argc_config_exit;
@@ -3330,8 +3432,11 @@
 		mdss_mdp_clk_ctrl(MDP_BLOCK_POWER_ON, false);
 		sum = pp_hist_read(v_base, hist_info);
 		mdss_mdp_clk_ctrl(MDP_BLOCK_POWER_OFF, false);
-		if (expect_sum && sum != expect_sum)
+		if (expect_sum && sum != expect_sum) {
+			pr_debug("hist error: bin sum incorrect! (%d/%d)\n",
+				sum, expect_sum);
 			ret = -ENODATA;
+		}
 	} else {
 		spin_unlock_irqrestore(&hist_info->hist_lock, flag);
 	}
@@ -3398,6 +3503,9 @@
 				temp_ret = ret;
 			ret = pp_hist_collect(hist, hists[i], ctl_base,
 								exp_sum);
+			if (ret)
+				pr_debug("hist error: dspp[%d] collect %d\n",
+					dspp_num, ret);
 		}
 		for (i = 0; i < hist_cnt; i++) {
 			/* reset read requests and re-intialize completions */
@@ -3495,6 +3603,10 @@
 				temp_ret = ret;
 			ret = pp_hist_collect(hist, hist_info, ctl_base,
 								exp_sum);
+			if (ret)
+				pr_debug("hist error: pipe[%d] collect: %d\n",
+					pipe->num, ret);
+
 			mdss_mdp_pipe_unmap(pipe);
 		}
 		for (i = pipe_num; i < MDSS_PP_ARG_NUM; i++) {
@@ -4586,7 +4698,8 @@
 			break;
 		}
 
-		for (stage = 0; stage < mdss_res->nmixers_intf; stage++)
+		for (stage = 0; stage < (mdss_res->nmixers_intf +
+					 mdss_res->nmixers_wb); stage++)
 			if (ptr == base + MDSS_MDP_REG_CTL_LAYER(stage)) {
 				ret = MDP_PP_OPS_READ | MDP_PP_OPS_WRITE;
 				goto End;
@@ -4677,7 +4790,10 @@
 		} else if (ptr == base + MDSS_MDP_REG_SSPP_SRC_OP_MODE) {
 			ret = MDP_PP_OPS_READ | MDP_PP_OPS_WRITE;
 			break;
-		} else if ((ptr == base + MDSS_MDP_REG_VIG_QSEED2_SHARP)) {
+		/* QSEED2 range */
+		} else if ((ptr >= base + MDSS_MDP_REG_VIG_QSEED2_SHARP) &&
+				(ptr <= base + MDSS_MDP_REG_VIG_QSEED2_SHARP +
+					MDSS_MDP_VIG_QSEED2_SHARP_SIZE)) {
 			ret = MDP_PP_OPS_READ | MDP_PP_OPS_WRITE;
 			break;
 		/* PA range */
@@ -4762,7 +4878,8 @@
 	int stage = 0;
 	struct mdss_mdp_mixer *mixer;
 
-	for (counter = 0; counter < mdss_res->nmixers_intf; counter++) {
+	for (counter = 0; counter < (mdss_res->nmixers_intf +
+					mdss_res->nmixers_wb); counter++) {
 		mixer = mdss_res->mixer_intf + counter;
 		base = mixer->base;
 
@@ -4813,6 +4930,7 @@
 	if ((unsigned int)addr % 4) {
 		ret = 0;
 	} else if (ptr == (mdss_res->mdp_base + MDSS_MDP_REG_HW_VERSION) ||
+	    ptr == (mdss_res->mdp_base + MDSS_REG_HW_VERSION) ||
 	    ptr == (mdss_res->mdp_base + MDSS_MDP_REG_DISP_INTF_SEL)) {
 		ret = MDP_PP_OPS_READ;
 	/* IGC DSPP range */
diff --git a/drivers/video/msm/mdss/mdss_mdp_rotator.c b/drivers/video/msm/mdss/mdss_mdp_rotator.c
old mode 100644
new mode 100755
index 91e6373..ee892e2
--- a/drivers/video/msm/mdss/mdss_mdp_rotator.c
+++ b/drivers/video/msm/mdss/mdss_mdp_rotator.c
@@ -226,7 +226,7 @@
 
 	ret = mdss_mdp_smp_reserve(pipe);
 	if (ret) {
-		pr_err("unable to mdss_mdp_smp_reserve rot data\n");
+		pr_debug("unable to mdss_mdp_smp_reserve rot data\n");
 		return ret;
 	}
 
@@ -642,7 +642,7 @@
 
 	if (rot_pipe) {
 		struct mdss_mdp_mixer *mixer = rot_pipe->mixer;
-		mdss_mdp_pipe_unmap(rot_pipe);
+		mdss_mdp_pipe_destroy(rot_pipe);
 		tmp = mdss_mdp_ctl_mixer_switch(mixer->ctl,
 				MDSS_MDP_WB_CTL_TYPE_BLOCK);
 		if (!tmp)
diff --git a/drivers/video/msm/mdss/mdss_mdp_wb.c b/drivers/video/msm/mdss/mdss_mdp_wb.c
index 454183d..aa17472 100644
--- a/drivers/video/msm/mdss/mdss_mdp_wb.c
+++ b/drivers/video/msm/mdss/mdss_mdp_wb.c
@@ -671,77 +671,30 @@
 int mdss_mdp_wb_get_format(struct msm_fb_data_type *mfd,
 					struct mdp_mixer_cfg *mixer_cfg)
 {
-	int dst_format;
 	struct mdss_mdp_ctl *ctl = mfd_to_ctl(mfd);
 
 	if (!ctl) {
 		pr_err("No panel data!\n");
 		return -EINVAL;
+	} else {
+		mixer_cfg->writeback_format = ctl->dst_format;
 	}
 
-	switch (ctl->dst_format) {
-	case MDP_RGB_888:
-		dst_format = WB_FORMAT_RGB_888;
-		break;
-	case MDP_RGB_565:
-		dst_format = WB_FORMAT_RGB_565;
-		break;
-	case MDP_XRGB_8888:
-		dst_format = WB_FORMAT_xRGB_8888;
-		break;
-	case MDP_ARGB_8888:
-		dst_format = WB_FORMAT_ARGB_8888;
-		break;
-	case MDP_BGRA_8888:
-		dst_format = WB_FORMAT_BGRA_8888;
-		break;
-	case MDP_BGRX_8888:
-		dst_format = WB_FORMAT_BGRX_8888;
-		break;
-	case MDP_Y_CBCR_H2V2_VENUS:
-		dst_format = WB_FORMAT_NV12;
-		break;
-	default:
-		return -EINVAL;
-	}
-	mixer_cfg->writeback_format = dst_format;
 	return 0;
 }
 
-int mdss_mdp_wb_set_format(struct msm_fb_data_type *mfd, int dst_format)
+int mdss_mdp_wb_set_format(struct msm_fb_data_type *mfd, u32 dst_format)
 {
 	struct mdss_mdp_ctl *ctl = mfd_to_ctl(mfd);
 
 	if (!ctl) {
 		pr_err("No panel data!\n");
 		return -EINVAL;
-	}
-
-	switch (dst_format) {
-	case WB_FORMAT_RGB_888:
-		ctl->dst_format = MDP_RGB_888;
-		break;
-	case WB_FORMAT_RGB_565:
-		ctl->dst_format = MDP_RGB_565;
-		break;
-	case WB_FORMAT_xRGB_8888:
-		ctl->dst_format = MDP_XRGB_8888;
-		break;
-	case WB_FORMAT_ARGB_8888:
-		ctl->dst_format = MDP_ARGB_8888;
-		break;
-	case WB_FORMAT_BGRA_8888:
-		ctl->dst_format = MDP_BGRA_8888;
-		break;
-	case WB_FORMAT_BGRX_8888:
-		ctl->dst_format = MDP_BGRX_8888;
-		break;
-	case WB_FORMAT_NV12:
-		ctl->dst_format = MDP_Y_CBCR_H2V2_VENUS;
-		break;
-	default:
-		pr_err("wfd format not supported\n");
+	} else if (dst_format >= MDP_IMGTYPE_LIMIT2) {
+		pr_err("Invalid dst format=%u\n", dst_format);
 		return -EINVAL;
+	} else {
+		ctl->dst_format = dst_format;
 	}
 
 	pr_debug("wfd format %d\n", ctl->dst_format);
diff --git a/drivers/video/msm/mdss/mdss_panel.h b/drivers/video/msm/mdss/mdss_panel.h
index 135a00a..c5ac72e 100644
--- a/drivers/video/msm/mdss/mdss_panel.h
+++ b/drivers/video/msm/mdss/mdss_panel.h
@@ -274,6 +274,17 @@
 	u32 lossy_mode_idx;
 };
 
+struct mdss_mdp_pp_tear_check {
+	u32 tear_check_en;
+	u32 sync_cfg_height;
+	u32 vsync_init_val;
+	u32 sync_threshold_start;
+	u32 sync_threshold_continue;
+	u32 start_pos;
+	u32 rd_ptr_irq;
+	u32 refx100;
+};
+
 struct mdss_panel_info {
 	u32 xres;
 	u32 yres;
@@ -316,6 +327,7 @@
 	u32 panel_power_on;
 
 	uint32_t panel_dead;
+	struct mdss_mdp_pp_tear_check te;
 
 	struct lcd_panel_info lcdc;
 	struct fbc_panel_info fbc;
diff --git a/drivers/video/msm/mdss/msm_mdss_io_8974.c b/drivers/video/msm/mdss/msm_mdss_io_8974.c
index 834ef66..34e383e 100644
--- a/drivers/video/msm/mdss/msm_mdss_io_8974.c
+++ b/drivers/video/msm/mdss/msm_mdss_io_8974.c
@@ -512,6 +512,11 @@
 {
 	int rc = 0;
 
+	if (!ctrl) {
+		pr_err("%s: Invalid arg\n", __func__);
+		return -EINVAL;
+	}
+
 	pr_debug("%s: ndx=%d clk_type=%08x enable=%d\n", __func__,
 		ctrl->ndx, clk_type, enable);
 
@@ -640,7 +645,8 @@
 error_mctrl_stop:
 	mdss_dsi_clk_ctrl_sub(ctrl, clk_type, enable ? 0 : 1);
 error_ctrl:
-	mdss_dsi_clk_ctrl_sub(mctrl, clk_type, 0);
+	if (enable && m_changed)
+		mdss_dsi_clk_ctrl_sub(mctrl, clk_type, 0);
 error_mctrl_start:
 	if (clk_type & DSI_BUS_CLKS) {
 		if (mctrl)
diff --git a/fs/ext4/super.c b/fs/ext4/super.c
index 48609bc..6577ae3 100644
--- a/fs/ext4/super.c
+++ b/fs/ext4/super.c
@@ -43,6 +43,7 @@
 
 #include <linux/kthread.h>
 #include <linux/freezer.h>
+#include <linux/ratelimit.h>
 
 #include "ext4.h"
 #include "ext4_extents.h"
@@ -667,7 +668,7 @@
 	va_start(args, fmt);
 	vaf.fmt = fmt;
 	vaf.va = &args;
-	printk("%sEXT4-fs (%s): %pV\n", prefix, sb->s_id, &vaf);
+	printk_ratelimited("%sEXT4-fs (%s): %pV\n", prefix, sb->s_id, &vaf);
 	va_end(args);
 }
 
diff --git a/include/linux/batterydata-lib.h b/include/linux/batterydata-lib.h
index ff38eb6..f556236 100644
--- a/include/linux/batterydata-lib.h
+++ b/include/linux/batterydata-lib.h
@@ -27,6 +27,7 @@
 #define MAX_SINGLE_LUT_COLS	20
 
 #define MAX_BATT_ID_NUM		4
+#define DEGC_SCALE		10
 
 struct single_row_lut {
 	int x[MAX_SINGLE_LUT_COLS];
diff --git a/include/linux/iopoll.h b/include/linux/iopoll.h
index b882fe2..d085e03 100644
--- a/include/linux/iopoll.h
+++ b/include/linux/iopoll.h
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2012-2013 The Linux Foundation. All rights reserved.
+ * Copyright (c) 2012-2014 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
@@ -17,7 +17,7 @@
 
 #include <linux/kernel.h>
 #include <linux/types.h>
-#include <linux/jiffies.h>
+#include <linux/hrtimer.h>
 #include <linux/delay.h>
 #include <asm-generic/errno.h>
 #include <asm/io.h>
@@ -36,13 +36,13 @@
  */
 #define readl_poll_timeout(addr, val, cond, sleep_us, timeout_us) \
 ({ \
-	unsigned long timeout = jiffies + usecs_to_jiffies(timeout_us); \
+	ktime_t timeout = ktime_add_us(ktime_get(), timeout_us); \
 	might_sleep_if(timeout_us); \
 	for (;;) { \
 		(val) = readl(addr); \
 		if (cond) \
 			break; \
-		if (timeout_us && time_after(jiffies, timeout)) { \
+		if (timeout_us && ktime_compare(ktime_get(), timeout) > 0) { \
 			(val) = readl(addr); \
 			break; \
 		} \
diff --git a/include/linux/ktime.h b/include/linux/ktime.h
index 603bec2..04ad123 100644
--- a/include/linux/ktime.h
+++ b/include/linux/ktime.h
@@ -289,6 +289,25 @@
 	return cmp1.tv64 == cmp2.tv64;
 }
 
+/**
+ * ktime_compare - Compares two ktime_t variables for less, greater or equal
+ * @cmp1:	comparable1
+ * @cmp2:	comparable2
+ *
+ * Returns ...
+ *   cmp1  < cmp2: return <0
+ *   cmp1 == cmp2: return 0
+ *   cmp1  > cmp2: return >0
+ */
+static inline int ktime_compare(const ktime_t cmp1, const ktime_t cmp2)
+{
+	if (cmp1.tv64 < cmp2.tv64)
+		return -1;
+	if (cmp1.tv64 > cmp2.tv64)
+		return 1;
+	return 0;
+}
+
 static inline s64 ktime_to_us(const ktime_t kt)
 {
 	struct timeval tv = ktime_to_timeval(kt);
diff --git a/include/linux/mmc/card.h b/include/linux/mmc/card.h
index 8b604e3..7d51070 100644
--- a/include/linux/mmc/card.h
+++ b/include/linux/mmc/card.h
@@ -454,6 +454,7 @@
 #define CID_MANFID_TOSHIBA	0x11
 #define CID_MANFID_MICRON	0x13
 #define CID_MANFID_SAMSUNG	0x15
+#define CID_MANFID_KINGSTON	0x70
 #define CID_MANFID_HYNIX	0x90
 
 #define END_FIXUP { 0 }
diff --git a/include/linux/mmc/host.h b/include/linux/mmc/host.h
index e53c350..2ed8a05 100644
--- a/include/linux/mmc/host.h
+++ b/include/linux/mmc/host.h
@@ -424,6 +424,8 @@
 		bool		enable;
 		bool		initialized;
 		bool		in_progress;
+		/* freq. transitions are not allowed in invalid state */
+		bool		invalid_state;
 		struct delayed_work work;
 		enum mmc_load	state;
 	} clk_scaling;
diff --git a/include/linux/msm_mdp.h b/include/linux/msm_mdp.h
index 3ec92e6..00eba66 100644
--- a/include/linux/msm_mdp.h
+++ b/include/linux/msm_mdp.h
@@ -119,6 +119,7 @@
 	NOTIFY_TYPE_NO_UPDATE,
 	NOTIFY_TYPE_SUSPEND,
 	NOTIFY_TYPE_UPDATE,
+	NOTIFY_TYPE_BL_UPDATE,
 };
 
 enum {
diff --git a/include/linux/nl80211.h b/include/linux/nl80211.h
index d797797..0b95337 100644
--- a/include/linux/nl80211.h
+++ b/include/linux/nl80211.h
@@ -370,8 +370,18 @@
  *	%NL80211_ATTR_SSID attribute, and can optionally specify the association
  *	IEs in %NL80211_ATTR_IE, %NL80211_ATTR_AUTH_TYPE, %NL80211_ATTR_USE_MFP,
  *	%NL80211_ATTR_MAC, %NL80211_ATTR_WIPHY_FREQ, %NL80211_ATTR_CONTROL_PORT,
- *	%NL80211_ATTR_CONTROL_PORT_ETHERTYPE and
- *	%NL80211_ATTR_CONTROL_PORT_NO_ENCRYPT.
+ *	%NL80211_ATTR_CONTROL_PORT_ETHERTYPE,
+ *	%NL80211_ATTR_CONTROL_PORT_NO_ENCRYPT, %NL80211_ATTR_MAC_HINT, and
+ *	%NL80211_ATTR_WIPHY_FREQ_HINT.
+ *	If included, %NL80211_ATTR_MAC and %NL80211_ATTR_WIPHY_FREQ are
+ *	restrictions on BSS selection, i.e., they effectively prevent roaming
+ *	within the ESS. %NL80211_ATTR_MAC_HINT and %NL80211_ATTR_WIPHY_FREQ_HINT
+ *	can be included to provide a recommendation of the initial BSS while
+ *	allowing the driver to roam to other BSSes within the ESS and also to
+ *	ignore this recommendation if the indicated BSS is not ideal. Only one
+ *	set of BSSID,frequency parameters is used (i.e., either the enforcing
+ *	%NL80211_ATTR_MAC,%NL80211_ATTR_WIPHY_FREQ or the less strict
+ *	%NL80211_ATTR_MAC_HINT and %NL80211_ATTR_WIPHY_FREQ_HINT).
  *	Background scan period can optionally be
  *	specified in %NL80211_ATTR_BG_SCAN_PERIOD,
  *	if not specified default background scan configuration
@@ -637,6 +647,12 @@
  *	(&struct nl80211_vendor_cmd_info) of the supported vendor commands.
  *	This may also be sent as an event with the same attributes.
  *
+ * @NL80211_CMD_SET_QOS_MAP: Set Interworking QoS mapping for IP DSCP values.
+ *	The QoS mapping information is included in %NL80211_ATTR_QOS_MAP. If
+ *	that attribute is not included, QoS mapping is disabled. Since this
+ *	QoS mapping is relevant for IP packets, it is only valid during an
+ *	association. This is cleared on disassociation and AP restart.
+ *
  * @NL80211_CMD_MAX: highest used command number
  * @__NL80211_CMD_AFTER_LAST: internal use
  */
@@ -807,6 +823,8 @@
 
 	NL80211_CMD_VENDOR,
 
+	NL80211_CMD_SET_QOS_MAP,
+
 	/* add new commands above here */
 
 	/* used to define NL80211_CMD_MAX below */
@@ -1446,6 +1464,23 @@
  * @NL80211_ATTR_VENDOR_EVENTS: used for event list advertising in the wiphy
  *	info, containing a nested array of possible events
  *
+ * @NL80211_ATTR_QOS_MAP: IP DSCP mapping for Interworking QoS mapping. This
+ *	data is in the format defined for the payload of the QoS Map Set element
+ *	in IEEE Std 802.11-2012, 8.4.2.97.
+ *
+ * @NL80211_ATTR_MAC_HINT: MAC address recommendation as initial BSS
+ * @NL80211_ATTR_WIPHY_FREQ_HINT: frequency of the recommended initial BSS
+ *
+ * @NL80211_ATTR_MAX_AP_ASSOC_STA: Device attribute that indicates how many
+ *	associated stations are supported in AP mode (including P2P GO); u32.
+ *	Since drivers may not have a fixed limit on the maximum number (e.g.,
+ *	other concurrent operations may affect this), drivers are allowed to
+ *	advertise values that cannot always be met. In such cases, an attempt
+ *	to add a new station entry with @NL80211_CMD_NEW_STATION may fail.
+ *
+ * @NL80211_ATTR_TDLS_PEER_CAPABILITY: flags for TDLS peer capabilities, u32.
+ *	As specified in the &enum nl80211_tdls_peer_capability.
+ *
  * @NL80211_ATTR_MAX: highest attribute number currently defined
  * @__NL80211_ATTR_AFTER_LAST: internal use
  */
@@ -1773,6 +1808,15 @@
 
 	NL80211_ATTR_VENDOR_EVENTS,
 
+	NL80211_ATTR_QOS_MAP,
+
+	NL80211_ATTR_MAC_HINT,
+	NL80211_ATTR_WIPHY_FREQ_HINT,
+
+	NL80211_ATTR_MAX_AP_ASSOC_STA,
+
+	NL80211_ATTR_TDLS_PEER_CAPABILITY,
+
 	/* add attributes here, update the policy in nl80211.c */
 
 	__NL80211_ATTR_AFTER_LAST,
@@ -3256,4 +3300,20 @@
 	__u32 subcmd;
 };
 
+/**
+ * enum nl80211_tdls_peer_capability - TDLS peer flags.
+ *
+ * Used by tdls_mgmt() to determine which conditional elements need
+ * to be added to TDLS Setup frames.
+ *
+ * @NL80211_TDLS_PEER_HT: TDLS peer is HT capable.
+ * @NL80211_TDLS_PEER_VHT: TDLS peer is VHT capable.
+ * @NL80211_TDLS_PEER_WMM: TDLS peer is WMM capable.
+ */
+enum nl80211_tdls_peer_capability {
+	NL80211_TDLS_PEER_HT = 1<<0,
+	NL80211_TDLS_PEER_VHT = 1<<1,
+	NL80211_TDLS_PEER_WMM = 1<<2,
+};
+
 #endif /* __LINUX_NL80211_H */
diff --git a/include/linux/power_supply.h b/include/linux/power_supply.h
index 0065203..0c89a42 100644
--- a/include/linux/power_supply.h
+++ b/include/linux/power_supply.h
@@ -45,6 +45,7 @@
 	POWER_SUPPLY_CHARGE_TYPE_NONE,
 	POWER_SUPPLY_CHARGE_TYPE_TRICKLE,
 	POWER_SUPPLY_CHARGE_TYPE_FAST,
+	POWER_SUPPLY_CHARGE_TYPE_TAPER,
 };
 
 enum {
@@ -230,6 +231,7 @@
 extern int power_supply_am_i_supplied(struct power_supply *psy);
 extern int power_supply_set_battery_charged(struct power_supply *psy);
 extern int power_supply_set_current_limit(struct power_supply *psy, int limit);
+extern int power_supply_set_voltage_limit(struct power_supply *psy, int limit);
 extern int power_supply_set_online(struct power_supply *psy, bool enable);
 extern int power_supply_set_health_state(struct power_supply *psy, int health);
 extern int power_supply_set_present(struct power_supply *psy, bool enable);
@@ -250,6 +252,9 @@
 							{ return -ENOSYS; }
 static inline int power_supply_set_battery_charged(struct power_supply *psy)
 							{ return -ENOSYS; }
+static inline int power_supply_set_voltage_limit(struct power_supply *psy,
+							int limit)
+							{ return -ENOSYS; }
 static inline int power_supply_set_current_limit(struct power_supply *psy,
 							int limit)
 							{ return -ENOSYS; }
diff --git a/include/linux/qseecom.h b/include/linux/qseecom.h
index b8adebb..b63b36e 100644
--- a/include/linux/qseecom.h
+++ b/include/linux/qseecom.h
@@ -138,6 +138,8 @@
 
 struct qseecom_wipe_key_req {
 	enum qseecom_key_management_usage_type usage;
+	int wipe_key_flag;/* 1->remove key from storage(alone with clear key) */
+			  /* 0->do not remove from storage (clear key) */
 };
 
 struct qseecom_update_key_userinfo_req {
diff --git a/include/linux/usb/android.h b/include/linux/usb/android.h
index 8d5e51b..4accfa0 100644
--- a/include/linux/usb/android.h
+++ b/include/linux/usb/android.h
@@ -29,6 +29,7 @@
 	bool internal_ums;
 	char streaming_func[MAX_STREAMING_FUNCS][FUNC_NAME_LEN];
 	int  streaming_func_count;
+	u32 uicc_nluns;
 };
 
 #ifndef CONFIG_TARGET_CORE
diff --git a/include/linux/usb/hcd.h b/include/linux/usb/hcd.h
index f9dec0b..ac0428d 100644
--- a/include/linux/usb/hcd.h
+++ b/include/linux/usb/hcd.h
@@ -352,6 +352,7 @@
 	void	(*dump_regs)(struct usb_hcd *);
 	void	(*set_autosuspend_delay)(struct usb_device *);
 	void	(*reset_sof_bug_handler)(struct usb_hcd *hcd, u32 val);
+	void	(*set_autosuspend)(struct usb_hcd *hcd, int enable_autosuspend);
 };
 
 extern int usb_hcd_link_urb_to_ep(struct usb_hcd *hcd, struct urb *urb);
diff --git a/include/linux/usb/msm_ext_chg.h b/include/linux/usb/msm_ext_chg.h
index 596ab49..9dbac1c 100644
--- a/include/linux/usb/msm_ext_chg.h
+++ b/include/linux/usb/msm_ext_chg.h
@@ -36,4 +36,7 @@
 /* To tell kernel about voltage request result */
 #define MSM_USB_EXT_CHG_RESULT _IOW('M', 3, int)
 
+/* To tell kernel whether charger connected is external charger or not */
+#define MSM_USB_EXT_CHG_TYPE _IOW('M', 4, int)
+
 #endif /* __LINUX_USB_MSM_EXT_CHG_H */
diff --git a/include/linux/usb/msm_hsusb.h b/include/linux/usb/msm_hsusb.h
index 195800f..4ecacc7 100644
--- a/include/linux/usb/msm_hsusb.h
+++ b/include/linux/usb/msm_hsusb.h
@@ -346,7 +346,10 @@
  * @chg_check_timer: The timer used to implement the workaround to detect
  *               very slow plug in of wall charger.
  * @ui_enabled: USB Intterupt is enabled or disabled.
- * @pm_done: Indicates whether USB is PM resumed
+ * @pm_done: It is used to increment the pm counter using pm_runtime_get_sync.
+	     This handles the race case when PM resume thread returns before
+	     the charger detection starts. When USB is disconnected pm_done
+	     is set to true.
  */
 struct msm_otg {
 	struct usb_phy phy;
diff --git a/include/linux/usb/otg.h b/include/linux/usb/otg.h
index ae3ffe4..7c82579 100644
--- a/include/linux/usb/otg.h
+++ b/include/linux/usb/otg.h
@@ -149,6 +149,9 @@
 	int	(*set_suspend)(struct usb_phy *x,
 				int suspend);
 
+	/* To enable/disable phy autosuspend feature */
+	int	(*set_phy_autosuspend)(struct usb_phy *x,
+					int enable_autosuspend);
 };
 
 
@@ -288,6 +291,15 @@
 }
 
 static inline int
+usb_phy_set_autosuspend(struct usb_phy *x, int enable_autosuspend)
+{
+	if (x && x->set_phy_autosuspend != NULL)
+		return x->set_phy_autosuspend(x, enable_autosuspend);
+	else
+		return 0;
+}
+
+static inline int
 otg_start_srp(struct usb_otg *otg)
 {
 	if (otg && otg->start_srp)
diff --git a/include/linux/usb_usual.h b/include/linux/usb_usual.h
index 17df360..ff30988 100644
--- a/include/linux/usb_usual.h
+++ b/include/linux/usb_usual.h
@@ -64,7 +64,9 @@
 	US_FLAG(NO_READ_CAPACITY_16,	0x00080000)		\
 		/* cannot handle READ_CAPACITY_16 */		\
 	US_FLAG(INITIAL_READ10,	0x00100000)			\
-		/* Initial READ(10) (and others) must be retried */
+		/* Initial READ(10) (and others) must be retried */ \
+	US_FLAG(TUR_AFTER_WRITE, 0x00200000)			\
+		/* 5 TEST_UNIT_READY after 8 WRITE(10) */ \
 
 #define US_FLAG(name, value)	US_FL_##name = value ,
 enum { US_DO_ALL_FLAGS };
diff --git a/include/linux/videodev2.h b/include/linux/videodev2.h
index f8f1ef4..174a575 100644
--- a/include/linux/videodev2.h
+++ b/include/linux/videodev2.h
@@ -1936,6 +1936,18 @@
 #define V4L2_CID_MPEG_VIDC_VIDEO_HIER_P_NUM_LAYERS \
 		(V4L2_CID_MPEG_MSM_VIDC_BASE + 43)
 
+#define V4L2_CID_MPEG_VIDC_VIDEO_ENABLE_INITIAL_QP \
+		(V4L2_CID_MPEG_MSM_VIDC_BASE + 44)
+
+#define V4L2_CID_MPEG_VIDC_VIDEO_I_FRAME_QP \
+		(V4L2_CID_MPEG_MSM_VIDC_BASE + 45)
+
+#define V4L2_CID_MPEG_VIDC_VIDEO_P_FRAME_QP \
+		(V4L2_CID_MPEG_MSM_VIDC_BASE + 46)
+
+#define V4L2_CID_MPEG_VIDC_VIDEO_B_FRAME_QP \
+		(V4L2_CID_MPEG_MSM_VIDC_BASE + 47)
+
 /*  Camera class control IDs */
 #define V4L2_CID_CAMERA_CLASS_BASE 	(V4L2_CTRL_CLASS_CAMERA | 0x900)
 #define V4L2_CID_CAMERA_CLASS 		(V4L2_CTRL_CLASS_CAMERA | 1)
diff --git a/include/media/msm_cam_sensor.h b/include/media/msm_cam_sensor.h
index 8199643..46cec76 100644
--- a/include/media/msm_cam_sensor.h
+++ b/include/media/msm_cam_sensor.h
@@ -480,8 +480,8 @@
 	CFG_GET_ACTUATOR_INFO,
 	CFG_SET_ACTUATOR_INFO,
 	CFG_SET_DEFAULT_FOCUS,
-	CFG_SET_POSITION,
 	CFG_MOVE_FOCUS,
+	CFG_SET_POSITION,
 };
 
 enum actuator_type {
@@ -658,10 +658,10 @@
 	_IOWR('V', BASE_VIDIOC_PRIVATE + 3, uint32_t)
 
 #define VIDIOC_MSM_CSIPHY_IO_CFG \
-	_IOWR('V', BASE_VIDIOC_PRIVATE + 4, struct csid_cfg_data)
+	_IOWR('V', BASE_VIDIOC_PRIVATE + 4, struct csiphy_cfg_data)
 
 #define VIDIOC_MSM_CSID_IO_CFG \
-	_IOWR('V', BASE_VIDIOC_PRIVATE + 5, struct csiphy_cfg_data)
+	_IOWR('V', BASE_VIDIOC_PRIVATE + 5, struct csid_cfg_data)
 
 #define VIDIOC_MSM_ACTUATOR_CFG \
 	_IOWR('V', BASE_VIDIOC_PRIVATE + 6, struct msm_actuator_cfg_data)
diff --git a/include/media/msm_media_info.h b/include/media/msm_media_info.h
index ddf9c8e..663809e 100644
--- a/include/media/msm_media_info.h
+++ b/include/media/msm_media_info.h
@@ -158,8 +158,8 @@
 static inline unsigned int VENUS_BUFFER_SIZE(
 	int color_fmt, int width, int height)
 {
-	unsigned int uv_alignment;
-	unsigned int size = 0;
+	const unsigned int extra_size = 8*1024;
+	unsigned int uv_alignment = 0, size = 0;
 	unsigned int y_plane, uv_plane, y_stride,
 		uv_stride, y_sclines, uv_sclines;
 	if (!width || !height)
@@ -175,7 +175,7 @@
 		uv_alignment = 4096;
 		y_plane = y_stride * y_sclines;
 		uv_plane = uv_stride * uv_sclines + uv_alignment;
-		size = y_plane + uv_plane;
+		size = y_plane + uv_plane + extra_size;
 		size = MSM_MEDIA_ALIGN(size, 4096);
 		break;
 	default:
diff --git a/include/media/msmb_pproc.h b/include/media/msmb_pproc.h
index 26c1048..df9f9e7 100644
--- a/include/media/msmb_pproc.h
+++ b/include/media/msmb_pproc.h
@@ -232,6 +232,9 @@
 #define VIDIOC_MSM_CPP_APPEND_STREAM_BUFF_INFO \
 	_IOWR('V', BASE_VIDIOC_PRIVATE + 15, struct msm_camera_v4l2_ioctl_t)
 
+#define VIDIOC_MSM_CPP_SET_CLOCK \
+	_IOWR('V', BASE_VIDIOC_PRIVATE + 16, struct msm_camera_v4l2_ioctl_t)
+
 #define V4L2_EVENT_CPP_FRAME_DONE  (V4L2_EVENT_PRIVATE_START + 0)
 #define V4L2_EVENT_VPE_FRAME_DONE  (V4L2_EVENT_PRIVATE_START + 1)
 
diff --git a/include/net/cfg80211.h b/include/net/cfg80211.h
index ecaef21..8b833dd 100644
--- a/include/net/cfg80211.h
+++ b/include/net/cfg80211.h
@@ -58,6 +58,8 @@
  * structures here describe these capabilities in detail.
  */
 
+#define TDLS_MGMT_VERSION2 1
+
 /*
  * wireless hardware capability structures
  */
@@ -1263,8 +1265,14 @@
  *
  * @channel: The channel to use or %NULL if not specified (auto-select based
  *	on scan results)
+ * @channel_hint: The channel of the recommended BSS for initial connection or
+ *	%NULL if not specified
  * @bssid: The AP BSSID or %NULL if not specified (auto-select based on scan
  *	results)
+ * @bssid_hint: The recommended AP BSSID for initial connection to the BSS or
+ *	%NULL if not specified. Unlike the @bssid parameter, the driver is
+ *	allowed to ignore this @bssid_hint if it has knowledge of a better BSS
+ *	to use.
  * @ssid: SSID
  * @ssid_len: Length of ssid in octets
  * @auth_type: Authentication type (algorithm)
@@ -1285,7 +1293,9 @@
  */
 struct cfg80211_connect_params {
 	struct ieee80211_channel *channel;
+	struct ieee80211_channel *channel_hint;
 	u8 *bssid;
+	const u8 *bssid_hint;
 	u8 *ssid;
 	size_t ssid_len;
 	enum nl80211_auth_type auth_type;
@@ -1407,6 +1417,50 @@
 };
 
 /**
+ * struct cfg80211_dscp_exception - DSCP exception
+ *
+ * @dscp: DSCP value that does not adhere to the user priority range definition
+ * @up: user priority value to which the corresponding DSCP value belongs
+ */
+struct cfg80211_dscp_exception {
+	u8 dscp;
+	u8 up;
+};
+
+/**
+ * struct cfg80211_dscp_range - DSCP range definition for user priority
+ *
+ * @low: lowest DSCP value of this user priority range, inclusive
+ * @high: highest DSCP value of this user priority range, inclusive
+ */
+struct cfg80211_dscp_range {
+	u8 low;
+	u8 high;
+};
+
+/* QoS Map Set element length defined in IEEE Std 802.11-2012, 8.4.2.97 */
+#define IEEE80211_QOS_MAP_MAX_EX	21
+#define IEEE80211_QOS_MAP_LEN_MIN	16
+#define IEEE80211_QOS_MAP_LEN_MAX \
+	(IEEE80211_QOS_MAP_LEN_MIN + 2 * IEEE80211_QOS_MAP_MAX_EX)
+
+/**
+ * struct cfg80211_qos_map - QoS Map Information
+ *
+ * This struct defines the Interworking QoS map setting for DSCP values
+ *
+ * @num_des: number of DSCP exceptions (0..21)
+ * @dscp_exception: optionally up to maximum of 21 DSCP exceptions from
+ *	the user priority DSCP range definition
+ * @up: DSCP range definition for a particular user priority
+ */
+struct cfg80211_qos_map {
+	u8 num_des;
+	struct cfg80211_dscp_exception dscp_exception[IEEE80211_QOS_MAP_MAX_EX];
+	struct cfg80211_dscp_range up[8];
+};
+
+/**
  * struct cfg80211_ops - backend description for wireless configuration
  *
  * This struct is registered by fullmac card drivers and/or wireless stacks
@@ -1597,6 +1651,7 @@
  *	when number of MAC addresses entries is passed as 0. Drivers which
  *	advertise the support for MAC based ACL have to implement this callback.
  *
+ * @set_qos_map: Set QoS mapping information to the driver
  */
 struct cfg80211_ops {
 	int	(*suspend)(struct wiphy *wiphy, struct cfg80211_wowlan *wow);
@@ -1781,7 +1836,8 @@
 
 	int	(*tdls_mgmt)(struct wiphy *wiphy, struct net_device *dev,
 			     u8 *peer, u8 action_code,  u8 dialog_token,
-			     u16 status_code, const u8 *buf, size_t len);
+			     u16 status_code, u32 peer_capability,
+			     const u8 *buf, size_t len);
 	int	(*tdls_oper)(struct wiphy *wiphy, struct net_device *dev,
 			     u8 *peer, enum nl80211_tdls_operation oper);
 
@@ -1798,6 +1854,10 @@
 
 	int (*set_mac_acl)(struct wiphy *wiphy, struct net_device *dev,
 			   const struct cfg80211_acl_data *params);
+	int (*set_qos_map)(struct wiphy *wiphy,
+			   struct net_device *dev,
+			   struct cfg80211_qos_map *qos_map);
+
 };
 
 /*
@@ -2177,6 +2237,11 @@
  * @n_vendor_commands: number of vendor commands
  * @vendor_events: array of vendor events supported by the hardware
  * @n_vendor_events: number of vendor events
+ *
+ * @max_ap_assoc_sta: maximum number of associated stations supported in AP mode
+ *	(including P2P GO) or 0 to indicate no such limit is advertised. The
+ *	driver is allowed to advertise a theoretical limit that it can reach in
+ *	some cases, but may not always reach.
  */
 struct wiphy {
 	/* assign these fields before you register the wiphy */
@@ -2285,6 +2350,8 @@
 	const struct nl80211_vendor_cmd_info *vendor_events;
 	int n_vendor_commands, n_vendor_events;
 
+	u16 max_ap_assoc_sta;
+
 	char priv[0] __attribute__((__aligned__(NETDEV_ALIGN)));
 };
 
@@ -2705,8 +2772,10 @@
 /**
  * cfg80211_classify8021d - determine the 802.1p/1d tag for a data frame
  * @skb: the data frame
+ * @qos_map: Interworking QoS mapping or %NULL if not in use
  */
-unsigned int cfg80211_classify8021d(struct sk_buff *skb);
+unsigned int cfg80211_classify8021d(struct sk_buff *skb,
+				    struct cfg80211_qos_map *qos_map);
 
 /**
  * cfg80211_find_ie - find information element in data
@@ -3730,6 +3799,15 @@
  * @gfp: context flags
  */
 void cfg80211_ap_stopped(struct net_device *netdev, gfp_t gfp);
+/**
+ * cfg80211_is_gratuitous_arp_unsolicited_na - packet is grat. ARP/unsol. NA
+ * @skb: the input packet, must be an ethernet frame already
+ *
+ * Return: %true if the packet is a gratuitous ARP or unsolicited NA packet.
+ * This is used to drop packets that shouldn't occur because the AP implements
+ * a proxy service.
+ */
+bool cfg80211_is_gratuitous_arp_unsolicited_na(struct sk_buff *skb);
 
 /* Logging, debugging and troubleshooting/diagnostic helpers. */
 
diff --git a/include/sound/apr_audio-v2.h b/include/sound/apr_audio-v2.h
index 1c6ea04..3b8b1cc 100644
--- a/include/sound/apr_audio-v2.h
+++ b/include/sound/apr_audio-v2.h
@@ -2264,6 +2264,7 @@
 #define VPM_TX_SM_ECNS_COPP_TOPOLOGY			0x00010F71
 #define VPM_TX_DM_FLUENCE_COPP_TOPOLOGY			0x00010F72
 #define VPM_TX_QMIC_FLUENCE_COPP_TOPOLOGY		0x00010F75
+#define VPM_TX_DM_RFECNS_COPP_TOPOLOGY			0x00010F86
 
 /* Memory map regions command payload used by the
  * #ASM_CMD_SHARED_MEM_MAP_REGIONS ,#ADM_CMD_SHARED_MEM_MAP_REGIONS
diff --git a/include/sound/q6asm-v2.h b/include/sound/q6asm-v2.h
index 1635fc3..07199e0 100644
--- a/include/sound/q6asm-v2.h
+++ b/include/sound/q6asm-v2.h
@@ -180,6 +180,7 @@
 	int					   stream_id;
 	/* audio cache operations fptr*/
 	int (*fptr_cache_ops)(struct audio_buffer *abuff, int cache_op);
+	atomic_t               unmap_cb_success;
 };
 
 void q6asm_audio_client_free(struct audio_client *ac);
diff --git a/include/trace/events/exception.h b/include/trace/events/exception.h
index 110e920..69dbf7c 100644
--- a/include/trace/events/exception.h
+++ b/include/trace/events/exception.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2012, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2012-2013, The Linux Foundation. All rights reserved.
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 and
@@ -63,6 +63,27 @@
 	TP_printk("pc:%p", __entry->prog_cnt)
 );
 
+TRACE_EVENT(unhandled_abort,
+
+	TP_PROTO(struct pt_regs *regs, unsigned long addr, unsigned int fsr),
+
+	TP_ARGS(regs, addr, fsr),
+
+	TP_STRUCT__entry(
+		__field(struct pt_regs *, regs)
+		__field(unsigned long, addr)
+		__field(unsigned int, fsr)
+	),
+
+	TP_fast_assign(
+		__entry->regs	= regs;
+		__entry->addr	= addr;
+		__entry->fsr	= fsr;
+	),
+
+	TP_printk("addr:%lu, fsr:%u", __entry->addr, __entry->fsr)
+);
+
 #endif
 
 #include <trace/define_trace.h>
diff --git a/kernel/ksysfs.c b/kernel/ksysfs.c
index 4e316e1..8715a79 100644
--- a/kernel/ksysfs.c
+++ b/kernel/ksysfs.c
@@ -141,6 +141,23 @@
 }
 KERNEL_ATTR_RO(fscaps);
 
+int rcu_expedited;
+static ssize_t rcu_expedited_show(struct kobject *kobj,
+				  struct kobj_attribute *attr, char *buf)
+{
+	return sprintf(buf, "%d\n", rcu_expedited);
+}
+static ssize_t rcu_expedited_store(struct kobject *kobj,
+				   struct kobj_attribute *attr,
+				   const char *buf, size_t count)
+{
+	if (kstrtoint(buf, 0, &rcu_expedited))
+		return -EINVAL;
+
+	return count;
+}
+KERNEL_ATTR_RW(rcu_expedited);
+
 /*
  * Make /sys/kernel/notes give the raw contents of our kernel .notes section.
  */
@@ -182,6 +199,7 @@
 	&kexec_crash_size_attr.attr,
 	&vmcoreinfo_attr.attr,
 #endif
+	&rcu_expedited_attr.attr,
 	NULL
 };
 
diff --git a/kernel/rcu.h b/kernel/rcu.h
index 8ba99cd..20dfba5 100644
--- a/kernel/rcu.h
+++ b/kernel/rcu.h
@@ -109,4 +109,6 @@
 	}
 }
 
+extern int rcu_expedited;
+
 #endif /* __LINUX_RCU_H */
diff --git a/kernel/rcupdate.c b/kernel/rcupdate.c
index a86f174..5746f18 100644
--- a/kernel/rcupdate.c
+++ b/kernel/rcupdate.c
@@ -45,12 +45,15 @@
 #include <linux/mutex.h>
 #include <linux/export.h>
 #include <linux/hardirq.h>
+#include <linux/module.h>
 
 #define CREATE_TRACE_POINTS
 #include <trace/events/rcu.h>
 
 #include "rcu.h"
 
+module_param(rcu_expedited, int, 0);
+
 #ifdef CONFIG_DEBUG_LOCK_ALLOC
 static struct lock_class_key rcu_lock_key;
 struct lockdep_map rcu_lock_map =
diff --git a/kernel/rcutiny_plugin.h b/kernel/rcutiny_plugin.h
index 22ecea0..5a0f324 100644
--- a/kernel/rcutiny_plugin.h
+++ b/kernel/rcutiny_plugin.h
@@ -750,7 +750,10 @@
 		return;
 
 	/* Once we get past the fastpath checks, same code as rcu_barrier(). */
-	rcu_barrier();
+	if (rcu_expedited)
+		synchronize_rcu_expedited();
+	else
+		rcu_barrier();
 }
 EXPORT_SYMBOL_GPL(synchronize_rcu);
 
diff --git a/kernel/rcutree.c b/kernel/rcutree.c
index 4eec66e..e269782 100644
--- a/kernel/rcutree.c
+++ b/kernel/rcutree.c
@@ -1926,7 +1926,10 @@
 			   "Illegal synchronize_sched() in RCU-sched read-side critical section");
 	if (rcu_blocking_is_gp())
 		return;
-	wait_rcu_gp(call_rcu_sched);
+	if (rcu_expedited)
+		synchronize_sched_expedited();
+	else
+		wait_rcu_gp(call_rcu_sched);
 }
 EXPORT_SYMBOL_GPL(synchronize_sched);
 
@@ -1947,7 +1950,10 @@
 			   "Illegal synchronize_rcu_bh() in RCU-bh read-side critical section");
 	if (rcu_blocking_is_gp())
 		return;
-	wait_rcu_gp(call_rcu_bh);
+	if (rcu_expedited)
+		synchronize_rcu_bh_expedited();
+	else
+		wait_rcu_gp(call_rcu_bh);
 }
 EXPORT_SYMBOL_GPL(synchronize_rcu_bh);
 
diff --git a/kernel/rcutree_plugin.h b/kernel/rcutree_plugin.h
index c023464..beafb9c 100644
--- a/kernel/rcutree_plugin.h
+++ b/kernel/rcutree_plugin.h
@@ -737,7 +737,10 @@
 			   "Illegal synchronize_rcu() in RCU read-side critical section");
 	if (!rcu_scheduler_active)
 		return;
-	wait_rcu_gp(call_rcu);
+	if (rcu_expedited)
+		synchronize_rcu_expedited();
+	else
+		wait_rcu_gp(call_rcu);
 }
 EXPORT_SYMBOL_GPL(synchronize_rcu);
 
diff --git a/mm/debug-pagealloc.c b/mm/debug-pagealloc.c
index bc91cba..87dde36 100644
--- a/mm/debug-pagealloc.c
+++ b/mm/debug-pagealloc.c
@@ -6,6 +6,14 @@
 #include <linux/poison.h>
 #include <linux/ratelimit.h>
 
+#ifndef mark_addr_rdonly
+#define mark_addr_rdonly(a)
+#endif
+
+#ifndef mark_addr_rdwrite
+#define mark_addr_rdwrite(a)
+#endif
+
 static inline void set_page_poison(struct page *page)
 {
 	__set_bit(PAGE_DEBUG_FLAG_POISON, &page->debug_flags);
@@ -27,6 +35,7 @@
 
 	set_page_poison(page);
 	memset(addr, PAGE_POISON, PAGE_SIZE);
+	mark_addr_rdonly(addr);
 	kunmap_atomic(addr);
 }
 
@@ -82,6 +91,7 @@
 
 	addr = kmap_atomic(page);
 	check_poison_mem(addr, PAGE_SIZE);
+	mark_addr_rdwrite(addr);
 	clear_page_poison(page);
 	kunmap_atomic(addr);
 }
diff --git a/net/core/pktgen.c b/net/core/pktgen.c
index b81369b..f6c785c 100644
--- a/net/core/pktgen.c
+++ b/net/core/pktgen.c
@@ -419,20 +419,6 @@
 #define REMOVE 1
 #define FIND   0
 
-static inline ktime_t ktime_now(void)
-{
-	struct timespec ts;
-	ktime_get_ts(&ts);
-
-	return timespec_to_ktime(ts);
-}
-
-/* This works even if 32 bit because of careful byte order choice */
-static inline int ktime_lt(const ktime_t cmp1, const ktime_t cmp2)
-{
-	return cmp1.tv64 < cmp2.tv64;
-}
-
 static const char version[] =
 	"Packet Generator for packet performance testing. "
 	"Version: " VERSION "\n";
@@ -677,7 +663,7 @@
 	seq_puts(seq, "\n");
 
 	/* not really stopped, more like last-running-at */
-	stopped = pkt_dev->running ? ktime_now() : pkt_dev->stopped_at;
+	stopped = pkt_dev->running ? ktime_get() : pkt_dev->stopped_at;
 	idle = pkt_dev->idle_acc;
 	do_div(idle, NSEC_PER_USEC);
 
@@ -2141,12 +2127,12 @@
 		return;
 	}
 
-	start_time = ktime_now();
+	start_time = ktime_get();
 	if (remaining < 100000) {
 		/* for small delays (<100us), just loop until limit is reached */
 		do {
-			end_time = ktime_now();
-		} while (ktime_lt(end_time, spin_until));
+			end_time = ktime_get();
+		} while (ktime_compare(end_time, spin_until) < 0);
 	} else {
 		/* see do_nanosleep */
 		hrtimer_init_sleeper(&t, current);
@@ -2162,7 +2148,7 @@
 			hrtimer_cancel(&t.timer);
 		} while (t.task && pkt_dev->running && !signal_pending(current));
 		__set_current_state(TASK_RUNNING);
-		end_time = ktime_now();
+		end_time = ktime_get();
 	}
 
 	pkt_dev->idle_acc += ktime_to_ns(ktime_sub(end_time, start_time));
@@ -3008,8 +2994,7 @@
 			pktgen_clear_counters(pkt_dev);
 			pkt_dev->running = 1;	/* Cranke yeself! */
 			pkt_dev->skb = NULL;
-			pkt_dev->started_at =
-				pkt_dev->next_tx = ktime_now();
+			pkt_dev->started_at = pkt_dev->next_tx = ktime_get();
 
 			set_pkt_overhead(pkt_dev);
 
@@ -3168,7 +3153,7 @@
 
 	kfree_skb(pkt_dev->skb);
 	pkt_dev->skb = NULL;
-	pkt_dev->stopped_at = ktime_now();
+	pkt_dev->stopped_at = ktime_get();
 	pkt_dev->running = 0;
 
 	show_results(pkt_dev, nr_frags);
@@ -3187,7 +3172,7 @@
 			continue;
 		if (best == NULL)
 			best = pkt_dev;
-		else if (ktime_lt(pkt_dev->next_tx, best->next_tx))
+		else if (ktime_compare(pkt_dev->next_tx, best->next_tx) < 0)
 			best = pkt_dev;
 	}
 	if_unlock(t);
@@ -3272,14 +3257,14 @@
 
 static void pktgen_resched(struct pktgen_dev *pkt_dev)
 {
-	ktime_t idle_start = ktime_now();
+	ktime_t idle_start = ktime_get();
 	schedule();
-	pkt_dev->idle_acc += ktime_to_ns(ktime_sub(ktime_now(), idle_start));
+	pkt_dev->idle_acc += ktime_to_ns(ktime_sub(ktime_get(), idle_start));
 }
 
 static void pktgen_wait_for_skb(struct pktgen_dev *pkt_dev)
 {
-	ktime_t idle_start = ktime_now();
+	ktime_t idle_start = ktime_get();
 
 	while (atomic_read(&(pkt_dev->skb->users)) != 1) {
 		if (signal_pending(current))
@@ -3290,7 +3275,7 @@
 		else
 			cpu_relax();
 	}
-	pkt_dev->idle_acc += ktime_to_ns(ktime_sub(ktime_now(), idle_start));
+	pkt_dev->idle_acc += ktime_to_ns(ktime_sub(ktime_get(), idle_start));
 }
 
 static void pktgen_xmit(struct pktgen_dev *pkt_dev)
@@ -3312,7 +3297,7 @@
 	 * "never transmit"
 	 */
 	if (unlikely(pkt_dev->delay == ULLONG_MAX)) {
-		pkt_dev->next_tx = ktime_add_ns(ktime_now(), ULONG_MAX);
+		pkt_dev->next_tx = ktime_add_ns(ktime_get(), ULONG_MAX);
 		return;
 	}
 
diff --git a/net/ipv4/sysfs_net_ipv4.c b/net/ipv4/sysfs_net_ipv4.c
index 0cbbf10..699075a 100644
--- a/net/ipv4/sysfs_net_ipv4.c
+++ b/net/ipv4/sysfs_net_ipv4.c
@@ -53,6 +53,9 @@
 CREATE_IPV4_FILE(tcp_rmem_def, sysctl_tcp_rmem[1]);
 CREATE_IPV4_FILE(tcp_rmem_max, sysctl_tcp_rmem[2]);
 
+CREATE_IPV4_FILE(tcp_delack_seg, sysctl_tcp_delack_seg);
+CREATE_IPV4_FILE(tcp_use_userconfig, sysctl_tcp_use_userconfig);
+
 static struct attribute *ipv4_attrs[] = {
 	&tcp_wmem_min_attr.attr,
 	&tcp_wmem_def_attr.attr,
@@ -60,6 +63,8 @@
 	&tcp_rmem_min_attr.attr,
 	&tcp_rmem_def_attr.attr,
 	&tcp_rmem_max_attr.attr,
+	&tcp_delack_seg_attr.attr,
+	&tcp_use_userconfig_attr.attr,
 	NULL
 };
 
diff --git a/net/mac80211/cfg.c b/net/mac80211/cfg.c
index 685553b..ff11148 100644
--- a/net/mac80211/cfg.c
+++ b/net/mac80211/cfg.c
@@ -2440,8 +2440,8 @@
 
 static int ieee80211_tdls_mgmt(struct wiphy *wiphy, struct net_device *dev,
 			       u8 *peer, u8 action_code, u8 dialog_token,
-			       u16 status_code, const u8 *extra_ies,
-			       size_t extra_ies_len)
+			       u16 status_code, u32 peer_capability,
+			       const u8 *extra_ies, size_t extra_ies_len)
 {
 	struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
 	struct ieee80211_local *local = sdata->local;
diff --git a/net/mac80211/wme.c b/net/mac80211/wme.c
index 89511be..262c305 100644
--- a/net/mac80211/wme.c
+++ b/net/mac80211/wme.c
@@ -134,7 +134,7 @@
 
 	/* use the data classifier to determine what 802.1d tag the
 	 * data frame has */
-	skb->priority = cfg80211_classify8021d(skb);
+	skb->priority = cfg80211_classify8021d(skb, NULL);
 
 	return ieee80211_downgrade_queue(local, skb);
 }
diff --git a/net/wireless/db.txt b/net/wireless/db.txt
index f6c74c9..6a77ffc 100644
--- a/net/wireless/db.txt
+++ b/net/wireless/db.txt
@@ -266,6 +266,9 @@
 
 country DZ:
 	(2402 - 2482 @ 40), (N/A, 20)
+	(5150 - 5250 @ 80), (N/A, 23)
+	(5250 - 5350 @ 80), (N/A,23), DFS
+	(5470 - 5670 @ 80), (N/A, 20), DFS
 
 country EC:
 	(2402 - 2482 @ 40), (N/A, 20)
@@ -416,8 +419,8 @@
 
 country ID:
 	# ref: http://www.postel.go.id/content/ID/regulasi/standardisasi/kepdir/bwa%205,8%20ghz.pdf
-	(2402 - 2482 @ 20), (N/A, 20)
-	(5735 - 5815 @ 20), (N/A, 23)
+	(2402 - 2482 @ 20), (N/A, 30)
+	(5735 - 5815 @ 20), (N/A, 30)
 
 country IE: DFS-ETSI
 	(2402 - 2482 @ 40), (N/A, 20)
diff --git a/net/wireless/ibss.c b/net/wireless/ibss.c
index 30f20fe..9890342 100644
--- a/net/wireless/ibss.c
+++ b/net/wireless/ibss.c
@@ -155,6 +155,10 @@
 	kfree(wdev->connect_keys);
 	wdev->connect_keys = NULL;
 
+	if (rdev->ops->set_qos_map) {
+		rdev->ops->set_qos_map(&rdev->wiphy, dev, NULL);
+	}
+
 	/*
 	 * Delete all the keys ... pairwise keys can't really
 	 * exist any more anyway, but default keys might.
diff --git a/net/wireless/mesh.c b/net/wireless/mesh.c
index ba21ab2..c892cce 100644
--- a/net/wireless/mesh.c
+++ b/net/wireless/mesh.c
@@ -152,8 +152,12 @@
 		return -ENOTCONN;
 
 	err = rdev->ops->leave_mesh(&rdev->wiphy, dev);
-	if (!err)
+	if (!err) {
 		wdev->mesh_id_len = 0;
+		if (rdev->ops->set_qos_map) {
+			rdev->ops->set_qos_map(&rdev->wiphy, dev, NULL);
+		}
+	}
 	return err;
 }
 
diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c
index 4a3719b..c3adef8 100644
--- a/net/wireless/nl80211.c
+++ b/net/wireless/nl80211.c
@@ -237,6 +237,11 @@
 	[NL80211_ATTR_VENDOR_ID] = { .type = NLA_U32 },
 	[NL80211_ATTR_VENDOR_SUBCMD] = { .type = NLA_U32 },
 	[NL80211_ATTR_VENDOR_DATA] = { .type = NLA_BINARY },
+	[NL80211_ATTR_QOS_MAP] = { .type = NLA_BINARY,
+				   .len = IEEE80211_QOS_MAP_LEN_MAX },
+	[NL80211_ATTR_MAC_HINT] = { .len = ETH_ALEN },
+	[NL80211_ATTR_WIPHY_FREQ_HINT] = { .type = NLA_U32 },
+	[NL80211_ATTR_TDLS_PEER_CAPABILITY] = { .type = NLA_U32 },
 };
 
 /* policy for the key attributes */
@@ -950,6 +955,7 @@
 		i++;
 		NLA_PUT_U32(msg, i, NL80211_CMD_REGISTER_BEACONS);
 	}
+	CMD(set_qos_map, SET_QOS_MAP);
 
 #ifdef CONFIG_NL80211_TESTMODE
 	CMD(testmode_cmd, TESTMODE);
@@ -1088,6 +1094,11 @@
 		NLA_PUT_U32(msg, NL80211_ATTR_MAC_ACL_MAX,
 			    dev->wiphy.max_acl_mac_addrs);
 
+	if (dev->wiphy.max_ap_assoc_sta &&
+	    nla_put_u32(msg, NL80211_ATTR_MAX_AP_ASSOC_STA,
+			dev->wiphy.max_ap_assoc_sta))
+		goto nla_put_failure;
+
 	if (dev->wiphy.n_vendor_commands) {
 		const struct nl80211_vendor_cmd_info *info;
 		struct nlattr *nested;
@@ -5530,6 +5541,9 @@
 
 	if (info->attrs[NL80211_ATTR_MAC])
 		connect.bssid = nla_data(info->attrs[NL80211_ATTR_MAC]);
+	else if (info->attrs[NL80211_ATTR_MAC_HINT])
+		connect.bssid_hint =
+			nla_data(info->attrs[NL80211_ATTR_MAC_HINT]);
 	connect.ssid = nla_data(info->attrs[NL80211_ATTR_SSID]);
 	connect.ssid_len = nla_len(info->attrs[NL80211_ATTR_SSID]);
 
@@ -5554,6 +5568,14 @@
 		if (!connect.channel ||
 		    connect.channel->flags & IEEE80211_CHAN_DISABLED)
 			return -EINVAL;
+	} else if (info->attrs[NL80211_ATTR_WIPHY_FREQ_HINT]) {
+		connect.channel_hint =
+			ieee80211_get_channel(wiphy,
+			    nla_get_u32(
+				    info->attrs[NL80211_ATTR_WIPHY_FREQ_HINT]));
+		if (!connect.channel_hint ||
+		    connect.channel_hint->flags & IEEE80211_CHAN_DISABLED)
+			return -EINVAL;
 	}
 
 	if (connect.privacy && info->attrs[NL80211_ATTR_KEYS]) {
@@ -5693,6 +5715,7 @@
 	struct cfg80211_registered_device *rdev = info->user_ptr[0];
 	struct net_device *dev = info->user_ptr[1];
 	u8 action_code, dialog_token;
+	u32 peer_capability = 0;
 	u16 status_code;
 	u8 *peer;
 
@@ -5711,9 +5734,12 @@
 	action_code = nla_get_u8(info->attrs[NL80211_ATTR_TDLS_ACTION]);
 	status_code = nla_get_u16(info->attrs[NL80211_ATTR_STATUS_CODE]);
 	dialog_token = nla_get_u8(info->attrs[NL80211_ATTR_TDLS_DIALOG_TOKEN]);
+	if (info->attrs[NL80211_ATTR_TDLS_PEER_CAPABILITY])
+		peer_capability =
+		    nla_get_u32(info->attrs[NL80211_ATTR_TDLS_PEER_CAPABILITY]);
 
 	return rdev->ops->tdls_mgmt(&rdev->wiphy, dev, peer, action_code,
-				    dialog_token, status_code,
+				    dialog_token, status_code, peer_capability,
 				    nla_data(info->attrs[NL80211_ATTR_IE]),
 				    nla_len(info->attrs[NL80211_ATTR_IE]));
 }
@@ -6796,6 +6822,57 @@
 }
 EXPORT_SYMBOL(cfg80211_vendor_cmd_reply);
 
+static int nl80211_set_qos_map(struct sk_buff *skb,
+			       struct genl_info *info)
+{
+	struct cfg80211_registered_device *rdev = info->user_ptr[0];
+	struct cfg80211_qos_map *qos_map = NULL;
+	struct net_device *dev = info->user_ptr[1];
+	u8 *pos, len, num_des, des_len, des;
+	int ret;
+
+	if (!rdev->ops->set_qos_map)
+		return -EOPNOTSUPP;
+
+	if (info->attrs[NL80211_ATTR_QOS_MAP]) {
+		pos = nla_data(info->attrs[NL80211_ATTR_QOS_MAP]);
+		len = nla_len(info->attrs[NL80211_ATTR_QOS_MAP]);
+
+		if (len % 2 || len < IEEE80211_QOS_MAP_LEN_MIN ||
+		    len > IEEE80211_QOS_MAP_LEN_MAX)
+			return -EINVAL;
+
+		qos_map = kzalloc(sizeof(struct cfg80211_qos_map), GFP_KERNEL);
+		if (!qos_map)
+			return -ENOMEM;
+
+		num_des = (len - IEEE80211_QOS_MAP_LEN_MIN) >> 1;
+		if (num_des) {
+			des_len = num_des *
+				sizeof(struct cfg80211_dscp_exception);
+			memcpy(qos_map->dscp_exception, pos, des_len);
+			qos_map->num_des = num_des;
+			for (des = 0; des < num_des; des++) {
+				if (qos_map->dscp_exception[des].up > 7) {
+					kfree(qos_map);
+					return -EINVAL;
+				}
+			}
+			pos += des_len;
+		}
+		memcpy(qos_map->up, pos, IEEE80211_QOS_MAP_LEN_MIN);
+	}
+
+	wdev_lock(dev->ieee80211_ptr);
+	ret = nl80211_key_allowed(dev->ieee80211_ptr);
+	if (!ret)
+		ret = rdev->ops->set_qos_map(&rdev->wiphy, dev, qos_map);
+	wdev_unlock(dev->ieee80211_ptr);
+
+	kfree(qos_map);
+	return ret;
+}
+
 #define NL80211_FLAG_NEED_WIPHY		0x01
 #define NL80211_FLAG_NEED_NETDEV	0x02
 #define NL80211_FLAG_NEED_RTNL		0x04
@@ -7408,6 +7485,14 @@
 		.internal_flags = NL80211_FLAG_NEED_NETDEV |
 				  NL80211_FLAG_NEED_RTNL,
 	},
+	{
+		.cmd = NL80211_CMD_SET_QOS_MAP,
+		.doit = nl80211_set_qos_map,
+		.policy = nl80211_policy,
+		.flags = GENL_ADMIN_PERM,
+		.internal_flags = NL80211_FLAG_NEED_NETDEV_UP |
+				  NL80211_FLAG_NEED_RTNL,
+	},
 };
 
 static struct genl_multicast_group nl80211_mlme_mcgrp = {
diff --git a/net/wireless/reg.c b/net/wireless/reg.c
index 78aa256..1f547f9 100755
--- a/net/wireless/reg.c
+++ b/net/wireless/reg.c
@@ -302,6 +302,11 @@
 	return true;
 }
 
+static bool is_cfg80211_regdom_intersected(void)
+{
+	return is_intersected_alpha2(cfg80211_regdomain->alpha2);
+}
+
 static int reg_copy_regd(const struct ieee80211_regdomain **dst_regd,
 			 const struct ieee80211_regdomain *src_regd)
 {
@@ -340,6 +345,9 @@
 	struct reg_regdb_search_request *request;
 	const struct ieee80211_regdomain *curdom, *regdom;
 	int i, r;
+	bool set_reg = false;
+
+	mutex_lock(&cfg80211_mutex);
 
 	mutex_lock(&reg_regdb_search_mutex);
 	while (!list_empty(&reg_regdb_search_list)) {
@@ -355,9 +363,7 @@
 				r = reg_copy_regd(&regdom, curdom);
 				if (r)
 					break;
-				mutex_lock(&cfg80211_mutex);
-				set_regdom(regdom);
-				mutex_unlock(&cfg80211_mutex);
+				set_reg = true;
 				break;
 			}
 		}
@@ -365,6 +371,11 @@
 		kfree(request);
 	}
 	mutex_unlock(&reg_regdb_search_mutex);
+
+	if (set_reg)
+		set_regdom(regdom);
+
+	mutex_unlock(&cfg80211_mutex);
 }
 
 static DECLARE_WORK(reg_regdb_work, reg_regdb_search);
@@ -1381,11 +1392,15 @@
 		 * Process user requests only after previous user/driver/core
 		 * requests have been processed
 		 */
-		if (last_request->initiator == NL80211_REGDOM_SET_BY_CORE ||
-		    last_request->initiator == NL80211_REGDOM_SET_BY_DRIVER ||
-		    last_request->initiator == NL80211_REGDOM_SET_BY_USER) {
-			if (regdom_changes(last_request->alpha2))
+		if ((last_request->initiator == NL80211_REGDOM_SET_BY_CORE ||
+		     last_request->initiator == NL80211_REGDOM_SET_BY_DRIVER ||
+		     last_request->initiator == NL80211_REGDOM_SET_BY_USER)) {
+			if (last_request->intersect) {
+				if (!is_cfg80211_regdom_intersected())
+					return -EAGAIN;
+			} else if (regdom_changes(last_request->alpha2)) {
 				return -EAGAIN;
+			}
 		}
 
 		if (!regdom_changes(pending_request->alpha2))
diff --git a/net/wireless/sme.c b/net/wireless/sme.c
index ab91446..87547ca 100644
--- a/net/wireless/sme.c
+++ b/net/wireless/sme.c
@@ -721,6 +721,10 @@
 		for (i = 0; i < 6; i++)
 			rdev->ops->del_key(wdev->wiphy, dev, i, false, NULL);
 
+	if (rdev->ops->set_qos_map) {
+		rdev->ops->set_qos_map(&rdev->wiphy, dev, NULL);
+	}
+
 #ifdef CONFIG_CFG80211_WEXT
 	memset(&wrqu, 0, sizeof(wrqu));
 	wrqu.ap_addr.sa_family = ARPHRD_ETHER;
diff --git a/net/wireless/util.c b/net/wireless/util.c
index b89fb94..b83c5b2 100644
--- a/net/wireless/util.c
+++ b/net/wireless/util.c
@@ -10,6 +10,8 @@
 #include <net/cfg80211.h>
 #include <net/ip.h>
 #include <net/dsfield.h>
+#include <net/ndisc.h>
+#include <linux/if_arp.h>
 #include "core.h"
 
 struct ieee80211_rate *
@@ -641,7 +643,8 @@
 EXPORT_SYMBOL(ieee80211_amsdu_to_8023s);
 
 /* Given a data frame determine the 802.1p/1d tag to use. */
-unsigned int cfg80211_classify8021d(struct sk_buff *skb)
+unsigned int cfg80211_classify8021d(struct sk_buff *skb,
+				    struct cfg80211_qos_map *qos_map)
 {
 	unsigned int dscp;
 
@@ -664,6 +667,21 @@
 		return 0;
 	}
 
+	if (qos_map) {
+		unsigned int i, tmp_dscp = dscp >> 2;
+
+		for (i = 0; i < qos_map->num_des; i++) {
+			if (tmp_dscp == qos_map->dscp_exception[i].dscp)
+				return qos_map->dscp_exception[i].up;
+		}
+
+		for (i = 0; i < 8; i++) {
+			if (tmp_dscp >= qos_map->up[i].low &&
+			    tmp_dscp <= qos_map->up[i].high)
+				return i;
+		}
+	}
+
 	return dscp >> 5;
 }
 EXPORT_SYMBOL(cfg80211_classify8021d);
@@ -817,6 +835,9 @@
 
 		dev->ieee80211_ptr->use_4addr = false;
 		dev->ieee80211_ptr->mesh_id_up_len = 0;
+		if (rdev->ops->set_qos_map) {
+			rdev->ops->set_qos_map(&rdev->wiphy, dev, NULL);
+		}
 
 		switch (otype) {
 		case NL80211_IFTYPE_ADHOC:
@@ -1131,3 +1152,54 @@
 const unsigned char bridge_tunnel_header[] __aligned(2) =
 	{ 0xaa, 0xaa, 0x03, 0x00, 0x00, 0xf8 };
 EXPORT_SYMBOL(bridge_tunnel_header);
+
+bool cfg80211_is_gratuitous_arp_unsolicited_na(struct sk_buff *skb)
+{
+	const struct ethhdr *eth = (void *)skb->data;
+	const struct {
+		struct arphdr hdr;
+		u8 ar_sha[ETH_ALEN];
+		u8 ar_sip[4];
+		u8 ar_tha[ETH_ALEN];
+		u8 ar_tip[4];
+	} __packed *arp;
+	const struct ipv6hdr *ipv6;
+	const struct icmp6hdr *icmpv6;
+
+	switch (eth->h_proto) {
+	case cpu_to_be16(ETH_P_ARP):
+		/* can't say - but will probably be dropped later anyway */
+		if (!pskb_may_pull(skb, sizeof(*eth) + sizeof(*arp)))
+			return false;
+
+		arp = (void *)(eth + 1);
+
+		if ((arp->hdr.ar_op == cpu_to_be16(ARPOP_REPLY) ||
+		     arp->hdr.ar_op == cpu_to_be16(ARPOP_REQUEST)) &&
+		    !memcmp(arp->ar_sip, arp->ar_tip, sizeof(arp->ar_sip)))
+			return true;
+		break;
+	case cpu_to_be16(ETH_P_IPV6):
+		/* can't say - but will probably be dropped later anyway */
+		if (!pskb_may_pull(skb, sizeof(*eth) + sizeof(*ipv6) +
+					sizeof(*icmpv6)))
+			return false;
+
+		ipv6 = (void *)(eth + 1);
+		icmpv6 = (void *)(ipv6 + 1);
+
+		if (icmpv6->icmp6_type == NDISC_NEIGHBOUR_ADVERTISEMENT &&
+		    !memcmp(&ipv6->saddr, &ipv6->daddr, sizeof(ipv6->saddr)))
+			return true;
+		break;
+	default:
+		/*
+		 * no need to support other protocols, proxy service isn't
+		 * specified for any others
+		 */
+		break;
+	}
+
+	return false;
+}
+EXPORT_SYMBOL(cfg80211_is_gratuitous_arp_unsolicited_na);
diff --git a/sound/soc/codecs/msm8x10-wcd.c b/sound/soc/codecs/msm8x10-wcd.c
index 2286e34..a5e0bb3 100644
--- a/sound/soc/codecs/msm8x10-wcd.c
+++ b/sound/soc/codecs/msm8x10-wcd.c
@@ -3151,9 +3151,25 @@
 	return 0;
 }
 
+static const struct wcd9xxx_mbhc_intr cdc_intr_ids = {
+	.poll_plug_rem = MSM8X10_WCD_IRQ_MBHC_REMOVAL,
+	.shortavg_complete = MSM8X10_WCD_IRQ_MBHC_SHORT_TERM,
+	.potential_button_press = MSM8X10_WCD_IRQ_MBHC_PRESS,
+	.button_release = MSM8X10_WCD_IRQ_MBHC_RELEASE,
+	.dce_est_complete = MSM8X10_WCD_IRQ_MBHC_POTENTIAL,
+	.insertion = MSM8X10_WCD_IRQ_MBHC_INSERTION,
+	.hph_left_ocp = MSM8X10_WCD_IRQ_HPH_PA_OCPL_FAULT,
+	.hph_right_ocp = MSM8X10_WCD_IRQ_HPH_PA_OCPR_FAULT,
+	.hs_jack_switch = MSM8X10_WCD_IRQ_MBHC_HS_DET,
+};
+
 static int msm8x10_wcd_device_up(struct snd_soc_codec *codec)
 {
-	dev_dbg(codec->dev, "%s: device up!\n", __func__);
+	int ret = 0;
+	struct msm8x10_wcd_priv *msm8x10_wcd_priv =
+					snd_soc_codec_get_drvdata(codec);
+
+	dev_err(codec->dev, "%s: device up!\n", __func__);
 
 	snd_soc_card_change_online_state(codec->card, 1);
 	/* delay is required to make sure sound card state updated */
@@ -3162,9 +3178,27 @@
 	mutex_lock(&codec->mutex);
 
 	msm8x10_wcd_bringup(codec);
-	msm8x10_wcd_codec_init_reg(codec);
+
 	msm8x10_wcd_update_reg_defaults(codec);
 
+	msm8x10_wcd_codec_init_reg(codec);
+
+	wcd9xxx_resmgr_post_ssr(&msm8x10_wcd_priv->resmgr);
+
+	wcd9xxx_mbhc_deinit(&msm8x10_wcd_priv->mbhc);
+
+	ret = wcd9xxx_mbhc_init(&msm8x10_wcd_priv->mbhc,
+				&msm8x10_wcd_priv->resmgr,
+				codec, msm8x10_wcd_enable_mbhc_micbias,
+				&mbhc_cb, &cdc_intr_ids,
+				HELICON_MCLK_CLK_9P6MHZ, true);
+	if (ret)
+		dev_err(codec->dev, "%s: Failed to initialize mbhc\n",
+			__func__);
+	else
+		wcd9xxx_mbhc_start(&msm8x10_wcd_priv->mbhc,
+				msm8x10_wcd_priv->mbhc.mbhc_cfg);
+
 	mutex_unlock(&codec->mutex);
 
 	return 0;
@@ -3203,18 +3237,6 @@
 	.priority = -INT_MAX,
 };
 
-static const struct wcd9xxx_mbhc_intr cdc_intr_ids = {
-	.poll_plug_rem = MSM8X10_WCD_IRQ_MBHC_REMOVAL,
-	.shortavg_complete = MSM8X10_WCD_IRQ_MBHC_SHORT_TERM,
-	.potential_button_press = MSM8X10_WCD_IRQ_MBHC_PRESS,
-	.button_release = MSM8X10_WCD_IRQ_MBHC_RELEASE,
-	.dce_est_complete = MSM8X10_WCD_IRQ_MBHC_POTENTIAL,
-	.insertion = MSM8X10_WCD_IRQ_MBHC_INSERTION,
-	.hph_left_ocp = MSM8X10_WCD_IRQ_HPH_PA_OCPL_FAULT,
-	.hph_right_ocp = MSM8X10_WCD_IRQ_HPH_PA_OCPR_FAULT,
-	.hs_jack_switch = MSM8X10_WCD_IRQ_MBHC_HS_DET,
-};
-
 static int msm8x10_wcd_handle_pdata(struct snd_soc_codec *codec,
 	struct msm8x10_wcd_pdata *pdata)
 {
diff --git a/sound/soc/codecs/wcd9306.c b/sound/soc/codecs/wcd9306.c
index f59456e..61a0682 100644
--- a/sound/soc/codecs/wcd9306.c
+++ b/sound/soc/codecs/wcd9306.c
@@ -2519,6 +2519,29 @@
 	return 0;
 }
 
+static int tapan_codec_rx_dem_select(struct snd_soc_dapm_widget *w,
+			struct snd_kcontrol *kcontrol, int event)
+{
+
+	struct snd_soc_codec *codec = w->codec;
+
+	pr_debug("%s %d %s\n", __func__, event, w->name);
+	switch (event) {
+	case SND_SOC_DAPM_PRE_PMU:
+		if (codec_ver == WCD9306)
+			snd_soc_update_bits(codec, TAPAN_A_CDC_RX2_B6_CTL,
+					    1 << 5, 1 << 5);
+		break;
+	case SND_SOC_DAPM_POST_PMD:
+		if (codec_ver == WCD9306)
+			snd_soc_update_bits(codec, TAPAN_A_CDC_RX2_B6_CTL,
+					    1 << 5, 0);
+		break;
+	}
+
+	return 0;
+}
+
 static int tapan_codec_enable_interpolator(struct snd_soc_dapm_widget *w,
 	struct snd_kcontrol *kcontrol, int event)
 {
@@ -4557,8 +4580,10 @@
 
 	SND_SOC_DAPM_MIXER("RX1 CHAIN", TAPAN_A_CDC_RX1_B6_CTL, 5, 0,
 						NULL, 0),
-	SND_SOC_DAPM_MIXER("RX2 CHAIN", TAPAN_A_CDC_RX2_B6_CTL, 5, 0,
-						NULL, 0),
+
+	SND_SOC_DAPM_MIXER_E("RX2 CHAIN", SND_SOC_NOPM, 0, 0, NULL,
+		0, tapan_codec_rx_dem_select, SND_SOC_DAPM_PRE_PMU |
+		SND_SOC_DAPM_POST_PMD),
 
 	SND_SOC_DAPM_MUX_E("CLASS_H_DSM MUX", SND_SOC_NOPM, 0, 0,
 		&class_h_dsm_mux, tapan_codec_dsm_mux_event,
@@ -5064,7 +5089,7 @@
 
 	/* RX1 and RX2 defaults */
 	TAPAN_REG_VAL(TAPAN_A_CDC_RX1_B6_CTL, 0xA0),
-	TAPAN_REG_VAL(TAPAN_A_CDC_RX2_B6_CTL, 0xA0),
+	TAPAN_REG_VAL(TAPAN_A_CDC_RX2_B6_CTL, 0x80),
 
 	/* Heaset set Right from RX2 */
 	TAPAN_REG_VAL(TAPAN_A_CDC_CONN_RX2_B2_CTL, 0x10),
@@ -5786,7 +5811,17 @@
 	const char *name)
 {
 	int i;
-	struct wcd9xxx *core = dev_get_drvdata(codec->dev->parent);
+	struct wcd9xxx *core = NULL;
+
+	if (codec == NULL) {
+		dev_err(codec->dev, "%s: codec not initialized\n", __func__);
+		return NULL;
+	}
+	core = dev_get_drvdata(codec->dev->parent);
+	if (core == NULL) {
+		dev_err(codec->dev, "%s: core not initialized\n", __func__);
+		return NULL;
+	}
 
 	for (i = 0; i < core->num_of_supplies; i++) {
 		if (core->supplies[i].supply &&
diff --git a/sound/soc/codecs/wcd9320.c b/sound/soc/codecs/wcd9320.c
index 50681f7..2b0c9d3 100644
--- a/sound/soc/codecs/wcd9320.c
+++ b/sound/soc/codecs/wcd9320.c
@@ -4360,13 +4360,8 @@
 static int taiko_startup(struct snd_pcm_substream *substream,
 		struct snd_soc_dai *dai)
 {
-	struct wcd9xxx *taiko_core = dev_get_drvdata(dai->codec->dev->parent);
 	pr_debug("%s(): substream = %s  stream = %d\n" , __func__,
 		 substream->name, substream->stream);
-	if ((taiko_core != NULL) &&
-	    (taiko_core->dev != NULL) &&
-	    (taiko_core->dev->parent != NULL))
-		pm_runtime_get_sync(taiko_core->dev->parent);
 
 	return 0;
 }
@@ -4374,15 +4369,8 @@
 static void taiko_shutdown(struct snd_pcm_substream *substream,
 		struct snd_soc_dai *dai)
 {
-	struct wcd9xxx *taiko_core = dev_get_drvdata(dai->codec->dev->parent);
 	pr_debug("%s(): substream = %s  stream = %d\n" , __func__,
 		 substream->name, substream->stream);
-	if ((taiko_core != NULL) &&
-	    (taiko_core->dev != NULL) &&
-	    (taiko_core->dev->parent != NULL)) {
-		pm_runtime_mark_last_busy(taiko_core->dev->parent);
-		pm_runtime_put(taiko_core->dev->parent);
-	}
 }
 
 int taiko_mclk_enable(struct snd_soc_codec *codec, int mclk_enable, bool dapm)
diff --git a/sound/soc/codecs/wcd9xxx-mbhc.c b/sound/soc/codecs/wcd9xxx-mbhc.c
index 0abd123..34cb21a 100644
--- a/sound/soc/codecs/wcd9xxx-mbhc.c
+++ b/sound/soc/codecs/wcd9xxx-mbhc.c
@@ -188,7 +188,7 @@
 
 static bool wcd9xxx_mbhc_polling(struct wcd9xxx_mbhc *mbhc)
 {
-	return mbhc->polling_active;
+	return snd_soc_read(mbhc->codec, WCD9XXX_A_CDC_MBHC_EN_CTL) & 0x1;
 }
 
 static void wcd9xxx_turn_onoff_override(struct wcd9xxx_mbhc *mbhc, bool on)
@@ -542,13 +542,13 @@
 
 	if (cfilt_mode.cur_mode_val
 			!= cfilt_mode.reg_mode_val) {
-		if (mbhc->polling_active)
+		if (mbhc->polling_active && wcd9xxx_mbhc_polling(mbhc))
 			wcd9xxx_pause_hs_polling(mbhc);
 		snd_soc_update_bits(codec,
 				    mbhc->mbhc_bias_regs.cfilt_ctl,
 					cfilt_mode.reg_mask,
 					cfilt_mode.reg_mode_val);
-		if (mbhc->polling_active)
+		if (mbhc->polling_active && wcd9xxx_mbhc_polling(mbhc))
 			wcd9xxx_start_hs_polling(mbhc);
 		pr_debug("%s: CFILT mode change (%x to %x)\n", __func__,
 			cfilt_mode.cur_mode_val,
@@ -3441,7 +3441,8 @@
  * wcd9xxx_update_rel_threshold : update mbhc release upper bound threshold
  *				  to ceilmv + buffer
  */
-static int wcd9xxx_update_rel_threshold(struct wcd9xxx_mbhc *mbhc, int ceilmv)
+static int wcd9xxx_update_rel_threshold(struct wcd9xxx_mbhc *mbhc, int ceilmv,
+					bool vddio)
 {
 	u16 v_brh, v_b1_hu;
 	int mv;
@@ -3451,6 +3452,8 @@
 
 	btn_det = WCD9XXX_MBHC_CAL_BTN_DET_PTR(calibration);
 	mv = ceilmv + btn_det->v_btn_press_delta_cic;
+	if (vddio)
+		mv = scale_v_micb_vddio(mbhc, mv, true);
 	pr_debug("%s: reprogram vb1hu/vbrh to %dmv\n", __func__, mv);
 
 	if (mbhc->mbhc_state != MBHC_STATE_POTENTIAL_RECOVERY) {
@@ -3651,7 +3654,7 @@
 						       MBHC_BTN_DET_V_BTN_HIGH);
 		WARN_ON(btn >= btn_det->num_btn);
 		/* reprogram release threshold to catch voltage ramp up early */
-		wcd9xxx_update_rel_threshold(mbhc, v_btn_high[btn]);
+		wcd9xxx_update_rel_threshold(mbhc, v_btn_high[btn], vddio);
 
 		mask = wcd9xxx_get_button_mask(btn);
 		mbhc->buttons_pressed |= mask;
diff --git a/sound/soc/msm/qdsp6v2/msm-compr-q6-v2.c b/sound/soc/msm/qdsp6v2/msm-compr-q6-v2.c
index bb325d8..5176bbe 100755
--- a/sound/soc/msm/qdsp6v2/msm-compr-q6-v2.c
+++ b/sound/soc/msm/qdsp6v2/msm-compr-q6-v2.c
@@ -1030,12 +1030,19 @@
 			int i;
 			struct snd_dec_ddp *ddp =
 				&compr->info.codec_param.codec.options.ddp;
-			uint32_t params_length = ddp->params_length*sizeof(int);
+			uint32_t params_length = 0;
+			/* check integer overflow */
+			if (ddp->params_length > UINT_MAX/sizeof(int)) {
+				pr_err("%s: Integer overflow ddp->params_length %d\n",
+				__func__, ddp->params_length);
+				return -EINVAL;
+			}
+			params_length = ddp->params_length*sizeof(int);
 			if (params_length > MAX_AC3_PARAM_SIZE) {
 				/*MAX is 36*sizeof(int) this should not happen*/
-				pr_err("params_length(%d) is greater than %d",
-				params_length, MAX_AC3_PARAM_SIZE);
-				params_length = MAX_AC3_PARAM_SIZE;
+				pr_err("%s: params_length(%d) is greater than %zd\n",
+				__func__, params_length, MAX_AC3_PARAM_SIZE);
+				return -EINVAL;
 			}
 			pr_debug("SND_AUDIOCODEC_AC3\n");
 			compr->codec = FORMAT_AC3;
@@ -1067,12 +1074,18 @@
 			int i;
 			struct snd_dec_ddp *ddp =
 				&compr->info.codec_param.codec.options.ddp;
-			uint32_t params_length = ddp->params_length*sizeof(int);
+			uint32_t params_length = 0;
+			/* check integer overflow */
+			if (ddp->params_length > UINT_MAX/sizeof(int)) {
+				pr_err("%s: Integer overflow ddp->params_length %d\n",
+				__func__, ddp->params_length);
+				return -EINVAL;
+			}
 			if (params_length > MAX_AC3_PARAM_SIZE) {
 				/*MAX is 36*sizeof(int) this should not happen*/
-				pr_err("params_length(%d) is greater than %d",
-				params_length, MAX_AC3_PARAM_SIZE);
-				params_length = MAX_AC3_PARAM_SIZE;
+				pr_err("%s: params_length(%d) is greater than %d\n",
+				__func__, params_length, MAX_AC3_PARAM_SIZE);
+				return -EINVAL;
 			}
 			pr_debug("SND_AUDIOCODEC_EAC3\n");
 			compr->codec = FORMAT_EAC3;
diff --git a/sound/soc/msm/qdsp6v2/msm-pcm-loopback-v2.c b/sound/soc/msm/qdsp6v2/msm-pcm-loopback-v2.c
index 57fc268..2755c29 100644
--- a/sound/soc/msm/qdsp6v2/msm-pcm-loopback-v2.c
+++ b/sound/soc/msm/qdsp6v2/msm-pcm-loopback-v2.c
@@ -202,19 +202,23 @@
 
 static void stop_pcm(struct msm_pcm_loopback *pcm)
 {
-	struct snd_soc_pcm_runtime *soc_pcm_rx =
-		pcm->playback_substream->private_data;
-	struct snd_soc_pcm_runtime *soc_pcm_tx =
-		pcm->capture_substream->private_data;
+	struct snd_soc_pcm_runtime *soc_pcm_rx;
+	struct snd_soc_pcm_runtime *soc_pcm_tx;
 
 	if (pcm->audio_client == NULL)
 		return;
 	q6asm_cmd(pcm->audio_client, CMD_CLOSE);
 
-	msm_pcm_routing_dereg_phy_stream(soc_pcm_rx->dai_link->be_id,
-			SNDRV_PCM_STREAM_PLAYBACK);
-	msm_pcm_routing_dereg_phy_stream(soc_pcm_tx->dai_link->be_id,
-			SNDRV_PCM_STREAM_CAPTURE);
+	if (pcm->playback_substream != NULL) {
+		soc_pcm_rx = pcm->playback_substream->private_data;
+		msm_pcm_routing_dereg_phy_stream(soc_pcm_rx->dai_link->be_id,
+				SNDRV_PCM_STREAM_PLAYBACK);
+	}
+	if (pcm->capture_substream != NULL) {
+		soc_pcm_tx = pcm->capture_substream->private_data;
+		msm_pcm_routing_dereg_phy_stream(soc_pcm_tx->dai_link->be_id,
+				SNDRV_PCM_STREAM_CAPTURE);
+	}
 	q6asm_audio_client_free(pcm->audio_client);
 	pcm->audio_client = NULL;
 }
diff --git a/sound/soc/msm/qdsp6v2/msm-pcm-routing-v2.c b/sound/soc/msm/qdsp6v2/msm-pcm-routing-v2.c
index 157d63a..a5c8f8d 100644
--- a/sound/soc/msm/qdsp6v2/msm-pcm-routing-v2.c
+++ b/sound/soc/msm/qdsp6v2/msm-pcm-routing-v2.c
@@ -73,7 +73,7 @@
 static int srs_alsa_ctrl_ever_called;
 static int lsm_mux_slim_port;
 static int slim0_rx_aanc_fb_port;
-static int msm_route_ec_ref_rx = 3; /* NONE */
+static int msm_route_ec_ref_rx = 7; /* NONE */
 static uint32_t voc_session_id = ALL_SESSION_VSID;
 static int msm_route_ext_ec_ref = AFE_PORT_INVALID;
 
@@ -104,6 +104,10 @@
 static const DECLARE_TLV_DB_LINEAR(fm_rx_vol_gain, 0,
 			INT_RX_VOL_MAX_STEPS);
 
+static int msm_route_hfp_vol_control;
+static const DECLARE_TLV_DB_LINEAR(hfp_rx_vol_gain, 0,
+			INT_RX_VOL_MAX_STEPS);
+
 static int msm_route_multimedia2_vol_control;
 static const DECLARE_TLV_DB_LINEAR(multimedia2_rx_vol_gain, 0,
 			INT_RX_VOL_MAX_STEPS);
@@ -1095,6 +1099,23 @@
 	return 0;
 }
 
+static int msm_routing_get_hfp_vol_mixer(struct snd_kcontrol *kcontrol,
+					 struct snd_ctl_elem_value *ucontrol)
+{
+	ucontrol->value.integer.value[0] = msm_route_hfp_vol_control;
+	return 0;
+}
+
+static int msm_routing_set_hfp_vol_mixer(struct snd_kcontrol *kcontrol,
+					 struct snd_ctl_elem_value *ucontrol)
+{
+	afe_loopback_gain(INT_BT_SCO_TX , ucontrol->value.integer.value[0]);
+
+	msm_route_hfp_vol_control = ucontrol->value.integer.value[0];
+
+	return 0;
+}
+
 static int msm_routing_get_multimedia2_vol_mixer(struct snd_kcontrol *kcontrol,
 				struct snd_ctl_elem_value *ucontrol)
 {
@@ -1408,9 +1429,25 @@
 		msm_route_ec_ref_rx = 1;
 		ec_ref_port_id = AFE_PORT_ID_PRIMARY_MI2S_RX;
 		break;
+	case 2:
+		msm_route_ec_ref_rx = 2;
+		ec_ref_port_id = AFE_PORT_ID_PRIMARY_MI2S_TX;
+		break;
+	case 3:
+		msm_route_ec_ref_rx = 3;
+		ec_ref_port_id = AFE_PORT_ID_SECONDARY_MI2S_TX;
+		break;
+	case 4:
+		msm_route_ec_ref_rx = 4;
+		ec_ref_port_id = AFE_PORT_ID_TERTIARY_MI2S_TX;
+		break;
+	case 5:
+		msm_route_ec_ref_rx = 5;
+		ec_ref_port_id = AFE_PORT_ID_QUATERNARY_MI2S_TX;
+		break;
 	default:
-		msm_route_ec_ref_rx = 3; /* NONE */
-		ec_ref_port_id = -1;
+		msm_route_ec_ref_rx = 6; /* NONE */
+		ec_ref_port_id = AFE_PORT_INVALID;
 		break;
 	}
 	adm_ec_ref_rx_id(ec_ref_port_id);
@@ -1420,16 +1457,46 @@
 	return 0;
 }
 
-static const char *const ec_ref_rx[] = { "SLIM_RX", "I2S_RX", "PROXY_RX",
-	"NONE" };
+static const char *const ec_ref_rx[] = { "SLIM_RX", "I2S_RX", "PRI_MI2S_TX",
+	"SEC_MI2S_TX", "TERT_MI2S_TX", "QUAT_MI2S_TX", "PROXY_RX", "NONE"};
 static const struct soc_enum msm_route_ec_ref_rx_enum[] = {
-	SOC_ENUM_SINGLE_EXT(4, ec_ref_rx),
+	SOC_ENUM_SINGLE_EXT(8, ec_ref_rx),
 };
 
-static const struct snd_kcontrol_new ec_ref_rx_mixer_controls[] = {
-	SOC_ENUM_EXT("EC_REF_RX", msm_route_ec_ref_rx_enum[0],
-		     msm_routing_ec_ref_rx_get, msm_routing_ec_ref_rx_put),
-};
+static const struct snd_kcontrol_new ext_ec_ref_mux_ul1 =
+	SOC_DAPM_ENUM_EXT("AUDIO_REF_EC_UL1 MUX Mux",
+		msm_route_ec_ref_rx_enum[0],
+		msm_routing_ec_ref_rx_get, msm_routing_ec_ref_rx_put);
+
+static const struct snd_kcontrol_new ext_ec_ref_mux_ul2 =
+	SOC_DAPM_ENUM_EXT("AUDIO_REF_EC_UL2 MUX Mux",
+		msm_route_ec_ref_rx_enum[0],
+		msm_routing_ec_ref_rx_get, msm_routing_ec_ref_rx_put);
+
+static const struct snd_kcontrol_new ext_ec_ref_mux_ul4 =
+	SOC_DAPM_ENUM_EXT("AUDIO_REF_EC_UL4 MUX Mux",
+		msm_route_ec_ref_rx_enum[0],
+		msm_routing_ec_ref_rx_get, msm_routing_ec_ref_rx_put);
+
+static const struct snd_kcontrol_new ext_ec_ref_mux_ul5 =
+	SOC_DAPM_ENUM_EXT("AUDIO_REF_EC_UL5 MUX Mux",
+		msm_route_ec_ref_rx_enum[0],
+		msm_routing_ec_ref_rx_get, msm_routing_ec_ref_rx_put);
+
+static const struct snd_kcontrol_new ext_ec_ref_mux_ul6 =
+	SOC_DAPM_ENUM_EXT("AUDIO_REF_EC_UL6 MUX Mux",
+		msm_route_ec_ref_rx_enum[0],
+		msm_routing_ec_ref_rx_get, msm_routing_ec_ref_rx_put);
+
+static const struct snd_kcontrol_new ext_ec_ref_mux_ul8 =
+	SOC_DAPM_ENUM_EXT("AUDIO_REF_EC_UL8 MUX Mux",
+		msm_route_ec_ref_rx_enum[0],
+		msm_routing_ec_ref_rx_get, msm_routing_ec_ref_rx_put);
+
+static const struct snd_kcontrol_new ext_ec_ref_mux_ul9 =
+	SOC_DAPM_ENUM_EXT("AUDIO_REF_EC_UL9 MUX Mux",
+		msm_route_ec_ref_rx_enum[0],
+		msm_routing_ec_ref_rx_get, msm_routing_ec_ref_rx_put);
 
 static int msm_routing_ext_ec_get(struct snd_kcontrol *kcontrol,
 				  struct snd_ctl_elem_value *ucontrol)
@@ -2757,6 +2824,12 @@
 	msm_routing_set_fm_vol_mixer, fm_rx_vol_gain),
 };
 
+static const struct snd_kcontrol_new int_hfp_vol_mixer_controls[] = {
+	SOC_SINGLE_EXT_TLV("Internal HFP RX Volume", SND_SOC_NOPM, 0,
+	INT_RX_VOL_GAIN, 0, msm_routing_get_hfp_vol_mixer,
+	msm_routing_set_hfp_vol_mixer, hfp_rx_vol_gain),
+};
+
 static const struct snd_kcontrol_new multimedia2_vol_mixer_controls[] = {
 	SOC_SINGLE_EXT_TLV("HIFI2 RX Volume", SND_SOC_NOPM, 0,
 	INT_RX_VOL_GAIN, 0, msm_routing_get_multimedia2_vol_mixer,
@@ -3546,7 +3619,20 @@
 				&slim0_rx_vi_fb_lch_mux),
 	SND_SOC_DAPM_MUX("VOC_EXT_EC MUX", SND_SOC_NOPM, 0, 0,
 			 &voc_ext_ec_mux),
-
+	SND_SOC_DAPM_MUX("AUDIO_REF_EC_UL1 MUX", SND_SOC_NOPM, 0, 0,
+		&ext_ec_ref_mux_ul1),
+	SND_SOC_DAPM_MUX("AUDIO_REF_EC_UL2 MUX", SND_SOC_NOPM, 0, 0,
+		&ext_ec_ref_mux_ul2),
+	SND_SOC_DAPM_MUX("AUDIO_REF_EC_UL4 MUX", SND_SOC_NOPM, 0, 0,
+		&ext_ec_ref_mux_ul4),
+	SND_SOC_DAPM_MUX("AUDIO_REF_EC_UL5 MUX", SND_SOC_NOPM, 0, 0,
+		&ext_ec_ref_mux_ul5),
+	SND_SOC_DAPM_MUX("AUDIO_REF_EC_UL6 MUX", SND_SOC_NOPM, 0, 0,
+		&ext_ec_ref_mux_ul6),
+	SND_SOC_DAPM_MUX("AUDIO_REF_EC_UL8 MUX", SND_SOC_NOPM, 0, 0,
+		&ext_ec_ref_mux_ul8),
+	SND_SOC_DAPM_MUX("AUDIO_REF_EC_UL9 MUX", SND_SOC_NOPM, 0, 0,
+		&ext_ec_ref_mux_ul9),
 };
 
 static const struct snd_soc_dapm_route intercon[] = {
@@ -3868,6 +3954,63 @@
 	{"VOIP_UL", NULL, "VOC_EXT_EC MUX"},
 	{"VoLTE_UL", NULL, "VOC_EXT_EC MUX"},
 
+	{"AUDIO_REF_EC_UL1 MUX", "PRI_MI2S_TX" , "PRI_MI2S_TX"},
+	{"AUDIO_REF_EC_UL1 MUX", "SEC_MI2S_TX" , "SEC_MI2S_TX"},
+	{"AUDIO_REF_EC_UL1 MUX", "TERT_MI2S_TX" , "TERT_MI2S_TX"},
+	{"AUDIO_REF_EC_UL1 MUX", "QUAT_MI2S_TX" , "QUAT_MI2S_TX"},
+	{"AUDIO_REF_EC_UL1 MUX", "I2S_RX" , "PRI_I2S_TX"},
+	{"AUDIO_REF_EC_UL1 MUX", "SLIM_RX" , "SLIMBUS_0_TX"},
+
+	{"AUDIO_REF_EC_UL2 MUX", "PRI_MI2S_TX" , "PRI_MI2S_TX"},
+	{"AUDIO_REF_EC_UL2 MUX", "SEC_MI2S_TX" , "SEC_MI2S_TX"},
+	{"AUDIO_REF_EC_UL2 MUX", "TERT_MI2S_TX" , "TERT_MI2S_TX"},
+	{"AUDIO_REF_EC_UL2 MUX", "QUAT_MI2S_TX" , "QUAT_MI2S_TX"},
+	{"AUDIO_REF_EC_UL2 MUX", "I2S_RX" , "PRI_I2S_TX"},
+	{"AUDIO_REF_EC_UL2 MUX", "SLIM_RX" , "SLIMBUS_0_TX"},
+
+	{"AUDIO_REF_EC_UL4 MUX", "PRI_MI2S_TX" , "PRI_MI2S_TX"},
+	{"AUDIO_REF_EC_UL4 MUX", "SEC_MI2S_TX" , "SEC_MI2S_TX"},
+	{"AUDIO_REF_EC_UL4 MUX", "TERT_MI2S_TX" , "TERT_MI2S_TX"},
+	{"AUDIO_REF_EC_UL4 MUX", "QUAT_MI2S_TX" , "QUAT_MI2S_TX"},
+	{"AUDIO_REF_EC_UL4 MUX", "I2S_RX" , "PRI_I2S_TX"},
+	{"AUDIO_REF_EC_UL4 MUX", "SLIM_RX" , "SLIMBUS_0_TX"},
+
+	{"AUDIO_REF_EC_UL5 MUX", "PRI_MI2S_TX" , "PRI_MI2S_TX"},
+	{"AUDIO_REF_EC_UL5 MUX", "SEC_MI2S_TX" , "SEC_MI2S_TX"},
+	{"AUDIO_REF_EC_UL5 MUX", "TERT_MI2S_TX" , "TERT_MI2S_TX"},
+	{"AUDIO_REF_EC_UL5 MUX", "QUAT_MI2S_TX" , "QUAT_MI2S_TX"},
+	{"AUDIO_REF_EC_UL5 MUX", "I2S_RX" , "PRI_I2S_TX"},
+	{"AUDIO_REF_EC_UL5 MUX", "SLIM_RX" , "SLIMBUS_0_TX"},
+
+	{"AUDIO_REF_EC_UL6 MUX", "PRI_MI2S_TX" , "PRI_MI2S_TX"},
+	{"AUDIO_REF_EC_UL6 MUX", "SEC_MI2S_TX" , "SEC_MI2S_TX"},
+	{"AUDIO_REF_EC_UL6 MUX", "TERT_MI2S_TX" , "TERT_MI2S_TX"},
+	{"AUDIO_REF_EC_UL6 MUX", "QUAT_MI2S_TX" , "QUAT_MI2S_TX"},
+	{"AUDIO_REF_EC_UL6 MUX", "I2S_RX" , "PRI_I2S_TX"},
+	{"AUDIO_REF_EC_UL6 MUX", "SLIM_RX" , "SLIMBUS_0_TX"},
+
+	{"AUDIO_REF_EC_UL8 MUX", "PRI_MI2S_TX" , "PRI_MI2S_TX"},
+	{"AUDIO_REF_EC_UL8 MUX", "SEC_MI2S_TX" , "SEC_MI2S_TX"},
+	{"AUDIO_REF_EC_UL8 MUX", "TERT_MI2S_TX" , "TERT_MI2S_TX"},
+	{"AUDIO_REF_EC_UL8 MUX", "QUAT_MI2S_TX" , "QUAT_MI2S_TX"},
+	{"AUDIO_REF_EC_UL8 MUX", "I2S_RX" , "PRI_I2S_TX"},
+	{"AUDIO_REF_EC_UL8 MUX", "SLIM_RX" , "SLIMBUS_0_TX"},
+
+	{"AUDIO_REF_EC_UL9 MUX", "PRI_MI2S_TX" , "PRI_MI2S_TX"},
+	{"AUDIO_REF_EC_UL9 MUX", "SEC_MI2S_TX" , "SEC_MI2S_TX"},
+	{"AUDIO_REF_EC_UL9 MUX", "TERT_MI2S_TX" , "TERT_MI2S_TX"},
+	{"AUDIO_REF_EC_UL9 MUX", "QUAT_MI2S_TX" , "QUAT_MI2S_TX"},
+	{"AUDIO_REF_EC_UL9 MUX", "I2S_RX" , "PRI_I2S_TX"},
+	{"AUDIO_REF_EC_UL9 MUX", "SLIM_RX" , "SLIMBUS_0_TX"},
+
+	{"MM_UL1", NULL, "AUDIO_REF_EC_UL1 MUX"},
+	{"MM_UL2", NULL, "AUDIO_REF_EC_UL2 MUX"},
+	{"MM_UL4", NULL, "AUDIO_REF_EC_UL4 MUX"},
+	{"MM_UL5", NULL, "AUDIO_REF_EC_UL5 MUX"},
+	{"MM_UL6", NULL, "AUDIO_REF_EC_UL6 MUX"},
+	{"MM_UL8", NULL, "AUDIO_REF_EC_UL8 MUX"},
+	{"MM_UL9", NULL, "AUDIO_REF_EC_UL9 MUX"},
+
 	{"Voice_Tx Mixer", "PRI_TX_Voice", "PRI_I2S_TX"},
 	{"Voice_Tx Mixer", "PRI_MI2S_TX_Voice", "PRI_MI2S_TX"},
 	{"Voice_Tx Mixer", "MI2S_TX_Voice", "MI2S_TX"},
@@ -4329,6 +4472,10 @@
 			ARRAY_SIZE(int_fm_vol_mixer_controls));
 
 	snd_soc_add_platform_controls(platform,
+				int_hfp_vol_mixer_controls,
+			ARRAY_SIZE(int_hfp_vol_mixer_controls));
+
+	snd_soc_add_platform_controls(platform,
 				eq_enable_mixer_controls,
 			ARRAY_SIZE(eq_enable_mixer_controls));
 
@@ -4392,10 +4539,6 @@
 			ARRAY_SIZE(dolby_dap_param_end_point_controls));
 
 	snd_soc_add_platform_controls(platform,
-				ec_ref_rx_mixer_controls,
-			ARRAY_SIZE(ec_ref_rx_mixer_controls));
-
-	snd_soc_add_platform_controls(platform,
 				get_rms_controls,
 			ARRAY_SIZE(get_rms_controls));
 
diff --git a/sound/soc/msm/qdsp6v2/q6adm.c b/sound/soc/msm/qdsp6v2/q6adm.c
index 2a6ce43..7b10815 100644
--- a/sound/soc/msm/qdsp6v2/q6adm.c
+++ b/sound/soc/msm/qdsp6v2/q6adm.c
@@ -1167,7 +1167,8 @@
 
 		open.topology_id = topology;
 		if ((open.topology_id == VPM_TX_SM_ECNS_COPP_TOPOLOGY) ||
-			(open.topology_id == VPM_TX_DM_FLUENCE_COPP_TOPOLOGY))
+			(open.topology_id == VPM_TX_DM_FLUENCE_COPP_TOPOLOGY) ||
+			(open.topology_id == VPM_TX_DM_RFECNS_COPP_TOPOLOGY))
 				rate = 16000;
 
 		if (perf_mode == ULTRA_LOW_LATENCY_PCM_MODE) {
@@ -1175,6 +1176,10 @@
 			rate = ULL_SUPPORTED_SAMPLE_RATE;
 			if(channel_mode > ULL_MAX_SUPPORTED_CHANNEL)
 				channel_mode = ULL_MAX_SUPPORTED_CHANNEL;
+		} else if (perf_mode == LOW_LATENCY_PCM_MODE) {
+			if ((open.topology_id == DOLBY_ADM_COPP_TOPOLOGY_ID) ||
+			    (open.topology_id == SRS_TRUMEDIA_TOPOLOGY_ID))
+				open.topology_id = DEFAULT_COPP_TOPOLOGY;
 		}
 		open.dev_num_channel = channel_mode & 0x00FF;
 		open.bit_width = bits_per_sample;
diff --git a/sound/soc/msm/qdsp6v2/q6asm.c b/sound/soc/msm/qdsp6v2/q6asm.c
index 0d19657..4b9d079 100644
--- a/sound/soc/msm/qdsp6v2/q6asm.c
+++ b/sound/soc/msm/qdsp6v2/q6asm.c
@@ -676,8 +676,11 @@
 
 		while (cnt >= 0) {
 			if (port->buf[cnt].data) {
-				msm_audio_ion_free(port->buf[cnt].client,
-						   port->buf[cnt].handle);
+				if (!rc)
+					msm_audio_ion_free(
+						port->buf[cnt].client,
+						port->buf[cnt].handle);
+
 				port->buf[cnt].client = NULL;
 				port->buf[cnt].handle = NULL;
 				port->buf[cnt].data = NULL;
@@ -723,7 +726,9 @@
 			(void *)&port->buf[0].phys,
 			(void *)port->buf[0].client,
 			(void *)port->buf[0].handle);
-		msm_audio_ion_free(port->buf[0].client, port->buf[0].handle);
+		if (!rc)
+			msm_audio_ion_free(port->buf[0].client,
+					   port->buf[0].handle);
 		port->buf[0].client = NULL;
 		port->buf[0].handle = NULL;
 	}
@@ -1171,6 +1176,13 @@
 			if (payload[1] != 0) {
 				pr_err("%s: cmd = 0x%x returned error = 0x%x sid:%d\n",
 					__func__, payload[0], payload[1], sid);
+				if (payload[0] ==
+				    ASM_CMD_SHARED_MEM_UNMAP_REGIONS)
+					atomic_set(&ac->unmap_cb_success, 0);
+			} else {
+				if (payload[0] ==
+				    ASM_CMD_SHARED_MEM_UNMAP_REGIONS)
+					atomic_set(&ac->unmap_cb_success, 1);
 			}
 
 			if (atomic_read(&ac->cmd_state)) {
@@ -3184,6 +3196,7 @@
 			TRUE, ((ac->session << 8) | dir));
 	atomic_set(&ac->cmd_state, 1);
 	mem_unmap.hdr.opcode = ASM_CMD_SHARED_MEM_UNMAP_REGIONS;
+	mem_unmap.mem_map_handle = 0;
 	list_for_each_safe(ptr, next, &ac->port[dir].mem_map_handle) {
 		buf_node = list_entry(ptr, struct asm_buffer_node,
 						list);
@@ -3195,6 +3208,12 @@
 	}
 	pr_debug("%s: mem_unmap-mem_map_handle: 0x%x",
 		__func__, mem_unmap.mem_map_handle);
+
+	if (mem_unmap.mem_map_handle == 0) {
+		pr_err("%s Do not send null mem handle to DSP\n", __func__);
+		rc = 0;
+		goto fail_cmd;
+	}
 	rc = apr_send_pkt(ac->mmap_apr, (uint32_t *) &mem_unmap);
 	if (rc < 0) {
 		pr_err("mem_unmap op[0x%x]rc[%d]\n",
@@ -3206,7 +3225,13 @@
 	rc = wait_event_timeout(ac->cmd_wait,
 			(atomic_read(&ac->cmd_state) == 0), 5 * HZ);
 	if (!rc) {
-		pr_err("timeout. waited for memory_unmap\n");
+		pr_err("%s timeout. waited for memory_unmap of handle 0x%x\n",
+			__func__, mem_unmap.mem_map_handle);
+		rc = -ETIMEDOUT;
+		goto fail_cmd;
+	} else if (atomic_read(&ac->unmap_cb_success) == 0) {
+		pr_err("%s Error in mem unmap callback of handle 0x%x\n",
+			__func__, mem_unmap.mem_map_handle);
 		rc = -EINVAL;
 		goto fail_cmd;
 	}
@@ -3366,6 +3391,7 @@
 	port = &ac->port[dir];
 	buf_add = (uint32_t)port->buf->phys;
 	mem_unmap.hdr.opcode = ASM_CMD_SHARED_MEM_UNMAP_REGIONS;
+	mem_unmap.mem_map_handle = 0;
 	list_for_each_safe(ptr, next, &ac->port[dir].mem_map_handle) {
 		buf_node = list_entry(ptr, struct asm_buffer_node,
 						list);
@@ -3378,6 +3404,12 @@
 
 	pr_debug("%s: mem_unmap-mem_map_handle: 0x%x",
 			__func__, mem_unmap.mem_map_handle);
+
+	if (mem_unmap.mem_map_handle == 0) {
+		pr_err("%s Do not send null mem handle to DSP\n", __func__);
+		rc = 0;
+		goto fail_cmd;
+	}
 	rc = apr_send_pkt(ac->mmap_apr, (uint32_t *) &mem_unmap);
 	if (rc < 0) {
 		pr_err("mmap_regions op[0x%x]rc[%d]\n",
@@ -3388,7 +3420,14 @@
 	rc = wait_event_timeout(ac->cmd_wait,
 			(atomic_read(&ac->cmd_state) == 0), 5*HZ);
 	if (!rc) {
-		pr_err("timeout. waited for memory_unmap\n");
+		pr_err("%s timeout. waited for memory_unmap of handle 0x%x\n",
+			__func__, mem_unmap.mem_map_handle);
+		rc = -ETIMEDOUT;
+		goto fail_cmd;
+	} else if (atomic_read(&ac->unmap_cb_success) == 0) {
+		pr_err("%s Error in mem unmap callback of handle 0x%x\n",
+			__func__, mem_unmap.mem_map_handle);
+		rc = -EINVAL;
 		goto fail_cmd;
 	}
 	rc = 0;
diff --git a/sound/soc/soc-dapm.c b/sound/soc/soc-dapm.c
index 56efb97..796d6b4 100644
--- a/sound/soc/soc-dapm.c
+++ b/sound/soc/soc-dapm.c
@@ -2102,8 +2102,10 @@
 {
 	struct snd_soc_dapm_widget *w = dapm_find_widget(dapm, pin, true);
 
+	mutex_lock_nested(&dapm->card->dapm_mutex, SND_SOC_DAPM_CLASS_PCM);
 	if (!w) {
 		dev_err(dapm->dev, "dapm: unknown pin %s\n", pin);
+		mutex_unlock(&dapm->card->dapm_mutex);
 		return -EINVAL;
 	}
 
@@ -2112,6 +2114,7 @@
 		w->force = 0;
 	dapm_mark_dirty(w, "pin configuration");
 
+	mutex_unlock(&dapm->card->dapm_mutex);
 	return 0;
 }
 
@@ -3101,7 +3104,7 @@
 
 	dev_dbg(rtd->dev, "rtd stream %d event %d\n", stream, event);
 
-	mutex_lock_nested(&card->dapm_mutex, SND_SOC_DAPM_CLASS_RUNTIME);
+	mutex_lock_nested(&card->dapm_mutex, SND_SOC_DAPM_CLASS_PCM);
 	if (stream == SNDRV_PCM_STREAM_PLAYBACK) {
 		widget_stream_event(pdapm, rtd->cpu_dai->playback_aif, event);
 		widget_stream_event(cdapm, rtd->codec_dai->playback_aif, event);
@@ -3186,8 +3189,10 @@
 {
 	struct snd_soc_dapm_widget *w = dapm_find_widget(dapm, pin, true);
 
+	mutex_lock_nested(&dapm->card->dapm_mutex, SND_SOC_DAPM_CLASS_PCM);
 	if (!w) {
 		dev_err(dapm->dev, "dapm: unknown pin %s\n", pin);
+		mutex_unlock(&dapm->card->dapm_mutex);
 		return -EINVAL;
 	}
 
@@ -3195,6 +3200,7 @@
 	w->connected = 1;
 	w->force = 1;
 	dapm_mark_dirty(w, "force enable");
+	mutex_unlock(&dapm->card->dapm_mutex);
 
 	return 0;
 }